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