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