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 PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
51 #define strequal(a,b) (strcasecmp(a,b)==0)
52 #define BOOLSTR(b) ((b) ? "Yes" : "No")
53 typedef char pstring[1024];
54 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
56 /* the following are used by loadparm for option lists */
59 P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
60 P_STRING,P_GSTRING,P_ENUM,P_SEP
65 P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
79 struct enum_list *enum_list;
83 static BOOL bLoaded = False;
86 #define GLOBAL_NAME "global"
89 /* some helpful bits */
90 #define pSERVICE(i) ServicePtrs[i]
91 #define iSERVICE(i) (*pSERVICE(i))
92 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
95 * This structure describes global (ie., server-wide) parameters.
105 char *socket_options;
108 static global Globals;
113 * This structure describes a single service.
134 /* This is a default service used to prime a services structure */
135 static service sDefault =
140 True, /* read only */
142 True, /* use chroot */
145 NULL, /* hosts allow */
146 NULL, /* hosts deny */
147 NULL, /* auth users */
148 NULL, /* secrets file */
150 NULL, /* exclude from */
155 /* local variables */
156 static service **ServicePtrs = NULL;
157 static int iNumServices = 0;
158 static int iServiceIndex = 0;
159 static BOOL bInGlobalSection = True;
161 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
163 static struct enum_list enum_facilities[] = {
165 { LOG_AUTH, "auth" },
168 { LOG_AUTHPRIV, "authpriv" },
171 { LOG_CRON, "cron" },
174 { LOG_DAEMON, "daemon" },
180 { LOG_KERN, "kern" },
186 { LOG_MAIL, "mail" },
189 { LOG_NEWS, "news" },
192 { LOG_AUTH, "security" },
195 { LOG_SYSLOG, "syslog" },
198 { LOG_USER, "user" },
201 { LOG_UUCP, "uucp" },
204 { LOG_LOCAL0, "local0" },
207 { LOG_LOCAL1, "local1" },
210 { LOG_LOCAL2, "local2" },
213 { LOG_LOCAL3, "local3" },
216 { LOG_LOCAL4, "local4" },
219 { LOG_LOCAL5, "local5" },
222 { LOG_LOCAL6, "local6" },
225 { LOG_LOCAL7, "local7" },
230 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
231 static struct parm_struct parm_table[] =
233 {"max connections", P_INTEGER, P_GLOBAL, &Globals.max_connections,NULL, 0},
234 {"motd file", P_STRING, P_GLOBAL, &Globals.motd_file, NULL, 0},
235 {"lock file", P_STRING, P_GLOBAL, &Globals.lock_file, NULL, 0},
236 {"syslog facility", P_ENUM, P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
237 {"socket options", P_STRING, P_GLOBAL, &Globals.socket_options,NULL, 0},
238 {"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0},
239 {"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0},
241 {"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
242 {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
243 {"path", P_STRING, P_LOCAL, &sDefault.path, NULL, 0},
244 {"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
245 {"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
246 {"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
247 {"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL, 0},
248 {"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL, 0},
249 {"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL, 0},
250 {"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL, 0},
251 {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
252 {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
253 {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0},
254 {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0},
255 {NULL, P_BOOL, P_NONE, NULL, NULL, 0}
259 /***************************************************************************
260 Initialise the global parameter structure.
261 ***************************************************************************/
262 static void init_globals(void)
264 memset(&Globals, 0, sizeof(Globals));
266 Globals.syslog_facility = LOG_DAEMON;
268 Globals.lock_file = "/var/run/rsyncd.lock";
271 /***************************************************************************
272 Initialise the sDefault parameter structure.
273 ***************************************************************************/
274 static void init_locals(void)
280 In this section all the functions that are used to access the
281 parameters from the rest of the program are defined
284 #define FN_GLOBAL_STRING(fn_name,ptr) \
285 char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
286 #define FN_GLOBAL_BOOL(fn_name,ptr) \
287 BOOL fn_name(void) {return(*(BOOL *)(ptr));}
288 #define FN_GLOBAL_CHAR(fn_name,ptr) \
289 char fn_name(void) {return(*(char *)(ptr));}
290 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
291 int fn_name(void) {return(*(int *)(ptr));}
293 #define FN_LOCAL_STRING(fn_name,val) \
294 char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
295 #define FN_LOCAL_BOOL(fn_name,val) \
296 BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
297 #define FN_LOCAL_CHAR(fn_name,val) \
298 char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
299 #define FN_LOCAL_INTEGER(fn_name,val) \
300 int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
303 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
304 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
305 FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
306 FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
307 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
308 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
309 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
311 FN_LOCAL_STRING(lp_name, name)
312 FN_LOCAL_STRING(lp_comment, comment)
313 FN_LOCAL_STRING(lp_path, path)
314 FN_LOCAL_BOOL(lp_read_only, read_only)
315 FN_LOCAL_BOOL(lp_list, list)
316 FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
317 FN_LOCAL_STRING(lp_uid, uid)
318 FN_LOCAL_STRING(lp_gid, gid)
319 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
320 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
321 FN_LOCAL_STRING(lp_auth_users, auth_users)
322 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
323 FN_LOCAL_STRING(lp_exclude, exclude)
324 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
326 /* local prototypes */
327 static int strwicmp( char *psz1, char *psz2 );
328 static int map_parameter( char *parmname);
329 static BOOL set_boolean( BOOL *pb, char *parmvalue );
330 static int getservicebyname(char *name, service *pserviceDest);
331 static void copy_service( service *pserviceDest,
332 service *pserviceSource);
333 static BOOL do_parameter(char *parmname, char *parmvalue);
334 static BOOL do_section(char *sectionname);
337 /***************************************************************************
338 initialise a service to the defaults
339 ***************************************************************************/
340 static void init_service(service *pservice)
342 memset((char *)pservice,0,sizeof(service));
343 copy_service(pservice,&sDefault);
346 static void string_set(char **s, char *v)
353 if (!*s) exit_cleanup(1);
357 /***************************************************************************
358 add a new service to the services array initialising it with the given
360 ***************************************************************************/
361 static int add_a_service(service *pservice, char *name)
365 int num_to_alloc = iNumServices+1;
367 tservice = *pservice;
369 /* it might already exist */
372 i = getservicebyname(name,NULL);
379 ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
382 pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
384 if (!ServicePtrs || !pSERVICE(iNumServices))
389 init_service(pSERVICE(i));
390 copy_service(pSERVICE(i),&tservice);
392 string_set(&iSERVICE(i).name,name);
397 /***************************************************************************
398 Do a case-insensitive, whitespace-ignoring string compare.
399 ***************************************************************************/
400 static int strwicmp(char *psz1, char *psz2)
402 /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
403 /* appropriate value. */
413 /* sync the strings on first non-whitespace */
416 while (isspace(*psz1))
418 while (isspace(*psz2))
420 if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
425 return (*psz1 - *psz2);
428 /***************************************************************************
429 Map a parameter's string representation to something we can use.
430 Returns False if the parameter string is not recognised, else TRUE.
431 ***************************************************************************/
432 static int map_parameter(char *parmname)
436 if (*parmname == '-')
439 for (iIndex = 0; parm_table[iIndex].label; iIndex++)
440 if (strwicmp(parm_table[iIndex].label, parmname) == 0)
443 rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
448 /***************************************************************************
449 Set a boolean variable from the text value stored in the passed string.
450 Returns True in success, False if the passed string does not correctly
452 ***************************************************************************/
453 static BOOL set_boolean(BOOL *pb, char *parmvalue)
458 if (strwicmp(parmvalue, "yes") == 0 ||
459 strwicmp(parmvalue, "true") == 0 ||
460 strwicmp(parmvalue, "1") == 0)
463 if (strwicmp(parmvalue, "no") == 0 ||
464 strwicmp(parmvalue, "False") == 0 ||
465 strwicmp(parmvalue, "0") == 0)
469 rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
476 /***************************************************************************
477 Find a service by name. Otherwise works like get_service.
478 ***************************************************************************/
479 static int getservicebyname(char *name, service *pserviceDest)
483 for (iService = iNumServices - 1; iService >= 0; iService--)
484 if (strwicmp(iSERVICE(iService).name, name) == 0)
486 if (pserviceDest != NULL)
487 copy_service(pserviceDest, pSERVICE(iService));
496 /***************************************************************************
497 Copy a service structure to another
499 ***************************************************************************/
500 static void copy_service(service *pserviceDest,
501 service *pserviceSource)
505 for (i=0;parm_table[i].label;i++)
506 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
507 void *def_ptr = parm_table[i].ptr;
509 ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
511 ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
513 switch (parm_table[i].type)
517 *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
523 *(int *)dest_ptr = *(int *)src_ptr;
527 *(char *)dest_ptr = *(char *)src_ptr;
531 string_set(dest_ptr,*(char **)src_ptr);
541 /***************************************************************************
542 Process a parameter for a particular service number. If snum < 0
543 then assume we are in the globals
544 ***************************************************************************/
545 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
548 void *parm_ptr=NULL; /* where we are going to store the result */
551 parmnum = map_parameter(parmname);
555 rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
559 def_ptr = parm_table[parmnum].ptr;
561 /* we might point at a service, the default service or a global */
565 if (parm_table[parmnum].class == P_GLOBAL) {
566 rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
569 parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
572 /* now switch on the type of variable it is */
573 switch (parm_table[parmnum].type)
576 set_boolean(parm_ptr,parmvalue);
580 set_boolean(parm_ptr,parmvalue);
581 *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
585 *(int *)parm_ptr = atoi(parmvalue);
589 *(char *)parm_ptr = *parmvalue;
593 sscanf(parmvalue,"%o",(int *)parm_ptr);
597 string_set(parm_ptr,parmvalue);
601 strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring)-1);
605 for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
606 if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
607 *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
611 if (!parm_table[parmnum].enum_list[i].name) {
612 if (atoi(parmvalue) > 0)
613 *(int *)parm_ptr = atoi(parmvalue);
623 /***************************************************************************
625 ***************************************************************************/
626 static BOOL do_parameter(char *parmname, char *parmvalue)
628 return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
631 /***************************************************************************
632 Process a new section (service). At this stage all sections are services.
633 Later we'll have special sections that permit server parameters to be set.
634 Returns True on success, False on failure.
635 ***************************************************************************/
636 static BOOL do_section(char *sectionname)
639 BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
642 /* if we were in a global section then do the local inits */
643 if (bInGlobalSection && !isglobal)
646 /* if we've just struck a global section, note the fact. */
647 bInGlobalSection = isglobal;
649 /* check for multiple global sections */
650 if (bInGlobalSection)
655 /* if we have a current service, tidy it up before moving on */
658 if (iServiceIndex >= 0)
661 /* if all is still well, move to the next record in the services array */
664 /* We put this here to avoid an odd message order if messages are */
665 /* issued by the post-processing of a previous section. */
667 if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
669 rprintf(FERROR,"Failed to add a new service\n");
678 /***************************************************************************
679 Load the services array from the services file. Return True on success,
681 ***************************************************************************/
682 BOOL lp_load(char *pszFname, int globals_only)
689 bInGlobalSection = True;
693 pstrcpy(n2,pszFname);
695 /* We get sections first, so have to start 'behind' to make up */
697 bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
705 /***************************************************************************
706 return the max number of services
707 ***************************************************************************/
708 int lp_numservices(void)
710 return(iNumServices);
713 /***************************************************************************
714 Return the number of the service with the given name, or -1 if it doesn't
715 exist. Note that this is a DIFFERENT ANIMAL from the internal function
716 getservicebyname()! This works ONLY if all services have been loaded, and
717 does not copy the found service.
718 ***************************************************************************/
719 int lp_number(char *name)
723 for (iService = iNumServices - 1; iService >= 0; iService--)
724 if (strequal(lp_name(iService), name))