loadparm.c: Cause IPC$ comment to be evaluated at runtime, rather than
[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-1998
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 /* Set default coding system for KANJI if none specified in Makefile. */
53 /* 
54  * We treat KANJI specially due to historical precedent (it was the
55  * first non-english codepage added to Samba). With the new dynamic
56  * codepage support this is not needed anymore.
57  *
58  * The define 'KANJI' is being overloaded to mean 'use kanji codepage
59  * by default' and also 'this is the filename-to-disk conversion 
60  * method to use'. This really should be removed and all control
61  * over this left in the smb.conf parameters 'client codepage'
62  * and 'coding system'.
63  */
64 #ifndef KANJI
65 #define KANJI "sbcs"
66 #endif /* KANJI */
67
68 BOOL bLoaded = False;
69
70 extern int DEBUGLEVEL;
71 extern pstring user_socket_options;
72 extern pstring myname;
73
74 #ifndef GLOBAL_NAME
75 #define GLOBAL_NAME "global"
76 #endif
77
78 #ifndef PRINTERS_NAME
79 #define PRINTERS_NAME "printers"
80 #endif
81
82 #ifndef HOMES_NAME
83 #define HOMES_NAME "homes"
84 #endif
85
86 /* some helpful bits */
87 #define pSERVICE(i) ServicePtrs[i]
88 #define iSERVICE(i) (*pSERVICE(i))
89 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices) && iSERVICE(iService).valid)
90 #define VALID(i) iSERVICE(i).valid
91
92 int keepalive=DEFAULT_KEEPALIVE;
93 extern BOOL use_getwd_cache;
94
95 extern int extra_time_offset;
96
97 static BOOL defaults_saved=False;
98
99 /* 
100  * This structure describes global (ie., server-wide) parameters.
101  */
102 typedef struct
103 {
104   char *szPrintcapname;
105   char *szLockDir;
106   char *szRootdir;
107   char *szDefaultService;
108   char *szDfree;
109   char *szMsgCommand;
110   char *szHostsEquiv;
111   char *szServerString;
112   char *szAutoServices;
113   char *szPasswdProgram;
114   char *szPasswdChat;
115   char *szLogFile;
116   char *szConfigFile;
117   char *szSMBPasswdFile;
118   char *szPasswordServer;
119   char *szSocketOptions;
120   char *szValidChars;
121   char *szWorkGroup;
122   char *szDomainAdminUsers;
123   char *szDomainGuestUsers;
124   char *szDomainHostsallow; 
125   char *szDomainHostsdeny;
126   char *szUsernameMap;
127   char *szCharacterSet;
128   char *szLogonScript;
129   char *szLogonPath;
130   char *szLogonDrive;
131   char *szLogonHome;
132   char *szSmbrun;
133   char *szWINSserver;
134   char *szCodingSystem;
135   char *szInterfaces;
136   char *szRemoteAnnounce;
137   char *szRemoteBrowseSync;
138   char *szSocketAddress;
139   char *szNISHomeMapName;
140   char *szAnnounceVersion; /* This is initialised in init_globals */
141   char *szNetbiosAliases;
142   char *szDomainSID;
143   char *szDomainOtherSIDs;
144   char *szDomainGroups;
145   char *szDriverFile;
146   char *szNameResolveOrder;
147   int max_log_size;
148   int mangled_stack;
149   int max_xmit;
150   int max_mux;
151   int max_packet;
152   int pwordlevel;
153   int unamelevel;
154   int deadtime;
155   int maxprotocol;
156   int security;
157   int maxdisksize;
158   int lpqcachetime;
159   int syslog;
160   int os_level;
161   int max_ttl;
162   int max_wins_ttl;
163   int min_wins_ttl;
164   int ReadSize;
165   int lm_announce;
166   int lm_interval;
167   int shmem_size;
168   int client_code_page;
169   int announce_as;   /* This is initialised in init_globals */
170   BOOL bDNSproxy;
171   BOOL bWINSsupport;
172   BOOL bWINSproxy;
173   BOOL bLocalMaster;
174   BOOL bPreferredMaster;
175   BOOL bDomainController;
176   BOOL bDomainMaster;
177   BOOL bDomainLogons;
178   BOOL bEncryptPasswords;
179   BOOL bStripDot;
180   BOOL bNullPasswords;
181   BOOL bLoadPrinters;
182   BOOL bUseRhosts;
183   BOOL bReadRaw;
184   BOOL bWriteRaw;
185   BOOL bReadPrediction;
186   BOOL bReadbmpx;
187   BOOL bSyslogOnly;
188   BOOL bBrowseList;
189   BOOL bUnixRealname;
190   BOOL bNISHomeMap;
191   BOOL bTimeServer;
192   BOOL bBindInterfacesOnly;
193   BOOL bNetWkstaUserLogon;
194   BOOL bUnixPasswdSync;
195 } global;
196
197 static global Globals;
198
199
200
201 /* 
202  * This structure describes a single service. 
203  */
204 typedef struct
205 {
206   BOOL valid;
207   char *szService;
208   char *szPath;
209   char *szUsername;
210   char *szGuestaccount;
211   char *szInvalidUsers;
212   char *szValidUsers;
213   char *szAdminUsers;
214   char *szCopy;
215   char *szInclude;
216   char *szPreExec;
217   char *szPostExec;
218   char *szRootPreExec;
219   char *szRootPostExec;
220   char *szPrintcommand;
221   char *szLpqcommand;
222   char *szLprmcommand;
223   char *szLppausecommand;
224   char *szLpresumecommand;
225   char *szPrintername;
226   char *szPrinterDriver;
227   char *szPrinterDriverLocation;
228   char *szDontdescend;
229   char *szHostsallow;
230   char *szHostsdeny;
231   char *szMagicScript;
232   char *szMagicOutput;
233   char *szMangledMap;
234   char *szVetoFiles;
235   char *szHideFiles;
236   char *szVetoOplockFiles;
237   char *comment;
238   char *force_user;
239   char *force_group;
240   char *readlist;
241   char *writelist;
242   char *volume;
243   int  iMinPrintSpace;
244   int  iCreate_mask;
245   int  iCreate_force_mode;
246   int  iDir_mask;
247   int  iDir_force_mode;
248   int  iMaxConnections;
249   int  iDefaultCase;
250   int  iPrinting;
251   BOOL bAlternatePerm;
252   BOOL bRevalidate;
253   BOOL bCaseSensitive;
254   BOOL bCasePreserve;
255   BOOL bShortCasePreserve;
256   BOOL bCaseMangle;
257   BOOL status;
258   BOOL bHideDotFiles;
259   BOOL bBrowseable;
260   BOOL bAvailable;
261   BOOL bRead_only;
262   BOOL bNo_set_dir;
263   BOOL bGuest_only;
264   BOOL bGuest_ok;
265   BOOL bPrint_ok;
266   BOOL bPostscript;
267   BOOL bMap_system;
268   BOOL bMap_hidden;
269   BOOL bMap_archive;
270   BOOL bLocking;
271   BOOL bStrictLocking;
272   BOOL bShareModes;
273   BOOL bOpLocks;
274   BOOL bOnlyUser;
275   BOOL bMangledNames;
276   BOOL bWidelinks;
277   BOOL bSymlinks;
278   BOOL bSyncAlways;
279   char magic_char;
280   BOOL *copymap;
281   BOOL bDeleteReadonly;
282   BOOL bFakeOplocks;
283   BOOL bDeleteVetoFiles;
284   BOOL bDosFiletimes;
285   BOOL bDosFiletimeResolution;
286   BOOL bFakeDirCreateTimes;
287   char dummy[3]; /* for alignment */
288 } service;
289
290
291 /* This is a default service used to prime a services structure */
292 static service sDefault = 
293 {
294   True,   /* valid */
295   NULL,    /* szService */
296   NULL,    /* szPath */
297   NULL,    /* szUsername */
298   NULL,    /* szGuestAccount  - this is set in init_globals() */
299   NULL,    /* szInvalidUsers */
300   NULL,    /* szValidUsers */
301   NULL,    /* szAdminUsers */
302   NULL,    /* szCopy */
303   NULL,    /* szInclude */
304   NULL,    /* szPreExec */
305   NULL,    /* szPostExec */
306   NULL,    /* szRootPreExec */
307   NULL,    /* szRootPostExec */
308   NULL,    /* szPrintcommand */
309   NULL,    /* szLpqcommand */
310   NULL,    /* szLprmcommand */
311   NULL,    /* szLppausecommand */
312   NULL,    /* szLpresumecommand */
313   NULL,    /* szPrintername */
314   NULL,    /* szPrinterDriver - this is set in init_globals() */
315   NULL,    /* szPrinterDriverLocation */
316   NULL,    /* szDontdescend */
317   NULL,    /* szHostsallow */
318   NULL,    /* szHostsdeny */
319   NULL,    /* szMagicScript */
320   NULL,    /* szMagicOutput */
321   NULL,    /* szMangledMap */
322   NULL,    /* szVetoFiles */
323   NULL,    /* szHideFiles */
324   NULL,    /* szVetoOplockFiles */
325   NULL,    /* comment */
326   NULL,    /* force user */
327   NULL,    /* force group */
328   NULL,    /* readlist */
329   NULL,    /* writelist */
330   NULL,    /* volume */
331   0,       /* iMinPrintSpace */
332   0744,    /* iCreate_mask */
333   0000,    /* iCreate_force_mode */
334   0755,    /* iDir_mask */
335   0000,    /* iDir_force_mode */
336   0,       /* iMaxConnections */
337   CASE_LOWER, /* iDefaultCase */
338   DEFAULT_PRINTING, /* iPrinting */
339   False,   /* bAlternatePerm */
340   False,   /* revalidate */
341   False,   /* case sensitive */
342   False,   /* case preserve */
343   False,   /* short case preserve */
344   False,  /* case mangle */
345   True,  /* status */
346   True,  /* bHideDotFiles */
347   True,  /* bBrowseable */
348   True,  /* bAvailable */
349   True,  /* bRead_only */
350   True,  /* bNo_set_dir */
351   False, /* bGuest_only */
352   False, /* bGuest_ok */
353   False, /* bPrint_ok */
354   False, /* bPostscript */
355   False, /* bMap_system */
356   False, /* bMap_hidden */
357   True,  /* bMap_archive */
358   True,  /* bLocking */
359   False,  /* bStrictLocking */
360   True,  /* bShareModes */
361   True,  /* bOpLocks */
362   False, /* bOnlyUser */
363   True,  /* bMangledNames */
364   True,  /* bWidelinks */
365   True,  /* bSymlinks */
366   False, /* bSyncAlways */
367   '~',   /* magic char */
368   NULL,  /* copymap */
369   False, /* bDeleteReadonly */
370   False, /* bFakeOplocks */
371   False, /* bDeleteVetoFiles */
372   False, /* bDosFiletimes */
373   False, /* bDosFiletimeResolution */
374   False, /* bFakeDirCreateTimes */
375   ""     /* dummy */
376 };
377
378
379
380 /* local variables */
381 static service **ServicePtrs = NULL;
382 static int iNumServices = 0;
383 static int iServiceIndex = 0;
384 static BOOL bInGlobalSection = True;
385 static BOOL bGlobalOnly = False;
386 static int default_server_announce;
387
388 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
389
390 /* prototypes for the special type handlers */
391 static BOOL handle_valid_chars(char *pszParmValue, char **ptr);
392 static BOOL handle_include(char *pszParmValue, char **ptr);
393 static BOOL handle_copy(char *pszParmValue, char **ptr);
394 static BOOL handle_character_set(char *pszParmValue,char **ptr);
395 static BOOL handle_coding_system(char *pszParmValue,char **ptr);
396
397 static void set_default_server_announce_type(void);
398
399 static struct enum_list enum_protocol[] = {{PROTOCOL_NT1, "NT1"}, {PROTOCOL_LANMAN2, "LANMAN2"}, 
400                                            {PROTOCOL_LANMAN1, "LANMAN1"}, {PROTOCOL_CORE,"CORE"}, 
401                                            {PROTOCOL_COREPLUS, "COREPLUS"}, 
402                                            {PROTOCOL_COREPLUS, "CORE+"}, {-1, NULL}};
403
404 static struct enum_list enum_security[] = {{SEC_SHARE, "SHARE"},  {SEC_USER, "USER"}, 
405                                            {SEC_SERVER, "SERVER"}, {-1, NULL}};
406
407 static struct enum_list enum_printing[] = {{PRINT_SYSV, "sysv"}, {PRINT_AIX, "aix"}, 
408                                            {PRINT_HPUX, "hpux"}, {PRINT_BSD, "bsd"},
409                                            {PRINT_QNX, "qnx"},   {PRINT_PLP, "plp"},
410                                            {PRINT_LPRNG, "lprng"}, {PRINT_SOFTQ, "softq"},
411                                            {-1, NULL}};
412
413 static struct enum_list enum_announce_as[] = {{ANNOUNCE_AS_NT, "NT"}, {ANNOUNCE_AS_WIN95, "win95"},
414                                               {ANNOUNCE_AS_WFW, "WfW"}, {-1, NULL}};
415
416 static struct enum_list enum_case[] = {{CASE_LOWER, "lower"}, {CASE_UPPER, "upper"}, {-1, NULL}};
417
418 static struct enum_list enum_lm_announce[] = {{0, "False"}, {1, "True"}, {2, "Auto"}, {-1, NULL}};
419
420 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
421 static struct parm_struct parm_table[] =
422 {
423   {"Base Options", P_SEP, P_SEPARATOR},
424   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,          NULL,   NULL,  FLAG_BASIC|FLAG_PRINT},
425   {"path",             P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL,   NULL,  FLAG_BASIC|FLAG_PRINT},
426   {"directory",        P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL,   NULL,  0},
427   {"workgroup",        P_USTRING, P_GLOBAL, &Globals.szWorkGroup,       NULL,   NULL,  FLAG_BASIC},
428   {"netbios name",     P_UGSTRING,P_GLOBAL, myname,                     NULL,   NULL,  FLAG_BASIC},
429   {"netbios aliases",  P_STRING,  P_GLOBAL, &Globals.szNetbiosAliases,  NULL,   NULL,  0},
430   {"server string",    P_STRING,  P_GLOBAL, &Globals.szServerString,    NULL,   NULL,  FLAG_BASIC},
431   {"interfaces",       P_STRING,  P_GLOBAL, &Globals.szInterfaces,      NULL,   NULL,  FLAG_BASIC},
432   {"bind interfaces only", P_BOOL,P_GLOBAL, &Globals.bBindInterfacesOnly,NULL,   NULL,  0},
433
434   {"Security Options", P_SEP, P_SEPARATOR},
435   {"security",         P_ENUM,    P_GLOBAL, &Globals.security,          NULL,   enum_security, FLAG_BASIC},
436   {"encrypt passwords",P_BOOL,    P_GLOBAL, &Globals.bEncryptPasswords, NULL,   NULL,  FLAG_BASIC},
437   {"use rhosts",       P_BOOL,    P_GLOBAL, &Globals.bUseRhosts,        NULL,   NULL,  0},
438   {"null passwords",   P_BOOL,    P_GLOBAL, &Globals.bNullPasswords,    NULL,   NULL,  0},
439   {"password server",  P_STRING,  P_GLOBAL, &Globals.szPasswordServer,  NULL,   NULL,  0},
440   {"smb passwd file",  P_STRING,  P_GLOBAL, &Globals.szSMBPasswdFile,   NULL,   NULL,  0},
441   {"hosts equiv",      P_STRING,  P_GLOBAL, &Globals.szHostsEquiv,      NULL,   NULL,  0},
442   {"root directory",   P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL,   NULL,  0},
443   {"root dir",         P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL,   NULL,  0},
444   {"root",             P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL,   NULL,  0},
445   {"passwd program",   P_STRING,  P_GLOBAL, &Globals.szPasswdProgram,   NULL,   NULL,  0},
446   {"passwd chat",      P_STRING,  P_GLOBAL, &Globals.szPasswdChat,      NULL,   NULL,  0},
447   {"username map",     P_STRING,  P_GLOBAL, &Globals.szUsernameMap,     NULL,   NULL,  0},
448   {"password level",   P_INTEGER, P_GLOBAL, &Globals.pwordlevel,        NULL,   NULL,  0},
449   {"username level",   P_INTEGER, P_GLOBAL, &Globals.unamelevel,        NULL,   NULL,  0},
450   {"unix password sync", P_BOOL,  P_GLOBAL, &Globals.bUnixPasswdSync,   NULL,   NULL,  0},
451   {"alternate permissions",P_BOOL,P_LOCAL,  &sDefault.bAlternatePerm,   NULL,   NULL,  FLAG_GLOBAL},
452   {"revalidate",       P_BOOL,    P_LOCAL,  &sDefault.bRevalidate,      NULL,   NULL,  FLAG_GLOBAL},
453   {"username",         P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL,   NULL,  FLAG_GLOBAL},
454   {"user",             P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL,   NULL,  0},
455   {"users",            P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL,   NULL,  0},
456   {"guest account",    P_STRING,  P_LOCAL,  &sDefault.szGuestaccount,   NULL,   NULL,  FLAG_BASIC|FLAG_PRINT|FLAG_GLOBAL},
457   {"invalid users",    P_STRING,  P_LOCAL,  &sDefault.szInvalidUsers,   NULL,   NULL,  FLAG_GLOBAL},
458   {"valid users",      P_STRING,  P_LOCAL,  &sDefault.szValidUsers,     NULL,   NULL,  FLAG_GLOBAL},
459   {"admin users",      P_STRING,  P_LOCAL,  &sDefault.szAdminUsers,     NULL,   NULL,  FLAG_GLOBAL},
460   {"read list",        P_STRING,  P_LOCAL,  &sDefault.readlist,         NULL,   NULL,  FLAG_GLOBAL},
461   {"write list",       P_STRING,  P_LOCAL,  &sDefault.writelist,        NULL,   NULL,  FLAG_GLOBAL},
462   {"force user",       P_STRING,  P_LOCAL,  &sDefault.force_user,       NULL,   NULL,  0},
463   {"force group",      P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL,   NULL,  0},
464   {"group",            P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL,   NULL,  0},
465   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL,  FLAG_BASIC},
466   {"write ok",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL,  0},
467   {"writeable",        P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL,  0},
468   {"writable",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL,  0},
469   {"create mask",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mask,     NULL,   NULL,  FLAG_GLOBAL},
470   {"create mode",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mask,     NULL,   NULL,  FLAG_GLOBAL},
471   {"force create mode",P_OCTAL,   P_LOCAL,  &sDefault.iCreate_force_mode,     NULL,   NULL,  FLAG_GLOBAL},
472   {"directory mask",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_mask,        NULL,   NULL,  FLAG_GLOBAL},
473   {"directory mode",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_mask,        NULL,   NULL,  FLAG_GLOBAL},
474   {"force directory mode",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_force_mode,        NULL,   NULL,  FLAG_GLOBAL},
475   {"guest only",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL,   NULL,  0},
476   {"only guest",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL,   NULL,  0},
477   {"guest ok",         P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL,   NULL,  FLAG_BASIC|FLAG_PRINT},
478   {"public",           P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL,   NULL,  0},
479   {"only user",        P_BOOL,    P_LOCAL,  &sDefault.bOnlyUser,        NULL,   NULL,  0},
480   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL,   NULL,  FLAG_GLOBAL|FLAG_BASIC|FLAG_PRINT},
481   {"allow hosts",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL,   NULL,  0},
482   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL,   NULL,  FLAG_GLOBAL|FLAG_BASIC|FLAG_PRINT},
483   {"deny hosts",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL,   NULL,  0},
484
485   {"Logging Options", P_SEP, P_SEPARATOR},
486   {"log level",        P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL,   NULL,  FLAG_BASIC},
487   {"debuglevel",       P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL,   NULL,  0},
488   {"syslog",           P_INTEGER, P_GLOBAL, &Globals.syslog,            NULL,   NULL,  0},
489   {"syslog only",      P_BOOL,    P_GLOBAL, &Globals.bSyslogOnly,       NULL,   NULL,  0},
490   {"log file",         P_STRING,  P_GLOBAL, &Globals.szLogFile,         NULL,   NULL,  0},
491   {"max log size",     P_INTEGER, P_GLOBAL, &Globals.max_log_size,      NULL,   NULL,  0},
492   {"status",           P_BOOL,    P_LOCAL,  &sDefault.status,           NULL,   NULL,  FLAG_GLOBAL},
493
494   {"Protocol Options", P_SEP, P_SEPARATOR},
495   {"protocol",         P_ENUM,    P_GLOBAL, &Globals.maxprotocol,       NULL,   enum_protocol, 0},
496   {"read bmpx",        P_BOOL,    P_GLOBAL, &Globals.bReadbmpx,         NULL,   NULL,  0},
497   {"read raw",         P_BOOL,    P_GLOBAL, &Globals.bReadRaw,          NULL,   NULL,  0},
498   {"write raw",        P_BOOL,    P_GLOBAL, &Globals.bWriteRaw,         NULL,   NULL,  0},
499   {"networkstation user login", P_BOOL,P_GLOBAL, &Globals.bNetWkstaUserLogon,NULL,   NULL,  0},
500   {"announce version", P_STRING,  P_GLOBAL, &Globals.szAnnounceVersion, NULL,   NULL,  0},
501   {"announce as",      P_ENUM,    P_GLOBAL, &Globals.announce_as,       NULL,   enum_announce_as, 0},
502   {"max mux",          P_INTEGER, P_GLOBAL, &Globals.max_mux,           NULL,   NULL,  0},
503   {"max xmit",         P_INTEGER, P_GLOBAL, &Globals.max_xmit,          NULL,   NULL,  0},
504   {"name resolve order",  P_STRING,  P_GLOBAL, &Globals.szNameResolveOrder,  NULL,   NULL, 0},
505   {"max packet",       P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL,   NULL,  0},
506   {"packet size",      P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL,   NULL,  0},
507   {"max ttl",          P_INTEGER, P_GLOBAL, &Globals.max_ttl,           NULL,   NULL,  0},
508   {"max wins ttl",     P_INTEGER, P_GLOBAL, &Globals.max_wins_ttl,      NULL,   NULL,  0},
509   {"min wins ttl",     P_INTEGER, P_GLOBAL, &Globals.min_wins_ttl,      NULL,   NULL,  0},
510   {"time server",      P_BOOL,    P_GLOBAL, &Globals.bTimeServer,       NULL,   NULL,  0},
511
512   {"Tuning Options", P_SEP, P_SEPARATOR},
513   {"max disk size",    P_INTEGER, P_GLOBAL, &Globals.maxdisksize,       NULL,   NULL,  0},
514   {"lpq cache time",   P_INTEGER, P_GLOBAL, &Globals.lpqcachetime,      NULL,   NULL,  0},
515   {"getwd cache",      P_BOOL,    P_GLOBAL, &use_getwd_cache,           NULL,   NULL,  0},
516   {"read prediction",  P_BOOL,    P_GLOBAL, &Globals.bReadPrediction,   NULL,   NULL,  0},
517   {"socket options",   P_GSTRING, P_GLOBAL, user_socket_options,        NULL,   NULL,  0},
518   {"keepalive",        P_INTEGER, P_GLOBAL, &keepalive,                 NULL,   NULL,  0},
519   {"deadtime",         P_INTEGER, P_GLOBAL, &Globals.deadtime,          NULL,   NULL,  0},
520   {"read size",        P_INTEGER, P_GLOBAL, &Globals.ReadSize,          NULL,   NULL,  0},
521   {"shared mem size",  P_INTEGER, P_GLOBAL, &Globals.shmem_size,        NULL,   NULL,  0},
522   {"max connections",  P_INTEGER, P_LOCAL,  &sDefault.iMaxConnections,  NULL,   NULL,  0},
523   {"min print space",  P_INTEGER, P_LOCAL,  &sDefault.iMinPrintSpace,   NULL,   NULL,  0},
524   {"sync always",      P_BOOL,    P_LOCAL,  &sDefault.bSyncAlways,      NULL,   NULL,  0},
525
526   {"Printing Options", P_SEP, P_SEPARATOR},
527   {"load printers",    P_BOOL,    P_GLOBAL, &Globals.bLoadPrinters,     NULL,   NULL,  0},
528   {"printcap name",    P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL,   NULL,  0},
529   {"printcap",         P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL,   NULL,  0},
530   {"printer driver file", P_STRING,  P_GLOBAL, &Globals.szDriverFile,   NULL,   NULL,  0},
531   {"print ok",         P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL,   NULL,  0},
532   {"printable",        P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL,   NULL,  0},
533   {"postscript",       P_BOOL,    P_LOCAL,  &sDefault.bPostscript,      NULL,   NULL,  FLAG_PRINT},
534   {"printing",         P_ENUM,    P_LOCAL,  &sDefault.iPrinting,        NULL,   enum_printing, FLAG_PRINT|FLAG_GLOBAL},
535   {"print command",    P_STRING,  P_LOCAL,  &sDefault.szPrintcommand,   NULL,   NULL,  FLAG_PRINT|FLAG_GLOBAL},
536   {"lpq command",      P_STRING,  P_LOCAL,  &sDefault.szLpqcommand,     NULL,   NULL,  FLAG_PRINT|FLAG_GLOBAL},
537   {"lprm command",     P_STRING,  P_LOCAL,  &sDefault.szLprmcommand,    NULL,   NULL,  FLAG_PRINT|FLAG_GLOBAL},
538   {"lppause command",  P_STRING,  P_LOCAL,  &sDefault.szLppausecommand, NULL,   NULL,  FLAG_GLOBAL},
539   {"lpresume command", P_STRING,  P_LOCAL,  &sDefault.szLpresumecommand,NULL,   NULL,  FLAG_GLOBAL},
540   {"printer name",     P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL,   NULL,  FLAG_PRINT},
541   {"printer",          P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL,   NULL,  0},
542   {"printer driver",   P_STRING,  P_LOCAL,  &sDefault.szPrinterDriver,  NULL,   NULL,  0},
543   {"printer driver location",   P_STRING,  P_LOCAL,  &sDefault.szPrinterDriverLocation,  NULL,   NULL,  FLAG_GLOBAL},
544
545
546   {"Filename Handling", P_SEP, P_SEPARATOR},
547   {"strip dot",        P_BOOL,    P_GLOBAL, &Globals.bStripDot,         NULL,   NULL,  0},
548   {"character set",    P_STRING,  P_GLOBAL, &Globals.szCharacterSet,    handle_character_set, NULL,  0},
549   {"mangled stack",    P_INTEGER, P_GLOBAL, &Globals.mangled_stack,     NULL,   NULL,  0},
550   {"coding system",    P_STRING,  P_GLOBAL, &Globals.szCodingSystem,    handle_coding_system, NULL,  0},
551   {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page,  NULL,   NULL,  0},
552   {"default case",     P_ENUM, P_LOCAL,  &sDefault.iDefaultCase,        NULL,   enum_case, 0},
553   {"case sensitive",   P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL,   NULL,  FLAG_GLOBAL},
554   {"casesignames",     P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL,   NULL,  0},
555   {"preserve case",    P_BOOL,    P_LOCAL,  &sDefault.bCasePreserve,    NULL,   NULL,  FLAG_GLOBAL},
556   {"short preserve case",P_BOOL,  P_LOCAL,  &sDefault.bShortCasePreserve,NULL,   NULL,  FLAG_GLOBAL},
557   {"mangle case",      P_BOOL,    P_LOCAL,  &sDefault.bCaseMangle,      NULL,   NULL,  FLAG_GLOBAL},
558   {"mangling char",    P_CHAR,    P_LOCAL,  &sDefault.magic_char,       NULL,   NULL,  FLAG_GLOBAL},
559   {"hide dot files",   P_BOOL,    P_LOCAL,  &sDefault.bHideDotFiles,    NULL,   NULL,  FLAG_GLOBAL},
560   {"delete veto files",P_BOOL,    P_LOCAL,  &sDefault.bDeleteVetoFiles, NULL,   NULL,  FLAG_GLOBAL},
561   {"veto files",       P_STRING,  P_LOCAL,  &sDefault.szVetoFiles,      NULL,   NULL,  FLAG_GLOBAL},
562   {"hide files",       P_STRING,  P_LOCAL,  &sDefault.szHideFiles,      NULL,   NULL,  FLAG_GLOBAL},
563   {"veto oplock files",P_STRING,  P_LOCAL,  &sDefault.szVetoOplockFiles,NULL,   NULL,  FLAG_GLOBAL},
564   {"map system",       P_BOOL,    P_LOCAL,  &sDefault.bMap_system,      NULL,   NULL,  FLAG_GLOBAL},
565   {"map hidden",       P_BOOL,    P_LOCAL,  &sDefault.bMap_hidden,      NULL,   NULL,  FLAG_GLOBAL},
566   {"map archive",      P_BOOL,    P_LOCAL,  &sDefault.bMap_archive,     NULL,   NULL,  FLAG_GLOBAL},
567   {"mangled names",    P_BOOL,    P_LOCAL,  &sDefault.bMangledNames,    NULL,   NULL,  FLAG_GLOBAL},
568   {"mangled map",      P_STRING,  P_LOCAL,  &sDefault.szMangledMap,     NULL,   NULL,  FLAG_GLOBAL},
569
570   {"Domain Options", P_SEP, P_SEPARATOR},
571   {"domain sid",       P_USTRING, P_GLOBAL, &Globals.szDomainSID,       NULL,   NULL,  0},
572   {"domain other sids",P_STRING,  P_GLOBAL, &Globals.szDomainOtherSIDs, NULL,   NULL,  0},
573   {"domain groups",    P_STRING,  P_GLOBAL, &Globals.szDomainGroups,    NULL,   NULL,  0},
574   {"domain controller",P_BOOL  ,  P_GLOBAL, &Globals.bDomainController,NULL,   NULL,  0},
575   {"domain admin users",P_STRING, P_GLOBAL, &Globals.szDomainAdminUsers, NULL,   NULL,  0},
576   {"domain guest users",P_STRING, P_GLOBAL, &Globals.szDomainGuestUsers, NULL,   NULL,  0},
577   {"domain hosts allow",P_STRING, P_GLOBAL, &Globals.szDomainHostsallow, NULL,   NULL,  0},
578   {"domain allow hosts",P_STRING, P_GLOBAL, &Globals.szDomainHostsallow, NULL,   NULL,  0},
579   {"domain hosts deny", P_STRING, P_GLOBAL, &Globals.szDomainHostsdeny,  NULL,   NULL,  0},
580   {"domain deny hosts", P_STRING, P_GLOBAL, &Globals.szDomainHostsdeny,  NULL,   NULL,  0},
581
582   {"Logon Options", P_SEP, P_SEPARATOR},
583   {"logon script",     P_STRING,  P_GLOBAL, &Globals.szLogonScript,     NULL,   NULL,  0},
584   {"logon path",       P_STRING,  P_GLOBAL, &Globals.szLogonPath,       NULL,   NULL,  0},
585   {"logon drive",      P_STRING,  P_GLOBAL, &Globals.szLogonDrive,      NULL,   NULL,  0},
586   {"logon home",       P_STRING,  P_GLOBAL, &Globals.szLogonHome,       NULL,   NULL,  0},
587   {"domain logons",    P_BOOL,    P_GLOBAL, &Globals.bDomainLogons,     NULL,   NULL,  0},
588
589   {"Browse Options", P_SEP, P_SEPARATOR},
590   {"os level",         P_INTEGER, P_GLOBAL, &Globals.os_level,          NULL,   NULL,  0},
591   {"lm announce",      P_ENUM,    P_GLOBAL, &Globals.lm_announce,       NULL,   enum_lm_announce, 0},
592   {"lm interval",      P_INTEGER, P_GLOBAL, &Globals.lm_interval,       NULL,   NULL,  0},
593   {"preferred master", P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL,   NULL,  0},
594   {"prefered master",  P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL,   NULL,  0},
595   {"local master",     P_BOOL,    P_GLOBAL, &Globals.bLocalMaster,      NULL,   NULL,  0},
596   {"domain master",    P_BOOL,    P_GLOBAL, &Globals.bDomainMaster,     NULL,   NULL,  0},
597   {"browse list",      P_BOOL,    P_GLOBAL, &Globals.bBrowseList,       NULL,   NULL,  0},
598   {"browseable",       P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL,   NULL,  0},
599   {"browsable",        P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL,   NULL,  0},
600
601   {"WINS Options", P_SEP, P_SEPARATOR},
602   {"dns proxy",        P_BOOL,    P_GLOBAL, &Globals.bDNSproxy,         NULL,   NULL,  0},
603   {"wins support",     P_BOOL,    P_GLOBAL, &Globals.bWINSsupport,      NULL,   NULL,  FLAG_BASIC},
604   {"wins proxy",       P_BOOL,    P_GLOBAL, &Globals.bWINSproxy,        NULL,   NULL,  0},
605   {"wins server",      P_STRING,  P_GLOBAL, &Globals.szWINSserver,      NULL,   NULL,  FLAG_BASIC},
606
607   {"Locking Options", P_SEP, P_SEPARATOR},
608   {"locking",          P_BOOL,    P_LOCAL,  &sDefault.bLocking,         NULL,   NULL,  FLAG_GLOBAL},
609   {"strict locking",   P_BOOL,    P_LOCAL,  &sDefault.bStrictLocking,   NULL,   NULL,  FLAG_GLOBAL},
610   {"share modes",      P_BOOL,    P_LOCAL,  &sDefault.bShareModes,      NULL,   NULL,  FLAG_GLOBAL},
611   {"oplocks",          P_BOOL,    P_LOCAL,  &sDefault.bOpLocks,         NULL,   NULL,  FLAG_GLOBAL},
612   {"fake oplocks",     P_BOOL,    P_LOCAL,  &sDefault.bFakeOplocks,     NULL,   NULL,  0},
613
614   {"Miscellaneous Options", P_SEP, P_SEPARATOR},
615   {"smbrun",           P_STRING,  P_GLOBAL, &Globals.szSmbrun,          NULL,   NULL,  0},
616   {"config file",      P_STRING,  P_GLOBAL, &Globals.szConfigFile,      NULL,   NULL,  FLAG_HIDE},
617   {"preload",          P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL,   NULL,  0},
618   {"auto services",    P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL,   NULL,  0},
619   {"lock dir",         P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL,   NULL,  0},
620   {"lock directory",   P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL,   NULL,  0},
621   {"default service",  P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL,   NULL,  0},
622   {"default",          P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL,   NULL,  0},
623   {"message command",  P_STRING,  P_GLOBAL, &Globals.szMsgCommand,      NULL,   NULL,  0},
624   {"dfree command",    P_STRING,  P_GLOBAL, &Globals.szDfree,           NULL,   NULL,  0},
625   {"valid chars",      P_STRING,  P_GLOBAL, &Globals.szValidChars,      handle_valid_chars, NULL,  0},
626   {"remote announce",  P_STRING,  P_GLOBAL, &Globals.szRemoteAnnounce,  NULL,   NULL,  0},
627   {"remote browse sync",P_STRING, P_GLOBAL, &Globals.szRemoteBrowseSync,NULL,   NULL,  0},
628   {"socket address",   P_STRING,  P_GLOBAL, &Globals.szSocketAddress,   NULL,   NULL,  0},
629   {"homedir map",      P_STRING,  P_GLOBAL, &Globals.szNISHomeMapName,  NULL,   NULL,  0},
630   {"time offset",      P_INTEGER, P_GLOBAL, &extra_time_offset,         NULL,   NULL,  0},
631   {"unix realname",    P_BOOL,    P_GLOBAL, &Globals.bUnixRealname,     NULL,   NULL,  0},
632   {"NIS homedir",      P_BOOL,    P_GLOBAL, &Globals.bNISHomeMap,       NULL,   NULL,  0},
633   {"-valid",           P_BOOL,    P_LOCAL,  &sDefault.valid,            NULL,   NULL,  FLAG_HIDE},
634   {"copy",             P_STRING,  P_LOCAL,  &sDefault.szCopy,           handle_copy, NULL,  FLAG_HIDE},
635   {"include",          P_STRING,  P_LOCAL,  &sDefault.szInclude,        handle_include, NULL,  FLAG_HIDE},
636   {"exec",             P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL,   NULL,  0},
637   {"preexec",          P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL,   NULL,  0},
638   {"postexec",         P_STRING,  P_LOCAL,  &sDefault.szPostExec,       NULL,   NULL,  0},
639   {"root preexec",     P_STRING,  P_LOCAL,  &sDefault.szRootPreExec,    NULL,   NULL,  0},
640   {"root postexec",    P_STRING,  P_LOCAL,  &sDefault.szRootPostExec,   NULL,   NULL,  0},
641   {"available",        P_BOOL,    P_LOCAL,  &sDefault.bAvailable,       NULL,   NULL,  0},
642   {"volume",           P_STRING,  P_LOCAL,  &sDefault.volume,           NULL,   NULL,  0},
643   {"set directory",    P_BOOLREV, P_LOCAL,  &sDefault.bNo_set_dir,      NULL,   NULL,  0},
644   {"wide links",       P_BOOL,    P_LOCAL,  &sDefault.bWidelinks,       NULL,   NULL,  FLAG_GLOBAL},
645   {"follow symlinks",  P_BOOL,    P_LOCAL,  &sDefault.bSymlinks,        NULL,   NULL,  FLAG_GLOBAL},
646   {"dont descend",     P_STRING,  P_LOCAL,  &sDefault.szDontdescend,    NULL,   NULL,  0},
647   {"magic script",     P_STRING,  P_LOCAL,  &sDefault.szMagicScript,    NULL,   NULL,  0},
648   {"magic output",     P_STRING,  P_LOCAL,  &sDefault.szMagicOutput,    NULL,   NULL,  0},
649   {"delete readonly",  P_BOOL,    P_LOCAL,  &sDefault.bDeleteReadonly,  NULL,   NULL,  FLAG_GLOBAL},
650   {"dos filetimes",    P_BOOL,    P_LOCAL,  &sDefault.bDosFiletimes,    NULL,   NULL,  FLAG_GLOBAL},
651   {"dos filetime resolution",P_BOOL,P_LOCAL,&sDefault.bDosFiletimeResolution,   NULL,  NULL,  FLAG_GLOBAL},
652   
653   {"fake directory create times", P_BOOL,P_LOCAL,  &sDefault.bFakeDirCreateTimes, NULL,   NULL, FLAG_GLOBAL},
654   {NULL,               P_BOOL,    P_NONE,   NULL,                       NULL,   NULL, 0}
655 };
656
657
658
659 /***************************************************************************
660 Initialise the global parameter structure.
661 ***************************************************************************/
662 static void init_globals(void)
663 {
664   static BOOL done_init = False;
665   pstring s;
666
667   if (!done_init)
668     {
669       int i;
670       bzero((void *)&Globals,sizeof(Globals));
671
672       for (i = 0; parm_table[i].label; i++) 
673         if ((parm_table[i].type == P_STRING ||
674              parm_table[i].type == P_USTRING) && 
675             parm_table[i].ptr)
676           string_init(parm_table[i].ptr,"");
677
678       string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
679       string_set(&sDefault.szPrinterDriver, "NULL");
680
681       done_init = True;
682     }
683
684
685   DEBUG(3,("Initialising global parameters\n"));
686
687   string_set(&Globals.szSMBPasswdFile, SMB_PASSWD_FILE);
688   string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
689   string_set(&Globals.szWorkGroup, WORKGROUP);
690   string_set(&Globals.szPasswdProgram, SMB_PASSWD);
691   string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
692   string_set(&Globals.szDriverFile, DRIVERFILE);
693   string_set(&Globals.szLockDir, LOCKDIR);
694   string_set(&Globals.szRootdir, "/");
695   string_set(&Globals.szSmbrun, SMBRUN);
696   string_set(&Globals.szSocketAddress, "0.0.0.0");
697   sprintf(s,"Samba %s",VERSION);
698   string_set(&Globals.szServerString,s);
699   sprintf(s,"%d.%d", DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION);
700   string_set(&Globals.szAnnounceVersion,s);
701
702   string_set(&Globals.szLogonDrive, "");
703   /* %N is the NIS auto.home server if -DAUTOHOME is used, else same as %L */
704   string_set(&Globals.szLogonHome, "\\\\%N\\%U");
705   string_set(&Globals.szLogonPath, "\\\\%N\\%U\\profile");
706
707   string_set(&Globals.szNameResolveOrder, "lmhosts host wins bcast");
708
709   Globals.bLoadPrinters = True;
710   Globals.bUseRhosts = False;
711   Globals.max_packet = 65535;
712   Globals.mangled_stack = 50;
713   Globals.max_xmit = 65535;
714   Globals.max_mux = 50; /* This is *needed* for profile support. */
715   Globals.lpqcachetime = 10;
716   Globals.pwordlevel = 0;
717   Globals.unamelevel = 0;
718   Globals.deadtime = 0;
719   Globals.max_log_size = 5000;
720   Globals.maxprotocol = PROTOCOL_NT1;
721   Globals.security = SEC_SHARE;
722   Globals.bEncryptPasswords = False;
723   Globals.bReadRaw = True;
724   Globals.bWriteRaw = True;
725   Globals.bReadPrediction = False;
726   Globals.bReadbmpx = True;
727   Globals.bNullPasswords = False;
728   Globals.bStripDot = False;
729   Globals.syslog = 1;
730   Globals.bSyslogOnly = False;
731   Globals.os_level = 0;
732   Globals.max_ttl = 60*60*4; /* 4 hours default */
733   Globals.max_wins_ttl = 60*60*24*3; /* 3 days default */
734   Globals.min_wins_ttl = 60*60*6; /* 6 hours default */
735   Globals.ReadSize = 16*1024;
736   Globals.lm_announce = 2;   /* = Auto: send only if LM clients found */
737   Globals.lm_interval = 60;
738   Globals.shmem_size = SHMEM_SIZE;
739   Globals.announce_as = ANNOUNCE_AS_NT;
740   Globals.bUnixRealname = False;
741 #if (defined(NETGROUP) && defined(AUTOMOUNT))
742   Globals.bNISHomeMap = False;
743   string_set(&Globals.szNISHomeMapName, "auto.home");
744 #endif
745   Globals.client_code_page = DEFAULT_CLIENT_CODE_PAGE;
746   Globals.bTimeServer = False;
747   Globals.bBindInterfacesOnly = False;
748   Globals.bNetWkstaUserLogon = True;
749   Globals.bUnixPasswdSync = False;
750
751 /* these parameters are set to defaults that are more appropriate
752    for the increasing samba install base:
753
754    as a member of the workgroup, that will possibly become a
755    _local_ master browser (lm = True).  this is opposed to a forced
756    local master browser startup (pm = True).
757
758    doesn't provide WINS server service by default (wsupp = False),
759    and doesn't provide domain master browser services by default, either.
760
761 */
762
763   Globals.bPreferredMaster = False;
764   Globals.bLocalMaster = True;
765   Globals.bDomainMaster = False;
766   Globals.bDomainLogons = False;
767   Globals.bBrowseList = True;
768   Globals.bWINSsupport = False;
769   Globals.bWINSproxy = False;
770
771   Globals.bDNSproxy = True;
772
773   /*
774    * This must be done last as it checks the value in 
775    * client_code_page.
776    */
777
778   interpret_coding_system(KANJI);
779 }
780
781 /***************************************************************************
782 check if a string is initialised and if not then initialise it
783 ***************************************************************************/
784 static void string_initial(char **s,char *v)
785 {
786   if (!*s || !**s)
787     string_init(s,v);
788 }
789
790
791 /***************************************************************************
792 Initialise the sDefault parameter structure.
793 ***************************************************************************/
794 static void init_locals(void)
795 {
796   /* choose defaults depending on the type of printing */
797   switch (sDefault.iPrinting)
798     {
799     case PRINT_BSD:
800     case PRINT_AIX:
801     case PRINT_LPRNG:
802     case PRINT_PLP:
803       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
804       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
805       string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
806       break;
807
808     case PRINT_SYSV:
809     case PRINT_HPUX:
810       string_initial(&sDefault.szLpqcommand,"lpstat -o%p");
811       string_initial(&sDefault.szLprmcommand,"cancel %p-%j");
812       string_initial(&sDefault.szPrintcommand,"lp -c -d%p %s; rm %s");
813 #ifdef SVR4
814       string_initial(&sDefault.szLppausecommand,"lp -i %p-%j -H hold");
815       string_initial(&sDefault.szLpresumecommand,"lp -i %p-%j -H resume");
816 #endif
817       break;
818
819     case PRINT_QNX:
820       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
821       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
822       string_initial(&sDefault.szPrintcommand,"lp -r -P%p %s");
823       break;
824
825     case PRINT_SOFTQ:
826       string_initial(&sDefault.szLpqcommand,"qstat -l -d%p");
827       string_initial(&sDefault.szLprmcommand,"qstat -s -j%j -c");
828       string_initial(&sDefault.szPrintcommand,"lp -d%p -s %s; rm %s");
829       string_initial(&sDefault.szLppausecommand,"qstat -s -j%j -h");
830       string_initial(&sDefault.szLpresumecommand,"qstat -s -j%j -r");
831       break;
832       
833     }
834 }
835
836
837 /******************************************************************* a
838 convenience routine to grab string parameters into a rotating buffer,
839 and run standard_sub_basic on them. The buffers can be written to by
840 callers without affecting the source string.
841 ********************************************************************/
842 char *lp_string(char *s)
843 {
844   static char *bufs[10];
845   static int buflen[10];
846   static int next = -1;  
847   char *ret;
848   int i;
849   int len = s?strlen(s):0;
850
851   if (next == -1) {
852     /* initialisation */
853     for (i=0;i<10;i++) {
854       bufs[i] = NULL;
855       buflen[i] = 0;
856     }
857     next = 0;
858   }
859
860   len = MAX(len+100,sizeof(pstring)); /* the +100 is for some
861                                          substitution room */
862
863   if (buflen[next] != len) {
864     buflen[next] = len;
865     if (bufs[next]) free(bufs[next]);
866     bufs[next] = (char *)malloc(len);
867     if (!bufs[next]) {
868       DEBUG(0,("out of memory in lp_string()"));
869       exit(1);
870     }
871   } 
872
873   ret = &bufs[next][0];
874   next = (next+1)%10;
875
876   if (!s) 
877     *ret = 0;
878   else
879     StrCpy(ret,s);
880
881   trim_string(ret, "\"", "\"");
882
883   standard_sub_basic(ret);
884   return(ret);
885 }
886
887
888 /*
889    In this section all the functions that are used to access the 
890    parameters from the rest of the program are defined 
891 */
892
893 #define FN_GLOBAL_STRING(fn_name,ptr) \
894  char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
895 #define FN_GLOBAL_BOOL(fn_name,ptr) \
896  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
897 #define FN_GLOBAL_CHAR(fn_name,ptr) \
898  char fn_name(void) {return(*(char *)(ptr));}
899 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
900  int fn_name(void) {return(*(int *)(ptr));}
901
902 #define FN_LOCAL_STRING(fn_name,val) \
903  char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : sDefault.val));}
904 #define FN_LOCAL_BOOL(fn_name,val) \
905  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
906 #define FN_LOCAL_CHAR(fn_name,val) \
907  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
908 #define FN_LOCAL_INTEGER(fn_name,val) \
909  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
910
911 FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile)
912 FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun)
913 FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
914 FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
915 FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
916 FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname)
917 FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir)
918 FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir)
919 FN_GLOBAL_STRING(lp_defaultservice,&Globals.szDefaultService)
920 FN_GLOBAL_STRING(lp_msg_command,&Globals.szMsgCommand)
921 FN_GLOBAL_STRING(lp_dfree_command,&Globals.szDfree)
922 FN_GLOBAL_STRING(lp_hosts_equiv,&Globals.szHostsEquiv)
923 FN_GLOBAL_STRING(lp_auto_services,&Globals.szAutoServices)
924 FN_GLOBAL_STRING(lp_passwd_program,&Globals.szPasswdProgram)
925 FN_GLOBAL_STRING(lp_passwd_chat,&Globals.szPasswdChat)
926 FN_GLOBAL_STRING(lp_passwordserver,&Globals.szPasswordServer)
927 FN_GLOBAL_STRING(lp_name_resolve_order,&Globals.szNameResolveOrder)
928 FN_GLOBAL_STRING(lp_workgroup,&Globals.szWorkGroup)
929 FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
930 FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) 
931 FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) 
932 FN_GLOBAL_STRING(lp_logon_path,&Globals.szLogonPath) 
933 FN_GLOBAL_STRING(lp_logon_drive,&Globals.szLogonDrive) 
934 FN_GLOBAL_STRING(lp_logon_home,&Globals.szLogonHome) 
935 FN_GLOBAL_STRING(lp_remote_announce,&Globals.szRemoteAnnounce) 
936 FN_GLOBAL_STRING(lp_remote_browse_sync,&Globals.szRemoteBrowseSync) 
937 FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
938 FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
939 FN_GLOBAL_STRING(lp_socket_address,&Globals.szSocketAddress)
940 FN_GLOBAL_STRING(lp_nis_home_map_name,&Globals.szNISHomeMapName)
941 FN_GLOBAL_STRING(lp_announce_version,&Globals.szAnnounceVersion)
942 FN_GLOBAL_STRING(lp_netbios_aliases,&Globals.szNetbiosAliases)
943 FN_GLOBAL_STRING(lp_driverfile,&Globals.szDriverFile)
944
945 FN_GLOBAL_STRING(lp_domain_sid,&Globals.szDomainSID)
946 FN_GLOBAL_STRING(lp_domain_other_sids,&Globals.szDomainOtherSIDs)
947 FN_GLOBAL_STRING(lp_domain_groups,&Globals.szDomainGroups)
948 FN_GLOBAL_STRING(lp_domain_admin_users,&Globals.szDomainAdminUsers)
949 FN_GLOBAL_STRING(lp_domain_guest_users,&Globals.szDomainGuestUsers)
950 FN_GLOBAL_STRING(lp_domain_hostsallow,&Globals.szDomainHostsallow)
951 FN_GLOBAL_STRING(lp_domain_hostsdeny,&Globals.szDomainHostsdeny)
952
953 FN_GLOBAL_BOOL(lp_dns_proxy,&Globals.bDNSproxy)
954 FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
955 FN_GLOBAL_BOOL(lp_we_are_a_wins_server,&Globals.bWINSsupport)
956 FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
957 FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster)
958 FN_GLOBAL_BOOL(lp_domain_controller,&Globals.bDomainController)
959 FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
960 FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
961 FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
962 FN_GLOBAL_BOOL(lp_load_printers,&Globals.bLoadPrinters)
963 FN_GLOBAL_BOOL(lp_use_rhosts,&Globals.bUseRhosts)
964 FN_GLOBAL_BOOL(lp_getwdcache,&use_getwd_cache)
965 FN_GLOBAL_BOOL(lp_readprediction,&Globals.bReadPrediction)
966 FN_GLOBAL_BOOL(lp_readbmpx,&Globals.bReadbmpx)
967 FN_GLOBAL_BOOL(lp_readraw,&Globals.bReadRaw)
968 FN_GLOBAL_BOOL(lp_writeraw,&Globals.bWriteRaw)
969 FN_GLOBAL_BOOL(lp_null_passwords,&Globals.bNullPasswords)
970 FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
971 FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
972 FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
973 FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
974 FN_GLOBAL_BOOL(lp_unix_realname,&Globals.bUnixRealname)
975 FN_GLOBAL_BOOL(lp_nis_home_map,&Globals.bNISHomeMap)
976 FN_GLOBAL_BOOL(lp_time_server,&Globals.bTimeServer)
977 FN_GLOBAL_BOOL(lp_bind_interfaces_only,&Globals.bBindInterfacesOnly)
978 FN_GLOBAL_BOOL(lp_net_wksta_user_logon,&Globals.bNetWkstaUserLogon)
979 FN_GLOBAL_BOOL(lp_unix_password_sync,&Globals.bUnixPasswdSync)
980
981 FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
982 FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
983 FN_GLOBAL_INTEGER(lp_max_wins_ttl,&Globals.max_wins_ttl)
984 FN_GLOBAL_INTEGER(lp_min_wins_ttl,&Globals.max_wins_ttl)
985 FN_GLOBAL_INTEGER(lp_max_log_size,&Globals.max_log_size)
986 FN_GLOBAL_INTEGER(lp_mangledstack,&Globals.mangled_stack)
987 FN_GLOBAL_INTEGER(lp_maxxmit,&Globals.max_xmit)
988 FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
989 FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
990 FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
991 FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
992 FN_GLOBAL_INTEGER(lp_usernamelevel,&Globals.unamelevel)
993 FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
994 FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size)
995 FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
996 FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
997 FN_GLOBAL_INTEGER(lp_security,&Globals.security)
998 FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
999 FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
1000 FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
1001 FN_GLOBAL_INTEGER(lp_client_code_page,&Globals.client_code_page)
1002 FN_GLOBAL_INTEGER(lp_announce_as,&Globals.announce_as)
1003 FN_GLOBAL_INTEGER(lp_lm_announce,&Globals.lm_announce)
1004 FN_GLOBAL_INTEGER(lp_lm_interval,&Globals.lm_interval)
1005
1006 FN_LOCAL_STRING(lp_preexec,szPreExec)
1007 FN_LOCAL_STRING(lp_postexec,szPostExec)
1008 FN_LOCAL_STRING(lp_rootpreexec,szRootPreExec)
1009 FN_LOCAL_STRING(lp_rootpostexec,szRootPostExec)
1010 FN_LOCAL_STRING(lp_servicename,szService)
1011 FN_LOCAL_STRING(lp_pathname,szPath)
1012 FN_LOCAL_STRING(lp_dontdescend,szDontdescend)
1013 FN_LOCAL_STRING(lp_username,szUsername)
1014 FN_LOCAL_STRING(lp_guestaccount,szGuestaccount)
1015 FN_LOCAL_STRING(lp_invalid_users,szInvalidUsers)
1016 FN_LOCAL_STRING(lp_valid_users,szValidUsers)
1017 FN_LOCAL_STRING(lp_admin_users,szAdminUsers)
1018 FN_LOCAL_STRING(lp_printcommand,szPrintcommand)
1019 FN_LOCAL_STRING(lp_lpqcommand,szLpqcommand)
1020 FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
1021 FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
1022 FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
1023 FN_LOCAL_STRING(lp_printername,szPrintername)
1024 FN_LOCAL_STRING(lp_printerdriver,szPrinterDriver)
1025 FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
1026 FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
1027 FN_LOCAL_STRING(lp_magicscript,szMagicScript)
1028 FN_LOCAL_STRING(lp_magicoutput,szMagicOutput)
1029 FN_LOCAL_STRING(lp_comment,comment)
1030 FN_LOCAL_STRING(lp_force_user,force_user)
1031 FN_LOCAL_STRING(lp_force_group,force_group)
1032 FN_LOCAL_STRING(lp_readlist,readlist)
1033 FN_LOCAL_STRING(lp_writelist,writelist)
1034 FN_LOCAL_STRING(lp_volume,volume)
1035 FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
1036 FN_LOCAL_STRING(lp_veto_files,szVetoFiles)
1037 FN_LOCAL_STRING(lp_hide_files,szHideFiles)
1038 FN_LOCAL_STRING(lp_veto_oplocks,szVetoOplockFiles)
1039 FN_LOCAL_STRING(lp_driverlocation,szPrinterDriverLocation)
1040
1041 FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
1042 FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
1043 FN_LOCAL_BOOL(lp_casesensitive,bCaseSensitive)
1044 FN_LOCAL_BOOL(lp_preservecase,bCasePreserve)
1045 FN_LOCAL_BOOL(lp_shortpreservecase,bShortCasePreserve)
1046 FN_LOCAL_BOOL(lp_casemangle,bCaseMangle)
1047 FN_LOCAL_BOOL(lp_status,status)
1048 FN_LOCAL_BOOL(lp_hide_dot_files,bHideDotFiles)
1049 FN_LOCAL_BOOL(lp_browseable,bBrowseable)
1050 FN_LOCAL_BOOL(lp_readonly,bRead_only)
1051 FN_LOCAL_BOOL(lp_no_set_dir,bNo_set_dir)
1052 FN_LOCAL_BOOL(lp_guest_ok,bGuest_ok)
1053 FN_LOCAL_BOOL(lp_guest_only,bGuest_only)
1054 FN_LOCAL_BOOL(lp_print_ok,bPrint_ok)
1055 FN_LOCAL_BOOL(lp_postscript,bPostscript)
1056 FN_LOCAL_BOOL(lp_map_hidden,bMap_hidden)
1057 FN_LOCAL_BOOL(lp_map_archive,bMap_archive)
1058 FN_LOCAL_BOOL(lp_locking,bLocking)
1059 FN_LOCAL_BOOL(lp_strict_locking,bStrictLocking)
1060 FN_LOCAL_BOOL(lp_share_modes,bShareModes)
1061 FN_LOCAL_BOOL(lp_oplocks,bOpLocks)
1062 FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
1063 FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
1064 FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
1065 FN_LOCAL_BOOL(lp_symlinks,bSymlinks)
1066 FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
1067 FN_LOCAL_BOOL(lp_map_system,bMap_system)
1068 FN_LOCAL_BOOL(lp_delete_readonly,bDeleteReadonly)
1069 FN_LOCAL_BOOL(lp_fake_oplocks,bFakeOplocks)
1070 FN_LOCAL_BOOL(lp_recursive_veto_delete,bDeleteVetoFiles)
1071 FN_LOCAL_BOOL(lp_dos_filetimes,bDosFiletimes)
1072 FN_LOCAL_BOOL(lp_dos_filetime_resolution,bDosFiletimeResolution)
1073 FN_LOCAL_BOOL(lp_fake_dir_create_times,bFakeDirCreateTimes)
1074
1075 FN_LOCAL_INTEGER(lp_create_mode,iCreate_mask)
1076 FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
1077 FN_LOCAL_INTEGER(lp_dir_mode,iDir_mask)
1078 FN_LOCAL_INTEGER(lp_force_dir_mode,iDir_force_mode)
1079 FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
1080 FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
1081 FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
1082 FN_LOCAL_INTEGER(lp_printing,iPrinting)
1083
1084 FN_LOCAL_CHAR(lp_magicchar,magic_char)
1085
1086
1087
1088 /* local prototypes */
1089 static int    strwicmp( char *psz1, char *psz2 );
1090 static int    map_parameter( char *pszParmName);
1091 static BOOL   set_boolean( BOOL *pb, char *pszParmValue );
1092 static int    getservicebyname(char *pszServiceName, service *pserviceDest);
1093 static void   copy_service( service *pserviceDest, 
1094                             service *pserviceSource,
1095                             BOOL *pcopymapDest );
1096 static BOOL   service_ok(int iService);
1097 static BOOL   do_parameter(char *pszParmName, char *pszParmValue);
1098 static BOOL   do_section(char *pszSectionName);
1099 static void init_copymap(service *pservice);
1100
1101
1102 /***************************************************************************
1103 initialise a service to the defaults
1104 ***************************************************************************/
1105 static void init_service(service *pservice)
1106 {
1107   bzero((char *)pservice,sizeof(service));
1108   copy_service(pservice,&sDefault,NULL);
1109 }
1110
1111
1112 /***************************************************************************
1113 free the dynamically allocated parts of a service struct
1114 ***************************************************************************/
1115 static void free_service(service *pservice)
1116 {
1117   int i;
1118   if (!pservice)
1119      return;
1120
1121   if(pservice->szService)
1122     DEBUG(5,("free_service: Freeing service %s\n", pservice->szService));
1123
1124   string_free(&pservice->szService);
1125   if (pservice->copymap)
1126   {
1127     free(pservice->copymap);
1128     pservice->copymap = NULL;
1129   }
1130  
1131   for (i=0;parm_table[i].label;i++)
1132     if ((parm_table[i].type == P_STRING ||
1133          parm_table[i].type == P_USTRING) &&
1134         parm_table[i].class == P_LOCAL)
1135       string_free((char **)(((char *)pservice) + PTR_DIFF(parm_table[i].ptr,&sDefault)));
1136 }
1137
1138 /***************************************************************************
1139 add a new service to the services array initialising it with the given 
1140 service
1141 ***************************************************************************/
1142 static int add_a_service(service *pservice, char *name)
1143 {
1144   int i;
1145   service tservice;
1146   int num_to_alloc = iNumServices+1;
1147
1148   tservice = *pservice;
1149
1150   /* it might already exist */
1151   if (name) 
1152     {
1153       i = getservicebyname(name,NULL);
1154       if (i >= 0)
1155         return(i);
1156     }
1157
1158   /* find an invalid one */
1159   for (i=0;i<iNumServices;i++)
1160     if (!pSERVICE(i)->valid)
1161       break;
1162
1163   /* if not, then create one */
1164   if (i == iNumServices)
1165     {
1166       ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
1167       if (ServicePtrs)
1168         pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
1169
1170       if (!ServicePtrs || !pSERVICE(iNumServices))
1171         return(-1);
1172
1173       iNumServices++;
1174     }
1175   else
1176     free_service(pSERVICE(i));
1177
1178   pSERVICE(i)->valid = True;
1179
1180   init_service(pSERVICE(i));
1181   copy_service(pSERVICE(i),&tservice,NULL);
1182   if (name)
1183     string_set(&iSERVICE(i).szService,name);  
1184
1185   return(i);
1186 }
1187
1188 /***************************************************************************
1189 add a new home service, with the specified home directory, defaults coming 
1190 from service ifrom
1191 ***************************************************************************/
1192 BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir)
1193 {
1194   int i = add_a_service(pSERVICE(iDefaultService),pszHomename);
1195
1196   if (i < 0)
1197     return(False);
1198
1199   if (!(*(iSERVICE(i).szPath)) || strequal(iSERVICE(i).szPath,lp_pathname(-1)))
1200     string_set(&iSERVICE(i).szPath,pszHomedir);
1201   if (!(*(iSERVICE(i).comment)))
1202     {
1203       pstring comment;
1204       sprintf(comment,"Home directory of %s",pszHomename);
1205       string_set(&iSERVICE(i).comment,comment);
1206     }
1207   iSERVICE(i).bAvailable = sDefault.bAvailable;
1208   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
1209
1210   DEBUG(3,("adding home directory %s at %s\n", pszHomename, pszHomedir));
1211
1212   return(True);
1213 }
1214
1215 /***************************************************************************
1216 add a new service, based on an old one
1217 ***************************************************************************/
1218 int lp_add_service(char *pszService, int iDefaultService)
1219 {
1220   return(add_a_service(pSERVICE(iDefaultService),pszService));
1221 }
1222
1223
1224 /***************************************************************************
1225 add the IPC service
1226 ***************************************************************************/
1227 static BOOL lp_add_ipc(void)
1228 {
1229   pstring comment;
1230   int i = add_a_service(&sDefault,"IPC$");
1231
1232   if (i < 0)
1233     return(False);
1234
1235   sprintf(comment,"IPC Service (%s)", Globals.szServerString );
1236
1237   string_set(&iSERVICE(i).szPath,tmpdir());
1238   string_set(&iSERVICE(i).szUsername,"");
1239   string_set(&iSERVICE(i).comment,comment);
1240   iSERVICE(i).status = False;
1241   iSERVICE(i).iMaxConnections = 0;
1242   iSERVICE(i).bAvailable = True;
1243   iSERVICE(i).bRead_only = True;
1244   iSERVICE(i).bGuest_only = False;
1245   iSERVICE(i).bGuest_ok = True;
1246   iSERVICE(i).bPrint_ok = False;
1247   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
1248
1249   DEBUG(3,("adding IPC service\n"));
1250
1251   return(True);
1252 }
1253
1254
1255 /***************************************************************************
1256 add a new printer service, with defaults coming from service iFrom
1257 ***************************************************************************/
1258 BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
1259 {
1260   char *comment = "From Printcap";
1261   int i = add_a_service(pSERVICE(iDefaultService),pszPrintername);
1262   
1263   if (i < 0)
1264     return(False);
1265   
1266   /* note that we do NOT default the availability flag to True - */
1267   /* we take it from the default service passed. This allows all */
1268   /* dynamic printers to be disabled by disabling the [printers] */
1269   /* entry (if/when the 'available' keyword is implemented!).    */
1270   
1271   /* the printer name is set to the service name. */
1272   string_set(&iSERVICE(i).szPrintername,pszPrintername);
1273   string_set(&iSERVICE(i).comment,comment);
1274   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
1275   /* Printers cannot be read_only. */
1276   iSERVICE(i).bRead_only = False;
1277   /* No share modes on printer services. */
1278   iSERVICE(i).bShareModes = False;
1279   /* No oplocks on printer services. */
1280   iSERVICE(i).bOpLocks = False;
1281   /* Printer services must be printable. */
1282   iSERVICE(i).bPrint_ok = True;
1283   
1284   DEBUG(3,("adding printer service %s\n",pszPrintername));
1285   
1286   return(True);
1287 }
1288
1289
1290 /***************************************************************************
1291 Do a case-insensitive, whitespace-ignoring string compare.
1292 ***************************************************************************/
1293 static int strwicmp(char *psz1, char *psz2)
1294 {
1295    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
1296    /* appropriate value. */
1297    if (psz1 == psz2)
1298       return (0);
1299    else
1300       if (psz1 == NULL)
1301          return (-1);
1302       else
1303           if (psz2 == NULL)
1304               return (1);
1305
1306    /* sync the strings on first non-whitespace */
1307    while (1)
1308    {
1309       while (isspace(*psz1))
1310          psz1++;
1311       while (isspace(*psz2))
1312          psz2++;
1313       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
1314          break;
1315       psz1++;
1316       psz2++;
1317    }
1318    return (*psz1 - *psz2);
1319 }
1320
1321 /***************************************************************************
1322 Map a parameter's string representation to something we can use. 
1323 Returns False if the parameter string is not recognised, else TRUE.
1324 ***************************************************************************/
1325 static int map_parameter(char *pszParmName)
1326 {
1327    int iIndex;
1328
1329    if (*pszParmName == '-')
1330      return(-1);
1331
1332    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
1333       if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1334          return(iIndex);
1335
1336    DEBUG(0,( "Unknown parameter encountered: \"%s\"\n", pszParmName));
1337    return(-1);
1338 }
1339
1340
1341 /***************************************************************************
1342 Set a boolean variable from the text value stored in the passed string.
1343 Returns True in success, False if the passed string does not correctly 
1344 represent a boolean.
1345 ***************************************************************************/
1346 static BOOL set_boolean(BOOL *pb, char *pszParmValue)
1347 {
1348    BOOL bRetval;
1349
1350    bRetval = True;
1351    if (strwicmp(pszParmValue, "yes") == 0 ||
1352        strwicmp(pszParmValue, "true") == 0 ||
1353        strwicmp(pszParmValue, "1") == 0)
1354       *pb = True;
1355    else
1356       if (strwicmp(pszParmValue, "no") == 0 ||
1357           strwicmp(pszParmValue, "False") == 0 ||
1358           strwicmp(pszParmValue, "0") == 0)
1359          *pb = False;
1360       else
1361       {
1362          DEBUG(0,( "Badly formed boolean in configuration file: \"%s\".\n",
1363                pszParmValue));
1364          bRetval = False;
1365       }
1366    return (bRetval);
1367 }
1368
1369 /***************************************************************************
1370 Find a service by name. Otherwise works like get_service.
1371 ***************************************************************************/
1372 static int getservicebyname(char *pszServiceName, service *pserviceDest)
1373 {
1374    int iService;
1375
1376    for (iService = iNumServices - 1; iService >= 0; iService--)
1377       if (VALID(iService) &&
1378           strwicmp(iSERVICE(iService).szService, pszServiceName) == 0) 
1379       {
1380          if (pserviceDest != NULL)
1381            copy_service(pserviceDest, pSERVICE(iService), NULL);
1382          break;
1383       }
1384
1385    return (iService);
1386 }
1387
1388
1389
1390 /***************************************************************************
1391 Copy a service structure to another
1392
1393 If pcopymapDest is NULL then copy all fields
1394 ***************************************************************************/
1395 static void copy_service(service *pserviceDest, 
1396                          service *pserviceSource,
1397                          BOOL *pcopymapDest)
1398 {
1399   int i;
1400   BOOL bcopyall = (pcopymapDest == NULL);
1401
1402   for (i=0;parm_table[i].label;i++)
1403     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL && 
1404         (bcopyall || pcopymapDest[i]))
1405       {
1406         void *def_ptr = parm_table[i].ptr;
1407         void *src_ptr = 
1408           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
1409         void *dest_ptr = 
1410           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
1411
1412         switch (parm_table[i].type)
1413           {
1414           case P_BOOL:
1415           case P_BOOLREV:
1416             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1417             break;
1418
1419           case P_INTEGER:
1420           case P_ENUM:
1421           case P_OCTAL:
1422             *(int *)dest_ptr = *(int *)src_ptr;
1423             break;
1424
1425           case P_CHAR:
1426             *(char *)dest_ptr = *(char *)src_ptr;
1427             break;
1428
1429           case P_STRING:
1430             string_set(dest_ptr,*(char **)src_ptr);
1431             break;
1432
1433           case P_USTRING:
1434             string_set(dest_ptr,*(char **)src_ptr);
1435             strupper(*(char **)dest_ptr);
1436             break;
1437           default:
1438             break;
1439           }
1440       }
1441
1442   if (bcopyall)
1443     {
1444       init_copymap(pserviceDest);
1445       if (pserviceSource->copymap)
1446         memcpy((void *)pserviceDest->copymap,
1447                (void *)pserviceSource->copymap,sizeof(BOOL)*NUMPARAMETERS);
1448     }
1449 }
1450
1451 /***************************************************************************
1452 Check a service for consistency. Return False if the service is in any way
1453 incomplete or faulty, else True.
1454 ***************************************************************************/
1455 static BOOL service_ok(int iService)
1456 {
1457    BOOL bRetval;
1458
1459    bRetval = True;
1460    if (iSERVICE(iService).szService[0] == '\0')
1461    {
1462       DEBUG(0,( "The following message indicates an internal error:\n"));
1463       DEBUG(0,( "No service name in service entry.\n"));
1464       bRetval = False;
1465    }
1466
1467    /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1468    /* I can't see why you'd want a non-printable printer service...        */
1469    if (strwicmp(iSERVICE(iService).szService,PRINTERS_NAME) == 0)
1470       if (!iSERVICE(iService).bPrint_ok)
1471       {
1472          DEBUG(0,( "WARNING: [%s] service MUST be printable!\n",
1473                iSERVICE(iService).szService));
1474          iSERVICE(iService).bPrint_ok = True;
1475       }
1476
1477    if (iSERVICE(iService).szPath[0] == '\0' &&
1478        strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
1479    {
1480       DEBUG(0,("No path in service %s - using %s\n",iSERVICE(iService).szService,tmpdir()));
1481       string_set(&iSERVICE(iService).szPath,tmpdir());      
1482    }
1483
1484    /* If a service is flagged unavailable, log the fact at level 0. */
1485    if (!iSERVICE(iService).bAvailable) 
1486       DEBUG(1,( "NOTE: Service %s is flagged unavailable.\n",
1487             iSERVICE(iService).szService));
1488
1489    return (bRetval);
1490 }
1491
1492 static struct file_lists {
1493   struct file_lists *next;
1494   char *name;
1495   time_t modtime;
1496 } *file_lists = NULL;
1497
1498 /*******************************************************************
1499 keep a linked list of all config files so we know when one has changed 
1500 it's date and needs to be reloaded
1501 ********************************************************************/
1502 static void add_to_file_list(char *fname)
1503 {
1504   struct file_lists *f=file_lists;
1505
1506   while (f) {
1507     if (f->name && !strcmp(f->name,fname)) break;
1508     f = f->next;
1509   }
1510
1511   if (!f) {
1512     f = (struct file_lists *)malloc(sizeof(file_lists[0]));
1513     if (!f) return;
1514     f->next = file_lists;
1515     f->name = strdup(fname);
1516     if (!f->name) {
1517       free(f);
1518       return;
1519     }
1520     file_lists = f;
1521   }
1522
1523   {
1524     pstring n2;
1525     pstrcpy(n2,fname);
1526     standard_sub_basic(n2);
1527     f->modtime = file_modtime(n2);
1528   }
1529
1530 }
1531
1532 /*******************************************************************
1533 check if a config file has changed date
1534 ********************************************************************/
1535 BOOL lp_file_list_changed(void)
1536 {
1537   struct file_lists *f = file_lists;
1538   DEBUG(6,("lp_file_list_changed()\n"));
1539
1540   while (f)
1541   {
1542     pstring n2;
1543     time_t mod_time;
1544
1545     pstrcpy(n2,f->name);
1546     standard_sub_basic(n2);
1547
1548     DEBUG(6,("file %s -> %s  last mod_time: %s\n",
1549              f->name, n2, ctime(&f->modtime)));
1550
1551     mod_time = file_modtime(n2);
1552
1553     if (f->modtime != mod_time) {
1554             DEBUG(6,("file %s modified: %s\n", n2, ctime(&mod_time)));
1555             f->modtime = mod_time;
1556             return(True);
1557     }
1558     f = f->next;   
1559   }
1560   return(False);
1561 }
1562
1563 /***************************************************************************
1564   handle the interpretation of the coding system parameter
1565   *************************************************************************/
1566 static BOOL handle_coding_system(char *pszParmValue,char **ptr)
1567 {
1568         string_set(ptr,pszParmValue);
1569         interpret_coding_system(pszParmValue);
1570         return(True);
1571 }
1572
1573 /***************************************************************************
1574 handle the interpretation of the character set system parameter
1575 ***************************************************************************/
1576 static BOOL handle_character_set(char *pszParmValue,char **ptr)
1577 {
1578         string_set(ptr,pszParmValue);
1579         interpret_character_set(pszParmValue);
1580         return(True);
1581 }
1582
1583
1584 /***************************************************************************
1585 handle the valid chars lines
1586 ***************************************************************************/
1587 static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
1588
1589   string_set(ptr,pszParmValue);
1590
1591   /* A dependency here is that the parameter client code page must be
1592      set before this is called - as calling codepage_initialise()
1593      would overwrite the valid char lines.
1594    */
1595   codepage_initialise(lp_client_code_page());
1596
1597   add_char_string(pszParmValue);
1598   return(True);
1599 }
1600
1601
1602 /***************************************************************************
1603 handle the include operation
1604 ***************************************************************************/
1605 static BOOL handle_include(char *pszParmValue,char **ptr)
1606
1607   pstring fname;
1608   pstrcpy(fname,pszParmValue);
1609
1610   add_to_file_list(fname);
1611
1612   standard_sub_basic(fname);
1613
1614   string_set(ptr,fname);
1615
1616   if (file_exist(fname,NULL))
1617     return(pm_process(fname, do_section, do_parameter));      
1618
1619   DEBUG(2,("Can't find include file %s\n",fname));
1620
1621   return(False);
1622 }
1623
1624
1625 /***************************************************************************
1626 handle the interpretation of the copy parameter
1627 ***************************************************************************/
1628 static BOOL handle_copy(char *pszParmValue,char **ptr)
1629 {
1630    BOOL bRetval;
1631    int iTemp;
1632    service serviceTemp;
1633
1634    string_set(ptr,pszParmValue);
1635
1636    init_service(&serviceTemp);
1637
1638    bRetval = False;
1639    
1640    DEBUG(3,("Copying service from service %s\n",pszParmValue));
1641
1642    if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0)
1643      {
1644        if (iTemp == iServiceIndex)
1645          {
1646            DEBUG(0,("Can't copy service %s - unable to copy self!\n",
1647                     pszParmValue));
1648          }
1649        else
1650          {
1651            copy_service(pSERVICE(iServiceIndex), 
1652                         &serviceTemp,
1653                         iSERVICE(iServiceIndex).copymap);
1654            bRetval = True;
1655          }
1656      }
1657    else
1658      {
1659        DEBUG(0,( "Unable to copy service - source not found: %s\n",
1660                 pszParmValue));
1661        bRetval = False;
1662      }
1663
1664    free_service(&serviceTemp);
1665    return (bRetval);
1666 }
1667
1668
1669 /***************************************************************************
1670 initialise a copymap
1671 ***************************************************************************/
1672 static void init_copymap(service *pservice)
1673 {
1674   int i;
1675   if (pservice->copymap) free(pservice->copymap);
1676   pservice->copymap = (BOOL *)malloc(sizeof(BOOL)*NUMPARAMETERS);
1677   if (!pservice->copymap)
1678     DEBUG(0,("Couldn't allocate copymap!! (size %d)\n",NUMPARAMETERS));
1679
1680   for (i=0;i<NUMPARAMETERS;i++)
1681     pservice->copymap[i] = True;
1682 }
1683
1684
1685 /***************************************************************************
1686  return the local pointer to a parameter given the service number and the 
1687  pointer into the default structure
1688 ***************************************************************************/
1689 void *lp_local_ptr(int snum, void *ptr)
1690 {
1691         return (void *)(((char *)pSERVICE(snum)) + PTR_DIFF(ptr,&sDefault));
1692 }
1693
1694 /***************************************************************************
1695 Process a parameter for a particular service number. If snum < 0
1696 then assume we are in the globals
1697 ***************************************************************************/
1698 BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue)
1699 {
1700    int parmnum, i;
1701    void *parm_ptr=NULL; /* where we are going to store the result */
1702    void *def_ptr=NULL;
1703
1704    parmnum = map_parameter(pszParmName);
1705
1706    if (parmnum < 0)
1707      {
1708        DEBUG(0,( "Ignoring unknown parameter \"%s\"\n", pszParmName));
1709        return(True);
1710      }
1711
1712    def_ptr = parm_table[parmnum].ptr;
1713
1714    /* we might point at a service, the default service or a global */
1715    if (snum < 0) {
1716      parm_ptr = def_ptr;
1717    } else {
1718        if (parm_table[parmnum].class == P_GLOBAL) {
1719            DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
1720            return(True);
1721          }
1722        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
1723    }
1724
1725    if (snum >= 0) {
1726            if (!iSERVICE(snum).copymap)
1727                    init_copymap(pSERVICE(snum));
1728            
1729            /* this handles the aliases - set the copymap for other entries with
1730               the same data pointer */
1731            for (i=0;parm_table[i].label;i++)
1732                    if (parm_table[i].ptr == parm_table[parmnum].ptr)
1733                            iSERVICE(snum).copymap[i] = False;
1734    }
1735
1736    /* if it is a special case then go ahead */
1737    if (parm_table[parmnum].special) {
1738            parm_table[parmnum].special(pszParmValue,parm_ptr);
1739            return(True);
1740    }
1741
1742    /* now switch on the type of variable it is */
1743    switch (parm_table[parmnum].type)
1744      {
1745      case P_BOOL:
1746        set_boolean(parm_ptr,pszParmValue);
1747        break;
1748
1749      case P_BOOLREV:
1750        set_boolean(parm_ptr,pszParmValue);
1751        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
1752        break;
1753
1754      case P_INTEGER:
1755        *(int *)parm_ptr = atoi(pszParmValue);
1756        break;
1757
1758      case P_CHAR:
1759        *(char *)parm_ptr = *pszParmValue;
1760        break;
1761
1762      case P_OCTAL:
1763        sscanf(pszParmValue,"%o",(int *)parm_ptr);
1764        break;
1765
1766      case P_STRING:
1767        string_set(parm_ptr,pszParmValue);
1768        break;
1769
1770      case P_USTRING:
1771        string_set(parm_ptr,pszParmValue);
1772        strupper(*(char **)parm_ptr);
1773        break;
1774
1775      case P_GSTRING:
1776        strcpy((char *)parm_ptr,pszParmValue);
1777        break;
1778
1779      case P_UGSTRING:
1780        strcpy((char *)parm_ptr,pszParmValue);
1781        strupper((char *)parm_ptr);
1782        break;
1783
1784      case P_ENUM:
1785              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
1786                      if (strequal(pszParmValue, parm_table[parmnum].enum_list[i].name)) {
1787                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
1788                              break;
1789                      }
1790              }
1791              break;
1792      case P_SEP:
1793              break;
1794      }
1795
1796    return(True);
1797 }
1798
1799 /***************************************************************************
1800 Process a parameter.
1801 ***************************************************************************/
1802 static BOOL do_parameter(char *pszParmName, char *pszParmValue)
1803 {
1804    if (!bInGlobalSection && bGlobalOnly) return(True);
1805
1806    DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
1807
1808    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, pszParmName, pszParmValue);
1809 }
1810
1811
1812 /***************************************************************************
1813 print a parameter of the specified type
1814 ***************************************************************************/
1815 static void print_parameter(struct parm_struct *p,void *ptr, FILE *f)
1816 {
1817         int i;
1818         switch (p->type) {
1819         case P_ENUM:
1820                 for (i=0;p->enum_list[i].name;i++) {
1821                         if (*(int *)ptr == p->enum_list[i].value) {
1822                                 fprintf(f,"%s",p->enum_list[i].name);
1823                                 break;
1824                         }
1825                 }
1826                 break;
1827
1828         case P_BOOL:
1829                 fprintf(f,"%s",BOOLSTR(*(BOOL *)ptr));
1830                 break;
1831       
1832         case P_BOOLREV:
1833                 fprintf(f,"%s",BOOLSTR(! *(BOOL *)ptr));
1834                 break;
1835       
1836         case P_INTEGER:
1837                 fprintf(f,"%d",*(int *)ptr);
1838                 break;
1839       
1840         case P_CHAR:
1841                 fprintf(f,"%c",*(char *)ptr);
1842                 break;
1843       
1844         case P_OCTAL:
1845                 fprintf(f,"0%o",*(int *)ptr);
1846                 break;
1847       
1848         case P_GSTRING:
1849         case P_UGSTRING:
1850                 if ((char *)ptr)
1851                         fprintf(f,"%s",(char *)ptr);
1852                 break;
1853                 
1854         case P_STRING:
1855         case P_USTRING:
1856                 if (*(char **)ptr)
1857                         fprintf(f,"%s",*(char **)ptr);
1858                 break;
1859         case P_SEP:
1860                 break;
1861         }
1862 }
1863
1864
1865 /***************************************************************************
1866 check if two parameters are equal
1867 ***************************************************************************/
1868 static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
1869 {
1870   switch (type)
1871     {
1872     case P_BOOL:
1873     case P_BOOLREV:
1874       return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
1875
1876     case P_INTEGER:
1877     case P_ENUM:
1878     case P_OCTAL:
1879       return(*((int *)ptr1) == *((int *)ptr2));
1880       
1881     case P_CHAR:
1882       return(*((char *)ptr1) == *((char *)ptr2));
1883
1884     case P_GSTRING:
1885     case P_UGSTRING:
1886       {
1887         char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
1888         if (p1 && !*p1) p1 = NULL;
1889         if (p2 && !*p2) p2 = NULL;
1890         return(p1==p2 || strequal(p1,p2));
1891       }
1892     case P_STRING:
1893     case P_USTRING:
1894       {
1895         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
1896         if (p1 && !*p1) p1 = NULL;
1897         if (p2 && !*p2) p2 = NULL;
1898         return(p1==p2 || strequal(p1,p2));
1899       }
1900      case P_SEP:
1901              break;
1902     }
1903   return(False);
1904 }
1905
1906 /***************************************************************************
1907 Process a new section (service). At this stage all sections are services.
1908 Later we'll have special sections that permit server parameters to be set.
1909 Returns True on success, False on failure.
1910 ***************************************************************************/
1911 static BOOL do_section(char *pszSectionName)
1912 {
1913    BOOL bRetval;
1914    BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) || 
1915                     (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
1916    bRetval = False;
1917
1918    /* if we were in a global section then do the local inits */
1919    if (bInGlobalSection && !isglobal)
1920      init_locals();
1921
1922    /* if we've just struck a global section, note the fact. */
1923    bInGlobalSection = isglobal;   
1924
1925    /* check for multiple global sections */
1926    if (bInGlobalSection)
1927    {
1928      DEBUG(3,( "Processing section \"[%s]\"\n", pszSectionName));
1929      return(True);
1930    }
1931
1932    if (!bInGlobalSection && bGlobalOnly) return(True);
1933
1934    /* if we have a current service, tidy it up before moving on */
1935    bRetval = True;
1936
1937    if (iServiceIndex >= 0)
1938      bRetval = service_ok(iServiceIndex);
1939
1940    /* if all is still well, move to the next record in the services array */
1941    if (bRetval)
1942      {
1943        /* We put this here to avoid an odd message order if messages are */
1944        /* issued by the post-processing of a previous section. */
1945        DEBUG(2,( "Processing section \"[%s]\"\n", pszSectionName));
1946
1947        if ((iServiceIndex=add_a_service(&sDefault,pszSectionName)) < 0)
1948          {
1949            DEBUG(0,("Failed to add a new service\n"));
1950            return(False);
1951          }
1952      }
1953
1954    return (bRetval);
1955 }
1956
1957
1958 /***************************************************************************
1959 determine if a partcular base parameter is currently set to the default value.
1960 ***************************************************************************/
1961 static BOOL is_default(int i)
1962 {
1963         if (!defaults_saved) return False;
1964         switch (parm_table[i].type) {
1965         case P_STRING:
1966         case P_USTRING:
1967                 return strequal(parm_table[i].def.svalue,*(char **)parm_table[i].ptr);
1968         case P_GSTRING:
1969         case P_UGSTRING:
1970                 return strequal(parm_table[i].def.svalue,(char *)parm_table[i].ptr);
1971         case P_BOOL:
1972         case P_BOOLREV:
1973                 return parm_table[i].def.bvalue == *(BOOL *)parm_table[i].ptr;
1974         case P_CHAR:
1975                 return parm_table[i].def.cvalue == *(char *)parm_table[i].ptr;
1976         case P_INTEGER:
1977         case P_OCTAL:
1978         case P_ENUM:
1979                 return parm_table[i].def.ivalue == *(int *)parm_table[i].ptr;
1980         case P_SEP:
1981                 break;
1982         }
1983         return False;
1984 }
1985
1986
1987 /***************************************************************************
1988 Display the contents of the global structure.
1989 ***************************************************************************/
1990 static void dump_globals(FILE *f)
1991 {
1992         int i;
1993         fprintf(f, "# Global parameters\n");
1994         
1995         for (i=0;parm_table[i].label;i++)
1996                 if (parm_table[i].class == P_GLOBAL &&
1997                     parm_table[i].ptr &&
1998                     (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr))) {
1999                         if (defaults_saved && is_default(i)) continue;
2000                         fprintf(f,"\t%s = ",parm_table[i].label);
2001                         print_parameter(&parm_table[i],parm_table[i].ptr, f);
2002                         fprintf(f,"\n");
2003                 }
2004 }
2005
2006 /***************************************************************************
2007 return True if a local parameter is currently set to the global default
2008 ***************************************************************************/
2009 BOOL lp_is_default(int snum, struct parm_struct *parm)
2010 {
2011         int pdiff = PTR_DIFF(parm->ptr,&sDefault);
2012                         
2013         return equal_parameter(parm->type,
2014                                ((char *)pSERVICE(snum)) + pdiff,
2015                                ((char *)&sDefault) + pdiff);
2016 }
2017
2018
2019 /***************************************************************************
2020 Display the contents of a single services record.
2021 ***************************************************************************/
2022 static void dump_a_service(service *pService, FILE *f)
2023 {
2024         int i;
2025         if (pService != &sDefault)
2026                 fprintf(f,"\n[%s]\n",pService->szService);
2027
2028         for (i=0;parm_table[i].label;i++)
2029                 if (parm_table[i].class == P_LOCAL &&
2030                     parm_table[i].ptr && 
2031                     (*parm_table[i].label != '-') &&
2032                     (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr))) {
2033                         int pdiff = PTR_DIFF(parm_table[i].ptr,&sDefault);
2034                         
2035                         if (pService == &sDefault) {
2036                                 if (defaults_saved && is_default(i)) continue;
2037                         } else {
2038                                 if (equal_parameter(parm_table[i].type,
2039                                                     ((char *)pService) + pdiff,
2040                                                     ((char *)&sDefault) + pdiff)) 
2041                                         continue;
2042                         }
2043
2044                         fprintf(f,"\t%s = ",parm_table[i].label);
2045                         print_parameter(&parm_table[i],
2046                                         ((char *)pService) + pdiff, f);
2047                         fprintf(f,"\n");
2048                 }
2049 }
2050
2051
2052 /***************************************************************************
2053 return info about the next service  in a service. snum==-1 gives the globals
2054
2055 return NULL when out of parameters
2056 ***************************************************************************/
2057 struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
2058 {
2059         if (snum == -1) {
2060                 /* do the globals */
2061                 for (;parm_table[*i].label;(*i)++) {
2062                         if (parm_table[*i].class == P_SEPARATOR) 
2063                                 return &parm_table[(*i)++];
2064
2065                         if (!parm_table[*i].ptr || (*parm_table[*i].label == '-'))
2066                                 continue;
2067                         
2068                         if ((*i) > 0 && (parm_table[*i].ptr == parm_table[(*i)-1].ptr))
2069                                 continue;
2070
2071                         return &parm_table[(*i)++];
2072                 }
2073         } else {
2074                 service *pService = pSERVICE(snum);
2075
2076                 for (;parm_table[*i].label;(*i)++) {
2077                         if (parm_table[*i].class == P_SEPARATOR) 
2078                                 return &parm_table[(*i)++];
2079
2080                         if (parm_table[*i].class == P_LOCAL &&
2081                             parm_table[*i].ptr && 
2082                             (*parm_table[*i].label != '-') &&
2083                             ((*i) == 0 || 
2084                              (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
2085                                 int pdiff = PTR_DIFF(parm_table[*i].ptr,&sDefault);
2086                                 
2087                                 if (allparameters ||
2088                                     !equal_parameter(parm_table[*i].type,
2089                                                      ((char *)pService) + pdiff,
2090                                                      ((char *)&sDefault) + pdiff)) {
2091                                         return &parm_table[(*i)++];
2092                                 }
2093                         }
2094                 }
2095         }
2096
2097         return NULL;
2098 }
2099
2100
2101 #if 0
2102 /***************************************************************************
2103 Display the contents of a single copy structure.
2104 ***************************************************************************/
2105 static void dump_copy_map(BOOL *pcopymap)
2106 {
2107   int i;
2108   if (!pcopymap) return;
2109
2110   printf("\n\tNon-Copied parameters:\n");
2111
2112   for (i=0;parm_table[i].label;i++)
2113     if (parm_table[i].class == P_LOCAL &&
2114         parm_table[i].ptr && !pcopymap[i] &&
2115         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
2116       {
2117         printf("\t\t%s\n",parm_table[i].label);
2118       }
2119 }
2120 #endif
2121
2122 /***************************************************************************
2123 Return TRUE if the passed service number is within range.
2124 ***************************************************************************/
2125 BOOL lp_snum_ok(int iService)
2126 {
2127    return (LP_SNUM_OK(iService) && iSERVICE(iService).bAvailable);
2128 }
2129
2130
2131 /***************************************************************************
2132 auto-load some homes and printer services
2133 ***************************************************************************/
2134 static void lp_add_auto_services(char *str)
2135 {
2136   char *s;
2137   char *p;
2138   int homes = lp_servicenumber(HOMES_NAME);
2139   int printers = lp_servicenumber(PRINTERS_NAME);
2140
2141   if (!str)
2142     return;
2143
2144   s = strdup(str);
2145   if (!s) return;
2146
2147   for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP))
2148     {
2149       char *home = get_home_dir(p);
2150
2151       if (lp_servicenumber(p) >= 0) continue;
2152
2153       if (home && homes >= 0)
2154         {
2155           lp_add_home(p,homes,home);
2156           continue;
2157         }
2158
2159       if (printers >= 0 && pcap_printername_ok(p,NULL))
2160         lp_add_printer(p,printers);
2161     }
2162   free(s);
2163 }
2164
2165 /***************************************************************************
2166 auto-load one printer
2167 ***************************************************************************/
2168 static void lp_add_one_printer(char *name,char *comment)
2169 {
2170   int printers = lp_servicenumber(PRINTERS_NAME);
2171   int i;
2172
2173   if (lp_servicenumber(name) < 0)
2174     {
2175       lp_add_printer(name,printers);
2176       if ((i=lp_servicenumber(name)) >= 0)
2177         string_set(&iSERVICE(i).comment,comment);
2178     }      
2179 }
2180
2181
2182 /***************************************************************************
2183 auto-load printer services
2184 ***************************************************************************/
2185 static void lp_add_all_printers(void)
2186 {
2187   int printers = lp_servicenumber(PRINTERS_NAME);
2188
2189   if (printers < 0) return;
2190
2191   pcap_printer_fn(lp_add_one_printer);
2192 }
2193
2194 /***************************************************************************
2195 have we loaded a services file yet?
2196 ***************************************************************************/
2197 BOOL lp_loaded(void)
2198 {
2199   return(bLoaded);
2200 }
2201
2202 /***************************************************************************
2203 unload unused services
2204 ***************************************************************************/
2205 void lp_killunused(BOOL (*snumused)(int ))
2206 {
2207   int i;
2208   for (i=0;i<iNumServices;i++)
2209     if (VALID(i) && (!snumused || !snumused(i)))
2210       {
2211         iSERVICE(i).valid = False;
2212         free_service(pSERVICE(i));
2213       }
2214 }
2215
2216
2217 /***************************************************************************
2218 save the curent values of all global and sDefault parameters into the 
2219 defaults union. This allows swat and testparm to show only the
2220 changed (ie. non-default) parameters.
2221 ***************************************************************************/
2222 static void lp_save_defaults(void)
2223 {
2224         int i;
2225         for (i = 0; parm_table[i].label; i++) {
2226                 if (i>0 && parm_table[i].ptr == parm_table[i-1].ptr) continue;
2227                 switch (parm_table[i].type) {
2228                 case P_STRING:
2229                 case P_USTRING:
2230                         parm_table[i].def.svalue = strdup(*(char **)parm_table[i].ptr);
2231                         break;
2232                 case P_GSTRING:
2233                 case P_UGSTRING:
2234                         parm_table[i].def.svalue = strdup((char *)parm_table[i].ptr);
2235                         break;
2236                 case P_BOOL:
2237                 case P_BOOLREV:
2238                         parm_table[i].def.bvalue = *(BOOL *)parm_table[i].ptr;
2239                         break;
2240                 case P_CHAR:
2241                         parm_table[i].def.cvalue = *(char *)parm_table[i].ptr;
2242                         break;
2243                 case P_INTEGER:
2244                 case P_OCTAL:
2245                 case P_ENUM:
2246                         parm_table[i].def.ivalue = *(int *)parm_table[i].ptr;
2247                         break;
2248                 case P_SEP:
2249                         break;
2250                 }
2251         }
2252         defaults_saved = True;
2253 }
2254
2255
2256 /***************************************************************************
2257 Load the services array from the services file. Return True on success, 
2258 False on failure.
2259 ***************************************************************************/
2260 BOOL lp_load(char *pszFname,BOOL global_only, BOOL save_defaults, BOOL add_ipc)
2261 {
2262   pstring n2;
2263   BOOL bRetval;
2264  
2265   add_to_file_list(pszFname);
2266
2267   bRetval = False;
2268
2269   bInGlobalSection = True;
2270   bGlobalOnly = global_only;
2271   
2272   init_globals();
2273
2274   if (save_defaults) {
2275           init_locals();
2276           lp_save_defaults();
2277   }
2278   
2279   pstrcpy(n2,pszFname);
2280   standard_sub_basic(n2);
2281
2282   /* We get sections first, so have to start 'behind' to make up */
2283   iServiceIndex = -1;
2284   bRetval = pm_process(n2, do_section, do_parameter);
2285   
2286   /* finish up the last section */
2287   DEBUG(3,("pm_process() returned %s\n", BOOLSTR(bRetval)));
2288   if (bRetval)
2289     if (iServiceIndex >= 0)
2290       bRetval = service_ok(iServiceIndex);         
2291
2292   lp_add_auto_services(lp_auto_services());
2293   if (lp_load_printers())
2294     lp_add_all_printers();
2295
2296   if (add_ipc)
2297           lp_add_ipc();
2298
2299   set_default_server_announce_type();
2300
2301   bLoaded = True;
2302
2303   return (bRetval);
2304 }
2305
2306
2307 /***************************************************************************
2308 return the max number of services
2309 ***************************************************************************/
2310 int lp_numservices(void)
2311 {
2312   return(iNumServices);
2313 }
2314
2315 /***************************************************************************
2316 Display the contents of the services array in human-readable form.
2317 ***************************************************************************/
2318 void lp_dump(FILE *f, BOOL show_defaults)
2319 {
2320    int iService;
2321
2322    if (show_defaults) {
2323            defaults_saved = False;
2324    }
2325
2326    dump_globals(f);
2327    
2328    dump_a_service(&sDefault, f);
2329
2330    for (iService = 0; iService < iNumServices; iService++)
2331    {
2332      if (VALID(iService))
2333        {
2334          if (iSERVICE(iService).szService[0] == '\0')
2335            break;
2336          dump_a_service(pSERVICE(iService), f);
2337        }
2338    }
2339 }
2340
2341
2342 /***************************************************************************
2343 Return the number of the service with the given name, or -1 if it doesn't
2344 exist. Note that this is a DIFFERENT ANIMAL from the internal function
2345 getservicebyname()! This works ONLY if all services have been loaded, and
2346 does not copy the found service.
2347 ***************************************************************************/
2348 int lp_servicenumber(char *pszServiceName)
2349 {
2350    int iService;
2351
2352    for (iService = iNumServices - 1; iService >= 0; iService--)
2353       if (VALID(iService) &&
2354           strequal(lp_servicename(iService), pszServiceName)) 
2355          break;
2356
2357    if (iService < 0)
2358      DEBUG(7,("lp_servicenumber: couldn't find %s\n",pszServiceName));
2359    
2360    return (iService);
2361 }
2362
2363 /*******************************************************************
2364   a useful volume label function
2365   ******************************************************************/
2366 char *volume_label(int snum)
2367 {
2368   char *ret = lp_volume(snum);
2369   if (!*ret) return(lp_servicename(snum));
2370   return(ret);
2371 }
2372
2373 #if 0
2374 /*
2375  * nmbd only loads the global section. There seems to be no way to
2376  * determine exactly is a service is printable by only looking at the
2377  * [global] section so for now always announce as a print server. This
2378  * will need looking at in the future. Jeremy (jallison@whistle.com).
2379  */
2380 /*******************************************************************
2381  Return true if any printer services are defined.
2382   ******************************************************************/
2383 static BOOL lp_printer_services(void)
2384 {
2385   int iService;
2386
2387   for (iService = iNumServices - 1; iService >= 0; iService--)
2388       if (VALID(iService) && iSERVICE(iService).bPrint_ok)
2389           return True;
2390   return False;
2391 }
2392 #endif
2393
2394 /*******************************************************************
2395  Set the server type we will announce as via nmbd.
2396 ********************************************************************/
2397 static void set_default_server_announce_type()
2398 {
2399   default_server_announce = (SV_TYPE_WORKSTATION | SV_TYPE_SERVER |
2400                               SV_TYPE_SERVER_UNIX | SV_TYPE_PRINTQ_SERVER);
2401   if(lp_announce_as() == ANNOUNCE_AS_NT)
2402     default_server_announce |= (SV_TYPE_SERVER_NT | SV_TYPE_NT);
2403   else if(lp_announce_as() == ANNOUNCE_AS_WIN95)
2404     default_server_announce |= SV_TYPE_WIN95_PLUS;
2405   else if(lp_announce_as() == ANNOUNCE_AS_WFW)
2406     default_server_announce |= SV_TYPE_WFW;
2407   default_server_announce |= (lp_time_server() ? SV_TYPE_TIME_SOURCE : 0);
2408 /*
2409  * nmbd only loads the [global] section. There seems to be no way to
2410  * determine exactly if any service is printable by only looking at the
2411  * [global] section so for now always announce as a print server. This
2412  * will need looking at in the future. Jeremy (jallison@whistle.com).
2413  */
2414 #if 0
2415   default_server_announce |= (lp_printer_services() ? SV_TYPE_PRINTQ_SERVER : 0);
2416 #endif
2417 }
2418
2419
2420 /*******************************************************************
2421 rename a service
2422 ********************************************************************/
2423 void lp_rename_service(int snum, char *new_name)
2424 {
2425         string_set(&pSERVICE(snum)->szService, new_name);
2426 }
2427
2428 /*******************************************************************
2429 remove a service
2430 ********************************************************************/
2431 void lp_remove_service(int snum)
2432 {
2433         pSERVICE(snum)->valid = False;
2434 }
2435
2436 /*******************************************************************
2437 copy a service
2438 ********************************************************************/
2439 void lp_copy_service(int snum, char *new_name)
2440 {
2441         char *oldname = lp_servicename(snum);
2442         do_section(new_name);
2443         if (snum >= 0) {
2444                 snum = lp_servicenumber(new_name);
2445                 if (snum >= 0)
2446                         lp_do_parameter(snum, "copy", oldname);
2447         }
2448 }
2449
2450
2451 /*******************************************************************
2452  Get the default server type we will announce as via nmbd.
2453 ********************************************************************/
2454 int lp_default_server_announce(void)
2455 {
2456   return default_server_announce;
2457 }
2458
2459 /*******************************************************************
2460  Split the announce version into major and minor numbers.
2461 ********************************************************************/
2462 int lp_major_announce_version(void)
2463 {
2464   static BOOL got_major = False;
2465   static int major_version = DEFAULT_MAJOR_VERSION;
2466   char *vers;
2467   char *p;
2468
2469   if(got_major)
2470     return major_version;
2471
2472   got_major = True;
2473   if((vers = lp_announce_version()) == NULL)
2474     return major_version;
2475   
2476   if((p = strchr(vers, '.')) == 0)
2477     return major_version;
2478
2479   *p = '\0';
2480   major_version = atoi(vers);
2481   return major_version;
2482 }
2483
2484 int lp_minor_announce_version(void)
2485 {
2486   static BOOL got_minor = False;
2487   static int minor_version = DEFAULT_MINOR_VERSION;
2488   char *vers;
2489   char *p;
2490
2491   if(got_minor)
2492     return minor_version;
2493
2494   got_minor = True;
2495   if((vers = lp_announce_version()) == NULL)
2496     return minor_version;
2497   
2498   if((p = strchr(vers, '.')) == 0)              
2499     return minor_version;
2500     
2501   p++;
2502   minor_version = atoi(p);
2503   return minor_version;
2504 }  
2505
2506 /***********************************************************
2507  Set the global name resolution order (used in smbclient).
2508 ************************************************************/
2509
2510 void lp_set_name_resolve_order(char *new_order)
2511
2512   Globals.szNameResolveOrder = new_order;
2513 }