0ddbc61a56f9aa305d1221b2b919b1e074ddc7d4
[rsync.git] / loadparm.c
1 /* This is based on loadparm.c from Samba, written by Andrew Tridgell
2    and Karl Auer */
3
4 /* 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /*
21  *  Load parameters.
22  *
23  *  This module provides suitable callback functions for the params
24  *  module. It builds the internal table of service details which is
25  *  then used by the rest of the server.
26  *
27  * To add a parameter:
28  *
29  * 1) add it to the global or service structure definition
30  * 2) add it to the parm_table
31  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
32  * 4) If it's a global then initialise it in init_globals. If a local
33  *    (ie. service) parameter then initialise it in the sDefault structure
34  *  
35  *
36  * Notes:
37  *   The configuration file is processed sequentially for speed. It is NOT
38  *   accessed randomly as happens in 'real' Windows. For this reason, there
39  *   is a fair bit of sequence-dependent code here - ie., code which assumes
40  *   that certain things happen before others. In particular, the code which
41  *   happens at the boundary between sections is delicately poised, so be
42  *   careful!
43  *
44  */
45
46 #include "rsync.h"
47 #define BOOL int
48 #define False 0
49 #define True 1
50 #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
51 #define strequal(a,b) (strcasecmp(a,b)==0)
52 #define BOOLSTR(b) ((b) ? "Yes" : "No")
53 typedef char pstring[1024];
54 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
55
56 /* the following are used by loadparm for option lists */
57 typedef enum
58 {
59         P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
60         P_STRING,P_GSTRING,P_ENUM,P_SEP
61 } parm_type;
62
63 typedef enum
64 {
65         P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
66 } parm_class;
67
68 struct enum_list {
69         int value;
70         char *name;
71 };
72
73 struct parm_struct
74 {
75         char *label;
76         parm_type type;
77         parm_class class;
78         void *ptr;
79         struct enum_list *enum_list;
80         unsigned flags;
81 };
82
83 static BOOL bLoaded = False;
84
85 #ifndef GLOBAL_NAME
86 #define GLOBAL_NAME "global"
87 #endif
88
89 /* some helpful bits */
90 #define pSERVICE(i) ServicePtrs[i]
91 #define iSERVICE(i) (*pSERVICE(i))
92 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
93
94 /* 
95  * This structure describes global (ie., server-wide) parameters.
96  */
97 typedef struct
98 {
99         char *motd_file;
100         char *lock_file;
101         int syslog_facility;
102         int max_connections;
103         char *socket_options;
104 } global;
105
106 static global Globals;
107
108
109
110 /* 
111  * This structure describes a single service. 
112  */
113 typedef struct
114 {
115         char *name;
116         char *path;
117         char *comment;
118         BOOL read_only;
119         BOOL list;
120         char *uid;
121         char *gid;
122         char *hosts_allow;
123         char *hosts_deny;
124         char *auth_users;
125         char *secrets_file;
126         char *exclude;
127         char *exclude_from;
128 } service;
129
130
131 /* This is a default service used to prime a services structure */
132 static service sDefault = 
133 {
134         NULL,    /* name */
135         NULL,    /* path */
136         NULL,    /* comment */
137         True,    /* read only */
138         True,    /* list */
139         "nobody",/* uid */
140         "nobody",/* gid */
141         NULL,    /* hosts allow */
142         NULL,    /* hosts deny */
143         NULL,    /* auth users */
144         NULL,    /* secrets file */
145         NULL,    /* exclude */
146         NULL,    /* exclude from */
147 };
148
149
150
151 /* local variables */
152 static service **ServicePtrs = NULL;
153 static int iNumServices = 0;
154 static int iServiceIndex = 0;
155 static BOOL bInGlobalSection = True;
156
157 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
158
159 static struct enum_list enum_facilities[] = {
160 #ifdef LOG_AUTH
161         { LOG_AUTH, "auth" },
162 #endif
163 #ifdef LOG_AUTHPRIV
164         { LOG_AUTHPRIV, "authpriv" },
165 #endif
166 #ifdef LOG_CRON
167         { LOG_CRON, "cron" },
168 #endif
169 #ifdef LOG_DAEMON
170         { LOG_DAEMON, "daemon" },
171 #endif
172 #ifdef LOG_FTP
173         { LOG_FTP, "ftp" },
174 #endif
175 #ifdef LOG_KERN
176         { LOG_KERN, "kern" },
177 #endif
178 #ifdef LOG_LPR
179         { LOG_LPR, "lpr" },
180 #endif
181 #ifdef LOG_MAIL
182         { LOG_MAIL, "mail" },
183 #endif
184 #ifdef LOG_NEWS
185         { LOG_NEWS, "news" },
186 #endif
187 #ifdef LOG_AUTH
188         { LOG_AUTH, "security" },               
189 #endif
190 #ifdef LOG_SYSLOG
191         { LOG_SYSLOG, "syslog" },
192 #endif
193 #ifdef LOG_USER
194         { LOG_USER, "user" },
195 #endif
196 #ifdef LOG_UUCP
197         { LOG_UUCP, "uucp" },
198 #endif
199 #ifdef LOG_LOCAL0
200         { LOG_LOCAL0, "local0" },
201 #endif
202 #ifdef LOG_LOCAL1
203         { LOG_LOCAL1, "local1" },
204 #endif
205 #ifdef LOG_LOCAL2
206         { LOG_LOCAL2, "local2" },
207 #endif
208 #ifdef LOG_LOCAL3
209         { LOG_LOCAL3, "local3" },
210 #endif
211 #ifdef LOG_LOCAL4
212         { LOG_LOCAL4, "local4" },
213 #endif
214 #ifdef LOG_LOCAL5
215         { LOG_LOCAL5, "local5" },
216 #endif
217 #ifdef LOG_LOCAL6
218         { LOG_LOCAL6, "local6" },
219 #endif
220 #ifdef LOG_LOCAL7
221         { LOG_LOCAL7, "local7" },
222 #endif
223         { -1, NULL }};
224
225
226 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
227 static struct parm_struct parm_table[] =
228 {
229   {"max connections",  P_INTEGER, P_GLOBAL, &Globals.max_connections,NULL, 0},
230   {"motd file",        P_STRING,  P_GLOBAL, &Globals.motd_file,    NULL,   0},
231   {"lock file",        P_STRING,  P_GLOBAL, &Globals.lock_file,    NULL,   0},
232   {"syslog facility",  P_ENUM,    P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
233   {"socket options",   P_STRING,  P_GLOBAL, &Globals.socket_options,NULL,  0},
234
235   {"name",             P_STRING,  P_LOCAL,  &sDefault.name,        NULL,   0},
236   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,     NULL,   0},
237   {"path",             P_STRING,  P_LOCAL,  &sDefault.path,        NULL,   0},
238   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.read_only,   NULL,   0},
239   {"list",             P_BOOL,    P_LOCAL,  &sDefault.list,        NULL,   0},
240   {"uid",              P_STRING,  P_LOCAL,  &sDefault.uid,         NULL,   0},
241   {"gid",              P_STRING,  P_LOCAL,  &sDefault.gid,         NULL,   0},
242   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.hosts_allow, NULL,   0},
243   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.hosts_deny,  NULL,   0},
244   {"auth users",       P_STRING,  P_LOCAL,  &sDefault.auth_users,  NULL,   0},
245   {"secrets file",     P_STRING,  P_LOCAL,  &sDefault.secrets_file,NULL,   0},
246   {"exclude",          P_STRING,  P_LOCAL,  &sDefault.exclude,     NULL,   0},
247   {"exclude from",     P_STRING,  P_LOCAL,  &sDefault.exclude_from,NULL,   0},
248   {NULL,               P_BOOL,    P_NONE,   NULL,                  NULL,   0}
249 };
250
251
252 /***************************************************************************
253 Initialise the global parameter structure.
254 ***************************************************************************/
255 static void init_globals(void)
256 {
257         memset(&Globals, 0, sizeof(Globals));
258 #ifdef LOG_DAEMON
259         Globals.syslog_facility = LOG_DAEMON;
260 #endif
261         Globals.lock_file = "/var/run/rsyncd.lock";
262 }
263
264 /***************************************************************************
265 Initialise the sDefault parameter structure.
266 ***************************************************************************/
267 static void init_locals(void)
268 {
269 }
270
271
272 /*
273    In this section all the functions that are used to access the 
274    parameters from the rest of the program are defined 
275 */
276
277 #define FN_GLOBAL_STRING(fn_name,ptr) \
278  char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
279 #define FN_GLOBAL_BOOL(fn_name,ptr) \
280  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
281 #define FN_GLOBAL_CHAR(fn_name,ptr) \
282  char fn_name(void) {return(*(char *)(ptr));}
283 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
284  int fn_name(void) {return(*(int *)(ptr));}
285
286 #define FN_LOCAL_STRING(fn_name,val) \
287  char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
288 #define FN_LOCAL_BOOL(fn_name,val) \
289  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
290 #define FN_LOCAL_CHAR(fn_name,val) \
291  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
292 #define FN_LOCAL_INTEGER(fn_name,val) \
293  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
294
295
296 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
297 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
298 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
299 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
300 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
301
302 FN_LOCAL_STRING(lp_name, name)
303 FN_LOCAL_STRING(lp_comment, comment)
304 FN_LOCAL_STRING(lp_path, path)
305 FN_LOCAL_BOOL(lp_read_only, read_only)
306 FN_LOCAL_BOOL(lp_list, list)
307 FN_LOCAL_STRING(lp_uid, uid)
308 FN_LOCAL_STRING(lp_gid, gid)
309 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
310 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
311 FN_LOCAL_STRING(lp_auth_users, auth_users)
312 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
313 FN_LOCAL_STRING(lp_exclude, exclude)
314 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
315
316 /* local prototypes */
317 static int    strwicmp( char *psz1, char *psz2 );
318 static int    map_parameter( char *parmname);
319 static BOOL   set_boolean( BOOL *pb, char *parmvalue );
320 static int    getservicebyname(char *name, service *pserviceDest);
321 static void   copy_service( service *pserviceDest, 
322                             service *pserviceSource);
323 static BOOL   do_parameter(char *parmname, char *parmvalue);
324 static BOOL   do_section(char *sectionname);
325
326
327 /***************************************************************************
328 initialise a service to the defaults
329 ***************************************************************************/
330 static void init_service(service *pservice)
331 {
332         bzero((char *)pservice,sizeof(service));
333         copy_service(pservice,&sDefault);
334 }
335
336 static void string_set(char **s, char *v)
337 {
338         if (!v) {
339                 *s = NULL;
340                 return;
341         }
342         *s = strdup(v);
343         if (!*s) exit_cleanup(1);
344 }
345
346
347 /***************************************************************************
348 add a new service to the services array initialising it with the given 
349 service
350 ***************************************************************************/
351 static int add_a_service(service *pservice, char *name)
352 {
353   int i;
354   service tservice;
355   int num_to_alloc = iNumServices+1;
356
357   tservice = *pservice;
358
359   /* it might already exist */
360   if (name) 
361     {
362       i = getservicebyname(name,NULL);
363       if (i >= 0)
364         return(i);
365     }
366
367   i = iNumServices;
368
369   if (ServicePtrs) {
370           ServicePtrs = (service **)realloc(ServicePtrs,
371                                             sizeof(service *)*num_to_alloc);
372   } else {
373           ServicePtrs = (service **)malloc(sizeof(service *)*num_to_alloc);
374   }
375
376   if (ServicePtrs)
377           pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
378
379   if (!ServicePtrs || !pSERVICE(iNumServices))
380           return(-1);
381
382   iNumServices++;
383
384   init_service(pSERVICE(i));
385   copy_service(pSERVICE(i),&tservice);
386   if (name)
387     string_set(&iSERVICE(i).name,name);  
388
389   return(i);
390 }
391
392 /***************************************************************************
393 Do a case-insensitive, whitespace-ignoring string compare.
394 ***************************************************************************/
395 static int strwicmp(char *psz1, char *psz2)
396 {
397    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
398    /* appropriate value. */
399    if (psz1 == psz2)
400       return (0);
401    else
402       if (psz1 == NULL)
403          return (-1);
404       else
405           if (psz2 == NULL)
406               return (1);
407
408    /* sync the strings on first non-whitespace */
409    while (1)
410    {
411       while (isspace(*psz1))
412          psz1++;
413       while (isspace(*psz2))
414          psz2++;
415       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
416          break;
417       psz1++;
418       psz2++;
419    }
420    return (*psz1 - *psz2);
421 }
422
423 /***************************************************************************
424 Map a parameter's string representation to something we can use. 
425 Returns False if the parameter string is not recognised, else TRUE.
426 ***************************************************************************/
427 static int map_parameter(char *parmname)
428 {
429    int iIndex;
430
431    if (*parmname == '-')
432      return(-1);
433
434    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
435       if (strwicmp(parm_table[iIndex].label, parmname) == 0)
436          return(iIndex);
437
438    rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
439    return(-1);
440 }
441
442
443 /***************************************************************************
444 Set a boolean variable from the text value stored in the passed string.
445 Returns True in success, False if the passed string does not correctly 
446 represent a boolean.
447 ***************************************************************************/
448 static BOOL set_boolean(BOOL *pb, char *parmvalue)
449 {
450    BOOL bRetval;
451
452    bRetval = True;
453    if (strwicmp(parmvalue, "yes") == 0 ||
454        strwicmp(parmvalue, "true") == 0 ||
455        strwicmp(parmvalue, "1") == 0)
456       *pb = True;
457    else
458       if (strwicmp(parmvalue, "no") == 0 ||
459           strwicmp(parmvalue, "False") == 0 ||
460           strwicmp(parmvalue, "0") == 0)
461          *pb = False;
462       else
463       {
464          rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
465                parmvalue);
466          bRetval = False;
467       }
468    return (bRetval);
469 }
470
471 /***************************************************************************
472 Find a service by name. Otherwise works like get_service.
473 ***************************************************************************/
474 static int getservicebyname(char *name, service *pserviceDest)
475 {
476    int iService;
477
478    for (iService = iNumServices - 1; iService >= 0; iService--)
479       if (strwicmp(iSERVICE(iService).name, name) == 0) 
480       {
481          if (pserviceDest != NULL)
482            copy_service(pserviceDest, pSERVICE(iService));
483          break;
484       }
485
486    return (iService);
487 }
488
489
490
491 /***************************************************************************
492 Copy a service structure to another
493
494 ***************************************************************************/
495 static void copy_service(service *pserviceDest, 
496                          service *pserviceSource)
497 {
498   int i;
499
500   for (i=0;parm_table[i].label;i++)
501     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
502         void *def_ptr = parm_table[i].ptr;
503         void *src_ptr = 
504           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
505         void *dest_ptr = 
506           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
507
508         switch (parm_table[i].type)
509           {
510           case P_BOOL:
511           case P_BOOLREV:
512             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
513             break;
514
515           case P_INTEGER:
516           case P_ENUM:
517           case P_OCTAL:
518             *(int *)dest_ptr = *(int *)src_ptr;
519             break;
520
521           case P_CHAR:
522             *(char *)dest_ptr = *(char *)src_ptr;
523             break;
524
525           case P_STRING:
526             string_set(dest_ptr,*(char **)src_ptr);
527             break;
528
529           default:
530             break;
531           }
532       }
533 }
534
535
536 /***************************************************************************
537 Process a parameter for a particular service number. If snum < 0
538 then assume we are in the globals
539 ***************************************************************************/
540 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
541 {
542    int parmnum, i;
543    void *parm_ptr=NULL; /* where we are going to store the result */
544    void *def_ptr=NULL;
545
546    parmnum = map_parameter(parmname);
547
548    if (parmnum < 0)
549      {
550        rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
551        return(True);
552      }
553
554    def_ptr = parm_table[parmnum].ptr;
555
556    /* we might point at a service, the default service or a global */
557    if (snum < 0) {
558      parm_ptr = def_ptr;
559    } else {
560        if (parm_table[parmnum].class == P_GLOBAL) {
561            rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
562            return(True);
563          }
564        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
565    }
566
567    /* now switch on the type of variable it is */
568    switch (parm_table[parmnum].type)
569      {
570      case P_BOOL:
571        set_boolean(parm_ptr,parmvalue);
572        break;
573
574      case P_BOOLREV:
575        set_boolean(parm_ptr,parmvalue);
576        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
577        break;
578
579      case P_INTEGER:
580        *(int *)parm_ptr = atoi(parmvalue);
581        break;
582
583      case P_CHAR:
584        *(char *)parm_ptr = *parmvalue;
585        break;
586
587      case P_OCTAL:
588        sscanf(parmvalue,"%o",(int *)parm_ptr);
589        break;
590
591      case P_STRING:
592        string_set(parm_ptr,parmvalue);
593        break;
594
595      case P_GSTRING:
596        strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring)-1);
597        break;
598
599      case P_ENUM:
600              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
601                      if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
602                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
603                              break;
604                      }
605              }
606              if (!parm_table[parmnum].enum_list[i].name) {
607                      if (atoi(parmvalue) > 0)
608                              *(int *)parm_ptr = atoi(parmvalue);
609              }
610              break;
611      case P_SEP:
612              break;
613      }
614
615    return(True);
616 }
617
618 /***************************************************************************
619 Process a parameter.
620 ***************************************************************************/
621 static BOOL do_parameter(char *parmname, char *parmvalue)
622 {
623    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
624 }
625
626 /***************************************************************************
627 Process a new section (service). At this stage all sections are services.
628 Later we'll have special sections that permit server parameters to be set.
629 Returns True on success, False on failure.
630 ***************************************************************************/
631 static BOOL do_section(char *sectionname)
632 {
633    BOOL bRetval;
634    BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
635    bRetval = False;
636
637    /* if we were in a global section then do the local inits */
638    if (bInGlobalSection && !isglobal)
639      init_locals();
640
641    /* if we've just struck a global section, note the fact. */
642    bInGlobalSection = isglobal;   
643
644    /* check for multiple global sections */
645    if (bInGlobalSection)
646    {
647      return(True);
648    }
649
650    /* if we have a current service, tidy it up before moving on */
651    bRetval = True;
652
653    if (iServiceIndex >= 0)
654      bRetval = True;
655
656    /* if all is still well, move to the next record in the services array */
657    if (bRetval)
658      {
659        /* We put this here to avoid an odd message order if messages are */
660        /* issued by the post-processing of a previous section. */
661
662        if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
663          {
664            rprintf(FERROR,"Failed to add a new service\n");
665            return(False);
666          }
667      }
668
669    return (bRetval);
670 }
671
672
673 /***************************************************************************
674 Load the services array from the services file. Return True on success, 
675 False on failure.
676 ***************************************************************************/
677 BOOL lp_load(char *pszFname, int globals_only)
678 {
679         pstring n2;
680         BOOL bRetval;
681  
682         bRetval = False;
683
684         bInGlobalSection = True;
685   
686         init_globals();
687
688         pstrcpy(n2,pszFname);
689
690         /* We get sections first, so have to start 'behind' to make up */
691         iServiceIndex = -1;
692         bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
693   
694         bLoaded = True;
695
696         return (bRetval);
697 }
698
699
700 /***************************************************************************
701 return the max number of services
702 ***************************************************************************/
703 int lp_numservices(void)
704 {
705   return(iNumServices);
706 }
707
708 /***************************************************************************
709 Return the number of the service with the given name, or -1 if it doesn't
710 exist. Note that this is a DIFFERENT ANIMAL from the internal function
711 getservicebyname()! This works ONLY if all services have been loaded, and
712 does not copy the found service.
713 ***************************************************************************/
714 int lp_number(char *name)
715 {
716    int iService;
717
718    for (iService = iNumServices - 1; iService >= 0; iService--)
719       if (strequal(lp_name(iService), name)) 
720          break;
721
722    return (iService);
723 }
724