"Fossies" - the Fresh Open Source Software Archive

Member "smbnetfs-0.6.3/src/reconfigure.c" (31 Jan 2021, 20822 Bytes) of package /linux/misc/smbnetfs-0.6.3.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "reconfigure.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.6.2_vs_0.6.3.

    1 #include "config.h"
    2 #include <stdio.h>
    3 #include <stdlib.h>
    4 #include <errno.h>
    5 #include <string.h>
    6 #include <sys/types.h>
    7 #include <sys/stat.h>
    8 #include <unistd.h>
    9 #include <pwd.h>
   10 
   11 #include "common.h"
   12 #include "smbitem.h"
   13 #include "auth-libsecret.h"
   14 #include "auth.h"
   15 #include "process.h"
   16 #include "smb_conn.h"
   17 #include "samba.h"
   18 #include "stat_workaround.h"
   19 #include "function.h"
   20 #include "event.h"
   21 #include "neg_cache.h"
   22 #include "reconfigure.h"
   23 
   24 #define FIELD_MAX   4
   25 #define PATTERN_SIZE    20
   26 #define LINE_SIZE   200
   27 
   28 enum config_read_mode{
   29     DELIMITER,
   30     PLAIN,
   31     QUOTED
   32 };
   33 
   34 
   35 static const char   *config_dir_postfix = "/.smb";
   36 static char     config_file[256]    = "smbnetfs.conf";
   37 static char     config_dir[2048]    = "/";
   38 static int      config_cmd_opts_cnt = 0;
   39 static int      config_cmd_opts_max_cnt = 32;
   40 static char     **config_cmd_opts   = NULL;
   41 
   42 const char *smbnetfs_option_list =
   43     "    -o config=PATH               path to config (~/.smb/smbnetfs.conf)\n"
   44     "    -o smbnetfs_debug=N          SMBNetFS debug level (N<=10)\n"
   45     "    -o smb_debug_level=N         Samba debug level (N<=10)\n"
   46     "    -o log_file=PATH             File to store SMBNetFS debug messages\n"
   47     "    -o local_charset=CHARSET     Local charset (autodetected)\n"
   48     "    -o samba_charset=CHARSET     Charset used by samba (utf-8)\n"
   49 #ifdef HAVE_LIBSECRET
   50     "    -o use_libsecret=BOOL        Enable/disable usage of libsecret\n"
   51     "    -o libsecret_timeout=T       auth retrieving timeout for libsecrer (500ms)\n"
   52 #endif /* HAVE_LIBSECRET */
   53     "    -o max_rw_block_size=N       Maximum size of r/w block in Kb (autodetected)\n"
   54     "    -o smb_tree_scan_period=T    Period of scanning samba network tree (300s)\n"
   55     "    -o smb_tree_elements_ttl=T   TTL of scanned elements in samba tree (900s)\n"
   56     "    -o smb_query_browsers=BOOL   Enable/disable scanning of samba tree (on)\n"
   57     "    -o smb_timeout=T               Samba reply timeout (20000ms)\n"
   58     "    -o show_$_shares=BOOL        Enable/disable showing of hidden shares (off)\n"
   59     "    -o show_hidden_hosts=BOOL    See in documentation (off)\n"
   60     "    -o free_space_size=N         Free space size in pages (0)\n"
   61     "    -o quiet_flag=BOOL           Do not fail on chown/chgroup (on)\n"
   62     "    -o neg_cache=BOOL            Enable/disable negative cache (on)\n"
   63     "    -o neg_cache_timeout=T       Negative cache records expiration time (3000ms)\n"
   64     "    -o stat_workaround_depth=N   konquerror and gnome terminal hack (3)\n"
   65     "    -o time_step=T               Scheduler sleep interval (10s)\n"
   66     "    -o config_update_period=T    Configuration update interval (300s)\n"
   67     "    -o max_ctx_count=N           Maximum number of children processes (15)\n"
   68     "    -o max_retry_count=N         Number of retries before fail (2)\n"
   69     "    -o listen_timeout=T          Child process inactivity timeout (300s)\n"
   70     "    -o reply_timeout=T           Child process reply timeout (30s)\n"
   71     "    -o max_passwd_query_count=N  See in documentation (10)\n";
   72 
   73 
   74 static void reconfigure_set_config_dir(const char *path){
   75     struct stat buf;
   76 
   77     if (strlen(path) + 2 > sizeof(config_dir)){
   78     DPRINTF(5, "path too long\n");
   79     return;
   80     }
   81     strcpy(config_dir, path);
   82     if (path[strlen(path) - 1] != '/') strcat(config_dir, "/");
   83     if ((stat(config_dir, &buf) == 0) && S_ISDIR(buf.st_mode)){
   84     DPRINTF(5, "config_dir=%s\n", config_dir);
   85     return;
   86     }
   87     fprintf(stderr,
   88     "WARNING!!! Configuration directory %s is not found. Please create it.\n"
   89     "This directory should contain at least two files: smb.conf and smbnetfs.conf.\n"
   90     "You may copy smb.conf from the /etc/samba directory. You can find a sample of\n"
   91     "smbnetfs.conf in the doc directory of original SMBNetFS distribution.\n\n"
   92     "Using default settings for now.\n", path);
   93 }
   94 
   95 void reconfigure_set_default_login_and_configdir(void){
   96     char            buf[2048];
   97     register struct passwd  *pwd;
   98     const char          *home, *user, *dir;
   99 
  100     pwd = getpwuid(getuid());
  101 
  102     user = getenv("USER");
  103     if ((user == NULL) || (*user == '\0')) user = getenv("LOGNAME");
  104     if ((user == NULL) || (*user == '\0')){
  105     user = ((pwd != NULL) && 
  106             (pwd->pw_name != NULL) &&
  107             (*pwd->pw_name != '\0')) ? pwd->pw_name : "anonymous";
  108     setenv("USER", user, 1);
  109     setenv("LOGNAME", user, 1);
  110     }
  111     auth_set_default_login_name(user);
  112 
  113     home = getenv("HOME");
  114     if ((home == NULL) || (*home != '/')){
  115     home = ((pwd != NULL) && 
  116             (pwd->pw_dir  != NULL) &&
  117             (*pwd->pw_dir == '/')) ? pwd->pw_dir : "/";
  118     setenv("HOME", home, 1);
  119     }
  120 
  121     dir = config_dir_postfix;
  122     if (strlen(home) + strlen(dir) + 1 > sizeof(buf)) home = "/";
  123     strcpy(buf, home);
  124     strcat(buf, (home[strlen(home) - 1] == '/') ? dir + 1 : dir);
  125     reconfigure_set_config_dir(buf);
  126 }
  127 
  128 static int reconfigure_get_number(char *value, int *result){
  129     char *endptr;
  130 
  131     *result = strtol(value, &endptr, 0);
  132     if (*endptr == '\0') return 1;
  133     else return 0;
  134 }
  135 
  136 static int reconfigure_set_number(char *value, int (*func)(int)){
  137     int result;
  138 
  139     if (reconfigure_get_number(value, &result)) return func(result);
  140     else return 0;
  141 }
  142 
  143 static int reconfigure_get_size(char *value, size_t *result){
  144     char *endptr;
  145 
  146     *result = strtol(value, &endptr, 0);
  147     if (*endptr == '\0') return 1;
  148     else return 0;
  149 }
  150 
  151 static int reconfigure_set_kb_size(char *value, int (*func)(size_t)){
  152     size_t result;
  153 
  154     if (reconfigure_get_size(value, &result)) return func(result * 1024);
  155     else return 0;
  156 }
  157 
  158 static int reconfigure_get_boolean(char *value, int *result){
  159     if ((strcasecmp(value, "true") == 0) || (strcasecmp(value, "yes") == 0)){
  160     *result = 1;
  161     return 1;
  162     }
  163     if ((strcasecmp(value, "false") == 0) || (strcasecmp(value, "no") == 0)){
  164     *result = 0;
  165     return 1;
  166     }
  167     return 0;
  168 }
  169 
  170 static int reconfigure_set_boolean(char *value, int (*func)(int)){
  171     int result;
  172 
  173     if (reconfigure_get_boolean(value, &result)) return func(result);
  174     else return 0;
  175 }
  176 
  177 static int reconfigure_find_cmd_opt(const char *option){
  178     int i;
  179 
  180     for(i = 0; i < config_cmd_opts_cnt; i++){
  181     if (strcasecmp(config_cmd_opts[i], option) == 0) return 1;
  182     }
  183     return 0;
  184 }
  185 
  186 static int reconfigure_add_cmd_opt(const char *option){
  187     char    *opt;
  188     char    **new_ptr;
  189     int     new_max_cnt;
  190 
  191     if (reconfigure_find_cmd_opt(option)) return 1;
  192 
  193     if (config_cmd_opts == NULL){
  194     config_cmd_opts = malloc(16 * sizeof(char*));
  195     if (config_cmd_opts == NULL) return 0;
  196     config_cmd_opts_max_cnt = 16;
  197     }
  198     if (config_cmd_opts_cnt == config_cmd_opts_max_cnt){
  199     new_max_cnt = 2 * config_cmd_opts_max_cnt;
  200     new_ptr = realloc(config_cmd_opts, new_max_cnt * sizeof(char*));
  201     if (new_ptr == NULL) return 0;
  202 
  203     config_cmd_opts_max_cnt = new_max_cnt;
  204     config_cmd_opts = new_ptr;
  205     }
  206 
  207     opt = strdup(option);
  208     if (opt == NULL) return 0;
  209     config_cmd_opts[config_cmd_opts_cnt++] = opt;
  210     return 1;
  211 }
  212 
  213 static int reconfigure_split_line(const char *line,
  214                 char *arg[], size_t arg_len[], int arg_cnt){
  215 
  216     enum config_read_mode   mode;
  217     const char          *orig_line;
  218     char            quote_char;
  219     size_t          cur_arg_len;
  220     int             cnt;
  221 
  222     for(cnt = 0; cnt < arg_cnt; cnt++) memset(arg[cnt], 0, arg_len[cnt]);
  223 
  224     cnt = 0;
  225     orig_line = line;
  226     mode = DELIMITER;
  227     cur_arg_len = 0;
  228     quote_char = '\0';
  229     while(1){
  230     switch(mode){
  231         case DELIMITER:
  232         if ((*line == '\0') || (*line == '#')) return cnt;
  233         if ((*line == '\t') || (*line == ' ')){
  234             line++;
  235             continue;
  236         }
  237         mode = PLAIN;
  238         cur_arg_len = 0;
  239         if ((*line == '\'') || (*line == '"')){
  240             mode = QUOTED;
  241             quote_char = *line++;
  242         }
  243         continue;
  244 
  245         case PLAIN:
  246         if (*line == '\0') return cnt + 1;
  247         if ((*line == '\t') || (*line == ' ')){
  248             mode = DELIMITER;
  249             cnt++;
  250             continue;
  251         }
  252         break;
  253 
  254         case QUOTED:
  255         if (*line == '\0') return -(line - orig_line + 1);
  256         if (*line == quote_char){
  257             line++;
  258             if ((*line != ' ' ) &&
  259             (*line != '\t') &&
  260             (*line != '\0')) return -(line - orig_line + 1);;
  261             mode = DELIMITER;
  262             cnt++;
  263             continue;
  264         }
  265         if ((*line == '\\') &&
  266             ((*(line + 1) == '\\') ||
  267              (*(line + 1) == quote_char))) line++;
  268         break;
  269 
  270         default:
  271         return -(line - orig_line + 1);
  272     }
  273 
  274     if (cnt < arg_cnt){
  275         if (cur_arg_len + 1 >= arg_len[cnt]) return -(line - orig_line + 1);
  276         arg[cnt][cur_arg_len++] = *line;
  277     }
  278     line++;
  279     }
  280     return -1;
  281 }
  282 
  283 static int reconfigure_analyse_simple_option(const char *option, char *value, int flags){
  284     if ( ! (flags & CONFIG_OPT_CMDLINE) && reconfigure_find_cmd_opt(option)){
  285     DPRINTF(8, "ignore overriding of command line option '%s'.\n", option);
  286     return 1;
  287     }
  288 
  289     /* common.h */
  290     if (strcasecmp(option, "smbnetfs_debug") == 0)
  291     return reconfigure_set_number(value, common_set_smbnetfs_debug_level);
  292     if (strcasecmp(option, "log_file") == 0)
  293         return common_set_log_file(value);
  294 
  295 #ifdef HAVE_LIBSECRET
  296     /* auth-libsecret.h */
  297     if (strcasecmp(option, "use_libsecret") == 0)
  298     return reconfigure_set_boolean(value, libsecret_enable);
  299     if (strcasecmp(option, "libsecret_timeout") == 0)
  300     return reconfigure_set_number(value, libsecret_set_request_timeout);
  301 #endif /* HAVE_LIBSECRET */
  302 
  303     /* process.h */
  304     if (strcasecmp(option, "listen_timeout") == 0)
  305     return reconfigure_set_number(value, process_set_server_listen_timeout);
  306     if (strcasecmp(option, "smb_timeout") == 0)
  307     return reconfigure_set_number(value, process_set_server_smb_timeout);
  308     if (strcasecmp(option, "smb_debug_level") == 0)
  309     return reconfigure_set_number(value, process_set_server_smb_debug_level);
  310     if (strcasecmp(option, "local_charset") == 0)
  311     return process_set_server_local_charset(value);
  312     if (strcasecmp(option, "samba_charset") == 0)
  313     return process_set_server_samba_charset(value);
  314 
  315     /* smb_conn.h */
  316     if (strcasecmp(option, "max_retry_count") == 0)
  317     return reconfigure_set_number(value, smb_conn_set_max_retry_count);
  318     if (strcasecmp(option, "max_passwd_query_count") == 0)
  319     return reconfigure_set_number(value, smb_conn_set_max_passwd_query_count);
  320     if (strcasecmp(option, "reply_timeout") == 0)
  321     return reconfigure_set_number(value, smb_conn_set_server_reply_timeout);
  322 
  323     /* samba.h */
  324     if (strcasecmp(option, "max_rw_block_size") == 0){
  325     if ( ! (flags & CONFIG_OPT_STARTUP)) return 1;  /* ignore this option*/
  326     return reconfigure_set_kb_size(value, samba_init);
  327     }
  328     if (strcasecmp(option, "max_ctx_count") == 0)
  329     return reconfigure_set_number(value, samba_set_max_ctx_count);
  330 
  331     /* event.h */
  332     if (strcasecmp(option, "time_step") == 0)
  333     return reconfigure_set_number(value, event_set_time_step);
  334     if (strcasecmp(option, "smb_tree_scan_period") == 0)
  335     return reconfigure_set_number(value, event_set_smb_tree_scan_period);
  336     if (strcasecmp(option, "smb_tree_elements_ttl") == 0)
  337     return reconfigure_set_number(value, event_set_smb_tree_elements_ttl);
  338     if (strcasecmp(option, "config_update_period") == 0)
  339     return reconfigure_set_number(value, event_set_config_update_period);
  340     if (strcasecmp(option, "smb_query_browsers") == 0)
  341     return reconfigure_set_boolean(value, event_set_query_browser_flag);
  342 
  343     /* stat_workaround.h */
  344     if (strcasecmp(option, "stat_workaround_depth") == 0)
  345     return reconfigure_set_number(value, stat_workaround_set_default_depth);
  346     if (strcasecmp(option, "stat_workaround_enable_default_entries") == 0)
  347     return reconfigure_set_boolean(value, stat_workaround_enable_default_entries);
  348 
  349     /* function.h */
  350     if (strcasecmp(option, "free_space_size") == 0)
  351     return reconfigure_set_number(value, function_set_free_space_size);
  352     if (strcasecmp(option, "quiet_flag") == 0)
  353     return reconfigure_set_boolean(value, function_set_quiet_flag);
  354     if (strcasecmp(option, "show_$_shares") == 0)
  355     return reconfigure_set_boolean(value, function_set_dollar_share_visibility);
  356     if (strcasecmp(option, "show_hidden_hosts") == 0)
  357     return reconfigure_set_boolean(value, function_set_hidden_hosts_visibility);
  358     if (strcasecmp(option, "noexec_attr") == 0)
  359     return reconfigure_set_boolean(value, function_set_noexec_attr);
  360 
  361 
  362     /* neg_cache.h */
  363     if (strcasecmp(option, "neg_cache") == 0)
  364     return reconfigure_set_boolean(value, neg_cache_enable);
  365     if (strcasecmp(option, "neg_cache_timeout") == 0)
  366     return reconfigure_set_number(value, neg_cache_set_timeout);
  367 
  368     /* unknown option */
  369     return 0;
  370 }
  371 
  372 int reconfigure_analyse_cmdline_option(const char *option, char *value){
  373     int     ret;
  374 
  375     if (reconfigure_find_cmd_opt(option))
  376     fprintf(stderr, "WARNING: duplicate option '%s' found.\n", option);
  377 
  378     if (strcmp(option, "config") == 0){
  379     char    *pos, *name, path[2048];
  380     size_t  len;
  381 
  382     len = 0;
  383     memset(path, 0, sizeof(path));
  384     if (*value != '/'){
  385         if (getcwd(path, sizeof(path) - 1) == NULL) goto error;
  386 
  387         len = strlen(path);
  388         if (path[len - 1] != '/'){
  389         if (len + 2 > sizeof(path)) goto error;
  390         strcat(path, "/");
  391         len++;
  392         }
  393     }
  394 
  395     name = value;
  396     if ((pos = strrchr(name, '/')) != NULL){
  397         pos++;
  398         if (len + (pos - name) + 1 > sizeof(path)) goto error;
  399         strncat(path, name, pos - name);
  400         name = pos;
  401     }
  402     if (*name == '\0') goto error;
  403 
  404     /* set config dir */
  405     if (strlen(path) + 1  > sizeof(config_dir))  goto error;
  406     reconfigure_set_config_dir(path);
  407 
  408     /* set config file name */
  409     if (strlen(name) + 1 > sizeof(config_file)) goto error;
  410     strcpy(config_file, name);
  411     reconfigure_add_cmd_opt(option);
  412     return 1;
  413 
  414       error:
  415     reconfigure_add_cmd_opt(option);
  416     fprintf(stderr, "Can't set alternative configuration file '%s'.\nUse default one instead.\n", value);
  417     return 1;
  418     }
  419 
  420     ret = reconfigure_analyse_simple_option(option, value,
  421             (CONFIG_OPT_STARTUP | CONFIG_OPT_CMDLINE));
  422     if (ret == 1) reconfigure_add_cmd_opt(option);
  423     return ret;
  424 }
  425 
  426 /*===========================================================*/
  427 /* WARNING: the value[i] can be changed inside this function */
  428 /*===========================================================*/
  429 static int reconfigure_parse_auth_option(char *value[], int count){
  430     char    *comp = "", *share = "";
  431     char    *domain = "", *user, *password;
  432     int     user_pos = 0;
  433 
  434     if ((count < 2) || (count > 3)) return 0;
  435 
  436     /* server and share */
  437     if (count == 3){
  438     if (*value[0] == '/') return 0;
  439 
  440     user_pos = 1;
  441     comp = value[0];
  442     if ((share = strchr(comp, '/')) != NULL){
  443         *share++ = '\0';
  444         if ((*share == '\0') || (strchr(share, '/') != NULL)) return 0;
  445     }else{
  446         share = "";
  447     }
  448     };
  449 
  450     /* domain and user */
  451     if (*value[user_pos] == '/') return 0;
  452     if ((user = strchr(value[user_pos], '/')) != NULL){
  453     domain = value[user_pos];
  454     *user++ = '\0';
  455     if ((*user == '\0') || (strchr(user, '/') != NULL)) return 0;
  456     }else{
  457     user = value[user_pos];
  458     }
  459 
  460     /* password */
  461     password = value[user_pos + 1];
  462 
  463     return (auth_store_auth_data(comp, share, domain, user, password) == 0);
  464 }
  465 
  466 static int reconfigure_parse_stat_workaround_name_option(char *value[], int count){
  467     const char  *case_ptn   = "case_sensitive=";
  468     const char  *depth_ptn  = "depth=";
  469     int     case_sensitive  = -1;
  470     int     depth       = -2;
  471     int     i;
  472     size_t  len;
  473 
  474     if ((count < 1) || (count > 3)) return 0;
  475 
  476     for(i = 1; i < count; i++){
  477     len = strlen(case_ptn);
  478     if (strncasecmp(value[i], case_ptn, len) == 0){
  479         if (case_sensitive != -1) return 0;
  480         if (! reconfigure_get_boolean(value[i] + len, &case_sensitive))
  481         return 0;
  482     }
  483     len = strlen(depth_ptn);
  484     if (strncasecmp(value[i], depth_ptn, len) == 0){
  485         if (depth != -2) return 0;
  486         if (! reconfigure_get_number(value[i] + len, &depth))
  487         return 0;
  488     }
  489     }
  490     if (case_sensitive == -1) case_sensitive = 1;
  491 
  492     return stat_workaround_add_name(value[0], case_sensitive, depth);
  493 }
  494 
  495 static int reconfigure_parse_host_option(char *value[], int count){
  496     const char  *group_ptn  = "parent_group=";
  497     const char  *visible_ptn    = "visible=";
  498     const char  *parent_group   = NULL;
  499     int     visibility  = -1;
  500     int     i;
  501     size_t  len;
  502 
  503     if ((count < 1) || (count > 3)) return 0;
  504 
  505     if (strchr(value[0], '/') != NULL) return 0;
  506 
  507     for(i = 1; i < count; i++){
  508     len = strlen(group_ptn);
  509     if (strncasecmp(value[i], group_ptn, len) == 0){
  510         if (parent_group != NULL) return 0;
  511         parent_group = value[i] + len;
  512         if ((*parent_group == '\0') ||
  513         (strchr(parent_group, '/') != NULL)) return 0;
  514     }
  515     len = strlen(visible_ptn);
  516     if (strncasecmp(value[i], visible_ptn, len) == 0){
  517         if (visibility != -1) return 0;
  518         if (! reconfigure_get_boolean(value[i] + len, &visibility))
  519         return 0;
  520     }
  521     }
  522     if (visibility == -1) visibility = 0;
  523 
  524     return (smbitem_mkhost(value[0], parent_group,
  525             !visibility, SMBITEM_USER_TREE) == 0);
  526 }
  527 
  528 static int reconfigure_parse_link_option(char *value[], int count){
  529     char    *name;
  530     int     result;
  531 
  532     if ((count < 1) || (count > 2)) return 0;
  533     if (*value[0] == '/') return 0;
  534 
  535     name = strchr(value[0], '/');
  536     if (name == NULL){
  537     if (*value[1] == '\0') return 0;
  538     }else{
  539     name++;
  540     if ((*name == '\0') || (strchr(name, '/') != NULL)) return 0;
  541     }
  542 
  543     if (*value[1] == '\0'){
  544     char    *link = malloc(strlen(name) + 4);
  545 
  546     if (link == NULL) return 0;
  547     strcpy(link, "../");
  548     strcat(link, name);
  549     result = (smbitem_mklink(value[0], link, SMBITEM_USER_TREE) == 0);
  550     free(link);
  551     }else{
  552     result = (smbitem_mklink(value[0], value[1], SMBITEM_USER_TREE) == 0);
  553     }
  554     return result;
  555 }
  556 
  557 static int reconfigure_parse_group_option(char *value[], int count){
  558     if (count != 1) return 0;
  559     if (strchr(value[0], '/') != NULL) return 0;
  560     return (smbitem_mkgroup(value[0], SMBITEM_USER_TREE) == 0);
  561 }
  562 
  563 static int reconfigure_read_config_file(const char *filename, int flags){
  564     FILE    *file;
  565     int     cnt, ok_permission;
  566     char    s[LINE_SIZE];
  567     char    pattern[PATTERN_SIZE];
  568     char    fields[FIELD_MAX][LINE_SIZE], *arg[FIELD_MAX];
  569     size_t  arg_len[FIELD_MAX];
  570     struct stat st;
  571 
  572     if ((filename == NULL) || (*filename == '\0')){
  573     errno = EINVAL;
  574     return -1;
  575     }
  576     if (*filename == '/'){
  577     if ((filename = strdup(filename)) == NULL) return -1;
  578     }else{
  579     char *tmp = malloc(strlen(config_dir) + strlen(filename) + 1);
  580     if (tmp == NULL) return -1;
  581     strcpy(tmp, config_dir);
  582     strcat(tmp, filename);
  583     filename = tmp;
  584     }
  585 
  586     for(cnt = 0; cnt < FIELD_MAX; cnt++){
  587     arg[cnt]     = fields[cnt];
  588     arg_len[cnt] = LINE_SIZE;
  589     }
  590     snprintf(pattern, sizeof(pattern), "%%%zd[^\n]\n", sizeof(s) - 1);
  591 
  592     DPRINTF(7, "reading file: %s\n", filename);
  593     if ((file = fopen(filename, "r")) == NULL){
  594     int error = errno;
  595     DPRINTF(3, "Open file %s error : %s.\n", filename, strerror(error));
  596     free((char *) filename);
  597     errno = error;
  598     return -1;
  599     }
  600 
  601     ok_permission = 0;
  602     if (fstat(fileno(file), &st) == 0)
  603     ok_permission = ((st.st_uid == getuid()) && ((st.st_mode & 0177) == 0));
  604     else DPRINTF(3, "Stat file %s error : %s\n", filename, strerror(errno));
  605 
  606     fscanf(file, "%[\n]", s);
  607     while(!feof(file)){
  608     memset(s, 0, sizeof(s));
  609     fscanf(file, pattern, s);
  610     cnt = reconfigure_split_line(s, arg, arg_len, FIELD_MAX);
  611     if (cnt < 0){
  612         DPRINTF(0, "Error: (file: %s), Syntax error at pos=%d in line : %s\n", filename, -(cnt + 1), s);
  613         continue;
  614     }
  615     if (cnt == 0) continue;
  616 
  617     if (strcasecmp(arg[0], "stat_workaround_name") == 0){
  618         if (reconfigure_parse_stat_workaround_name_option(arg + 1, cnt - 1)) continue;
  619     }
  620     if (strcasecmp(arg[0], "stat_workaround_exception") == 0){
  621         if ((cnt == 2) && stat_workaround_add_exception(arg[1])) continue;
  622     }
  623 
  624     if (cnt == 2){
  625         if (strcasecmp(arg[0], "include") == 0){
  626         reconfigure_read_config_file(arg[1], flags);
  627         continue;
  628         }
  629         if (reconfigure_analyse_simple_option(arg[0], arg[1], flags)) continue;
  630     }
  631 
  632     if (strcasecmp(arg[0], "auth") == 0){
  633         if (!ok_permission) goto insecure_permission;
  634         /* WARNING: this function can change the contents of arg[i] */
  635         if (reconfigure_parse_auth_option(arg + 1, cnt - 1)) continue;
  636     }
  637     if (strcasecmp(arg[0], "host") == 0){
  638         if (!ok_permission) goto insecure_permission;
  639         if (reconfigure_parse_host_option(arg + 1, cnt - 1)) continue;
  640     }
  641     if (strcasecmp(arg[0], "link") == 0){
  642         if (!ok_permission) goto insecure_permission;
  643         if (reconfigure_parse_link_option(arg + 1, cnt - 1)) continue;
  644     }
  645     if (strcasecmp(arg[0], "group") == 0){
  646         if (!ok_permission) goto insecure_permission;
  647         if (reconfigure_parse_group_option(arg + 1, cnt - 1)) continue;
  648     }
  649 
  650     DPRINTF(0, "Error: (file: %s) Invalid input line : %s\n", filename, s);
  651     continue;
  652     
  653       insecure_permission:
  654     DPRINTF(0, "Error: Insecure config file permission.\n"
  655         "Can't apply '%s' directive.\n"
  656         "Run 'chmod 600 %s' to fix it.\n", arg[0], filename);
  657         continue;
  658     }
  659     fclose(file);
  660     free((char *) filename);
  661     return 0;
  662 }
  663 
  664 int reconfigure_read_config(int flags){
  665     int status;
  666 
  667     status = reconfigure_read_config_file(config_file, flags);
  668     stat_workaround_add_default_entries();
  669     return status;
  670 }