Initial version imported to CVS
[jra/samba/.git] / source3 / param / loadparm.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Parameter loading functions
5    Copyright (C) Karl Auer 1993,1994
6
7    Largely re-written by Andrew Tridgell, September 1994
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /*
25  *  Load parameters.
26  *
27  *  This module provides suitable callback functions for the params
28  *  module. It builds the internal table of service details which is
29  *  then used by the rest of the server.
30  *
31  * To add a parameter:
32  *
33  * 1) add it to the global or service structure definition
34  * 2) add it to the parm_table
35  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
36  * 4) If it's a global then initialise it in init_globals. If a local
37  *    (ie. service) parameter then initialise it in the sDefault structure
38  *  
39  *
40  * Notes:
41  *   The configuration file is processed sequentially for speed. It is NOT
42  *   accessed randomly as happens in 'real' Windows. For this reason, there
43  *   is a fair bit of sequence-dependent code here - ie., code which assumes
44  *   that certain things happen before others. In particular, the code which
45  *   happens at the boundary between sections is delicately poised, so be
46  *   careful!
47  *
48  */
49
50 #include "includes.h"
51
52 #include "params.h"
53 #include "loadparm.h"
54 #include "pcap.h"
55
56 BOOL bLoaded = False;
57
58 extern int DEBUGLEVEL;
59 extern int ReadSize;
60 extern pstring user_socket_options;
61 extern pstring smbrun_path;
62
63 #ifndef GLOBAL_NAME
64 #define GLOBAL_NAME "global"
65 #endif
66
67 #ifndef PRINTCAP_NAME
68 #ifdef AIX
69 #define PRINTCAP_NAME "/etc/qconfig"
70 #else
71 #define PRINTCAP_NAME "/etc/printcap"
72 #endif
73 #endif
74
75 #ifndef PRINTERS_NAME
76 #define PRINTERS_NAME "printers"
77 #endif
78
79 #ifndef HOMES_NAME
80 #define HOMES_NAME "homes"
81 #endif
82
83 /* some helpful bits */
84 #define pSERVICE(i) ServicePtrs[i]
85 #define iSERVICE(i) (*pSERVICE(i))
86 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices) && iSERVICE(iService).valid)
87 #define VALID(i) iSERVICE(i).valid
88
89 /* these are the types of parameter we have */
90 typedef enum
91 {
92   P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_STRING,P_GSTRING
93 } parm_type;
94
95 typedef enum
96 {
97   P_LOCAL,P_GLOBAL,P_NONE
98 } parm_class;
99
100 int keepalive=0;
101 extern BOOL use_getwd_cache;
102
103 extern int extra_time_offset;
104 #ifdef KANJI
105 extern int coding_system;
106 #endif
107
108 /* 
109  * This structure describes global (ie., server-wide) parameters.
110  */
111 typedef struct
112 {
113    char *szPrintcapname;
114    char *szLockDir;
115    char *szRootdir;
116    char *szDefaultService;
117    char *szDfree;
118    char *szMsgCommand;
119    char *szHostsEquiv;
120    char *szServerString;
121    char *szAutoServices;
122    char *szPasswdProgram;
123    char *szPasswdChat;
124    char *szLogFile;
125    char *szConfigFile;
126    char *szSMBPasswdFile;
127    char *szPasswordServer;
128    char *szSocketOptions;
129    char *szValidChars;
130    char *szWorkGroup;
131    char *szDomainController;
132    char *szUsernameMap;
133    char *szCharacterSet;
134    char *szLogonScript;
135    int max_log_size;
136    int mangled_stack;
137    int max_xmit;
138    int max_mux;
139    int max_packet;
140    int pwordlevel;
141    int deadtime;
142    int maxprotocol;
143    int security;
144    int printing;
145    int maxdisksize;
146    int lpqcachetime;
147    int syslog;
148    int os_level;
149    int max_ttl;
150    BOOL bPreferredMaster;
151    BOOL bDomainMaster;
152    BOOL bDomainLogons;
153    BOOL bEncryptPasswords;
154    BOOL bStripDot;
155    BOOL bNullPasswords;
156    BOOL bLoadPrinters;
157    BOOL bUseRhosts;
158    BOOL bReadRaw;
159    BOOL bWriteRaw;
160    BOOL bReadPrediction;
161    BOOL bReadbmpx;
162    BOOL bSyslogOnly;
163    BOOL bBrowseList;
164 } global;
165
166 static global Globals;
167
168
169
170 /* 
171  * This structure describes a single service. 
172  */
173 typedef struct
174 {
175   BOOL valid;
176   char *szService;
177   char *szPath;
178   char *szUsername;
179   char *szGuestaccount;
180   char *szInvalidUsers;
181   char *szValidUsers;
182   char *szAdminUsers;
183   char *szCopy;
184   char *szInclude;
185   char *szPreExec;
186   char *szPostExec;
187   char *szRootPreExec;
188   char *szRootPostExec;
189   char *szPrintcommand;
190   char *szLpqcommand;
191   char *szLprmcommand;
192   char *szLppausecommand;
193   char *szLpresumecommand;
194   char *szPrintername;
195   char *szDontdescend;
196   char *szHostsallow;
197   char *szHostsdeny;
198   char *szMagicScript;
199   char *szMagicOutput;
200   char *szMangledMap;
201   char *comment;
202   char *force_user;
203   char *force_group;
204   char *readlist;
205   char *writelist;
206   char *volume;
207   int  iMinPrintSpace;
208   int  iCreate_mode;
209   int  iMaxConnections;
210   int  iDefaultCase;
211   BOOL bAlternatePerm;
212   BOOL bRevalidate;
213   BOOL bCaseSensitive;
214   BOOL bCasePreserve;
215   BOOL bShortCasePreserve;
216   BOOL bCaseMangle;
217   BOOL status;
218   BOOL bHideDotFiles;
219   BOOL bBrowseable;
220   BOOL bAvailable;
221   BOOL bRead_only;
222   BOOL bNo_set_dir;
223   BOOL bGuest_only;
224   BOOL bGuest_ok;
225   BOOL bPrint_ok;
226   BOOL bPostscript;
227   BOOL bMap_system;
228   BOOL bMap_hidden;
229   BOOL bMap_archive;
230   BOOL bLocking;
231   BOOL bStrictLocking;
232   BOOL bShareModes;
233   BOOL bOnlyUser;
234   BOOL bMangledNames;
235   BOOL bWidelinks;
236   BOOL bSyncAlways;
237   char magic_char;
238   BOOL *copymap;
239   char dummy[3]; /* for alignment */
240 } service;
241
242
243 /* This is a default service used to prime a services structure */
244 static service sDefault = 
245 {
246   True,   /* valid */
247   NULL,    /* szService */
248   NULL,    /* szPath */
249   NULL,    /* szUsername */
250   NULL,    /* szGuestAccount */
251   NULL,    /* szInvalidUsers */
252   NULL,    /* szValidUsers */
253   NULL,    /* szAdminUsers */
254   NULL,    /* szCopy */
255   NULL,    /* szInclude */
256   NULL,    /* szPreExec */
257   NULL,    /* szPostExec */
258   NULL,    /* szRootPreExec */
259   NULL,    /* szRootPostExec */
260   NULL,    /* szPrintcommand */
261   NULL,    /* szLpqcommand */
262   NULL,    /* szLprmcommand */
263   NULL,    /* szLppausecommand */
264   NULL,    /* szLpresumecommand */
265   NULL,    /* szPrintername */
266   NULL,    /* szDontdescend */
267   NULL,    /* szHostsallow */
268   NULL,    /* szHostsdeny */
269   NULL,    /* szMagicScript */
270   NULL,    /* szMagicOutput */
271   NULL,    /* szMangledMap */
272   NULL,    /* comment */
273   NULL,    /* force user */
274   NULL,    /* force group */
275   NULL,    /* readlist */
276   NULL,    /* writelist */
277   NULL,    /* volume */
278   0,       /* iMinPrintSpace */
279   0755,    /* iCreate_mode */
280   0,       /* iMaxConnections */
281   CASE_LOWER, /* iDefaultCase */
282   False,   /* bAlternatePerm */
283   False,   /* revalidate */
284   False,   /* case sensitive */
285   False,   /* case preserve */
286   False,   /* short case preserve */
287   False,  /* case mangle */
288   True,  /* status */
289   True,  /* bHideDotFiles */
290   True,  /* bBrowseable */
291   True,  /* bAvailable */
292   True,  /* bRead_only */
293   True,  /* bNo_set_dir */
294   False, /* bGuest_only */
295   False, /* bGuest_ok */
296   False, /* bPrint_ok */
297   False, /* bPostscript */
298   False, /* bMap_system */
299   False, /* bMap_hidden */
300   True,  /* bMap_archive */
301   True,  /* bLocking */
302   False,  /* bStrictLocking */
303   True,  /* bShareModes */
304   False, /* bOnlyUser */
305   True,  /* bMangledNames */
306   True,  /* bWidelinks */
307   False, /* bSyncAlways */
308   '~',   /* magic char */
309   NULL,  /* copymap */
310   ""     /* dummy */
311 };
312
313
314
315 /* local variables */
316 static service **ServicePtrs = NULL;
317 static int iNumServices = 0;
318 static int iServiceIndex = 0;
319 static BOOL bInGlobalSection = True;
320 static BOOL bGlobalOnly = False;
321
322
323 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
324
325 /* prototypes for the special type handlers */
326 static BOOL handle_valid_chars(char *pszParmValue, char **ptr);
327 static BOOL handle_include(char *pszParmValue, char **ptr);
328 static BOOL handle_copy(char *pszParmValue, char **ptr);
329 static BOOL handle_protocol(char *pszParmValue,int *val);
330 static BOOL handle_security(char *pszParmValue,int *val);
331 static BOOL handle_case(char *pszParmValue,int *val);
332 static BOOL handle_printing(char *pszParmValue,int *val);
333 static BOOL handle_character_set(char *pszParmValue,int *val);
334 #ifdef KANJI
335 static BOOL handle_coding_system(char *pszParmValue,int *val);
336 #endif /* KANJI */
337
338 struct parm_struct
339 {
340   char *label;
341   parm_type type;
342   parm_class class;
343   void *ptr;
344   BOOL (*special)();
345 } parm_table[] =
346 {
347   {"debuglevel",       P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL},
348   {"log level",        P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL},
349   {"syslog",           P_INTEGER, P_GLOBAL, &Globals.syslog,            NULL},
350   {"syslog only",      P_BOOL,    P_GLOBAL, &Globals.bSyslogOnly,       NULL},
351   {"protocol",         P_INTEGER, P_GLOBAL, &Globals.maxprotocol,handle_protocol},
352   {"security",         P_INTEGER, P_GLOBAL, &Globals.security,handle_security},
353   {"printing",         P_INTEGER, P_GLOBAL, &Globals.printing,handle_printing},
354   {"max disk size",    P_INTEGER, P_GLOBAL, &Globals.maxdisksize,       NULL},
355   {"lpq cache time",   P_INTEGER, P_GLOBAL, &Globals.lpqcachetime,      NULL},
356   {"encrypt passwords",P_BOOL,    P_GLOBAL, &Globals.bEncryptPasswords, NULL},
357   {"getwd cache",      P_BOOL,    P_GLOBAL, &use_getwd_cache,           NULL},
358   {"read prediction",  P_BOOL,    P_GLOBAL, &Globals.bReadPrediction,   NULL},
359   {"read bmpx",        P_BOOL,    P_GLOBAL, &Globals.bReadbmpx,         NULL},
360   {"read raw",         P_BOOL,    P_GLOBAL, &Globals.bReadRaw,          NULL},
361   {"write raw",        P_BOOL,    P_GLOBAL, &Globals.bWriteRaw,         NULL},
362   {"use rhosts",       P_BOOL,    P_GLOBAL, &Globals.bUseRhosts,        NULL},
363   {"load printers",    P_BOOL,    P_GLOBAL, &Globals.bLoadPrinters,     NULL},
364   {"null passwords",   P_BOOL,    P_GLOBAL, &Globals.bNullPasswords,    NULL},
365   {"strip dot",        P_BOOL,    P_GLOBAL, &Globals.bStripDot,         NULL},
366   {"password server",  P_STRING,  P_GLOBAL, &Globals.szPasswordServer,  NULL},
367   {"socket options",   P_GSTRING, P_GLOBAL, user_socket_options,        NULL},
368   {"smbrun",           P_GSTRING, P_GLOBAL, smbrun_path,                NULL},
369   {"log file",         P_STRING,  P_GLOBAL, &Globals.szLogFile,         NULL},
370   {"config file",      P_STRING,  P_GLOBAL, &Globals.szConfigFile,      NULL},
371   {"smb passwd file",  P_STRING,  P_GLOBAL, &Globals.szSMBPasswdFile,   NULL},
372   {"hosts equiv",      P_STRING,  P_GLOBAL, &Globals.szHostsEquiv,      NULL},
373   {"preload",          P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL},
374   {"auto services",    P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL},
375   {"server string",    P_STRING,  P_GLOBAL, &Globals.szServerString,    NULL},
376   {"printcap name",    P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL},
377   {"printcap",         P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL},
378   {"lock dir",         P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL},
379   {"lock directory",   P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL},
380   {"root directory",   P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL},
381   {"root dir",         P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL},
382   {"root",             P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL},
383   {"default service",  P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL},
384   {"default",          P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL},
385   {"message command",  P_STRING,  P_GLOBAL, &Globals.szMsgCommand,      NULL},
386   {"dfree command",    P_STRING,  P_GLOBAL, &Globals.szDfree,           NULL},
387   {"passwd program",   P_STRING,  P_GLOBAL, &Globals.szPasswdProgram,   NULL},
388   {"passwd chat",      P_STRING,  P_GLOBAL, &Globals.szPasswdChat,      NULL},
389   {"valid chars",      P_STRING,  P_GLOBAL, &Globals.szValidChars,      handle_valid_chars},
390   {"workgroup",        P_STRING,  P_GLOBAL, &Globals.szWorkGroup,       NULL},
391   {"domain controller",P_STRING,  P_GLOBAL, &Globals.szDomainController,NULL},
392   {"username map",     P_STRING,  P_GLOBAL, &Globals.szUsernameMap,     NULL},
393   {"character set",    P_STRING,  P_GLOBAL, &Globals.szCharacterSet,    handle_character_set},
394   {"logon script",     P_STRING,  P_GLOBAL, &Globals.szLogonScript,     NULL},
395   {"max log size",     P_INTEGER, P_GLOBAL, &Globals.max_log_size,      NULL},
396   {"mangled stack",    P_INTEGER, P_GLOBAL, &Globals.mangled_stack,     NULL},
397   {"max mux",          P_INTEGER, P_GLOBAL, &Globals.max_mux,           NULL},
398   {"max xmit",         P_INTEGER, P_GLOBAL, &Globals.max_xmit,          NULL},
399   {"max packet",       P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL},
400   {"packet size",      P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL},
401   {"password level",   P_INTEGER, P_GLOBAL, &Globals.pwordlevel,        NULL},
402   {"keepalive",        P_INTEGER, P_GLOBAL, &keepalive,                 NULL},
403   {"deadtime",         P_INTEGER, P_GLOBAL, &Globals.deadtime,          NULL},
404   {"time offset",      P_INTEGER, P_GLOBAL, &extra_time_offset,         NULL},
405   {"read size",        P_INTEGER, P_GLOBAL, &ReadSize,                  NULL},
406 #ifdef KANJI
407   {"coding system",    P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
408 #endif /* KANJI */
409   {"os level",         P_INTEGER, P_GLOBAL, &Globals.os_level,          NULL},
410   {"max ttl",          P_INTEGER, P_GLOBAL, &Globals.max_ttl,           NULL},
411   {"preferred master", P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL},
412   {"prefered master",  P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL},
413   {"domain master",    P_BOOL,    P_GLOBAL, &Globals.bDomainMaster,     NULL},
414   {"domain logons",    P_BOOL,    P_GLOBAL, &Globals.bDomainLogons,     NULL},
415   {"browse list",      P_BOOL,    P_GLOBAL, &Globals.bBrowseList,       NULL},
416
417   {"-valid",           P_BOOL,    P_LOCAL,  &sDefault.valid,            NULL},
418   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,          NULL},
419   {"copy",             P_STRING,  P_LOCAL,  &sDefault.szCopy,    handle_copy},
420   {"include",          P_STRING,  P_LOCAL,  &sDefault.szInclude, handle_include},
421   {"exec",             P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL},
422   {"preexec",          P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL},
423   {"postexec",         P_STRING,  P_LOCAL,  &sDefault.szPostExec,       NULL},
424   {"root preexec",     P_STRING,  P_LOCAL,  &sDefault.szRootPreExec,    NULL},
425   {"root postexec",    P_STRING,  P_LOCAL,  &sDefault.szRootPostExec,   NULL},
426   {"alternate permissions",P_BOOL,P_LOCAL,  &sDefault.bAlternatePerm,   NULL},
427   {"revalidate",       P_BOOL,    P_LOCAL,  &sDefault.bRevalidate,      NULL},
428   {"default case",     P_INTEGER, P_LOCAL,  &sDefault.iDefaultCase,   handle_case},
429   {"case sensitive",   P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL},
430   {"casesignames",     P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL},
431   {"preserve case",    P_BOOL,    P_LOCAL,  &sDefault.bCasePreserve,    NULL},
432   {"short preserve case",P_BOOL,  P_LOCAL,  &sDefault.bShortCasePreserve,NULL},
433   {"mangle case",      P_BOOL,    P_LOCAL,  &sDefault.bCaseMangle,      NULL},
434   {"mangling char",    P_CHAR,    P_LOCAL,  &sDefault.magic_char,       NULL},
435   {"browseable",       P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL},
436   {"browsable",        P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL},
437   {"available",        P_BOOL,    P_LOCAL,  &sDefault.bAvailable,       NULL},
438   {"path",             P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL},
439   {"directory",        P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL},
440   {"username",         P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL},
441   {"user",             P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL},
442   {"users",            P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL},
443   {"guest account",    P_STRING,  P_LOCAL,  &sDefault.szGuestaccount,   NULL},
444   {"invalid users",    P_STRING,  P_LOCAL,  &sDefault.szInvalidUsers,   NULL},
445   {"valid users",      P_STRING,  P_LOCAL,  &sDefault.szValidUsers,     NULL},
446   {"admin users",      P_STRING,  P_LOCAL,  &sDefault.szAdminUsers,     NULL},
447   {"read list",        P_STRING,  P_LOCAL,  &sDefault.readlist,         NULL},
448   {"write list",       P_STRING,  P_LOCAL,  &sDefault.writelist,        NULL},
449   {"volume",           P_STRING,  P_LOCAL,  &sDefault.volume,           NULL},
450   {"force user",       P_STRING,  P_LOCAL,  &sDefault.force_user,       NULL},
451   {"force group",      P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL},
452   {"group",            P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL},
453   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.bRead_only,       NULL},
454   {"write ok",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
455   {"writeable",        P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
456   {"writable",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
457   {"max connections",  P_INTEGER, P_LOCAL,  &sDefault.iMaxConnections,  NULL},
458   {"min print space",  P_INTEGER, P_LOCAL,  &sDefault.iMinPrintSpace,   NULL},
459   {"create mask",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mode,     NULL},
460   {"create mode",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mode,     NULL},
461   {"set directory",    P_BOOLREV, P_LOCAL,  &sDefault.bNo_set_dir,      NULL},
462   {"status",           P_BOOL,    P_LOCAL,  &sDefault.status,           NULL},
463   {"hide dot files",   P_BOOL,    P_LOCAL,  &sDefault.bHideDotFiles,    NULL},
464   {"guest only",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL},
465   {"only guest",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL},
466   {"guest ok",         P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL},
467   {"public",           P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL},
468   {"print ok",         P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL},
469   {"printable",        P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL},
470   {"postscript",       P_BOOL,    P_LOCAL,  &sDefault.bPostscript,      NULL},
471   {"map system",       P_BOOL,    P_LOCAL,  &sDefault.bMap_system,      NULL},
472   {"map hidden",       P_BOOL,    P_LOCAL,  &sDefault.bMap_hidden,      NULL},
473   {"map archive",      P_BOOL,    P_LOCAL,  &sDefault.bMap_archive,     NULL},
474   {"locking",          P_BOOL,    P_LOCAL,  &sDefault.bLocking,         NULL},
475   {"strict locking",   P_BOOL,    P_LOCAL,  &sDefault.bStrictLocking,   NULL},
476   {"share modes",      P_BOOL,    P_LOCAL,  &sDefault.bShareModes,      NULL},
477   {"only user",        P_BOOL,    P_LOCAL,  &sDefault.bOnlyUser,        NULL},
478   {"wide links",       P_BOOL,    P_LOCAL,  &sDefault.bWidelinks,       NULL},
479   {"sync always",      P_BOOL,    P_LOCAL,  &sDefault.bSyncAlways,      NULL},
480   {"mangled names",    P_BOOL,    P_LOCAL,  &sDefault.bMangledNames,    NULL},
481   {"print command",    P_STRING,  P_LOCAL,  &sDefault.szPrintcommand,   NULL},
482   {"lpq command",      P_STRING,  P_LOCAL,  &sDefault.szLpqcommand,     NULL},
483   {"lprm command",     P_STRING,  P_LOCAL,  &sDefault.szLprmcommand,    NULL},
484   {"lppause command",  P_STRING,  P_LOCAL,  &sDefault.szLppausecommand, NULL},
485   {"lpresume command", P_STRING,  P_LOCAL,  &sDefault.szLpresumecommand,NULL},
486   {"printer",          P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL},
487   {"printer name",     P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL},
488   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL},
489   {"allow hosts",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL},
490   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL},
491   {"deny hosts",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL},
492   {"dont descend",     P_STRING,  P_LOCAL,  &sDefault.szDontdescend,    NULL},
493   {"magic script",     P_STRING,  P_LOCAL,  &sDefault.szMagicScript,    NULL},
494   {"magic output",     P_STRING,  P_LOCAL,  &sDefault.szMagicOutput,    NULL},
495   {"mangled map",      P_STRING,  P_LOCAL,  &sDefault.szMangledMap,     NULL},
496
497   {NULL,               P_BOOL,    P_NONE,   NULL,                       NULL}
498 };
499
500
501
502 /***************************************************************************
503 Initialise the global parameter structure.
504 ***************************************************************************/
505 static void init_globals(void)
506 {
507   static BOOL done_init = False;
508   pstring s;
509
510   if (!done_init)
511     {
512       int i;
513       bzero((void *)&Globals,sizeof(Globals));
514
515       for (i = 0; parm_table[i].label; i++) 
516         if (parm_table[i].type == P_STRING && 
517             parm_table[i].ptr)
518           string_init(parm_table[i].ptr,"");
519
520       string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
521
522       done_init = True;
523     }
524
525
526   DEBUG(3,("Initialising global parameters\n"));
527
528 #ifdef SMB_PASSWD_FILE
529   string_set(&Globals.szSMBPasswdFile, SMB_PASSWD_FILE);
530 #endif
531   string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
532   string_set(&Globals.szWorkGroup, WORKGROUP);
533 #ifdef SMB_PASSWD
534   string_set(&Globals.szPasswdProgram, SMB_PASSWD);
535 #else
536   string_set(&Globals.szPasswdProgram, "/bin/passwd");
537 #endif
538   string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
539   string_set(&Globals.szLockDir, LOCKDIR);
540   string_set(&Globals.szRootdir, "/");
541   sprintf(s,"Samba %s",VERSION);
542   string_set(&Globals.szServerString,s);
543   Globals.bLoadPrinters = True;
544   Globals.bUseRhosts = False;
545   Globals.max_packet = 65535;
546   Globals.mangled_stack = 50;
547   Globals.max_xmit = Globals.max_packet;
548   Globals.max_mux = 2;
549   Globals.lpqcachetime = 10;
550   Globals.pwordlevel = 0;
551   Globals.deadtime = 0;
552   Globals.max_log_size = 5000;
553   Globals.maxprotocol = PROTOCOL_NT1;
554   Globals.security = SEC_SHARE;
555   Globals.bEncryptPasswords = False;
556   Globals.printing = DEFAULT_PRINTING;
557   Globals.bReadRaw = True;
558   Globals.bWriteRaw = True;
559   Globals.bReadPrediction = False;
560   Globals.bReadbmpx = True;
561   Globals.bNullPasswords = False;
562   Globals.bStripDot = False;
563   Globals.syslog = 1;
564   Globals.bSyslogOnly = False;
565   Globals.os_level = 0;
566   Globals.max_ttl = 60*60*4; /* 2 hours default */
567   Globals.bPreferredMaster = True;
568   Globals.bDomainMaster = False;
569   Globals.bDomainLogons = False;
570   Globals.bBrowseList = True;
571
572 #ifdef KANJI
573   coding_system = interpret_coding_system (KANJI, SJIS_CODE);
574 #endif /* KANJI */
575
576 }
577
578 /***************************************************************************
579 check if a string is initialised and if not then initialise it
580 ***************************************************************************/
581 static void string_initial(char **s,char *v)
582 {
583   if (!*s || !**s)
584     string_init(s,v);
585 }
586
587
588 /***************************************************************************
589 Initialise the sDefault parameter structure.
590 ***************************************************************************/
591 static void init_locals(void)
592 {
593   /* choose defaults depending on the type of printing */
594   switch (Globals.printing)
595     {
596     case PRINT_BSD:
597     case PRINT_AIX:
598       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
599       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
600       string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
601       break;
602
603     case PRINT_SYSV:
604     case PRINT_HPUX:
605       string_initial(&sDefault.szLpqcommand,"lpstat -o%p");
606       string_initial(&sDefault.szLprmcommand,"cancel %p-%j");
607       string_initial(&sDefault.szPrintcommand,"lp -c -d%p %s; rm %s");
608 #ifdef SVR4
609       string_initial(&sDefault.szLppausecommand,"lp -i %p-%j -H hold");
610       string_initial(&sDefault.szLpresumecommand,"lp -i %p-%j -H resume");
611 #endif
612       break;
613
614     case PRINT_QNX:
615       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
616       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
617       string_initial(&sDefault.szPrintcommand,"lp -r -P%p %s");
618       break;
619
620       
621     }
622 }
623
624
625 /*******************************************************************
626 a convenience rooutine to grab string parameters into a rotating
627 static buffer, and run standard_sub_basic on them. The buffers
628 can be written to by callers
629 ********************************************************************/
630 char *lp_string(char *s)
631 {
632   static pstring bufs[10];
633   static int next=0;
634   char *ret;
635   
636   ret = &bufs[next][0];
637   next = (next+1)%10;
638
639   if (!s) 
640     *ret = 0;
641   else
642     StrnCpy(ret,s,sizeof(pstring)-1);
643
644   standard_sub_basic(ret);
645   return(ret);
646 }
647
648
649 /*
650    In this section all the functions that are used to access the 
651    parameters from the rest of the program are defined 
652 */
653
654 #define FN_GLOBAL_STRING(fn_name,ptr) \
655  char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
656 #define FN_GLOBAL_BOOL(fn_name,ptr) \
657  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
658 #define FN_GLOBAL_CHAR(fn_name,ptr) \
659  char fn_name(void) {return(*(char *)(ptr));}
660 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
661  int fn_name(void) {return(*(int *)(ptr));}
662
663 #define FN_LOCAL_STRING(fn_name,val) \
664  char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : sDefault.val));}
665 #define FN_LOCAL_BOOL(fn_name,val) \
666  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
667 #define FN_LOCAL_CHAR(fn_name,val) \
668  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
669 #define FN_LOCAL_INTEGER(fn_name,val) \
670  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
671
672 FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile)
673 FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
674 FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
675 FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
676 FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname)
677 FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir)
678 FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir)
679 FN_GLOBAL_STRING(lp_defaultservice,&Globals.szDefaultService)
680 FN_GLOBAL_STRING(lp_msg_command,&Globals.szMsgCommand)
681 FN_GLOBAL_STRING(lp_dfree_command,&Globals.szDfree)
682 FN_GLOBAL_STRING(lp_hosts_equiv,&Globals.szHostsEquiv)
683 FN_GLOBAL_STRING(lp_auto_services,&Globals.szAutoServices)
684 FN_GLOBAL_STRING(lp_passwd_program,&Globals.szPasswdProgram)
685 FN_GLOBAL_STRING(lp_passwd_chat,&Globals.szPasswdChat)
686 FN_GLOBAL_STRING(lp_passwordserver,&Globals.szPasswordServer)
687 FN_GLOBAL_STRING(lp_workgroup,&Globals.szWorkGroup)
688 FN_GLOBAL_STRING(lp_domain_controller,&Globals.szDomainController)
689 FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
690 FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) 
691 FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) 
692
693 FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
694 FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
695 FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
696 FN_GLOBAL_BOOL(lp_load_printers,&Globals.bLoadPrinters)
697 FN_GLOBAL_BOOL(lp_use_rhosts,&Globals.bUseRhosts)
698 FN_GLOBAL_BOOL(lp_getwdcache,&use_getwd_cache)
699 FN_GLOBAL_BOOL(lp_readprediction,&Globals.bReadPrediction)
700 FN_GLOBAL_BOOL(lp_readbmpx,&Globals.bReadbmpx)
701 FN_GLOBAL_BOOL(lp_readraw,&Globals.bReadRaw)
702 FN_GLOBAL_BOOL(lp_writeraw,&Globals.bWriteRaw)
703 FN_GLOBAL_BOOL(lp_null_passwords,&Globals.bNullPasswords)
704 FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
705 FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
706 FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
707 FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
708
709 FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
710 FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
711 FN_GLOBAL_INTEGER(lp_max_log_size,&Globals.max_log_size)
712 FN_GLOBAL_INTEGER(lp_mangledstack,&Globals.mangled_stack)
713 FN_GLOBAL_INTEGER(lp_maxxmit,&Globals.max_xmit)
714 FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
715 FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
716 FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
717 FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
718 FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
719 FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
720 FN_GLOBAL_INTEGER(lp_security,&Globals.security)
721 FN_GLOBAL_INTEGER(lp_printing,&Globals.printing)
722 FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
723 FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
724 FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
725
726 FN_LOCAL_STRING(lp_preexec,szPreExec)
727 FN_LOCAL_STRING(lp_postexec,szPostExec)
728 FN_LOCAL_STRING(lp_rootpreexec,szRootPreExec)
729 FN_LOCAL_STRING(lp_rootpostexec,szRootPostExec)
730 FN_LOCAL_STRING(lp_servicename,szService)
731 FN_LOCAL_STRING(lp_pathname,szPath)
732 FN_LOCAL_STRING(lp_dontdescend,szDontdescend)
733 FN_LOCAL_STRING(lp_username,szUsername)
734 FN_LOCAL_STRING(lp_guestaccount,szGuestaccount)
735 FN_LOCAL_STRING(lp_invalid_users,szInvalidUsers)
736 FN_LOCAL_STRING(lp_valid_users,szValidUsers)
737 FN_LOCAL_STRING(lp_admin_users,szAdminUsers)
738 FN_LOCAL_STRING(lp_printcommand,szPrintcommand)
739 FN_LOCAL_STRING(lp_lpqcommand,szLpqcommand)
740 FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
741 FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
742 FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
743 FN_LOCAL_STRING(lp_printername,szPrintername)
744 FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
745 FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
746 FN_LOCAL_STRING(lp_magicscript,szMagicScript)
747 FN_LOCAL_STRING(lp_magicoutput,szMagicOutput)
748 FN_LOCAL_STRING(lp_comment,comment)
749 FN_LOCAL_STRING(lp_force_user,force_user)
750 FN_LOCAL_STRING(lp_force_group,force_group)
751 FN_LOCAL_STRING(lp_readlist,readlist)
752 FN_LOCAL_STRING(lp_writelist,writelist)
753 FN_LOCAL_STRING(lp_volume,volume)
754 FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
755
756 FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
757 FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
758 FN_LOCAL_BOOL(lp_casesensitive,bCaseSensitive)
759 FN_LOCAL_BOOL(lp_preservecase,bCasePreserve)
760 FN_LOCAL_BOOL(lp_shortpreservecase,bShortCasePreserve)
761 FN_LOCAL_BOOL(lp_casemangle,bCaseMangle)
762 FN_LOCAL_BOOL(lp_status,status)
763 FN_LOCAL_BOOL(lp_hide_dot_files,bHideDotFiles)
764 FN_LOCAL_BOOL(lp_browseable,bBrowseable)
765 FN_LOCAL_BOOL(lp_readonly,bRead_only)
766 FN_LOCAL_BOOL(lp_no_set_dir,bNo_set_dir)
767 FN_LOCAL_BOOL(lp_guest_ok,bGuest_ok)
768 FN_LOCAL_BOOL(lp_guest_only,bGuest_only)
769 FN_LOCAL_BOOL(lp_print_ok,bPrint_ok)
770 FN_LOCAL_BOOL(lp_postscript,bPostscript)
771 FN_LOCAL_BOOL(lp_map_hidden,bMap_hidden)
772 FN_LOCAL_BOOL(lp_map_archive,bMap_archive)
773 FN_LOCAL_BOOL(lp_locking,bLocking)
774 FN_LOCAL_BOOL(lp_strict_locking,bStrictLocking)
775 FN_LOCAL_BOOL(lp_share_modes,bShareModes)
776 FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
777 FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
778 FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
779 FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
780 FN_LOCAL_BOOL(lp_map_system,bMap_system)
781
782 FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
783 FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
784 FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
785 FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
786
787 FN_LOCAL_CHAR(lp_magicchar,magic_char)
788
789
790
791 /* local prototypes */
792 static int    strwicmp( char *psz1, char *psz2 );
793 static int    map_parameter( char *pszParmName);
794 static BOOL   set_boolean( BOOL *pb, char *pszParmValue );
795 static int    getservicebyname(char *pszServiceName, service *pserviceDest);
796 static void   copy_service( service *pserviceDest, 
797                             service *pserviceSource,
798                             BOOL *pcopymapDest );
799 static BOOL   service_ok(int iService);
800 static BOOL   do_parameter(char *pszParmName, char *pszParmValue);
801 static BOOL   do_section(char *pszSectionName);
802 static void   dump_globals(void);
803 static void   dump_a_service(service *pService);
804 static void init_copymap(service *pservice);
805
806
807 /***************************************************************************
808 initialise a service to the defaults
809 ***************************************************************************/
810 static void init_service(service *pservice)
811 {
812   bzero((char *)pservice,sizeof(service));
813   copy_service(pservice,&sDefault,NULL);
814 }
815
816
817 /***************************************************************************
818 free the dynamically allocated parts of a service struct
819 ***************************************************************************/
820 static void free_service(service *pservice)
821 {
822   int i;
823   if (!pservice)
824      return;
825
826   for (i=0;parm_table[i].label;i++)
827     if (parm_table[i].type == P_STRING && parm_table[i].class == P_LOCAL)
828       string_free((char **)(((char *)pservice) + PTR_DIFF(parm_table[i].ptr,&sDefault)));
829 }
830
831 /***************************************************************************
832 add a new service to the services array initialising it with the given 
833 service
834 ***************************************************************************/
835 static int add_a_service(service *pservice, char *name)
836 {
837   int i;
838   service tservice;
839   int num_to_alloc = iNumServices+1;
840
841   tservice = *pservice;
842
843   /* it might already exist */
844   if (name) 
845     {
846       i = getservicebyname(name,NULL);
847       if (i >= 0)
848         return(i);
849     }
850
851   /* find an invalid one */
852   for (i=0;i<iNumServices;i++)
853     if (!pSERVICE(i)->valid)
854       break;
855
856   /* if not, then create one */
857   if (i == iNumServices)
858     {
859       ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
860       if (ServicePtrs)
861         pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
862
863       if (!ServicePtrs || !pSERVICE(iNumServices))
864         return(-1);
865
866       iNumServices++;
867     }
868   else
869     free_service(pSERVICE(i));
870
871   pSERVICE(i)->valid = True;
872
873   init_service(pSERVICE(i));
874   copy_service(pSERVICE(i),&tservice,NULL);
875   if (name)
876     string_set(&iSERVICE(i).szService,name);  
877
878   return(i);
879 }
880
881 /***************************************************************************
882 add a new home service, with the specified home directory, defaults coming 
883 from service ifrom
884 ***************************************************************************/
885 BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir)
886 {
887   int i = add_a_service(pSERVICE(iDefaultService),pszHomename);
888
889   if (i < 0)
890     return(False);
891
892   if (!(*(iSERVICE(i).szPath)) || strequal(iSERVICE(i).szPath,lp_pathname(-1)))
893     string_set(&iSERVICE(i).szPath,pszHomedir);
894   if (!(*(iSERVICE(i).comment)))
895     {
896       pstring comment;
897       sprintf(comment,"Home directory of %s",pszHomename);
898       string_set(&iSERVICE(i).comment,comment);
899     }
900   iSERVICE(i).bAvailable = sDefault.bAvailable;
901   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
902
903   DEBUG(3,("adding home directory %s at %s\n", pszHomename, pszHomedir));
904
905   return(True);
906 }
907
908 /***************************************************************************
909 add a new service, based on an old one
910 ***************************************************************************/
911 int lp_add_service(char *pszService, int iDefaultService)
912 {
913   return(add_a_service(pSERVICE(iDefaultService),pszService));
914 }
915
916
917 /***************************************************************************
918 add the IPC service
919 ***************************************************************************/
920 static BOOL lp_add_ipc(void)
921 {
922   pstring comment;
923   int i = add_a_service(&sDefault,"IPC$");
924
925   if (i < 0)
926     return(False);
927
928   sprintf(comment,"IPC Service (%s)",lp_serverstring());
929
930   string_set(&iSERVICE(i).szPath,"/tmp");
931   string_set(&iSERVICE(i).szUsername,"");
932   string_set(&iSERVICE(i).comment,comment);
933   iSERVICE(i).status = False;
934   iSERVICE(i).iMaxConnections = 0;
935   iSERVICE(i).bAvailable = True;
936   iSERVICE(i).bRead_only = True;
937   iSERVICE(i).bGuest_only = False;
938   iSERVICE(i).bGuest_ok = True;
939   iSERVICE(i).bPrint_ok = False;
940   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
941
942   DEBUG(3,("adding IPC service\n"));
943
944   return(True);
945 }
946
947
948 /***************************************************************************
949 add a new printer service, with defaults coming from service iFrom
950 ***************************************************************************/
951 BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
952 {
953   char *comment = "From Printcap";
954   int i = add_a_service(pSERVICE(iDefaultService),pszPrintername);
955   
956   if (i < 0)
957     return(False);
958   
959   /* note that we do NOT default the availability flag to True - */
960   /* we take it from the default service passed. This allows all */
961   /* dynamic printers to be disabled by disabling the [printers] */
962   /* entry (if/when the 'available' keyword is implemented!).    */
963   
964   /* the printer name is set to the service name. */
965   string_set(&iSERVICE(i).szPrintername,pszPrintername);
966   string_set(&iSERVICE(i).comment,comment);
967   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
968   
969   DEBUG(3,("adding printer service %s\n",pszPrintername));
970   
971   return(True);
972 }
973
974
975 /***************************************************************************
976 Do a case-insensitive, whitespace-ignoring string compare.
977 ***************************************************************************/
978 static int strwicmp(char *psz1, char *psz2)
979 {
980    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
981    /* appropriate value. */
982    if (psz1 == psz2)
983       return (0);
984    else
985       if (psz1 == NULL)
986          return (-1);
987       else
988           if (psz2 == NULL)
989               return (1);
990
991    /* sync the strings on first non-whitespace */
992    while (1)
993    {
994       while (isspace(*psz1))
995          psz1++;
996       while (isspace(*psz2))
997          psz2++;
998       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
999          break;
1000       psz1++;
1001       psz2++;
1002    }
1003    return (*psz1 - *psz2);
1004 }
1005
1006 /***************************************************************************
1007 Map a parameter's string representation to something we can use. 
1008 Returns False if the parameter string is not recognised, else TRUE.
1009 ***************************************************************************/
1010 static int map_parameter(char *pszParmName)
1011 {
1012    int iIndex;
1013
1014    if (*pszParmName == '-')
1015      return(-1);
1016
1017    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
1018       if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1019          return(iIndex);
1020
1021    DEBUG(0,( "Unknown parameter encountered: \"%s\"\n", pszParmName));
1022    return(-1);
1023 }
1024
1025
1026 /***************************************************************************
1027 Set a boolean variable from the text value stored in the passed string.
1028 Returns True in success, False if the passed string does not correctly 
1029 represent a boolean.
1030 ***************************************************************************/
1031 static BOOL set_boolean(BOOL *pb, char *pszParmValue)
1032 {
1033    BOOL bRetval;
1034
1035    bRetval = True;
1036    if (strwicmp(pszParmValue, "yes") == 0 ||
1037        strwicmp(pszParmValue, "true") == 0 ||
1038        strwicmp(pszParmValue, "1") == 0)
1039       *pb = True;
1040    else
1041       if (strwicmp(pszParmValue, "no") == 0 ||
1042           strwicmp(pszParmValue, "False") == 0 ||
1043           strwicmp(pszParmValue, "0") == 0)
1044          *pb = False;
1045       else
1046       {
1047          DEBUG(0,( "Badly formed boolean in configuration file: \"%s\".\n",
1048                pszParmValue));
1049          bRetval = False;
1050       }
1051    return (bRetval);
1052 }
1053
1054 /***************************************************************************
1055 Find a service by name. Otherwise works like get_service.
1056 ***************************************************************************/
1057 static int getservicebyname(char *pszServiceName, service *pserviceDest)
1058 {
1059    int iService;
1060
1061    for (iService = iNumServices - 1; iService >= 0; iService--)
1062       if (VALID(iService) &&
1063           strwicmp(iSERVICE(iService).szService, pszServiceName) == 0) 
1064       {
1065          if (pserviceDest != NULL)
1066            copy_service(pserviceDest, pSERVICE(iService), NULL);
1067          break;
1068       }
1069
1070    return (iService);
1071 }
1072
1073
1074
1075 /***************************************************************************
1076 Copy a service structure to another
1077
1078 If pcopymapDest is NULL then copy all fields
1079 ***************************************************************************/
1080 static void copy_service(service *pserviceDest, 
1081                          service *pserviceSource,
1082                          BOOL *pcopymapDest)
1083 {
1084   int i;
1085   BOOL bcopyall = (pcopymapDest == NULL);
1086
1087   for (i=0;parm_table[i].label;i++)
1088     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL && 
1089         (bcopyall || pcopymapDest[i]))
1090       {
1091         void *def_ptr = parm_table[i].ptr;
1092         void *src_ptr = 
1093           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
1094         void *dest_ptr = 
1095           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
1096
1097         switch (parm_table[i].type)
1098           {
1099           case P_BOOL:
1100           case P_BOOLREV:
1101             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1102             break;
1103
1104           case P_INTEGER:
1105           case P_OCTAL:
1106             *(int *)dest_ptr = *(int *)src_ptr;
1107             break;
1108
1109           case P_CHAR:
1110             *(char *)dest_ptr = *(char *)src_ptr;
1111             break;
1112
1113           case P_STRING:
1114             string_set(dest_ptr,*(char **)src_ptr);
1115             break;
1116           default:
1117             break;
1118           }
1119       }
1120
1121   if (bcopyall)
1122     {
1123       init_copymap(pserviceDest);
1124       if (pserviceSource->copymap)
1125         memcpy((void *)pserviceDest->copymap,
1126                (void *)pserviceSource->copymap,sizeof(BOOL)*NUMPARAMETERS);
1127     }
1128 }
1129
1130 /***************************************************************************
1131 Check a service for consistency. Return False if the service is in any way
1132 incomplete or faulty, else True.
1133 ***************************************************************************/
1134 static BOOL service_ok(int iService)
1135 {
1136    BOOL bRetval;
1137
1138    bRetval = True;
1139    if (iSERVICE(iService).szService[0] == '\0')
1140    {
1141       DEBUG(0,( "The following message indicates an internal error:\n"));
1142       DEBUG(0,( "No service name in service entry.\n"));
1143       bRetval = False;
1144    }
1145
1146    /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1147    /* I can't see why you'd want a non-printable printer service...        */
1148    if (strwicmp(iSERVICE(iService).szService,PRINTERS_NAME) == 0)
1149       if (!iSERVICE(iService).bPrint_ok)
1150       {
1151          DEBUG(0,( "WARNING: [%s] service MUST be printable!\n",
1152                iSERVICE(iService).szService));
1153          iSERVICE(iService).bPrint_ok = True;
1154       }
1155
1156    if (iSERVICE(iService).szPath[0] == '\0' &&
1157        strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
1158    {
1159       DEBUG(0,("No path in service %s - using /tmp\n",iSERVICE(iService).szService));
1160       string_set(&iSERVICE(iService).szPath,"/tmp");      
1161    }
1162
1163    /* If a service is flagged unavailable, log the fact at level 0. */
1164    if (!iSERVICE(iService).bAvailable) 
1165       DEBUG(1,( "NOTE: Service %s is flagged unavailable.\n",
1166             iSERVICE(iService).szService));
1167
1168    return (bRetval);
1169 }
1170
1171 static struct file_lists {
1172   struct file_lists *next;
1173   char *name;
1174   time_t modtime;
1175 } *file_lists = NULL;
1176
1177 /*******************************************************************
1178 keep a linked list of all config files so we know when one has changed 
1179 it's date and needs to be reloaded
1180 ********************************************************************/
1181 static void add_to_file_list(char *fname)
1182 {
1183   struct file_lists *f=file_lists;
1184
1185   while (f) {
1186     if (f->name && !strcmp(f->name,fname)) break;
1187     f = f->next;
1188   }
1189
1190   if (!f) {
1191     f = (struct file_lists *)malloc(sizeof(file_lists[0]));
1192     if (!f) return;
1193     f->next = file_lists;
1194     f->name = strdup(fname);
1195     if (!f->name) {
1196       free(f);
1197       return;
1198     }
1199     file_lists = f;
1200   }
1201
1202   {
1203     pstring n2;
1204     strcpy(n2,fname);
1205     standard_sub_basic(n2);
1206     f->modtime = file_modtime(n2);
1207   }
1208
1209 }
1210
1211 /*******************************************************************
1212 check if a config file has changed date
1213 ********************************************************************/
1214 BOOL lp_file_list_changed(void)
1215 {
1216   struct file_lists *f = file_lists;
1217   while (f) {
1218     pstring n2;
1219     strcpy(n2,f->name);
1220     standard_sub_basic(n2);
1221     if (f->modtime != file_modtime(n2)) return(True);
1222     f = f->next;   
1223   }
1224   return(False);
1225 }
1226
1227 #ifdef KANJI
1228 /***************************************************************************
1229   handle the interpretation of the coding system parameter
1230   *************************************************************************/
1231 static BOOL handle_coding_system(char *pszParmValue,int *val)
1232 {
1233   *val = interpret_coding_system(pszParmValue,*val);
1234   return(True);
1235 }
1236 #endif /* KANJI */
1237
1238 /***************************************************************************
1239 handle the interpretation of the character set system parameter
1240 ***************************************************************************/
1241 static BOOL handle_character_set(char *pszParmValue,int *val)
1242 {
1243   string_set(&Globals.szCharacterSet,pszParmValue);
1244   *val = interpret_character_set(pszParmValue,*val);
1245   return(True);
1246 }
1247
1248
1249 /***************************************************************************
1250 handle the interpretation of the protocol parameter
1251 ***************************************************************************/
1252 static BOOL handle_protocol(char *pszParmValue,int *val)
1253 {
1254   *val = interpret_protocol(pszParmValue,*val);
1255   return(True);
1256 }
1257
1258 /***************************************************************************
1259 handle the interpretation of the security parameter
1260 ***************************************************************************/
1261 static BOOL handle_security(char *pszParmValue,int *val)
1262 {
1263   *val = interpret_security(pszParmValue,*val);
1264   return(True);
1265 }
1266
1267 /***************************************************************************
1268 handle the interpretation of the default case
1269 ***************************************************************************/
1270 static BOOL handle_case(char *pszParmValue,int *val)
1271 {
1272   if (strequal(pszParmValue,"LOWER"))
1273     *val = CASE_LOWER;
1274   else if (strequal(pszParmValue,"UPPER"))
1275     *val = CASE_UPPER;
1276   return(True);
1277 }
1278
1279 /***************************************************************************
1280 handle the interpretation of the printing system
1281 ***************************************************************************/
1282 static BOOL handle_printing(char *pszParmValue,int *val)
1283 {
1284   if (strequal(pszParmValue,"sysv"))
1285     *val = PRINT_SYSV;
1286   else if (strequal(pszParmValue,"aix"))
1287     *val = PRINT_AIX;
1288   else if (strequal(pszParmValue,"hpux"))
1289     *val = PRINT_HPUX;
1290   else if (strequal(pszParmValue,"bsd"))
1291     *val = PRINT_BSD;
1292   else if (strequal(pszParmValue,"qnx"))
1293     *val = PRINT_QNX;
1294   return(True);
1295 }
1296
1297 /***************************************************************************
1298 handle the valid chars lines
1299 ***************************************************************************/
1300 static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
1301
1302   string_set(ptr,pszParmValue);
1303
1304   add_char_string(pszParmValue);
1305   return(True);
1306 }
1307
1308
1309 /***************************************************************************
1310 handle the include operation
1311 ***************************************************************************/
1312 static BOOL handle_include(char *pszParmValue,char **ptr)
1313
1314   pstring fname;
1315   strcpy(fname,pszParmValue);
1316
1317   add_to_file_list(fname);
1318
1319   standard_sub_basic(fname);
1320
1321   string_set(ptr,fname);
1322
1323   if (file_exist(fname,NULL))
1324     return(pm_process(fname, do_section, do_parameter));      
1325
1326   DEBUG(2,("Can't find include file %s\n",fname));
1327
1328   return(False);
1329 }
1330
1331
1332 /***************************************************************************
1333 handle the interpretation of the copy parameter
1334 ***************************************************************************/
1335 static BOOL handle_copy(char *pszParmValue,char **ptr)
1336 {
1337    BOOL bRetval;
1338    int iTemp;
1339    service serviceTemp;
1340
1341    string_set(ptr,pszParmValue);
1342
1343    init_service(&serviceTemp);
1344
1345    bRetval = False;
1346    
1347    DEBUG(3,("Copying service from service %s\n",pszParmValue));
1348
1349    if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0)
1350      {
1351        if (iTemp == iServiceIndex)
1352          {
1353            DEBUG(0,("Can't copy service %s - unable to copy self!\n",
1354                     pszParmValue));
1355          }
1356        else
1357          {
1358            copy_service(pSERVICE(iServiceIndex), 
1359                         &serviceTemp,
1360                         iSERVICE(iServiceIndex).copymap);
1361            bRetval = True;
1362          }
1363      }
1364    else
1365      {
1366        DEBUG(0,( "Unable to copy service - source not found: %s\n",
1367                 pszParmValue));
1368        bRetval = False;
1369      }
1370
1371    free_service(&serviceTemp);
1372    return (bRetval);
1373 }
1374
1375
1376 /***************************************************************************
1377 initialise a copymap
1378 ***************************************************************************/
1379 static void init_copymap(service *pservice)
1380 {
1381   int i;
1382   if (pservice->copymap) free(pservice->copymap);
1383   pservice->copymap = (BOOL *)malloc(sizeof(BOOL)*NUMPARAMETERS);
1384   if (!pservice->copymap)
1385     DEBUG(0,("Couldn't allocate copymap!! (size %d)\n",NUMPARAMETERS));
1386
1387   for (i=0;i<NUMPARAMETERS;i++)
1388     pservice->copymap[i] = True;
1389 }
1390
1391
1392 /***************************************************************************
1393 Process a parameter.
1394 ***************************************************************************/
1395 static BOOL do_parameter(char *pszParmName, char *pszParmValue)
1396 {
1397    int parmnum;
1398    void *parm_ptr=NULL; /* where we are going to store the result */
1399    void *def_ptr=NULL;
1400
1401    if (!bInGlobalSection && bGlobalOnly) return(True);
1402
1403    DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
1404    
1405    parmnum = map_parameter(pszParmName);
1406
1407    if (parmnum < 0)
1408      {
1409        DEBUG(0,( "Ignoring unknown parameter \"%s\"\n", pszParmName));
1410        return(True);
1411      }
1412
1413    def_ptr = parm_table[parmnum].ptr;
1414
1415    /* we might point at a service, the default service or a global */
1416    if (bInGlobalSection)
1417      parm_ptr = def_ptr;
1418    else
1419      {
1420        if (parm_table[parmnum].class == P_GLOBAL)
1421          {
1422            DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
1423            return(True);
1424          }
1425        parm_ptr = ((char *)pSERVICE(iServiceIndex)) + PTR_DIFF(def_ptr,&sDefault);
1426      }
1427
1428    if (!bInGlobalSection)
1429      {
1430        int i;
1431        if (!iSERVICE(iServiceIndex).copymap)
1432          init_copymap(pSERVICE(iServiceIndex));
1433        
1434        /* this handles the aliases - set the copymap for other entries with
1435           the same data pointer */
1436        for (i=0;parm_table[i].label;i++)
1437          if (parm_table[i].ptr == parm_table[parmnum].ptr)
1438            iSERVICE(iServiceIndex).copymap[i] = False;
1439      }
1440
1441    /* if it is a special case then go ahead */
1442    if (parm_table[parmnum].special)
1443      {
1444        parm_table[parmnum].special(pszParmValue,parm_ptr);
1445        return(True);
1446      }
1447
1448    /* now switch on the type of variable it is */
1449    switch (parm_table[parmnum].type)
1450      {
1451      case P_BOOL:
1452        set_boolean(parm_ptr,pszParmValue);
1453        break;
1454
1455      case P_BOOLREV:
1456        set_boolean(parm_ptr,pszParmValue);
1457        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
1458        break;
1459
1460      case P_INTEGER:
1461        *(int *)parm_ptr = atoi(pszParmValue);
1462        break;
1463
1464      case P_CHAR:
1465        *(char *)parm_ptr = *pszParmValue;
1466        break;
1467
1468      case P_OCTAL:
1469        sscanf(pszParmValue,"%o",(int *)parm_ptr);
1470        break;
1471
1472      case P_STRING:
1473        string_set(parm_ptr,pszParmValue);
1474        break;
1475
1476      case P_GSTRING:
1477        strcpy((char *)parm_ptr,pszParmValue);
1478        break;
1479      }
1480
1481    return(True);
1482 }
1483
1484 /***************************************************************************
1485 print a parameter of the specified type
1486 ***************************************************************************/
1487 static void print_parameter(parm_type type,void *ptr)
1488 {
1489   switch (type)
1490     {
1491     case P_BOOL:
1492       printf("%s",BOOLSTR(*(BOOL *)ptr));
1493       break;
1494       
1495     case P_BOOLREV:
1496       printf("%s",BOOLSTR(! *(BOOL *)ptr));
1497       break;
1498       
1499     case P_INTEGER:
1500       printf("%d",*(int *)ptr);
1501       break;
1502       
1503     case P_CHAR:
1504       printf("%c",*(char *)ptr);
1505       break;
1506       
1507     case P_OCTAL:
1508       printf("0%o",*(int *)ptr);
1509       break;
1510       
1511     case P_GSTRING:
1512       if ((char *)ptr)
1513         printf("%s",(char *)ptr);
1514       break;
1515
1516     case P_STRING:
1517       if (*(char **)ptr)
1518         printf("%s",*(char **)ptr);
1519       break;
1520     }
1521 }
1522
1523
1524 /***************************************************************************
1525 check if two parameters are equal
1526 ***************************************************************************/
1527 static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
1528 {
1529   switch (type)
1530     {
1531     case P_BOOL:
1532     case P_BOOLREV:
1533       return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
1534
1535     case P_INTEGER:
1536     case P_OCTAL:
1537       return(*((int *)ptr1) == *((int *)ptr2));
1538       
1539     case P_CHAR:
1540       return(*((char *)ptr1) == *((char *)ptr2));
1541
1542     case P_GSTRING:
1543       {
1544         char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
1545         if (p1 && !*p1) p1 = NULL;
1546         if (p2 && !*p2) p2 = NULL;
1547         return(p1==p2 || strequal(p1,p2));
1548       }
1549     case P_STRING:
1550       {
1551         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
1552         if (p1 && !*p1) p1 = NULL;
1553         if (p2 && !*p2) p2 = NULL;
1554         return(p1==p2 || strequal(p1,p2));
1555       }
1556     }
1557   return(False);
1558 }
1559
1560 /***************************************************************************
1561 Process a new section (service). At this stage all sections are services.
1562 Later we'll have special sections that permit server parameters to be set.
1563 Returns True on success, False on failure.
1564 ***************************************************************************/
1565 static BOOL do_section(char *pszSectionName)
1566 {
1567    BOOL bRetval;
1568    BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) || 
1569                     (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
1570    bRetval = False;
1571
1572    /* if we were in a global section then do the local inits */
1573    if (bInGlobalSection && !isglobal)
1574      init_locals();
1575
1576    /* if we've just struck a global section, note the fact. */
1577    bInGlobalSection = isglobal;   
1578
1579    /* check for multiple global sections */
1580    if (bInGlobalSection)
1581    {
1582      DEBUG(3,( "Processing section \"[%s]\"\n", pszSectionName));
1583      return(True);
1584    }
1585
1586    if (!bInGlobalSection && bGlobalOnly) return(True);
1587
1588    /* if we have a current service, tidy it up before moving on */
1589    bRetval = True;
1590
1591    if (iServiceIndex >= 0)
1592      bRetval = service_ok(iServiceIndex);
1593
1594    /* if all is still well, move to the next record in the services array */
1595    if (bRetval)
1596      {
1597        /* We put this here to avoid an odd message order if messages are */
1598        /* issued by the post-processing of a previous section. */
1599        DEBUG(2,( "Processing section \"[%s]\"\n", pszSectionName));
1600
1601        if ((iServiceIndex=add_a_service(&sDefault,pszSectionName)) < 0)
1602          {
1603            DEBUG(0,("Failed to add a new service\n"));
1604            return(False);
1605          }
1606      }
1607
1608    return (bRetval);
1609 }
1610
1611 /***************************************************************************
1612 Display the contents of the global structure.
1613 ***************************************************************************/
1614 static void dump_globals(void)
1615 {
1616   int i;
1617   printf("Global parameters:\n");
1618
1619   for (i=0;parm_table[i].label;i++)
1620     if (parm_table[i].class == P_GLOBAL &&
1621         parm_table[i].ptr &&
1622         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1623       {
1624         printf("\t%s: ",parm_table[i].label);
1625         print_parameter(parm_table[i].type,parm_table[i].ptr);
1626         printf("\n");
1627       }
1628 }
1629
1630 /***************************************************************************
1631 Display the contents of a single services record.
1632 ***************************************************************************/
1633 static void dump_a_service(service *pService)
1634 {
1635   int i;
1636   if (pService == &sDefault)
1637     printf("\nDefault service parameters:\n");
1638   else
1639     printf("\nService parameters [%s]:\n",pService->szService);
1640
1641   for (i=0;parm_table[i].label;i++)
1642     if (parm_table[i].class == P_LOCAL &&
1643         parm_table[i].ptr && 
1644         (*parm_table[i].label != '-') &&
1645         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1646       {
1647         int pdiff = PTR_DIFF(parm_table[i].ptr,&sDefault);
1648
1649         if (pService == &sDefault || !equal_parameter(parm_table[i].type,
1650                                                       ((char *)pService) + pdiff,
1651                                                       ((char *)&sDefault) + pdiff))
1652           {
1653             printf("\t%s: ",parm_table[i].label);
1654             print_parameter(parm_table[i].type,
1655                             ((char *)pService) + pdiff);
1656             printf("\n");
1657           }
1658       }
1659 }
1660
1661 #if 0
1662 /***************************************************************************
1663 Display the contents of a single copy structure.
1664 ***************************************************************************/
1665 static void dump_copy_map(BOOL *pcopymap)
1666 {
1667   int i;
1668   if (!pcopymap) return;
1669
1670   printf("\n\tNon-Copied parameters:\n");
1671
1672   for (i=0;parm_table[i].label;i++)
1673     if (parm_table[i].class == P_LOCAL &&
1674         parm_table[i].ptr && !pcopymap[i] &&
1675         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1676       {
1677         printf("\t\t%s\n",parm_table[i].label);
1678       }
1679 }
1680 #endif
1681
1682 /***************************************************************************
1683 Return TRUE if the passed service number is within range.
1684 ***************************************************************************/
1685 BOOL lp_snum_ok(int iService)
1686 {
1687    return (LP_SNUM_OK(iService) && iSERVICE(iService).bAvailable);
1688 }
1689
1690
1691 /***************************************************************************
1692 auto-load some homes and printer services
1693 ***************************************************************************/
1694 static void lp_add_auto_services(char *str)
1695 {
1696   char *s;
1697   char *p;
1698   int homes = lp_servicenumber(HOMES_NAME);
1699   int printers = lp_servicenumber(PRINTERS_NAME);
1700
1701   if (!str)
1702     return;
1703
1704   s = strdup(str);
1705   if (!s) return;
1706
1707   for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP))
1708     {
1709       char *home = get_home_dir(p);
1710
1711       if (lp_servicenumber(p) >= 0) continue;
1712
1713       if (home && homes >= 0)
1714         {
1715           lp_add_home(p,homes,home);
1716           continue;
1717         }
1718
1719       if (printers >= 0 && pcap_printername_ok(p,NULL))
1720         lp_add_printer(p,printers);
1721     }
1722   free(s);
1723 }
1724
1725 /***************************************************************************
1726 auto-load one printer
1727 ***************************************************************************/
1728 static void lp_add_one_printer(char *name,char *comment)
1729 {
1730   int printers = lp_servicenumber(PRINTERS_NAME);
1731   int i;
1732
1733   if (lp_servicenumber(name) < 0)
1734     {
1735       lp_add_printer(name,printers);
1736       if ((i=lp_servicenumber(name)) >= 0)
1737         string_set(&iSERVICE(i).comment,comment);
1738     }      
1739 }
1740
1741
1742 /***************************************************************************
1743 auto-load printer services
1744 ***************************************************************************/
1745 static void lp_add_all_printers(void)
1746 {
1747   int printers = lp_servicenumber(PRINTERS_NAME);
1748
1749   if (printers < 0) return;
1750
1751   pcap_printer_fn(lp_add_one_printer);
1752 }
1753
1754 /***************************************************************************
1755 have we loaded a services file yet?
1756 ***************************************************************************/
1757 BOOL lp_loaded(void)
1758 {
1759   return(bLoaded);
1760 }
1761
1762 /***************************************************************************
1763 unload unused services
1764 ***************************************************************************/
1765 void lp_killunused(BOOL (*snumused)(int ))
1766 {
1767   int i;
1768   for (i=0;i<iNumServices;i++)
1769     if (VALID(i) && !snumused(i))
1770       {
1771         iSERVICE(i).valid = False;
1772         free_service(pSERVICE(i));
1773       }
1774 }
1775
1776 /***************************************************************************
1777 Load the services array from the services file. Return True on success, 
1778 False on failure.
1779 ***************************************************************************/
1780 BOOL lp_load(char *pszFname,BOOL global_only)
1781 {
1782   pstring n2;
1783   BOOL bRetval;
1784   
1785   add_to_file_list(pszFname);
1786
1787   bRetval = False;
1788
1789   bInGlobalSection = True;
1790   bGlobalOnly = global_only;
1791   
1792   init_globals();
1793   
1794   strcpy(n2,pszFname);
1795   standard_sub_basic(n2);
1796
1797   /* We get sections first, so have to start 'behind' to make up */
1798   iServiceIndex = -1;
1799   bRetval = pm_process(n2, do_section, do_parameter);
1800   
1801   /* finish up the last section */
1802   DEBUG(3,("pm_process() returned %s\n", BOOLSTR(bRetval)));
1803   if (bRetval)
1804     if (iServiceIndex >= 0)
1805       bRetval = service_ok(iServiceIndex);         
1806
1807   lp_add_auto_services(lp_auto_services());
1808   if (lp_load_printers())
1809     lp_add_all_printers();
1810
1811   lp_add_ipc();
1812
1813   bLoaded = True;
1814
1815   return (bRetval);
1816 }
1817
1818
1819 /***************************************************************************
1820 return the max number of services
1821 ***************************************************************************/
1822 int lp_numservices(void)
1823 {
1824   return(iNumServices);
1825 }
1826
1827 /***************************************************************************
1828 Display the contents of the services array in human-readable form.
1829 ***************************************************************************/
1830 void lp_dump(void)
1831 {
1832    int iService;
1833
1834    dump_globals();
1835    
1836    dump_a_service(&sDefault);
1837
1838    for (iService = 0; iService < iNumServices; iService++)
1839    {
1840      if (VALID(iService))
1841        {
1842          if (iSERVICE(iService).szService[0] == '\0')
1843            break;
1844          dump_a_service(pSERVICE(iService));
1845        }
1846    }
1847 }
1848
1849 /***************************************************************************
1850 Return the number of the service with the given name, or -1 if it doesn't
1851 exist. Note that this is a DIFFERENT ANIMAL from the internal function
1852 getservicebyname()! This works ONLY if all services have been loaded, and
1853 does not copy the found service.
1854 ***************************************************************************/
1855 int lp_servicenumber(char *pszServiceName)
1856 {
1857    int iService;
1858
1859    for (iService = iNumServices - 1; iService >= 0; iService--)
1860       if (VALID(iService) &&
1861           strwicmp(iSERVICE(iService).szService, pszServiceName) == 0) 
1862          break;
1863
1864    if (iService < 0)
1865      DEBUG(7,("lp_servicenumber: couldn't find %s\n",pszServiceName));
1866    
1867    return (iService);
1868 }
1869
1870
1871
1872
1873 /*******************************************************************
1874   get a workgroup - but map to standalone if '*'
1875   ******************************************************************/
1876 char *my_workgroup(void)
1877 {
1878   char *res = lp_workgroup();
1879   if (*res == '*') return("STANDALONE");
1880   return(res);
1881 }
1882
1883 /*******************************************************************
1884   a useful volume label function
1885   ******************************************************************/
1886 char *volume_label(int snum)
1887 {
1888   char *ret = lp_volume(snum);
1889   if (!*ret) return(lp_servicename(snum));
1890   return(ret);
1891 }