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