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