1 /* This is based on loadparm.c from Samba, written by Andrew Tridgell
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.
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.
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.
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.
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
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
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)
57 /* the following are used by loadparm for option lists */
60 P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
61 P_STRING,P_GSTRING,P_ENUM,P_SEP
66 P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
80 struct enum_list *enum_list;
84 static BOOL bLoaded = False;
87 #define GLOBAL_NAME "global"
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))
96 * This structure describes global (ie., server-wide) parameters.
106 static global Globals;
111 * This structure describes a single service.
129 /* This is a default service used to prime a services structure */
130 static service sDefault =
135 True, /* read only */
139 NULL, /* hosts allow */
140 NULL, /* hosts deny */
141 NULL, /* auth users */
142 NULL, /* secrets file */
147 /* local variables */
148 static service **ServicePtrs = NULL;
149 static int iNumServices = 0;
150 static int iServiceIndex = 0;
151 static BOOL bInGlobalSection = True;
153 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
155 static struct enum_list enum_facilities[] = {
157 { LOG_AUTH, "auth" },
160 { LOG_AUTHPRIV, "authpriv" },
163 { LOG_CRON, "cron" },
166 { LOG_DAEMON, "daemon" },
172 { LOG_KERN, "kern" },
178 { LOG_MAIL, "mail" },
181 { LOG_NEWS, "news" },
184 { LOG_AUTH, "security" },
187 { LOG_SYSLOG, "syslog" },
190 { LOG_USER, "user" },
193 { LOG_UUCP, "uucp" },
196 { LOG_LOCAL0, "local0" },
199 { LOG_LOCAL1, "local1" },
202 { LOG_LOCAL2, "local2" },
205 { LOG_LOCAL3, "local3" },
208 { LOG_LOCAL4, "local4" },
211 { LOG_LOCAL5, "local5" },
214 { LOG_LOCAL6, "local6" },
217 { LOG_LOCAL7, "local7" },
222 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
223 static struct parm_struct parm_table[] =
225 {"max connections", P_INTEGER, P_GLOBAL, &Globals.max_connections,NULL, 0},
226 {"motd file", P_STRING, P_GLOBAL, &Globals.motd_file, NULL, 0},
227 {"lock file", P_STRING, P_GLOBAL, &Globals.lock_file, NULL, 0},
228 {"syslog facility", P_ENUM, P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
229 {"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
230 {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
231 {"path", P_STRING, P_LOCAL, &sDefault.path, NULL, 0},
232 {"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
233 {"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
234 {"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL, 0},
235 {"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL, 0},
236 {"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL, 0},
237 {"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL, 0},
238 {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
239 {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
240 {NULL, P_BOOL, P_NONE, NULL, NULL, 0}
244 /***************************************************************************
245 Initialise the global parameter structure.
246 ***************************************************************************/
247 static void init_globals(void)
250 Globals.syslog_facility = LOG_DAEMON;
252 Globals.lock_file = "/var/run/rsyncd.lock";
255 /***************************************************************************
256 Initialise the sDefault parameter structure.
257 ***************************************************************************/
258 static void init_locals(void)
264 In this section all the functions that are used to access the
265 parameters from the rest of the program are defined
268 #define FN_GLOBAL_STRING(fn_name,ptr) \
269 char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
270 #define FN_GLOBAL_BOOL(fn_name,ptr) \
271 BOOL fn_name(void) {return(*(BOOL *)(ptr));}
272 #define FN_GLOBAL_CHAR(fn_name,ptr) \
273 char fn_name(void) {return(*(char *)(ptr));}
274 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
275 int fn_name(void) {return(*(int *)(ptr));}
277 #define FN_LOCAL_STRING(fn_name,val) \
278 char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
279 #define FN_LOCAL_BOOL(fn_name,val) \
280 BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
281 #define FN_LOCAL_CHAR(fn_name,val) \
282 char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
283 #define FN_LOCAL_INTEGER(fn_name,val) \
284 int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
287 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
288 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
289 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
290 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
291 FN_LOCAL_STRING(lp_name, name)
292 FN_LOCAL_STRING(lp_comment, comment)
293 FN_LOCAL_STRING(lp_path, path)
294 FN_LOCAL_BOOL(lp_read_only, read_only)
295 FN_LOCAL_BOOL(lp_list, list)
296 FN_LOCAL_STRING(lp_uid, uid)
297 FN_LOCAL_STRING(lp_gid, gid)
298 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
299 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
300 FN_LOCAL_STRING(lp_auth_users, auth_users)
301 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
303 /* local prototypes */
304 static int strwicmp( char *psz1, char *psz2 );
305 static int map_parameter( char *parmname);
306 static BOOL set_boolean( BOOL *pb, char *parmvalue );
307 static int getservicebyname(char *name, service *pserviceDest);
308 static void copy_service( service *pserviceDest,
309 service *pserviceSource);
310 static BOOL do_parameter(char *parmname, char *parmvalue);
311 static BOOL do_section(char *sectionname);
314 /***************************************************************************
315 initialise a service to the defaults
316 ***************************************************************************/
317 static void init_service(service *pservice)
319 bzero((char *)pservice,sizeof(service));
320 copy_service(pservice,&sDefault);
323 static void string_set(char **s, char *v)
330 if (!*s) exit_cleanup(1);
334 /***************************************************************************
335 add a new service to the services array initialising it with the given
337 ***************************************************************************/
338 static int add_a_service(service *pservice, char *name)
342 int num_to_alloc = iNumServices+1;
344 tservice = *pservice;
346 /* it might already exist */
349 i = getservicebyname(name,NULL);
356 ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
358 pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
360 if (!ServicePtrs || !pSERVICE(iNumServices))
365 init_service(pSERVICE(i));
366 copy_service(pSERVICE(i),&tservice);
368 string_set(&iSERVICE(i).name,name);
373 /***************************************************************************
374 Do a case-insensitive, whitespace-ignoring string compare.
375 ***************************************************************************/
376 static int strwicmp(char *psz1, char *psz2)
378 /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
379 /* appropriate value. */
389 /* sync the strings on first non-whitespace */
392 while (isspace(*psz1))
394 while (isspace(*psz2))
396 if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
401 return (*psz1 - *psz2);
404 /***************************************************************************
405 Map a parameter's string representation to something we can use.
406 Returns False if the parameter string is not recognised, else TRUE.
407 ***************************************************************************/
408 static int map_parameter(char *parmname)
412 if (*parmname == '-')
415 for (iIndex = 0; parm_table[iIndex].label; iIndex++)
416 if (strwicmp(parm_table[iIndex].label, parmname) == 0)
419 rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
424 /***************************************************************************
425 Set a boolean variable from the text value stored in the passed string.
426 Returns True in success, False if the passed string does not correctly
428 ***************************************************************************/
429 static BOOL set_boolean(BOOL *pb, char *parmvalue)
434 if (strwicmp(parmvalue, "yes") == 0 ||
435 strwicmp(parmvalue, "true") == 0 ||
436 strwicmp(parmvalue, "1") == 0)
439 if (strwicmp(parmvalue, "no") == 0 ||
440 strwicmp(parmvalue, "False") == 0 ||
441 strwicmp(parmvalue, "0") == 0)
445 rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
452 /***************************************************************************
453 Find a service by name. Otherwise works like get_service.
454 ***************************************************************************/
455 static int getservicebyname(char *name, service *pserviceDest)
459 for (iService = iNumServices - 1; iService >= 0; iService--)
460 if (strwicmp(iSERVICE(iService).name, name) == 0)
462 if (pserviceDest != NULL)
463 copy_service(pserviceDest, pSERVICE(iService));
472 /***************************************************************************
473 Copy a service structure to another
475 ***************************************************************************/
476 static void copy_service(service *pserviceDest,
477 service *pserviceSource)
481 for (i=0;parm_table[i].label;i++)
482 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
483 void *def_ptr = parm_table[i].ptr;
485 ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
487 ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
489 switch (parm_table[i].type)
493 *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
499 *(int *)dest_ptr = *(int *)src_ptr;
503 *(char *)dest_ptr = *(char *)src_ptr;
507 string_set(dest_ptr,*(char **)src_ptr);
517 /***************************************************************************
518 Process a parameter for a particular service number. If snum < 0
519 then assume we are in the globals
520 ***************************************************************************/
521 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
524 void *parm_ptr=NULL; /* where we are going to store the result */
527 parmnum = map_parameter(parmname);
531 rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
535 def_ptr = parm_table[parmnum].ptr;
537 /* we might point at a service, the default service or a global */
541 if (parm_table[parmnum].class == P_GLOBAL) {
542 rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
545 parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
548 /* now switch on the type of variable it is */
549 switch (parm_table[parmnum].type)
552 set_boolean(parm_ptr,parmvalue);
556 set_boolean(parm_ptr,parmvalue);
557 *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
561 *(int *)parm_ptr = atoi(parmvalue);
565 *(char *)parm_ptr = *parmvalue;
569 sscanf(parmvalue,"%o",(int *)parm_ptr);
573 string_set(parm_ptr,parmvalue);
577 strcpy((char *)parm_ptr,parmvalue);
581 for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
582 if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
583 *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
595 /***************************************************************************
597 ***************************************************************************/
598 static BOOL do_parameter(char *parmname, char *parmvalue)
600 return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
603 /***************************************************************************
604 Process a new section (service). At this stage all sections are services.
605 Later we'll have special sections that permit server parameters to be set.
606 Returns True on success, False on failure.
607 ***************************************************************************/
608 static BOOL do_section(char *sectionname)
611 BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
614 /* if we were in a global section then do the local inits */
615 if (bInGlobalSection && !isglobal)
618 /* if we've just struck a global section, note the fact. */
619 bInGlobalSection = isglobal;
621 /* check for multiple global sections */
622 if (bInGlobalSection)
627 /* if we have a current service, tidy it up before moving on */
630 if (iServiceIndex >= 0)
633 /* if all is still well, move to the next record in the services array */
636 /* We put this here to avoid an odd message order if messages are */
637 /* issued by the post-processing of a previous section. */
639 if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
641 rprintf(FERROR,"Failed to add a new service\n");
650 /***************************************************************************
651 Load the services array from the services file. Return True on success,
653 ***************************************************************************/
654 BOOL lp_load(char *pszFname)
661 bInGlobalSection = True;
665 pstrcpy(n2,pszFname);
667 /* We get sections first, so have to start 'behind' to make up */
669 bRetval = pm_process(n2, do_section, do_parameter);
677 /***************************************************************************
678 return the max number of services
679 ***************************************************************************/
680 int lp_numservices(void)
682 return(iNumServices);
685 /***************************************************************************
686 Return the number of the service with the given name, or -1 if it doesn't
687 exist. Note that this is a DIFFERENT ANIMAL from the internal function
688 getservicebyname()! This works ONLY if all services have been loaded, and
689 does not copy the found service.
690 ***************************************************************************/
691 int lp_number(char *name)
695 for (iService = iNumServices - 1; iService >= 0; iService--)
696 if (strequal(lp_name(iService), name))