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