- changed the log messages to show the requested path
[rsync/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 Realloc realloc
51 #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
52 #define strequal(a,b) (strcasecmp(a,b)==0)
53 #define BOOLSTR(b) ((b) ? "Yes" : "No")
54 typedef char pstring[1024];
55 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
56
57 /* the following are used by loadparm for option lists */
58 typedef enum
59 {
60         P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
61         P_STRING,P_GSTRING,P_ENUM,P_SEP
62 } parm_type;
63
64 typedef enum
65 {
66         P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
67 } parm_class;
68
69 struct enum_list {
70         int value;
71         char *name;
72 };
73
74 struct parm_struct
75 {
76         char *label;
77         parm_type type;
78         parm_class class;
79         void *ptr;
80         struct enum_list *enum_list;
81         unsigned flags;
82 };
83
84 static BOOL bLoaded = False;
85
86 #ifndef GLOBAL_NAME
87 #define GLOBAL_NAME "global"
88 #endif
89
90 /* some helpful bits */
91 #define pSERVICE(i) ServicePtrs[i]
92 #define iSERVICE(i) (*pSERVICE(i))
93 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
94
95 /* 
96  * This structure describes global (ie., server-wide) parameters.
97  */
98 typedef struct
99 {
100         char *motd_file;
101         char *lock_file;
102         int syslog_facility;
103         int max_connections;
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
234   {"name",             P_STRING,  P_LOCAL,  &sDefault.name,        NULL,   0},
235   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,     NULL,   0},
236   {"path",             P_STRING,  P_LOCAL,  &sDefault.path,        NULL,   0},
237   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.read_only,   NULL,   0},
238   {"list",             P_BOOL,    P_LOCAL,  &sDefault.list,        NULL,   0},
239   {"uid",              P_STRING,  P_LOCAL,  &sDefault.uid,         NULL,   0},
240   {"gid",              P_STRING,  P_LOCAL,  &sDefault.gid,         NULL,   0},
241   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.hosts_allow, NULL,   0},
242   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.hosts_deny,  NULL,   0},
243   {"auth users",       P_STRING,  P_LOCAL,  &sDefault.auth_users,  NULL,   0},
244   {"secrets file",     P_STRING,  P_LOCAL,  &sDefault.secrets_file,NULL,   0},
245   {"exclude",          P_STRING,  P_LOCAL,  &sDefault.exclude,     NULL,   0},
246   {"exclude from",     P_STRING,  P_LOCAL,  &sDefault.exclude_from,NULL,   0},
247   {NULL,               P_BOOL,    P_NONE,   NULL,                  NULL,   0}
248 };
249
250
251 /***************************************************************************
252 Initialise the global parameter structure.
253 ***************************************************************************/
254 static void init_globals(void)
255 {
256 #ifdef LOG_DAEMON
257         Globals.syslog_facility = LOG_DAEMON;
258 #endif
259         Globals.lock_file = "/var/run/rsyncd.lock";
260 }
261
262 /***************************************************************************
263 Initialise the sDefault parameter structure.
264 ***************************************************************************/
265 static void init_locals(void)
266 {
267 }
268
269
270 /*
271    In this section all the functions that are used to access the 
272    parameters from the rest of the program are defined 
273 */
274
275 #define FN_GLOBAL_STRING(fn_name,ptr) \
276  char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
277 #define FN_GLOBAL_BOOL(fn_name,ptr) \
278  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
279 #define FN_GLOBAL_CHAR(fn_name,ptr) \
280  char fn_name(void) {return(*(char *)(ptr));}
281 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
282  int fn_name(void) {return(*(int *)(ptr));}
283
284 #define FN_LOCAL_STRING(fn_name,val) \
285  char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
286 #define FN_LOCAL_BOOL(fn_name,val) \
287  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
288 #define FN_LOCAL_CHAR(fn_name,val) \
289  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
290 #define FN_LOCAL_INTEGER(fn_name,val) \
291  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
292
293
294 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
295 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
296 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
297 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
298 FN_LOCAL_STRING(lp_name, name)
299 FN_LOCAL_STRING(lp_comment, comment)
300 FN_LOCAL_STRING(lp_path, path)
301 FN_LOCAL_BOOL(lp_read_only, read_only)
302 FN_LOCAL_BOOL(lp_list, list)
303 FN_LOCAL_STRING(lp_uid, uid)
304 FN_LOCAL_STRING(lp_gid, gid)
305 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
306 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
307 FN_LOCAL_STRING(lp_auth_users, auth_users)
308 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
309 FN_LOCAL_STRING(lp_exclude, exclude)
310 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
311
312 /* local prototypes */
313 static int    strwicmp( char *psz1, char *psz2 );
314 static int    map_parameter( char *parmname);
315 static BOOL   set_boolean( BOOL *pb, char *parmvalue );
316 static int    getservicebyname(char *name, service *pserviceDest);
317 static void   copy_service( service *pserviceDest, 
318                             service *pserviceSource);
319 static BOOL   do_parameter(char *parmname, char *parmvalue);
320 static BOOL   do_section(char *sectionname);
321
322
323 /***************************************************************************
324 initialise a service to the defaults
325 ***************************************************************************/
326 static void init_service(service *pservice)
327 {
328         bzero((char *)pservice,sizeof(service));
329         copy_service(pservice,&sDefault);
330 }
331
332 static void string_set(char **s, char *v)
333 {
334         if (!v) {
335                 *s = NULL;
336                 return;
337         }
338         *s = strdup(v);
339         if (!*s) exit_cleanup(1);
340 }
341
342
343 /***************************************************************************
344 add a new service to the services array initialising it with the given 
345 service
346 ***************************************************************************/
347 static int add_a_service(service *pservice, char *name)
348 {
349   int i;
350   service tservice;
351   int num_to_alloc = iNumServices+1;
352
353   tservice = *pservice;
354
355   /* it might already exist */
356   if (name) 
357     {
358       i = getservicebyname(name,NULL);
359       if (i >= 0)
360         return(i);
361     }
362
363   i = iNumServices;
364
365   ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
366   if (ServicePtrs)
367           pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
368
369   if (!ServicePtrs || !pSERVICE(iNumServices))
370           return(-1);
371
372   iNumServices++;
373
374   init_service(pSERVICE(i));
375   copy_service(pSERVICE(i),&tservice);
376   if (name)
377     string_set(&iSERVICE(i).name,name);  
378
379   return(i);
380 }
381
382 /***************************************************************************
383 Do a case-insensitive, whitespace-ignoring string compare.
384 ***************************************************************************/
385 static int strwicmp(char *psz1, char *psz2)
386 {
387    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
388    /* appropriate value. */
389    if (psz1 == psz2)
390       return (0);
391    else
392       if (psz1 == NULL)
393          return (-1);
394       else
395           if (psz2 == NULL)
396               return (1);
397
398    /* sync the strings on first non-whitespace */
399    while (1)
400    {
401       while (isspace(*psz1))
402          psz1++;
403       while (isspace(*psz2))
404          psz2++;
405       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
406          break;
407       psz1++;
408       psz2++;
409    }
410    return (*psz1 - *psz2);
411 }
412
413 /***************************************************************************
414 Map a parameter's string representation to something we can use. 
415 Returns False if the parameter string is not recognised, else TRUE.
416 ***************************************************************************/
417 static int map_parameter(char *parmname)
418 {
419    int iIndex;
420
421    if (*parmname == '-')
422      return(-1);
423
424    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
425       if (strwicmp(parm_table[iIndex].label, parmname) == 0)
426          return(iIndex);
427
428    rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
429    return(-1);
430 }
431
432
433 /***************************************************************************
434 Set a boolean variable from the text value stored in the passed string.
435 Returns True in success, False if the passed string does not correctly 
436 represent a boolean.
437 ***************************************************************************/
438 static BOOL set_boolean(BOOL *pb, char *parmvalue)
439 {
440    BOOL bRetval;
441
442    bRetval = True;
443    if (strwicmp(parmvalue, "yes") == 0 ||
444        strwicmp(parmvalue, "true") == 0 ||
445        strwicmp(parmvalue, "1") == 0)
446       *pb = True;
447    else
448       if (strwicmp(parmvalue, "no") == 0 ||
449           strwicmp(parmvalue, "False") == 0 ||
450           strwicmp(parmvalue, "0") == 0)
451          *pb = False;
452       else
453       {
454          rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
455                parmvalue);
456          bRetval = False;
457       }
458    return (bRetval);
459 }
460
461 /***************************************************************************
462 Find a service by name. Otherwise works like get_service.
463 ***************************************************************************/
464 static int getservicebyname(char *name, service *pserviceDest)
465 {
466    int iService;
467
468    for (iService = iNumServices - 1; iService >= 0; iService--)
469       if (strwicmp(iSERVICE(iService).name, name) == 0) 
470       {
471          if (pserviceDest != NULL)
472            copy_service(pserviceDest, pSERVICE(iService));
473          break;
474       }
475
476    return (iService);
477 }
478
479
480
481 /***************************************************************************
482 Copy a service structure to another
483
484 ***************************************************************************/
485 static void copy_service(service *pserviceDest, 
486                          service *pserviceSource)
487 {
488   int i;
489
490   for (i=0;parm_table[i].label;i++)
491     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
492         void *def_ptr = parm_table[i].ptr;
493         void *src_ptr = 
494           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
495         void *dest_ptr = 
496           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
497
498         switch (parm_table[i].type)
499           {
500           case P_BOOL:
501           case P_BOOLREV:
502             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
503             break;
504
505           case P_INTEGER:
506           case P_ENUM:
507           case P_OCTAL:
508             *(int *)dest_ptr = *(int *)src_ptr;
509             break;
510
511           case P_CHAR:
512             *(char *)dest_ptr = *(char *)src_ptr;
513             break;
514
515           case P_STRING:
516             string_set(dest_ptr,*(char **)src_ptr);
517             break;
518
519           default:
520             break;
521           }
522       }
523 }
524
525
526 /***************************************************************************
527 Process a parameter for a particular service number. If snum < 0
528 then assume we are in the globals
529 ***************************************************************************/
530 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
531 {
532    int parmnum, i;
533    void *parm_ptr=NULL; /* where we are going to store the result */
534    void *def_ptr=NULL;
535
536    parmnum = map_parameter(parmname);
537
538    if (parmnum < 0)
539      {
540        rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
541        return(True);
542      }
543
544    def_ptr = parm_table[parmnum].ptr;
545
546    /* we might point at a service, the default service or a global */
547    if (snum < 0) {
548      parm_ptr = def_ptr;
549    } else {
550        if (parm_table[parmnum].class == P_GLOBAL) {
551            rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
552            return(True);
553          }
554        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
555    }
556
557    /* now switch on the type of variable it is */
558    switch (parm_table[parmnum].type)
559      {
560      case P_BOOL:
561        set_boolean(parm_ptr,parmvalue);
562        break;
563
564      case P_BOOLREV:
565        set_boolean(parm_ptr,parmvalue);
566        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
567        break;
568
569      case P_INTEGER:
570        *(int *)parm_ptr = atoi(parmvalue);
571        break;
572
573      case P_CHAR:
574        *(char *)parm_ptr = *parmvalue;
575        break;
576
577      case P_OCTAL:
578        sscanf(parmvalue,"%o",(int *)parm_ptr);
579        break;
580
581      case P_STRING:
582        string_set(parm_ptr,parmvalue);
583        break;
584
585      case P_GSTRING:
586        strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring)-1);
587        break;
588
589      case P_ENUM:
590              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
591                      if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
592                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
593                              break;
594                      }
595              }
596              if (!parm_table[parmnum].enum_list[i].name) {
597                      if (atoi(parmvalue) > 0)
598                              *(int *)parm_ptr = atoi(parmvalue);
599              }
600              break;
601      case P_SEP:
602              break;
603      }
604
605    return(True);
606 }
607
608 /***************************************************************************
609 Process a parameter.
610 ***************************************************************************/
611 static BOOL do_parameter(char *parmname, char *parmvalue)
612 {
613    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
614 }
615
616 /***************************************************************************
617 Process a new section (service). At this stage all sections are services.
618 Later we'll have special sections that permit server parameters to be set.
619 Returns True on success, False on failure.
620 ***************************************************************************/
621 static BOOL do_section(char *sectionname)
622 {
623    BOOL bRetval;
624    BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
625    bRetval = False;
626
627    /* if we were in a global section then do the local inits */
628    if (bInGlobalSection && !isglobal)
629      init_locals();
630
631    /* if we've just struck a global section, note the fact. */
632    bInGlobalSection = isglobal;   
633
634    /* check for multiple global sections */
635    if (bInGlobalSection)
636    {
637      return(True);
638    }
639
640    /* if we have a current service, tidy it up before moving on */
641    bRetval = True;
642
643    if (iServiceIndex >= 0)
644      bRetval = True;
645
646    /* if all is still well, move to the next record in the services array */
647    if (bRetval)
648      {
649        /* We put this here to avoid an odd message order if messages are */
650        /* issued by the post-processing of a previous section. */
651
652        if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
653          {
654            rprintf(FERROR,"Failed to add a new service\n");
655            return(False);
656          }
657      }
658
659    return (bRetval);
660 }
661
662
663 /***************************************************************************
664 Load the services array from the services file. Return True on success, 
665 False on failure.
666 ***************************************************************************/
667 BOOL lp_load(char *pszFname)
668 {
669   pstring n2;
670   BOOL bRetval;
671  
672   bRetval = False;
673
674   bInGlobalSection = True;
675   
676   init_globals();
677
678   pstrcpy(n2,pszFname);
679
680   /* We get sections first, so have to start 'behind' to make up */
681   iServiceIndex = -1;
682   bRetval = pm_process(n2, do_section, do_parameter);
683   
684   bLoaded = True;
685
686   return (bRetval);
687 }
688
689
690 /***************************************************************************
691 return the max number of services
692 ***************************************************************************/
693 int lp_numservices(void)
694 {
695   return(iNumServices);
696 }
697
698 /***************************************************************************
699 Return the number of the service with the given name, or -1 if it doesn't
700 exist. Note that this is a DIFFERENT ANIMAL from the internal function
701 getservicebyname()! This works ONLY if all services have been loaded, and
702 does not copy the found service.
703 ***************************************************************************/
704 int lp_number(char *name)
705 {
706    int iService;
707
708    for (iService = iNumServices - 1; iService >= 0; iService--)
709       if (strequal(lp_name(iService), name)) 
710          break;
711
712    return (iService);
713 }
714