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.
103 static global Globals;
108 * This structure describes a single service.
124 /* This is a default service used to prime a services structure */
125 static service sDefault =
130 True, /* read only */
134 NULL, /* hosts allow */
135 NULL, /* hosts deny */
140 /* local variables */
141 static service **ServicePtrs = NULL;
142 static int iNumServices = 0;
143 static int iServiceIndex = 0;
144 static BOOL bInGlobalSection = True;
146 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
149 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
150 static struct parm_struct parm_table[] =
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}
166 /***************************************************************************
167 Initialise the global parameter structure.
168 ***************************************************************************/
169 static void init_globals(void)
173 /***************************************************************************
174 Initialise the sDefault parameter structure.
175 ***************************************************************************/
176 static void init_locals(void)
182 In this section all the functions that are used to access the
183 parameters from the rest of the program are defined
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));}
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);}
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)
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);
227 /***************************************************************************
228 initialise a service to the defaults
229 ***************************************************************************/
230 static void init_service(service *pservice)
232 bzero((char *)pservice,sizeof(service));
233 copy_service(pservice,&sDefault);
236 static void string_set(char **s, char *v)
243 if (!*s) exit_cleanup(1);
247 /***************************************************************************
248 add a new service to the services array initialising it with the given
250 ***************************************************************************/
251 static int add_a_service(service *pservice, char *name)
255 int num_to_alloc = iNumServices+1;
257 tservice = *pservice;
259 /* it might already exist */
262 i = getservicebyname(name,NULL);
269 ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
271 pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
273 if (!ServicePtrs || !pSERVICE(iNumServices))
278 init_service(pSERVICE(i));
279 copy_service(pSERVICE(i),&tservice);
281 string_set(&iSERVICE(i).name,name);
286 /***************************************************************************
287 Do a case-insensitive, whitespace-ignoring string compare.
288 ***************************************************************************/
289 static int strwicmp(char *psz1, char *psz2)
291 /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
292 /* appropriate value. */
302 /* sync the strings on first non-whitespace */
305 while (isspace(*psz1))
307 while (isspace(*psz2))
309 if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
314 return (*psz1 - *psz2);
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)
325 if (*parmname == '-')
328 for (iIndex = 0; parm_table[iIndex].label; iIndex++)
329 if (strwicmp(parm_table[iIndex].label, parmname) == 0)
332 rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
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
341 ***************************************************************************/
342 static BOOL set_boolean(BOOL *pb, char *parmvalue)
347 if (strwicmp(parmvalue, "yes") == 0 ||
348 strwicmp(parmvalue, "true") == 0 ||
349 strwicmp(parmvalue, "1") == 0)
352 if (strwicmp(parmvalue, "no") == 0 ||
353 strwicmp(parmvalue, "False") == 0 ||
354 strwicmp(parmvalue, "0") == 0)
358 rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
365 /***************************************************************************
366 Find a service by name. Otherwise works like get_service.
367 ***************************************************************************/
368 static int getservicebyname(char *name, service *pserviceDest)
372 for (iService = iNumServices - 1; iService >= 0; iService--)
373 if (strwicmp(iSERVICE(iService).name, name) == 0)
375 if (pserviceDest != NULL)
376 copy_service(pserviceDest, pSERVICE(iService));
385 /***************************************************************************
386 Copy a service structure to another
388 ***************************************************************************/
389 static void copy_service(service *pserviceDest,
390 service *pserviceSource)
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;
398 ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
400 ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
402 switch (parm_table[i].type)
406 *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
412 *(int *)dest_ptr = *(int *)src_ptr;
416 *(char *)dest_ptr = *(char *)src_ptr;
420 string_set(dest_ptr,*(char **)src_ptr);
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)
437 void *parm_ptr=NULL; /* where we are going to store the result */
440 parmnum = map_parameter(parmname);
444 rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
448 def_ptr = parm_table[parmnum].ptr;
450 /* we might point at a service, the default service or a global */
454 if (parm_table[parmnum].class == P_GLOBAL) {
455 rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
458 parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
461 /* now switch on the type of variable it is */
462 switch (parm_table[parmnum].type)
465 set_boolean(parm_ptr,parmvalue);
469 set_boolean(parm_ptr,parmvalue);
470 *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
474 *(int *)parm_ptr = atoi(parmvalue);
478 *(char *)parm_ptr = *parmvalue;
482 sscanf(parmvalue,"%o",(int *)parm_ptr);
486 string_set(parm_ptr,parmvalue);
490 strcpy((char *)parm_ptr,parmvalue);
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;
508 /***************************************************************************
510 ***************************************************************************/
511 static BOOL do_parameter(char *parmname, char *parmvalue)
513 return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
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)
524 BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
527 /* if we were in a global section then do the local inits */
528 if (bInGlobalSection && !isglobal)
531 /* if we've just struck a global section, note the fact. */
532 bInGlobalSection = isglobal;
534 /* check for multiple global sections */
535 if (bInGlobalSection)
540 /* if we have a current service, tidy it up before moving on */
543 if (iServiceIndex >= 0)
546 /* if all is still well, move to the next record in the services array */
549 /* We put this here to avoid an odd message order if messages are */
550 /* issued by the post-processing of a previous section. */
552 if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
554 rprintf(FERROR,"Failed to add a new service\n");
563 /***************************************************************************
564 Load the services array from the services file. Return True on success,
566 ***************************************************************************/
567 BOOL lp_load(char *pszFname)
574 bInGlobalSection = True;
578 pstrcpy(n2,pszFname);
580 /* We get sections first, so have to start 'behind' to make up */
582 bRetval = pm_process(n2, do_section, do_parameter);
590 /***************************************************************************
591 return the max number of services
592 ***************************************************************************/
593 int lp_numservices(void)
595 return(iNumServices);
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)
608 for (iService = iNumServices - 1; iService >= 0; iService--)
609 if (strequal(lp_name(iService), name))