added hosts allow and hosts deny support. I ended up writing my own as
[rsync/rsync.git] / loadparm.c
... / ...
CommitLineData
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")
54typedef 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 */
58typedef 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
64typedef enum
65{
66 P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
67} parm_class;
68
69struct enum_list {
70 int value;
71 char *name;
72};
73
74struct 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
84static 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 */
98typedef struct
99{
100 char *motd_file;
101} global;
102
103static global Globals;
104
105
106
107/*
108 * This structure describes a single service.
109 */
110typedef 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 */
125static 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 */
141static service **ServicePtrs = NULL;
142static int iNumServices = 0;
143static int iServiceIndex = 0;
144static 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 */
150static 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/***************************************************************************
167Initialise the global parameter structure.
168***************************************************************************/
169static void init_globals(void)
170{
171}
172
173/***************************************************************************
174Initialise the sDefault parameter structure.
175***************************************************************************/
176static 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
205FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
206FN_LOCAL_STRING(lp_name, name)
207FN_LOCAL_STRING(lp_comment, comment)
208FN_LOCAL_STRING(lp_path, path)
209FN_LOCAL_BOOL(lp_read_only, read_only)
210FN_LOCAL_BOOL(lp_list, list)
211FN_LOCAL_STRING(lp_uid, uid)
212FN_LOCAL_STRING(lp_gid, gid)
213FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
214FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
215
216/* local prototypes */
217static int strwicmp( char *psz1, char *psz2 );
218static int map_parameter( char *parmname);
219static BOOL set_boolean( BOOL *pb, char *parmvalue );
220static int getservicebyname(char *name, service *pserviceDest);
221static void copy_service( service *pserviceDest,
222 service *pserviceSource);
223static BOOL do_parameter(char *parmname, char *parmvalue);
224static BOOL do_section(char *sectionname);
225
226
227/***************************************************************************
228initialise a service to the defaults
229***************************************************************************/
230static void init_service(service *pservice)
231{
232 bzero((char *)pservice,sizeof(service));
233 copy_service(pservice,&sDefault);
234}
235
236static 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/***************************************************************************
248add a new service to the services array initialising it with the given
249service
250***************************************************************************/
251static 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/***************************************************************************
287Do a case-insensitive, whitespace-ignoring string compare.
288***************************************************************************/
289static 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/***************************************************************************
318Map a parameter's string representation to something we can use.
319Returns False if the parameter string is not recognised, else TRUE.
320***************************************************************************/
321static 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/***************************************************************************
338Set a boolean variable from the text value stored in the passed string.
339Returns True in success, False if the passed string does not correctly
340represent a boolean.
341***************************************************************************/
342static 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/***************************************************************************
366Find a service by name. Otherwise works like get_service.
367***************************************************************************/
368static 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/***************************************************************************
386Copy a service structure to another
387
388***************************************************************************/
389static 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/***************************************************************************
431Process a parameter for a particular service number. If snum < 0
432then assume we are in the globals
433***************************************************************************/
434static 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/***************************************************************************
509Process a parameter.
510***************************************************************************/
511static BOOL do_parameter(char *parmname, char *parmvalue)
512{
513 return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
514}
515
516/***************************************************************************
517Process a new section (service). At this stage all sections are services.
518Later we'll have special sections that permit server parameters to be set.
519Returns True on success, False on failure.
520***************************************************************************/
521static 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/***************************************************************************
564Load the services array from the services file. Return True on success,
565False on failure.
566***************************************************************************/
567BOOL 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/***************************************************************************
591return the max number of services
592***************************************************************************/
593int lp_numservices(void)
594{
595 return(iNumServices);
596}
597
598/***************************************************************************
599Return the number of the service with the given name, or -1 if it doesn't
600exist. Note that this is a DIFFERENT ANIMAL from the internal function
601getservicebyname()! This works ONLY if all services have been loaded, and
602does not copy the found service.
603***************************************************************************/
604int 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