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