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