r13206: This patch finally re-adds a -k option that works reasonably.
[bbaumbach/samba-autobuild/.git] / source4 / param / loadparm.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Parameter loading functions
4    Copyright (C) Karl Auer 1993-1998
5
6    Largely re-written by Andrew Tridgell, September 1994
7
8    Copyright (C) Simo Sorce 2001
9    Copyright (C) Alexander Bokovoy 2002
10    Copyright (C) Stefan (metze) Metzmacher 2002
11    Copyright (C) Jim McDonough (jmcd@us.ibm.com)  2003.
12    Copyright (C) James Myers 2003 <myersjj@samba.org>
13    
14    This program is free software; you can redistribute it and/or modify
15    it under the terms of the GNU General Public License as published by
16    the Free Software Foundation; either version 2 of the License, or
17    (at your option) any later version.
18    
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License for more details.
23    
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*
30  *  Load parameters.
31  *
32  *  This module provides suitable callback functions for the params
33  *  module. It builds the internal table of service details which is
34  *  then used by the rest of the server.
35  *
36  * To add a parameter:
37  *
38  * 1) add it to the global or service structure definition
39  * 2) add it to the parm_table
40  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
41  * 4) If it's a global then initialise it in init_globals. If a local
42  *    (ie. service) parameter then initialise it in the sDefault structure
43  *  
44  *
45  * Notes:
46  *   The configuration file is processed sequentially for speed. It is NOT
47  *   accessed randomly as happens in 'real' Windows. For this reason, there
48  *   is a fair bit of sequence-dependent code here - ie., code which assumes
49  *   that certain things happen before others. In particular, the code which
50  *   happens at the boundary between sections is delicately poised, so be
51  *   careful!
52  *
53  */
54
55 #include "includes.h"
56 #include "smb.h"
57 #include "version.h"
58 #include "dynconfig.h"
59 #include "pstring.h"
60 #include "system/time.h"
61 #include "system/iconv.h"
62 #include "librpc/gen_ndr/ndr_svcctl.h"
63 #include "librpc/gen_ndr/ndr_samr.h"
64 #include "dlinklist.h"
65 #include "param/loadparm.h"
66
67 static BOOL bLoaded = False;
68
69 /* some helpful bits */
70 #define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && ServicePtrs[(i)]->valid)
71 #define VALID(i) ServicePtrs[i]->valid
72
73 static BOOL do_parameter(const char *, const char *, void *);
74 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...);
75
76 static BOOL defaults_saved = False;
77
78
79 struct param_opt {
80         struct param_opt *prev, *next;
81         char *key;
82         char *value;
83         int flags;
84 };
85
86 /* 
87  * This structure describes global (ie., server-wide) parameters.
88  */
89 typedef struct
90 {
91         int server_role;
92
93         char **smb_ports;
94         char *dos_charset;
95         char *unix_charset;
96         char *ncalrpc_dir;
97         char *display_charset;
98         char *szLockDir;
99         char *szPidDir;
100         char *szSetupDir;
101         char *szServerString;
102         char *szAutoServices;
103         char *szPasswdChat;
104         char *szLogFile;
105         char *szConfigFile;
106         char *szSAM_URL;
107         char *szSPOOLSS_URL;
108         char *szWINS_CONFIG_URL;
109         char *szWINS_URL;
110         char *szPrivateDir;
111         char **jsInclude;
112         char **szPasswordServers;
113         char *szSocketOptions;
114         char *szRealm;
115         char **szWINSservers;
116         char **szInterfaces;
117         char *szSocketAddress;
118         char *szAnnounceVersion;        /* This is initialised in init_globals */
119         char *szWorkgroup;
120         char *szNetbiosName;
121         char **szNetbiosAliases;
122         char *szNetbiosScope;
123         char *szDomainOtherSIDs;
124         char **szNameResolveOrder;
125         char *szPanicAction;
126         char **dcerpc_ep_servers;
127         char **server_services;
128         char *ntptr_providor;
129         char *szWinbindSeparator;
130         BOOL bWinbindSealedPipes;
131         char *swat_directory;
132         BOOL tls_enabled;
133         char *tls_keyfile;
134         char *tls_certfile;
135         char *tls_cafile;
136         char *tls_crlfile;
137         int max_mux;
138         int max_xmit;
139         int pwordlevel;
140         int maxprotocol;
141         int minprotocol;
142         int security;
143         char **AuthMethods;
144         BOOL paranoid_server_security;
145         int max_wins_ttl;
146         int min_wins_ttl;
147         int announce_as;        /* This is initialised in init_globals */
148         int nbt_port;
149         int dgram_port;
150         int cldap_port;
151         int krb5_port;
152         int kpasswd_port;
153         int web_port;
154         char *socket_options;
155         BOOL bWINSsupport;
156         BOOL bWINSdnsProxy;
157         char *szWINSHook; 
158         BOOL bLocalMaster;
159         BOOL bPreferredMaster;
160         BOOL bEncryptPasswords;
161         BOOL bNullPasswords;
162         BOOL bObeyPamRestrictions;
163         BOOL bLargeReadwrite;
164         BOOL bReadRaw;
165         BOOL bWriteRaw;
166         BOOL bTimeServer;
167         BOOL bBindInterfacesOnly;
168         BOOL bNTSmbSupport;
169         BOOL bNTStatusSupport;
170         BOOL bLanmanAuth;
171         BOOL bNTLMAuth;
172         BOOL bUseSpnego;
173         int  server_signing;
174         int  client_signing;
175         BOOL bClientPlaintextAuth;
176         BOOL bClientLanManAuth;
177         BOOL bClientNTLMv2Auth;
178         BOOL client_use_spnego_principal;
179         BOOL bHostMSDfs;
180         BOOL bUnicode;
181         BOOL bUnixExtensions;
182         BOOL bDisableNetbios;
183         BOOL bRpcBigEndian;
184         struct param_opt *param_opt;
185 }
186 global;
187
188 static global Globals;
189
190 /* 
191  * This structure describes a single service. 
192  */
193 typedef struct
194 {
195         BOOL valid;
196         char *szService;
197         char *szPath;
198         char *szCopy;
199         char *szInclude;
200         char *szPrintername;
201         char **szHostsallow;
202         char **szHostsdeny;
203         char *comment;
204         char *volume;
205         char *fstype;
206         char **ntvfs_handler;
207         int iMaxPrintJobs;
208         int iMaxConnections;
209         int iCSCPolicy;
210         BOOL bAvailable;
211         BOOL bBrowseable;
212         BOOL bRead_only;
213         BOOL bPrint_ok;
214         BOOL bMap_system;
215         BOOL bMap_hidden;
216         BOOL bMap_archive;
217         BOOL bStrictLocking;
218         BOOL *copymap;
219         BOOL bMSDfsRoot;
220         BOOL bStrictSync;
221         BOOL bCIFileSystem;
222         struct param_opt *param_opt;
223
224         char dummy[3];          /* for alignment */
225 }
226 service;
227
228
229 /* This is a default service used to prime a services structure */
230 static service sDefault = {
231         True,                   /* valid */
232         NULL,                   /* szService */
233         NULL,                   /* szPath */
234         NULL,                   /* szCopy */
235         NULL,                   /* szInclude */
236         NULL,                   /* szPrintername */
237         NULL,                   /* szHostsallow */
238         NULL,                   /* szHostsdeny */
239         NULL,                   /* comment */
240         NULL,                   /* volume */
241         NULL,                   /* fstype */
242         NULL,                   /* ntvfs_handler */
243         1000,                   /* iMaxPrintJobs */
244         0,                      /* iMaxConnections */
245         0,                      /* iCSCPolicy */
246         True,                   /* bAvailable */
247         True,                   /* bBrowseable */
248         True,                   /* bRead_only */
249         False,                  /* bPrint_ok */
250         False,                  /* bMap_system */
251         False,                  /* bMap_hidden */
252         True,                   /* bMap_archive */
253         True,                   /* bStrictLocking */
254         NULL,                   /* copymap */
255         False,                  /* bMSDfsRoot */
256         False,                  /* bStrictSync */
257         False,                  /* bCIFileSystem */
258         NULL,                   /* Parametric options */
259
260         ""                      /* dummy */
261 };
262
263 /* local variables */
264 static service **ServicePtrs = NULL;
265 static int iNumServices = 0;
266 static int iServiceIndex = 0;
267 static BOOL bInGlobalSection = True;
268 static int default_server_announce;
269
270 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
271
272 /* prototypes for the special type handlers */
273 static BOOL handle_include(const char *pszParmValue, char **ptr);
274 static BOOL handle_copy(const char *pszParmValue, char **ptr);
275
276 static void set_default_server_announce_type(void);
277
278 static const struct enum_list enum_protocol[] = {
279         {PROTOCOL_NT1, "NT1"},
280         {PROTOCOL_LANMAN2, "LANMAN2"},
281         {PROTOCOL_LANMAN1, "LANMAN1"},
282         {PROTOCOL_CORE, "CORE"},
283         {PROTOCOL_COREPLUS, "COREPLUS"},
284         {PROTOCOL_COREPLUS, "CORE+"},
285         {-1, NULL}
286 };
287
288 static const struct enum_list enum_security[] = {
289         {SEC_SHARE, "SHARE"},
290         {SEC_USER, "USER"},
291         {-1, NULL}
292 };
293
294 /* Types of machine we can announce as. */
295 #define ANNOUNCE_AS_NT_SERVER 1
296 #define ANNOUNCE_AS_WIN95 2
297 #define ANNOUNCE_AS_WFW 3
298 #define ANNOUNCE_AS_NT_WORKSTATION 4
299
300 static const struct enum_list enum_announce_as[] = {
301         {ANNOUNCE_AS_NT_SERVER, "NT"},
302         {ANNOUNCE_AS_NT_SERVER, "NT Server"},
303         {ANNOUNCE_AS_NT_WORKSTATION, "NT Workstation"},
304         {ANNOUNCE_AS_WIN95, "win95"},
305         {ANNOUNCE_AS_WFW, "WfW"},
306         {-1, NULL}
307 };
308
309 static const struct enum_list enum_bool_auto[] = {
310         {False, "No"},
311         {False, "False"},
312         {False, "0"},
313         {True, "Yes"},
314         {True, "True"},
315         {True, "1"},
316         {Auto, "Auto"},
317         {-1, NULL}
318 };
319
320 /* Client-side offline caching policy types */
321 #define CSC_POLICY_MANUAL 0
322 #define CSC_POLICY_DOCUMENTS 1
323 #define CSC_POLICY_PROGRAMS 2
324 #define CSC_POLICY_DISABLE 3
325
326 static const struct enum_list enum_csc_policy[] = {
327         {CSC_POLICY_MANUAL, "manual"},
328         {CSC_POLICY_DOCUMENTS, "documents"},
329         {CSC_POLICY_PROGRAMS, "programs"},
330         {CSC_POLICY_DISABLE, "disable"},
331         {-1, NULL}
332 };
333
334 /* SMB signing types. */
335 static const struct enum_list enum_smb_signing_vals[] = {
336         {SMB_SIGNING_OFF, "No"},
337         {SMB_SIGNING_OFF, "False"},
338         {SMB_SIGNING_OFF, "0"},
339         {SMB_SIGNING_OFF, "Off"},
340         {SMB_SIGNING_OFF, "disabled"},
341         {SMB_SIGNING_SUPPORTED, "Yes"},
342         {SMB_SIGNING_SUPPORTED, "True"},
343         {SMB_SIGNING_SUPPORTED, "1"},
344         {SMB_SIGNING_SUPPORTED, "On"},
345         {SMB_SIGNING_SUPPORTED, "enabled"},
346         {SMB_SIGNING_REQUIRED, "required"},
347         {SMB_SIGNING_REQUIRED, "mandatory"},
348         {SMB_SIGNING_REQUIRED, "force"},
349         {SMB_SIGNING_REQUIRED, "forced"},
350         {SMB_SIGNING_REQUIRED, "enforced"},
351         {SMB_SIGNING_AUTO, "auto"},
352         {-1, NULL}
353 };
354
355 static const struct enum_list enum_server_role[] = {
356         {ROLE_STANDALONE, "standalone"},
357         {ROLE_DOMAIN_MEMBER, "member server"},
358         {ROLE_DOMAIN_BDC, "bdc"},
359         {ROLE_DOMAIN_PDC, "pdc"},
360         {-1, NULL}
361 };
362
363
364 /* Note: We do not initialise the defaults union - it is not allowed in ANSI C
365  *
366  * Note: We have a flag called FLAG_DEVELOPER but is not used at this time, it
367  * is implied in current control logic. This may change at some later time. A
368  * flag value of 0 means - show as development option only.
369  *
370  * The FLAG_HIDE is explicit. Paramters set this way do NOT appear in any edit
371  * screen in SWAT. This is used to exclude parameters as well as to squash all
372  * parameters that have been duplicated by pseudonyms.
373  */
374 static struct parm_struct parm_table[] = {
375         {"Base Options", P_SEP, P_SEPARATOR},
376
377         {"server role", P_ENUM, P_GLOBAL, &Globals.server_role, NULL, enum_server_role, FLAG_BASIC},
378
379         {"dos charset", P_STRING, P_GLOBAL, &Globals.dos_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
380         {"unix charset", P_STRING, P_GLOBAL, &Globals.unix_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
381         {"ncalrpc dir", P_STRING, P_GLOBAL, &Globals.ncalrpc_dir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
382         {"display charset", P_STRING, P_GLOBAL, &Globals.display_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
383         {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
384         {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
385         {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_HIDE},
386         {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkgroup, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
387         {"realm", P_STRING, P_GLOBAL, &Globals.szRealm, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
388         {"netbios name", P_USTRING, P_GLOBAL, &Globals.szNetbiosName, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
389         {"netbios aliases", P_LIST, P_GLOBAL, &Globals.szNetbiosAliases, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
390         {"netbios scope", P_USTRING, P_GLOBAL, &Globals.szNetbiosScope, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
391         {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED  | FLAG_DEVELOPER},
392         {"interfaces", P_LIST, P_GLOBAL, &Globals.szInterfaces, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
393         {"bind interfaces only", P_BOOL, P_GLOBAL, &Globals.bBindInterfacesOnly, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
394         {"ntvfs handler", P_LIST, P_LOCAL, &sDefault.ntvfs_handler, NULL, NULL, FLAG_ADVANCED},
395         {"ntptr providor", P_STRING, P_GLOBAL, &Globals.ntptr_providor, NULL, NULL, FLAG_ADVANCED},
396         {"dcerpc endpoint servers", P_LIST, P_GLOBAL, &Globals.dcerpc_ep_servers, NULL, NULL, FLAG_ADVANCED},
397         {"server services", P_LIST, P_GLOBAL, &Globals.server_services, NULL, NULL, FLAG_ADVANCED},
398
399         {"Security Options", P_SEP, P_SEPARATOR},
400         
401         {"security", P_ENUM, P_GLOBAL, &Globals.security, NULL, enum_security, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
402         {"auth methods", P_LIST, P_GLOBAL, &Globals.AuthMethods, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
403         {"encrypt passwords", P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
404         {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
405         {"obey pam restrictions", P_BOOL, P_GLOBAL, &Globals.bObeyPamRestrictions, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
406         {"password server", P_LIST, P_GLOBAL, &Globals.szPasswordServers, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
407         {"sam database", P_STRING, P_GLOBAL, &Globals.szSAM_URL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
408         {"spoolss database", P_STRING, P_GLOBAL, &Globals.szSPOOLSS_URL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
409         {"wins config database", P_STRING, P_GLOBAL, &Globals.szWINS_CONFIG_URL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
410         {"wins database", P_STRING, P_GLOBAL, &Globals.szWINS_URL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
411         {"private dir", P_STRING, P_GLOBAL, &Globals.szPrivateDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
412         {"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
413         {"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
414         {"lanman auth", P_BOOL, P_GLOBAL, &Globals.bLanmanAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
415         {"ntlm auth", P_BOOL, P_GLOBAL, &Globals.bNTLMAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
416         {"client NTLMv2 auth", P_BOOL, P_GLOBAL, &Globals.bClientNTLMv2Auth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
417         {"client lanman auth", P_BOOL, P_GLOBAL, &Globals.bClientLanManAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
418         {"client plaintext auth", P_BOOL, P_GLOBAL, &Globals.bClientPlaintextAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
419         {"client use spnego principal", P_BOOL, P_GLOBAL, &Globals.client_use_spnego_principal, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
420         
421         {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE},
422
423         {"hosts allow", P_LIST, P_LOCAL, &sDefault.szHostsallow, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
424         {"hosts deny", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
425
426         {"Logging Options", P_SEP, P_SEPARATOR},
427
428         {"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
429         {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL, FLAG_HIDE},
430         {"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
431         
432         {"Protocol Options", P_SEP, P_SEPARATOR},
433         
434         {"smb ports", P_LIST, P_GLOBAL, &Globals.smb_ports, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
435         {"nbt port", P_INTEGER, P_GLOBAL, &Globals.nbt_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
436         {"dgram port", P_INTEGER, P_GLOBAL, &Globals.dgram_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
437         {"cldap port", P_INTEGER, P_GLOBAL, &Globals.cldap_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
438         {"krb5 port", P_INTEGER, P_GLOBAL, &Globals.krb5_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
439         {"kpasswd port", P_INTEGER, P_GLOBAL, &Globals.kpasswd_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
440         {"web port", P_INTEGER, P_GLOBAL, &Globals.web_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
441         {"tls enabled", P_BOOL, P_GLOBAL, &Globals.tls_enabled, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
442         {"tls keyfile", P_STRING, P_GLOBAL, &Globals.tls_keyfile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
443         {"tls certfile", P_STRING, P_GLOBAL, &Globals.tls_certfile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
444         {"tls cafile", P_STRING, P_GLOBAL, &Globals.tls_cafile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
445         {"tls crlfile", P_STRING, P_GLOBAL, &Globals.tls_crlfile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
446         {"swat directory", P_STRING, P_GLOBAL, &Globals.swat_directory, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
447         {"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, FLAG_DEVELOPER},
448         {"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
449         {"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
450         {"unicode", P_BOOL, P_GLOBAL, &Globals.bUnicode, NULL, NULL, FLAG_DEVELOPER},
451         {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL, NULL, FLAG_DEVELOPER},
452         {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL, NULL, FLAG_DEVELOPER},
453         {"disable netbios", P_BOOL, P_GLOBAL, &Globals.bDisableNetbios, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
454         
455         {"nt status support", P_BOOL, P_GLOBAL, &Globals.bNTStatusSupport, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
456
457         {"announce version", P_STRING, P_GLOBAL, &Globals.szAnnounceVersion, NULL, NULL, FLAG_DEVELOPER},
458         {"announce as", P_ENUM, P_GLOBAL, &Globals.announce_as, NULL, enum_announce_as, FLAG_DEVELOPER},
459         {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
460         {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
461
462         {"name resolve order", P_LIST, P_GLOBAL, &Globals.szNameResolveOrder, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
463         {"max wins ttl", P_INTEGER, P_GLOBAL, &Globals.max_wins_ttl, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
464         {"min wins ttl", P_INTEGER, P_GLOBAL, &Globals.min_wins_ttl, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
465         {"time server", P_BOOL, P_GLOBAL, &Globals.bTimeServer, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
466         {"unix extensions", P_BOOL, P_GLOBAL, &Globals.bUnixExtensions, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
467         {"use spnego", P_BOOL, P_GLOBAL, &Globals.bUseSpnego, NULL, NULL, FLAG_DEVELOPER},
468         {"server signing", P_ENUM, P_GLOBAL, &Globals.server_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED}, 
469         {"client signing", P_ENUM, P_GLOBAL, &Globals.client_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED}, 
470         {"rpc big endian", P_BOOL, P_GLOBAL, &Globals.bRpcBigEndian, NULL, NULL, FLAG_DEVELOPER},
471
472         {"Tuning Options", P_SEP, P_SEPARATOR},
473                 
474         {"max connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL, NULL, FLAG_SHARE},
475         {"paranoid server security", P_BOOL, P_GLOBAL, &Globals.paranoid_server_security, NULL, NULL, FLAG_DEVELOPER},
476         {"socket options", P_STRING, P_GLOBAL, &Globals.socket_options, NULL, NULL, FLAG_DEVELOPER},
477
478         {"strict sync", P_BOOL, P_LOCAL, &sDefault.bStrictSync, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
479         {"case insensitive filesystem", P_BOOL, P_LOCAL, &sDefault.bCIFileSystem, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
480
481         {"Printing Options", P_SEP, P_SEPARATOR},
482         
483         {"max print jobs", P_INTEGER, P_LOCAL, &sDefault.iMaxPrintJobs, NULL, NULL, FLAG_PRINT},
484         {"printable", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_PRINT},
485         {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_HIDE},
486         
487         {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_PRINT},
488         {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_HIDE},
489
490         {"Filename Handling", P_SEP, P_SEPARATOR},
491         
492         {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
493         {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
494         {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
495
496         {"Domain Options", P_SEP, P_SEPARATOR},
497         
498         {"Logon Options", P_SEP, P_SEPARATOR},
499
500
501         {"Browse Options", P_SEP, P_SEPARATOR},
502         
503         {"preferred master", P_ENUM, P_GLOBAL, &Globals.bPreferredMaster, NULL, enum_bool_auto, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
504         {"prefered master", P_ENUM, P_GLOBAL, &Globals.bPreferredMaster, NULL, enum_bool_auto, FLAG_HIDE},
505         {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
506         {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
507         {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, FLAG_HIDE},
508
509         {"WINS Options", P_SEP, P_SEPARATOR},
510         
511         {"wins server", P_LIST, P_GLOBAL, &Globals.szWINSservers, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
512         {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
513         {"dns proxy", P_BOOL, P_GLOBAL, &Globals.bWINSdnsProxy, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
514         {"wins hook", P_STRING, P_GLOBAL, &Globals.szWINSHook, NULL, NULL, FLAG_ADVANCED}, 
515
516         {"Locking Options", P_SEP, P_SEPARATOR},
517         
518         {"csc policy", P_ENUM, P_LOCAL, &sDefault.iCSCPolicy, NULL, enum_csc_policy, FLAG_SHARE | FLAG_GLOBAL},
519         
520         {"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
521
522         {"Miscellaneous Options", P_SEP, P_SEPARATOR},
523         
524         {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL, NULL, FLAG_HIDE},
525         {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
526         {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
527         {"lock dir", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL, FLAG_HIDE}, 
528         {"lock directory", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
529         {"pid directory", P_STRING, P_GLOBAL, &Globals.szPidDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, 
530         {"js include", P_LIST, P_GLOBAL, &Globals.jsInclude, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
531         {"setup directory", P_STRING, P_GLOBAL, &Globals.szSetupDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
532         
533         {"socket address", P_STRING, P_GLOBAL, &Globals.szSocketAddress, NULL, NULL, FLAG_DEVELOPER},
534         {"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL, NULL, FLAG_HIDE},
535         
536         {"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy, NULL, FLAG_HIDE},
537         {"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include, NULL, FLAG_HIDE},
538         
539         {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
540         {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL, FLAG_SHARE },
541         {"fstype", P_STRING, P_LOCAL, &sDefault.fstype, NULL, NULL, FLAG_SHARE},
542
543         {"panic action", P_STRING, P_GLOBAL, &Globals.szPanicAction, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
544
545         {"msdfs root", P_BOOL, P_LOCAL, &sDefault.bMSDfsRoot, NULL, NULL, FLAG_SHARE},
546         {"host msdfs", P_BOOL, P_GLOBAL, &Globals.bHostMSDfs, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
547         {"winbind separator", P_STRING, P_GLOBAL, &Globals.szWinbindSeparator, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER },
548         {"winbind sealed pipes", P_BOOL, P_GLOBAL, &Globals.bWinbindSealedPipes, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER },
549
550         {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
551 };
552
553
554 /*
555   return the parameter table
556 */
557 struct parm_struct *lp_parm_table(void)
558 {
559         return parm_table;
560 }
561
562 /***************************************************************************
563  Initialise the global parameter structure.
564 ***************************************************************************/
565 static void init_globals(void)
566 {
567         int i;
568         char *myname;
569
570         DEBUG(3, ("Initialising global parameters\n"));
571
572         for (i = 0; parm_table[i].label; i++) {
573                 if ((parm_table[i].type == P_STRING ||
574                      parm_table[i].type == P_USTRING) &&
575                     parm_table[i].ptr &&
576                     !(parm_table[i].flags & FLAG_CMDLINE)) {
577                         string_set(parm_table[i].ptr, "");
578                 }
579         }
580
581         do_parameter("config file", dyn_CONFIGFILE, NULL);
582
583         do_parameter("server role", "standalone", NULL);
584
585         /* options that can be set on the command line must be initialised via
586            the slower do_parameter() to ensure that FLAG_CMDLINE is obeyed */
587 #ifdef TCP_NODELAY
588         do_parameter("socket options", "TCP_NODELAY", NULL);
589 #endif
590         do_parameter("workgroup", DEFAULT_WORKGROUP, NULL);
591         myname = get_myname();
592         do_parameter("netbios name", myname, NULL);
593         SAFE_FREE(myname);
594         do_parameter("max protocol", "NT1", NULL);
595         do_parameter("name resolve order", "lmhosts wins host bcast", NULL);
596
597         do_parameter("fstype", FSTYPE_STRING, NULL);
598         do_parameter("ntvfs handler", "unixuid default", NULL);
599         do_parameter("max connections", "-1", NULL);
600
601         do_parameter("dcerpc endpoint servers", "epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi winreg dssetup", NULL);
602         do_parameter("server services", "smb rpc nbt wrepl ldap cldap web kdc", NULL);
603         do_parameter("ntptr providor", "simple_ldb", NULL);
604         do_parameter("auth methods", "anonymous sam_ignoredomain", NULL);
605         do_parameter("private dir", dyn_PRIVATE_DIR, NULL);
606         do_parameter("sam database", "sam.ldb", NULL);
607         do_parameter("spoolss database", "spoolss.ldb", NULL);
608         do_parameter("wins config database", "wins_config.ldb", NULL);
609         do_parameter("wins database", "wins.ldb", NULL);
610         do_parameter("registry:HKEY_LOCAL_MACHINE", "hklm.ldb", NULL);
611
612         /* This hive should be dynamically generated by Samba using
613            data from the sam, but for the moment leave it in a tdb to
614            keep regedt32 from popping up an annoying dialog. */
615         do_parameter("registry:HKEY_USERS", "hku.ldb", NULL);
616         
617         /* using UTF8 by default allows us to support all chars */
618         do_parameter("unix charset", "UTF8", NULL);
619
620         /* Use codepage 850 as a default for the dos character set */
621         do_parameter("dos charset", "CP850", NULL);
622
623         /*
624          * Allow the default PASSWD_CHAT to be overridden in local.h.
625          */
626         do_parameter("passwd chat", DEFAULT_PASSWD_CHAT, NULL);
627
628         do_parameter("pid directory", dyn_PIDDIR, NULL);
629         do_parameter("lock dir", dyn_LOCKDIR, NULL);
630         do_parameter("ncalrpc dir", dyn_NCALRPCDIR, NULL);
631
632         do_parameter("socket address", "0.0.0.0", NULL);
633         do_parameter_var("server string", "Samba %s", SAMBA_VERSION_STRING);
634
635         do_parameter_var("announce version", "%d.%d", 
636                          DEFAULT_MAJOR_VERSION,
637                          DEFAULT_MINOR_VERSION);
638
639         do_parameter("password server", "*", NULL);
640
641         do_parameter("max mux", "50", NULL);
642         do_parameter("max xmit", "12288", NULL);
643         do_parameter("password level", "0", NULL);
644         do_parameter("LargeReadwrite", "True", NULL);
645         do_parameter("minprotocol", "CORE", NULL);
646         do_parameter("security", "USER", NULL);
647         do_parameter("paranoid server security", "True", NULL);
648         do_parameter("EncryptPasswords", "True", NULL);
649         do_parameter("ReadRaw", "True", NULL);
650         do_parameter("WriteRaw", "True", NULL);
651         do_parameter("NullPasswords", "False", NULL);
652         do_parameter("ObeyPamRestrictions", "False", NULL);
653         do_parameter("announce as", "NT SERVER", NULL);
654
655         do_parameter("TimeServer", "False", NULL);
656         do_parameter("BindInterfacesOnly", "False", NULL);
657         do_parameter("Unicode", "True", NULL);
658         do_parameter("ClientLanManAuth", "True", NULL);
659         do_parameter("LanmanAuth", "True", NULL);
660         do_parameter("NTLMAuth", "True", NULL);
661         do_parameter("client use spnego principal", "False", NULL);
662         
663         do_parameter("UnixExtensions", "False", NULL);
664
665         do_parameter("PreferredMaster", "Auto", NULL);
666         do_parameter("LocalMaster", "True", NULL);
667
668         do_parameter("wins support", "False", NULL);
669         do_parameter("dns proxy", "True", NULL);
670
671         do_parameter("winbind separator", "\\", NULL);
672         do_parameter("winbind sealed pipes", "True", NULL);
673
674         do_parameter("client signing", "Yes", NULL);
675         do_parameter("server signing", "auto", NULL);
676
677         do_parameter("use spnego", "True", NULL);
678
679         do_parameter("smb ports", SMB_PORTS, NULL);
680         do_parameter("nbt port", "137", NULL);
681         do_parameter("dgram port", "138", NULL);
682         do_parameter("cldap port", "389", NULL);
683         do_parameter("krb5 port", "88", NULL);
684         do_parameter("kpasswd port", "464", NULL);
685         do_parameter("web port", "901", NULL);
686         do_parameter("swat directory", dyn_SWATDIR, NULL);
687
688         do_parameter("nt status support", "True", NULL);
689
690         do_parameter("max wins ttl", "518400", NULL); /* 6 days */
691         do_parameter("min wins ttl", "10", NULL);
692
693         do_parameter("tls enabled", "True", NULL);
694         do_parameter("tls keyfile", "tls/key.pem", NULL);
695         do_parameter("tls certfile", "tls/cert.pem", NULL);
696         do_parameter("tls cafile", "tls/ca.pem", NULL);
697         do_parameter_var("js include", "%s", dyn_JSDIR);
698         do_parameter_var("setup directory", "%s", dyn_SETUPDIR);
699
700         for (i = 0; parm_table[i].label; i++) {
701                 if (!(parm_table[i].flags & FLAG_CMDLINE)) {
702                         parm_table[i].flags |= FLAG_DEFAULT;
703                 }
704         }
705 }
706
707 static TALLOC_CTX *lp_talloc;
708
709 /******************************************************************* a
710  Free up temporary memory - called from the main loop.
711 ********************************************************************/
712
713 void lp_talloc_free(void)
714 {
715         if (!lp_talloc)
716                 return;
717         talloc_free(lp_talloc);
718         lp_talloc = NULL;
719 }
720
721 /*******************************************************************
722  Convenience routine to grab string parameters into temporary memory
723  and run standard_sub_basic on them. The buffers can be written to by
724  callers without affecting the source string.
725 ********************************************************************/
726
727 static const char *lp_string(const char *s)
728 {
729 #if 0  /* until REWRITE done to make thread-safe */
730         size_t len = s ? strlen(s) : 0;
731         char *ret;
732 #endif
733
734         /* The follow debug is useful for tracking down memory problems
735            especially if you have an inner loop that is calling a lp_*()
736            function that returns a string.  Perhaps this debug should be
737            present all the time? */
738
739 #if 0
740         DEBUG(10, ("lp_string(%s)\n", s));
741 #endif
742
743 #if 0  /* until REWRITE done to make thread-safe */
744         if (!lp_talloc)
745                 lp_talloc = talloc_init("lp_talloc");
746
747         ret = talloc_array(lp_talloc, char, len + 100); /* leave room for substitution */
748
749         if (!ret)
750                 return NULL;
751
752         if (!s)
753                 *ret = 0;
754         else
755                 StrnCpy(ret, s, len);
756
757         if (trim_string(ret, "\"", "\"")) {
758                 if (strchr(ret,'"') != NULL)
759                         StrnCpy(ret, s, len);
760         }
761
762         standard_sub_basic(ret,len+100);
763         return (ret);
764 #endif
765         return s;
766 }
767
768 /*
769    In this section all the functions that are used to access the 
770    parameters from the rest of the program are defined 
771 */
772
773 #define FN_GLOBAL_STRING(fn_name,ptr) \
774  const char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
775 #define FN_GLOBAL_CONST_STRING(fn_name,ptr) \
776  const char *fn_name(void) {return(*(const char **)(ptr) ? *(const char **)(ptr) : "");}
777 #define FN_GLOBAL_LIST(fn_name,ptr) \
778  const char **fn_name(void) {return(*(const char ***)(ptr));}
779 #define FN_GLOBAL_BOOL(fn_name,ptr) \
780  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
781 #define FN_GLOBAL_CHAR(fn_name,ptr) \
782  char fn_name(void) {return(*(char *)(ptr));}
783 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
784  int fn_name(void) {return(*(int *)(ptr));}
785
786 #define FN_LOCAL_STRING(fn_name,val) \
787  const char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val));}
788 #define FN_LOCAL_CONST_STRING(fn_name,val) \
789  const char *fn_name(int i) {return (const char *)((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val);}
790 #define FN_LOCAL_LIST(fn_name,val) \
791  const char **fn_name(int i) {return(const char **)(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
792 #define FN_LOCAL_BOOL(fn_name,val) \
793  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
794 #define FN_LOCAL_CHAR(fn_name,val) \
795  char fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
796 #define FN_LOCAL_INTEGER(fn_name,val) \
797  int fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
798
799 FN_GLOBAL_INTEGER(lp_server_role, &Globals.server_role)
800 FN_GLOBAL_LIST(lp_smb_ports, &Globals.smb_ports)
801 FN_GLOBAL_INTEGER(lp_nbt_port, &Globals.nbt_port)
802 FN_GLOBAL_INTEGER(lp_dgram_port, &Globals.dgram_port)
803 FN_GLOBAL_INTEGER(lp_cldap_port, &Globals.cldap_port)
804 FN_GLOBAL_INTEGER(lp_krb5_port, &Globals.krb5_port)
805 FN_GLOBAL_INTEGER(lp_kpasswd_port, &Globals.kpasswd_port)
806 FN_GLOBAL_INTEGER(lp_web_port, &Globals.web_port)
807 FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
808 FN_GLOBAL_STRING(lp_swat_directory, &Globals.swat_directory)
809 FN_GLOBAL_BOOL(lp_tls_enabled, &Globals.tls_enabled)
810 FN_GLOBAL_STRING(lp_tls_keyfile, &Globals.tls_keyfile)
811 FN_GLOBAL_STRING(lp_tls_certfile, &Globals.tls_certfile)
812 FN_GLOBAL_STRING(lp_tls_cafile, &Globals.tls_cafile)
813 FN_GLOBAL_STRING(lp_tls_crlfile, &Globals.tls_crlfile)
814 FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
815 FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)
816 FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)
817 FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
818 FN_GLOBAL_STRING(lp_sam_url, &Globals.szSAM_URL)
819 FN_GLOBAL_STRING(lp_spoolss_url, &Globals.szSPOOLSS_URL)
820 FN_GLOBAL_STRING(lp_wins_config_url, &Globals.szWINS_CONFIG_URL)
821 FN_GLOBAL_STRING(lp_wins_url, &Globals.szWINS_URL)
822 FN_GLOBAL_CONST_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
823 FN_GLOBAL_BOOL(lp_winbind_sealed_pipes, &Globals.bWinbindSealedPipes)
824 FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir)
825 FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
826 FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
827 FN_GLOBAL_STRING(lp_setupdir, &Globals.szSetupDir)
828 FN_GLOBAL_STRING(lp_ncalrpc_dir, &Globals.ncalrpc_dir)
829 FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir)
830 FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers)
831 FN_GLOBAL_LIST(lp_server_services, &Globals.server_services)
832 FN_GLOBAL_STRING(lp_ntptr_providor, &Globals.ntptr_providor)
833 FN_GLOBAL_STRING(lp_auto_services, &Globals.szAutoServices)
834 FN_GLOBAL_STRING(lp_passwd_chat, &Globals.szPasswdChat)
835 FN_GLOBAL_LIST(lp_passwordserver, &Globals.szPasswordServers)
836 FN_GLOBAL_LIST(lp_name_resolve_order, &Globals.szNameResolveOrder)
837 FN_GLOBAL_STRING(lp_realm, &Globals.szRealm)
838 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
839 FN_GLOBAL_STRING(lp_workgroup, &Globals.szWorkgroup)
840 FN_GLOBAL_STRING(lp_netbios_name, &Globals.szNetbiosName)
841 FN_GLOBAL_STRING(lp_netbios_scope, &Globals.szNetbiosScope)
842 FN_GLOBAL_LIST(lp_wins_server_list, &Globals.szWINSservers)
843 FN_GLOBAL_LIST(lp_interfaces, &Globals.szInterfaces)
844 FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
845 FN_GLOBAL_LIST(lp_netbios_aliases, &Globals.szNetbiosAliases)
846 FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction)
847
848 FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios)
849 FN_GLOBAL_BOOL(lp_wins_support, &Globals.bWINSsupport)
850 FN_GLOBAL_BOOL(lp_wins_dns_proxy, &Globals.bWINSdnsProxy)
851 FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
852 FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster)
853 FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw)
854 FN_GLOBAL_BOOL(lp_large_readwrite, &Globals.bLargeReadwrite)
855 FN_GLOBAL_BOOL(lp_writeraw, &Globals.bWriteRaw)
856 FN_GLOBAL_BOOL(lp_null_passwords, &Globals.bNullPasswords)
857 FN_GLOBAL_BOOL(lp_obey_pam_restrictions, &Globals.bObeyPamRestrictions)
858 FN_GLOBAL_BOOL(lp_encrypted_passwords, &Globals.bEncryptPasswords)
859 static FN_GLOBAL_BOOL(lp_time_server, &Globals.bTimeServer)
860 FN_GLOBAL_BOOL(lp_bind_interfaces_only, &Globals.bBindInterfacesOnly)
861 FN_GLOBAL_BOOL(lp_unicode, &Globals.bUnicode)
862 FN_GLOBAL_BOOL(lp_nt_status_support, &Globals.bNTStatusSupport)
863 FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
864 FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
865 FN_GLOBAL_BOOL(lp_client_plaintext_auth, &Globals.bClientPlaintextAuth)
866 FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
867 FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
868 FN_GLOBAL_BOOL(lp_client_use_spnego_principal, &Globals.client_use_spnego_principal)
869 FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
870 FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions)
871 FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
872 FN_GLOBAL_BOOL(lp_rpc_big_endian, &Globals.bRpcBigEndian)
873 FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
874 FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.min_wins_ttl)
875 FN_GLOBAL_INTEGER(lp_maxmux, &Globals.max_mux)
876 FN_GLOBAL_INTEGER(lp_max_xmit, &Globals.max_xmit)
877 FN_GLOBAL_INTEGER(lp_passwordlevel, &Globals.pwordlevel)
878 FN_GLOBAL_INTEGER(lp_maxprotocol, &Globals.maxprotocol)
879 FN_GLOBAL_INTEGER(lp_minprotocol, &Globals.minprotocol)
880 FN_GLOBAL_INTEGER(lp_security, &Globals.security)
881 FN_GLOBAL_LIST(lp_auth_methods, &Globals.AuthMethods)
882 FN_GLOBAL_BOOL(lp_paranoid_server_security, &Globals.paranoid_server_security)
883 static FN_GLOBAL_INTEGER(lp_announce_as, &Globals.announce_as)
884 FN_GLOBAL_LIST(lp_js_include, &Globals.jsInclude)
885
886
887 FN_LOCAL_STRING(lp_servicename, szService)
888 FN_LOCAL_CONST_STRING(lp_const_servicename, szService)
889 FN_LOCAL_STRING(lp_pathname, szPath)
890 static FN_LOCAL_STRING(_lp_printername, szPrintername)
891 FN_LOCAL_LIST(lp_hostsallow, szHostsallow)
892 FN_LOCAL_LIST(lp_hostsdeny, szHostsdeny)
893 FN_LOCAL_STRING(lp_comment, comment)
894 FN_LOCAL_STRING(lp_fstype, fstype)
895 static FN_LOCAL_STRING(lp_volume, volume)
896 FN_LOCAL_LIST(lp_ntvfs_handler, ntvfs_handler)
897 FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
898 FN_LOCAL_BOOL(lp_browseable, bBrowseable)
899 FN_LOCAL_BOOL(lp_readonly, bRead_only)
900 FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
901 FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
902 FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
903 FN_LOCAL_BOOL(lp_strict_locking, bStrictLocking)
904 FN_LOCAL_BOOL(lp_strict_sync, bStrictSync)
905 FN_LOCAL_BOOL(lp_ci_filesystem, bCIFileSystem)
906 FN_LOCAL_BOOL(lp_map_system, bMap_system)
907 FN_LOCAL_INTEGER(lp_max_connections, iMaxConnections)
908 FN_LOCAL_INTEGER(lp_csc_policy, iCSCPolicy)
909 FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
910 FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
911
912 /* local prototypes */
913
914 static int map_parameter(const char *pszParmName);
915 static int getservicebyname(const char *pszServiceName,
916                             service * pserviceDest);
917 static void copy_service(service * pserviceDest,
918                          service * pserviceSource, BOOL *pcopymapDest);
919 static BOOL service_ok(int iService);
920 static BOOL do_section(const char *pszSectionName, void *);
921 static void init_copymap(service * pservice);
922
923 /* This is a helper function for parametrical options support. */
924 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
925 /* Actual parametrical functions are quite simple */
926 const char *lp_get_parametric(int lookup_service, const char *type, const char *option)
927 {
928         char *vfskey;
929         struct param_opt *data;
930         
931         if (lookup_service >= iNumServices) return NULL;
932         
933         data = (lookup_service < 0) ? 
934                 Globals.param_opt : ServicePtrs[lookup_service]->param_opt;
935     
936         asprintf(&vfskey, "%s:%s", type, option);
937         strlower(vfskey);
938
939         while (data) {
940                 if (strcmp(data->key, vfskey) == 0) {
941                         free(vfskey);
942                         return data->value;
943                 }
944                 data = data->next;
945         }
946
947         if (lookup_service >= 0) {
948                 /* Try to fetch the same option but from globals */
949                 /* but only if we are not already working with Globals */
950                 data = Globals.param_opt;
951                 while (data) {
952                         if (strcmp(data->key, vfskey) == 0) {
953                                 free(vfskey);
954                                 return data->value;
955                         }
956                         data = data->next;
957                 }
958         }
959
960         free(vfskey);
961         
962         return NULL;
963 }
964
965
966 /*******************************************************************
967 convenience routine to return int parameters.
968 ********************************************************************/
969 static int lp_int(const char *s)
970 {
971
972         if (!s) {
973                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
974                 return (-1);
975         }
976
977         return strtol(s, NULL, 0); 
978 }
979
980 /*******************************************************************
981 convenience routine to return unsigned long parameters.
982 ********************************************************************/
983 static int lp_ulong(const char *s)
984 {
985
986         if (!s) {
987                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
988                 return (-1);
989         }
990
991         return strtoul(s, NULL, 0);
992 }
993
994 /*******************************************************************
995 convenience routine to return boolean parameters.
996 ********************************************************************/
997 static BOOL lp_bool(const char *s)
998 {
999         BOOL ret = False;
1000
1001         if (!s) {
1002                 DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
1003                 return False;
1004         }
1005         
1006         if (!set_boolean(s, &ret)) {
1007                 DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
1008                 return False;
1009         }
1010
1011         return ret;
1012 }
1013
1014
1015 /* Return parametric option from a given service. Type is a part of option before ':' */
1016 /* Parametric option has following syntax: 'Type: option = value' */
1017 /* Returned value is allocated in 'lp_talloc' context */
1018
1019 const char *lp_parm_string(int lookup_service, const char *type, const char *option)
1020 {
1021         const char *value = lp_get_parametric(lookup_service, type, option);
1022
1023         if (value)
1024                 return lp_string(value);
1025
1026         return NULL;
1027 }
1028
1029 /* Return parametric option from a given service. Type is a part of option before ':' */
1030 /* Parametric option has following syntax: 'Type: option = value' */
1031 /* Returned value is allocated in 'lp_talloc' context */
1032
1033 const char **lp_parm_string_list(int lookup_service, const char *type, const char *option,
1034                                  const char *separator)
1035 {
1036         const char *value = lp_get_parametric(lookup_service, type, option);
1037         
1038         if (value)
1039                 return str_list_make(talloc_autofree_context(), value, separator);
1040
1041         return NULL;
1042 }
1043
1044 /* Return parametric option from a given service. Type is a part of option before ':' */
1045 /* Parametric option has following syntax: 'Type: option = value' */
1046
1047 int lp_parm_int(int lookup_service, const char *type, const char *option, int default_v)
1048 {
1049         const char *value = lp_get_parametric(lookup_service, type, option);
1050         
1051         if (value)
1052                 return lp_int(value);
1053
1054         return default_v;
1055 }
1056
1057 /* Return parametric option from a given service. Type is a part of option before ':' */
1058 /* Parametric option has following syntax: 'Type: option = value' */
1059
1060 unsigned long lp_parm_ulong(int lookup_service, const char *type, const char *option, unsigned long default_v)
1061 {
1062         const char *value = lp_get_parametric(lookup_service, type, option);
1063         
1064         if (value)
1065                 return lp_ulong(value);
1066
1067         return default_v;
1068 }
1069
1070 /* Return parametric option from a given service. Type is a part of option before ':' */
1071 /* Parametric option has following syntax: 'Type: option = value' */
1072
1073 BOOL lp_parm_bool(int lookup_service, const char *type, const char *option, BOOL default_v)
1074 {
1075         const char *value = lp_get_parametric(lookup_service, type, option);
1076         
1077         if (value)
1078                 return lp_bool(value);
1079
1080         return default_v;
1081 }
1082
1083
1084 /***************************************************************************
1085  Initialise a service to the defaults.
1086 ***************************************************************************/
1087
1088 static void init_service(service * pservice)
1089 {
1090         memset((char *)pservice, '\0', sizeof(service));
1091         copy_service(pservice, &sDefault, NULL);
1092 }
1093
1094 /***************************************************************************
1095  Free the dynamically allocated parts of a service struct.
1096 ***************************************************************************/
1097
1098 static void free_service(service *pservice)
1099 {
1100         int i;
1101         struct param_opt *data, *pdata;
1102         if (!pservice)
1103                 return;
1104
1105         if (pservice->szService)
1106                 DEBUG(5, ("free_service: Freeing service %s\n",
1107                        pservice->szService));
1108
1109         string_free(&pservice->szService);
1110         SAFE_FREE(pservice->copymap);
1111
1112         for (i = 0; parm_table[i].label; i++) {
1113                 if ((parm_table[i].type == P_STRING ||
1114                      parm_table[i].type == P_USTRING) &&
1115                     parm_table[i].class == P_LOCAL) {
1116                         string_free((char **)
1117                                     (((char *)pservice) +
1118                                      PTR_DIFF(parm_table[i].ptr, &sDefault)));
1119                 } else if (parm_table[i].type == P_LIST &&
1120                            parm_table[i].class == P_LOCAL) {
1121                         char ***listp = (char ***)(((char *)pservice) + 
1122                                                    PTR_DIFF(parm_table[i].ptr, &sDefault));
1123                         talloc_free(*listp);
1124                         *listp = NULL;
1125                 }
1126         }
1127                                 
1128         DEBUG(5,("Freeing parametrics:\n"));
1129         data = pservice->param_opt;
1130         while (data) {
1131                 DEBUG(5,("[%s = %s]\n", data->key, data->value));
1132                 string_free(&data->key);
1133                 string_free(&data->value);
1134                 pdata = data->next;
1135                 SAFE_FREE(data);
1136                 data = pdata;
1137         }
1138
1139         ZERO_STRUCTP(pservice);
1140 }
1141
1142 /***************************************************************************
1143  Add a new service to the services array initialising it with the given 
1144  service. 
1145 ***************************************************************************/
1146
1147 static int add_a_service(const service *pservice, const char *name)
1148 {
1149         int i;
1150         service tservice;
1151         int num_to_alloc = iNumServices + 1;
1152         struct param_opt *data, *pdata;
1153
1154         tservice = *pservice;
1155
1156         /* it might already exist */
1157         if (name) {
1158                 i = getservicebyname(name, NULL);
1159                 if (i >= 0) {
1160                         /* Clean all parametric options for service */
1161                         /* They will be added during parsing again */
1162                         data = ServicePtrs[i]->param_opt;
1163                         while (data) {
1164                                 string_free(&data->key);
1165                                 string_free(&data->value);
1166                                 pdata = data->next;
1167                                 SAFE_FREE(data);
1168                                 data = pdata;
1169                         }
1170                         ServicePtrs[i]->param_opt = NULL;
1171                         return (i);
1172                 }
1173         }
1174
1175         /* find an invalid one */
1176         for (i = 0; i < iNumServices; i++)
1177                 if (!ServicePtrs[i]->valid)
1178                         break;
1179
1180         /* if not, then create one */
1181         if (i == iNumServices) {
1182                 service **tsp;
1183                 
1184                 tsp = realloc_p(ServicePtrs, service *, num_to_alloc);
1185                                            
1186                 if (!tsp) {
1187                         DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
1188                         return (-1);
1189                 }
1190                 else {
1191                         ServicePtrs = tsp;
1192                         ServicePtrs[iNumServices] = malloc_p(service);
1193                 }
1194                 if (!ServicePtrs[iNumServices]) {
1195                         DEBUG(0,("add_a_service: out of memory!\n"));
1196                         return (-1);
1197                 }
1198
1199                 iNumServices++;
1200         } else
1201                 free_service(ServicePtrs[i]);
1202
1203         ServicePtrs[i]->valid = True;
1204
1205         init_service(ServicePtrs[i]);
1206         copy_service(ServicePtrs[i], &tservice, NULL);
1207         if (name)
1208                 string_set(&ServicePtrs[i]->szService, name);
1209         return (i);
1210 }
1211
1212 /***************************************************************************
1213  Add a new home service, with the specified home directory, defaults coming 
1214  from service ifrom.
1215 ***************************************************************************/
1216
1217 BOOL lp_add_home(const char *pszHomename, int iDefaultService, 
1218                  const char *user, const char *pszHomedir)
1219 {
1220         int i;
1221         pstring newHomedir;
1222
1223         i = add_a_service(ServicePtrs[iDefaultService], pszHomename);
1224
1225         if (i < 0)
1226                 return (False);
1227
1228         if (!(*(ServicePtrs[iDefaultService]->szPath))
1229             || strequal(ServicePtrs[iDefaultService]->szPath, lp_pathname(-1))) {
1230                 pstrcpy(newHomedir, pszHomedir);
1231         } else {
1232                 pstrcpy(newHomedir, lp_pathname(iDefaultService));
1233                 string_sub(newHomedir,"%H", pszHomedir, sizeof(newHomedir)); 
1234         }
1235
1236         string_set(&ServicePtrs[i]->szPath, newHomedir);
1237
1238         if (!(*(ServicePtrs[i]->comment))) {
1239                 pstring comment;
1240                 slprintf(comment, sizeof(comment) - 1,
1241                          "Home directory of %s", user);
1242                 string_set(&ServicePtrs[i]->comment, comment);
1243         }
1244         ServicePtrs[i]->bAvailable = sDefault.bAvailable;
1245         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1246
1247         DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename, 
1248                user, newHomedir));
1249         
1250         return (True);
1251 }
1252
1253 /***************************************************************************
1254  Add a new service, based on an old one.
1255 ***************************************************************************/
1256
1257 int lp_add_service(const char *pszService, int iDefaultService)
1258 {
1259         return (add_a_service(ServicePtrs[iDefaultService], pszService));
1260 }
1261
1262 /***************************************************************************
1263  Add the IPC service.
1264 ***************************************************************************/
1265
1266 static BOOL lp_add_hidden(const char *name, const char *fstype)
1267 {
1268         pstring comment;
1269         int i = add_a_service(&sDefault, name);
1270
1271         if (i < 0)
1272                 return (False);
1273
1274         slprintf(comment, sizeof(comment) - 1,
1275                  "%s Service (%s)", fstype, Globals.szServerString);
1276
1277         string_set(&ServicePtrs[i]->szPath, tmpdir());
1278         string_set(&ServicePtrs[i]->comment, comment);
1279         string_set(&ServicePtrs[i]->fstype, fstype);
1280         ServicePtrs[i]->iMaxConnections = -1;
1281         ServicePtrs[i]->bAvailable = True;
1282         ServicePtrs[i]->bRead_only = True;
1283         ServicePtrs[i]->bPrint_ok = False;
1284         ServicePtrs[i]->bBrowseable = False;
1285
1286         if (strcasecmp(fstype, "IPC") == 0) {
1287                 lp_do_parameter(i, "ntvfs handler", "default");
1288         }
1289
1290         DEBUG(3, ("adding hidden service %s\n", name));
1291
1292         return (True);
1293 }
1294
1295 /***************************************************************************
1296  Add a new printer service, with defaults coming from service iFrom.
1297 ***************************************************************************/
1298
1299 BOOL lp_add_printer(const char *pszPrintername, int iDefaultService)
1300 {
1301         const char *comment = "From Printcap";
1302         int i = add_a_service(ServicePtrs[iDefaultService], pszPrintername);
1303
1304         if (i < 0)
1305                 return (False);
1306
1307         /* note that we do NOT default the availability flag to True - */
1308         /* we take it from the default service passed. This allows all */
1309         /* dynamic printers to be disabled by disabling the [printers] */
1310         /* entry (if/when the 'available' keyword is implemented!).    */
1311
1312         /* the printer name is set to the service name. */
1313         string_set(&ServicePtrs[i]->szPrintername, pszPrintername);
1314         string_set(&ServicePtrs[i]->comment, comment);
1315         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1316         /* Printers cannot be read_only. */
1317         ServicePtrs[i]->bRead_only = False;
1318         /* Printer services must be printable. */
1319         ServicePtrs[i]->bPrint_ok = True;
1320
1321         DEBUG(3, ("adding printer service %s\n", pszPrintername));
1322
1323         update_server_announce_as_printserver();
1324
1325         return (True);
1326 }
1327
1328 /***************************************************************************
1329  Map a parameter's string representation to something we can use. 
1330  Returns False if the parameter string is not recognised, else TRUE.
1331 ***************************************************************************/
1332
1333 static int map_parameter(const char *pszParmName)
1334 {
1335         int iIndex;
1336
1337         if (*pszParmName == '-')
1338                 return (-1);
1339
1340         for (iIndex = 0; parm_table[iIndex].label; iIndex++)
1341                 if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1342                         return (iIndex);
1343
1344         /* Warn only if it isn't parametric option */
1345         if (strchr(pszParmName, ':') == NULL)
1346                 DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
1347         /* We do return 'fail' for parametric options as well because they are
1348            stored in different storage
1349          */
1350         return (-1);
1351 }
1352
1353
1354 /*
1355   return the parameter structure for a parameter
1356 */
1357 struct parm_struct *lp_parm_struct(const char *name)
1358 {
1359         int parmnum = map_parameter(name);
1360         if (parmnum == -1) return NULL;
1361         return &parm_table[parmnum];
1362 }
1363
1364 /*
1365   return the parameter pointer for a parameter
1366 */
1367 void *lp_parm_ptr(int snum, struct parm_struct *parm)
1368 {
1369         if (snum == -1) {
1370                 return parm->ptr;
1371         }
1372         return ((char *)ServicePtrs[snum]) + PTR_DIFF(parm->ptr, &sDefault);
1373 }
1374
1375 /***************************************************************************
1376 Find a service by name. Otherwise works like get_service.
1377 ***************************************************************************/
1378
1379 static int getservicebyname(const char *pszServiceName, service * pserviceDest)
1380 {
1381         int iService;
1382
1383         for (iService = iNumServices - 1; iService >= 0; iService--)
1384                 if (VALID(iService) &&
1385                     strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0) {
1386                         if (pserviceDest != NULL)
1387                                 copy_service(pserviceDest, ServicePtrs[iService], NULL);
1388                         break;
1389                 }
1390
1391         return (iService);
1392 }
1393
1394 /***************************************************************************
1395  Copy a service structure to another.
1396  If pcopymapDest is NULL then copy all fields
1397 ***************************************************************************/
1398
1399 static void copy_service(service * pserviceDest, service * pserviceSource, BOOL *pcopymapDest)
1400 {
1401         int i;
1402         BOOL bcopyall = (pcopymapDest == NULL);
1403         struct param_opt *data, *pdata, *paramo;
1404         BOOL not_added;
1405
1406         for (i = 0; parm_table[i].label; i++)
1407                 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL &&
1408                     (bcopyall || pcopymapDest[i])) {
1409                         void *def_ptr = parm_table[i].ptr;
1410                         void *src_ptr =
1411                                 ((char *)pserviceSource) + PTR_DIFF(def_ptr,
1412                                                                     &sDefault);
1413                         void *dest_ptr =
1414                                 ((char *)pserviceDest) + PTR_DIFF(def_ptr,
1415                                                                   &sDefault);
1416
1417                         switch (parm_table[i].type) {
1418                                 case P_BOOL:
1419                                         *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1420                                         break;
1421
1422                                 case P_INTEGER:
1423                                 case P_ENUM:
1424                                         *(int *)dest_ptr = *(int *)src_ptr;
1425                                         break;
1426
1427                                 case P_STRING:
1428                                         string_set(dest_ptr,
1429                                                    *(char **)src_ptr);
1430                                         break;
1431
1432                                 case P_USTRING:
1433                                         string_set(dest_ptr,
1434                                                    *(char **)src_ptr);
1435                                         strupper(*(char **)dest_ptr);
1436                                         break;
1437                                 case P_LIST:
1438                                         *(const char ***)dest_ptr = str_list_copy(talloc_autofree_context(), 
1439                                                                                   *(const char ***)src_ptr);
1440                                         break;
1441                                 default:
1442                                         break;
1443                         }
1444                 }
1445
1446         if (bcopyall) {
1447                 init_copymap(pserviceDest);
1448                 if (pserviceSource->copymap)
1449                         memcpy((void *)pserviceDest->copymap,
1450                                (void *)pserviceSource->copymap,
1451                                sizeof(BOOL) * NUMPARAMETERS);
1452         }
1453         
1454         data = pserviceSource->param_opt;
1455         while (data) {
1456                 not_added = True;
1457                 pdata = pserviceDest->param_opt;
1458                 /* Traverse destination */
1459                 while (pdata) {
1460                         /* If we already have same option, override it */
1461                         if (strcmp(pdata->key, data->key) == 0) {
1462                                 string_free(&pdata->value);
1463                                 pdata->value = strdup(data->value);
1464                                 not_added = False;
1465                                 break;
1466                         }
1467                         pdata = pdata->next;
1468                 }
1469                 if (not_added) {
1470                         paramo = malloc_p(struct param_opt);
1471                         if (!paramo)
1472                                 smb_panic("OOM");
1473                         paramo->key = strdup(data->key);
1474                         paramo->value = strdup(data->value);
1475                         DLIST_ADD(pserviceDest->param_opt, paramo);
1476                 }
1477                 data = data->next;
1478         }
1479 }
1480
1481 /***************************************************************************
1482 Check a service for consistency. Return False if the service is in any way
1483 incomplete or faulty, else True.
1484 ***************************************************************************/
1485
1486 static BOOL service_ok(int iService)
1487 {
1488         BOOL bRetval;
1489
1490         bRetval = True;
1491         if (ServicePtrs[iService]->szService[0] == '\0') {
1492                 DEBUG(0, ("The following message indicates an internal error:\n"));
1493                 DEBUG(0, ("No service name in service entry.\n"));
1494                 bRetval = False;
1495         }
1496
1497         /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1498         /* I can't see why you'd want a non-printable printer service...        */
1499         if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
1500                 if (!ServicePtrs[iService]->bPrint_ok) {
1501                         DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
1502                                ServicePtrs[iService]->szService));
1503                         ServicePtrs[iService]->bPrint_ok = True;
1504                         update_server_announce_as_printserver();
1505                 }
1506                 /* [printers] service must also be non-browsable. */
1507                 if (ServicePtrs[iService]->bBrowseable)
1508                         ServicePtrs[iService]->bBrowseable = False;
1509         }
1510
1511         /* If a service is flagged unavailable, log the fact at level 0. */
1512         if (!ServicePtrs[iService]->bAvailable)
1513                 DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
1514                           ServicePtrs[iService]->szService));
1515
1516         return (bRetval);
1517 }
1518
1519 static struct file_lists {
1520         struct file_lists *next;
1521         char *name;
1522         char *subfname;
1523         time_t modtime;
1524 } *file_lists = NULL;
1525
1526 /*******************************************************************
1527  Keep a linked list of all config files so we know when one has changed 
1528  it's date and needs to be reloaded.
1529 ********************************************************************/
1530
1531 static void add_to_file_list(const char *fname, const char *subfname)
1532 {
1533         struct file_lists *f = file_lists;
1534
1535         while (f) {
1536                 if (f->name && !strcmp(f->name, fname))
1537                         break;
1538                 f = f->next;
1539         }
1540
1541         if (!f) {
1542                 f = malloc_p(struct file_lists);
1543                 if (!f)
1544                         return;
1545                 f->next = file_lists;
1546                 f->name = strdup(fname);
1547                 if (!f->name) {
1548                         SAFE_FREE(f);
1549                         return;
1550                 }
1551                 f->subfname = strdup(subfname);
1552                 if (!f->subfname) {
1553                         SAFE_FREE(f);
1554                         return;
1555                 }
1556                 file_lists = f;
1557                 f->modtime = file_modtime(subfname);
1558         } else {
1559                 time_t t = file_modtime(subfname);
1560                 if (t)
1561                         f->modtime = t;
1562         }
1563 }
1564
1565 /*******************************************************************
1566  Check if a config file has changed date.
1567 ********************************************************************/
1568
1569 BOOL lp_file_list_changed(void)
1570 {
1571         struct file_lists *f = file_lists;
1572         DEBUG(6, ("lp_file_list_changed()\n"));
1573
1574         while (f) {
1575                 pstring n2;
1576                 time_t mod_time;
1577
1578                 pstrcpy(n2, f->name);
1579                 standard_sub_basic(n2,sizeof(n2));
1580
1581                 DEBUGADD(6, ("file %s -> %s  last mod_time: %s\n",
1582                              f->name, n2, ctime(&f->modtime)));
1583
1584                 mod_time = file_modtime(n2);
1585
1586                 if (mod_time && ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))) {
1587                         DEBUGADD(6,
1588                                  ("file %s modified: %s\n", n2,
1589                                   ctime(&mod_time)));
1590                         f->modtime = mod_time;
1591                         SAFE_FREE(f->subfname);
1592                         f->subfname = strdup(n2);
1593                         return (True);
1594                 }
1595                 f = f->next;
1596         }
1597         return (False);
1598 }
1599
1600 /***************************************************************************
1601  Handle the include operation.
1602 ***************************************************************************/
1603
1604 static BOOL handle_include(const char *pszParmValue, char **ptr)
1605 {
1606         pstring fname;
1607         pstrcpy(fname, pszParmValue);
1608
1609         standard_sub_basic(fname,sizeof(fname));
1610
1611         add_to_file_list(pszParmValue, fname);
1612
1613         string_set(ptr, fname);
1614
1615         if (file_exist(fname))
1616                 return (pm_process(fname, do_section, do_parameter, NULL));
1617
1618         DEBUG(2, ("Can't find include file %s\n", fname));
1619
1620         return (False);
1621 }
1622
1623 /***************************************************************************
1624  Handle the interpretation of the copy parameter.
1625 ***************************************************************************/
1626
1627 static BOOL handle_copy(const char *pszParmValue, char **ptr)
1628 {
1629         BOOL bRetval;
1630         int iTemp;
1631         service serviceTemp;
1632
1633         string_set(ptr, pszParmValue);
1634
1635         init_service(&serviceTemp);
1636
1637         bRetval = False;
1638
1639         DEBUG(3, ("Copying service from service %s\n", pszParmValue));
1640
1641         if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0) {
1642                 if (iTemp == iServiceIndex) {
1643                         DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
1644                 } else {
1645                         copy_service(ServicePtrs[iServiceIndex],
1646                                      &serviceTemp,
1647                                      ServicePtrs[iServiceIndex]->copymap);
1648                         bRetval = True;
1649                 }
1650         } else {
1651                 DEBUG(0, ("Unable to copy service - source not found: %s\n", pszParmValue));
1652                 bRetval = False;
1653         }
1654
1655         free_service(&serviceTemp);
1656         return (bRetval);
1657 }
1658
1659 /***************************************************************************
1660  Initialise a copymap.
1661 ***************************************************************************/
1662
1663 static void init_copymap(service * pservice)
1664 {
1665         int i;
1666         SAFE_FREE(pservice->copymap);
1667         pservice->copymap = malloc_array_p(BOOL, NUMPARAMETERS);
1668         if (!pservice->copymap)
1669                 DEBUG(0,
1670                       ("Couldn't allocate copymap!! (size %d)\n",
1671                        (int)NUMPARAMETERS));
1672         else
1673                 for (i = 0; i < NUMPARAMETERS; i++)
1674                         pservice->copymap[i] = True;
1675 }
1676
1677 /***************************************************************************
1678  Return the local pointer to a parameter given the service number and the 
1679  pointer into the default structure.
1680 ***************************************************************************/
1681
1682 void *lp_local_ptr(int snum, void *ptr)
1683 {
1684         return (void *)(((char *)ServicePtrs[snum]) + PTR_DIFF(ptr, &sDefault));
1685 }
1686
1687
1688 /***************************************************************************
1689  Process a parametric option
1690 ***************************************************************************/
1691 static BOOL lp_do_parameter_parametric(int snum, const char *pszParmName, const char *pszParmValue, int flags)
1692 {
1693         struct param_opt *paramo, *data;
1694         char *name;
1695
1696         while (isspace((unsigned char)*pszParmName)) {
1697                 pszParmName++;
1698         }
1699
1700         name = strdup(pszParmName);
1701         if (!name) return False;
1702
1703         strlower(name);
1704
1705         if (snum < 0) {
1706                 data = Globals.param_opt;
1707         } else {
1708                 data = ServicePtrs[snum]->param_opt;
1709         }
1710
1711         /* Traverse destination */
1712         for (paramo=data; paramo; paramo=paramo->next) {
1713                 /* If we already have the option set, override it unless
1714                    it was a command line option and the new one isn't */
1715                 if (strcmp(paramo->key, name) == 0) {
1716                         if ((paramo->flags & FLAG_CMDLINE) &&
1717                             !(flags & FLAG_CMDLINE)) {
1718                                 return True;
1719                         }
1720
1721                         free(paramo->value);
1722                         paramo->value = strdup(pszParmValue);
1723                         paramo->flags = flags;
1724                         free(name);
1725                         return True;
1726                 }
1727         }
1728
1729         paramo = malloc_p(struct param_opt);
1730         if (!paramo)
1731                 smb_panic("OOM");
1732         paramo->key = strdup(name);
1733         paramo->value = strdup(pszParmValue);
1734         paramo->flags = flags;
1735         if (snum < 0) {
1736                 DLIST_ADD(Globals.param_opt, paramo);
1737         } else {
1738                 DLIST_ADD(ServicePtrs[snum]->param_opt, paramo);
1739         }
1740
1741         free(name);
1742         
1743         return True;
1744 }
1745
1746 /***************************************************************************
1747  Process a parameter for a particular service number. If snum < 0
1748  then assume we are in the globals.
1749 ***************************************************************************/
1750 BOOL lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue)
1751 {
1752         int parmnum, i;
1753         void *parm_ptr = NULL;  /* where we are going to store the result */
1754         void *def_ptr = NULL;
1755
1756         parmnum = map_parameter(pszParmName);
1757
1758         if (parmnum < 0) {
1759                 if (strchr(pszParmName, ':')) {
1760                         return lp_do_parameter_parametric(snum, pszParmName, pszParmValue, 0);
1761                 }
1762                 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
1763                 return (True);
1764         }
1765
1766         if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
1767                 DEBUG(1, ("WARNING: The \"%s\" option is deprecated\n",
1768                           pszParmName));
1769         }
1770
1771         /* if the flag has been set on the command line, then don't allow override,
1772            but don't report an error */
1773         if (parm_table[parmnum].flags & FLAG_CMDLINE) {
1774                 return True;
1775         }
1776
1777         def_ptr = parm_table[parmnum].ptr;
1778
1779         /* we might point at a service, the default service or a global */
1780         if (snum < 0) {
1781                 parm_ptr = def_ptr;
1782         } else {
1783                 if (parm_table[parmnum].class == P_GLOBAL) {
1784                         DEBUG(0,
1785                               ("Global parameter %s found in service section!\n",
1786                                pszParmName));
1787                         return (True);
1788                 }
1789                 parm_ptr =
1790                         ((char *)ServicePtrs[snum]) + PTR_DIFF(def_ptr,
1791                                                             &sDefault);
1792         }
1793
1794         if (snum >= 0) {
1795                 if (!ServicePtrs[snum]->copymap)
1796                         init_copymap(ServicePtrs[snum]);
1797
1798                 /* this handles the aliases - set the copymap for other entries with
1799                    the same data pointer */
1800                 for (i = 0; parm_table[i].label; i++)
1801                         if (parm_table[i].ptr == parm_table[parmnum].ptr)
1802                                 ServicePtrs[snum]->copymap[i] = False;
1803         }
1804
1805         /* if it is a special case then go ahead */
1806         if (parm_table[parmnum].special) {
1807                 parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
1808                 return (True);
1809         }
1810
1811         /* now switch on the type of variable it is */
1812         switch (parm_table[parmnum].type)
1813         {
1814                 case P_BOOL:
1815                         if (!set_boolean(pszParmValue, parm_ptr)) {
1816                                 DEBUG(0,("lp_do_parameter(%s): value is not boolean!\n", pszParmValue));
1817                                 return False;
1818                         }
1819                         break;
1820
1821                 case P_INTEGER:
1822                         *(int *)parm_ptr = atoi(pszParmValue);
1823                         break;
1824
1825                 case P_LIST:
1826                         *(const char ***)parm_ptr = str_list_make(talloc_autofree_context(), 
1827                                                                   pszParmValue, NULL);
1828                         break;
1829
1830                 case P_STRING:
1831                         string_set(parm_ptr, pszParmValue);
1832                         break;
1833
1834                 case P_USTRING:
1835                         string_set(parm_ptr, pszParmValue);
1836                         strupper(*(char **)parm_ptr);
1837                         break;
1838
1839                 case P_ENUM:
1840                         for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
1841                                 if (strequal
1842                                     (pszParmValue,
1843                                      parm_table[parmnum].enum_list[i].name)) {
1844                                         *(int *)parm_ptr =
1845                                                 parm_table[parmnum].
1846                                                 enum_list[i].value;
1847                                         break;
1848                                 }
1849                         }
1850                         if (!parm_table[parmnum].enum_list[i].name) {
1851                                 DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
1852                                          pszParmValue, pszParmName));
1853                                 return False;
1854                         }
1855                         break;
1856                 case P_SEP:
1857                         break;
1858         }
1859
1860         if (parm_table[parmnum].flags & FLAG_DEFAULT) {
1861                 parm_table[parmnum].flags &= ~FLAG_DEFAULT;
1862                 /* we have to also unset FLAG_DEFAULT on aliases */
1863                 for (i=parmnum-1;i>=0 && parm_table[i].ptr == parm_table[parmnum].ptr;i--) {
1864                         parm_table[i].flags &= ~FLAG_DEFAULT;
1865                 }
1866                 for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].ptr == parm_table[parmnum].ptr;i++) {
1867                         parm_table[i].flags &= ~FLAG_DEFAULT;
1868                 }
1869         }
1870
1871         return (True);
1872 }
1873
1874 /***************************************************************************
1875  Process a parameter.
1876 ***************************************************************************/
1877
1878 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue, void *userdata)
1879 {
1880         return (lp_do_parameter(bInGlobalSection ? -2 : iServiceIndex,
1881                                 pszParmName, pszParmValue));
1882 }
1883
1884 /*
1885   variable argument do parameter
1886 */
1887 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
1888
1889 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...)
1890 {
1891         char *s;
1892         BOOL ret;
1893         va_list ap;
1894
1895         va_start(ap, fmt);      
1896         s = talloc_vasprintf(NULL, fmt, ap);
1897         va_end(ap);
1898         ret = do_parameter(pszParmName, s, NULL);
1899         talloc_free(s);
1900         return ret;
1901 }
1902
1903
1904 /*
1905   set a parameter from the commandline - this is called from command line parameter
1906   parsing code. It sets the parameter then marks the parameter as unable to be modified
1907   by smb.conf processing
1908 */
1909 BOOL lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
1910 {
1911         int parmnum = map_parameter(pszParmName);
1912         int i;
1913
1914         while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
1915
1916
1917         if (parmnum < 0 && strchr(pszParmName, ':')) {
1918                 /* set a parametric option */
1919                 return lp_do_parameter_parametric(-1, pszParmName, pszParmValue, FLAG_CMDLINE);
1920         }
1921
1922         if (parmnum < 0) {
1923                 DEBUG(0,("Unknown option '%s'\n", pszParmName));
1924                 return False;
1925         }
1926
1927         /* reset the CMDLINE flag in case this has been called before */
1928         parm_table[parmnum].flags &= ~FLAG_CMDLINE;
1929
1930         if (!lp_do_parameter(-2, pszParmName, pszParmValue)) {
1931                 return False;
1932         }
1933
1934         parm_table[parmnum].flags |= FLAG_CMDLINE;
1935
1936         /* we have to also set FLAG_CMDLINE on aliases */
1937         for (i=parmnum-1;i>=0 && parm_table[i].ptr == parm_table[parmnum].ptr;i--) {
1938                 parm_table[i].flags |= FLAG_CMDLINE;
1939         }
1940         for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].ptr == parm_table[parmnum].ptr;i++) {
1941                 parm_table[i].flags |= FLAG_CMDLINE;
1942         }
1943
1944         return True;
1945 }
1946
1947 /*
1948   set a option from the commandline in 'a=b' format. Use to support --option
1949 */
1950 BOOL lp_set_option(const char *option)
1951 {
1952         char *p, *s;
1953         BOOL ret;
1954
1955         s = strdup(option);
1956         if (!s) {
1957                 return False;
1958         }
1959
1960         p = strchr(s, '=');
1961         if (!p) {
1962                 free(s);
1963                 return False;
1964         }
1965
1966         *p = 0;
1967
1968         ret = lp_set_cmdline(s, p+1);
1969         free(s);
1970         return ret;
1971 }
1972
1973
1974 #define BOOLSTR(b) ((b) ? "Yes" : "No")
1975
1976 /***************************************************************************
1977  Print a parameter of the specified type.
1978 ***************************************************************************/
1979
1980 static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
1981 {
1982         int i;
1983         switch (p->type)
1984         {
1985                 case P_ENUM:
1986                         for (i = 0; p->enum_list[i].name; i++) {
1987                                 if (*(int *)ptr == p->enum_list[i].value) {
1988                                         fprintf(f, "%s",
1989                                                 p->enum_list[i].name);
1990                                         break;
1991                                 }
1992                         }
1993                         break;
1994
1995                 case P_BOOL:
1996                         fprintf(f, "%s", BOOLSTR(*(BOOL *)ptr));
1997                         break;
1998
1999                 case P_INTEGER:
2000                         fprintf(f, "%d", *(int *)ptr);
2001                         break;
2002
2003                 case P_LIST:
2004                         if ((char ***)ptr && *(char ***)ptr) {
2005                                 char **list = *(char ***)ptr;
2006                                 
2007                                 for (; *list; list++)
2008                                         fprintf(f, "%s%s", *list,
2009                                                 ((*(list+1))?", ":""));
2010                         }
2011                         break;
2012
2013                 case P_STRING:
2014                 case P_USTRING:
2015                         if (*(char **)ptr) {
2016                                 fprintf(f, "%s", *(char **)ptr);
2017                         }
2018                         break;
2019                 case P_SEP:
2020                         break;
2021         }
2022 }
2023
2024 /***************************************************************************
2025  Check if two parameters are equal.
2026 ***************************************************************************/
2027
2028 static BOOL equal_parameter(parm_type type, void *ptr1, void *ptr2)
2029 {
2030         switch (type) {
2031                 case P_BOOL:
2032                         return (*((BOOL *)ptr1) == *((BOOL *)ptr2));
2033
2034                 case P_INTEGER:
2035                 case P_ENUM:
2036                         return (*((int *)ptr1) == *((int *)ptr2));
2037
2038                 case P_LIST:
2039                         return str_list_equal((const char **)(*(char ***)ptr1), 
2040                                               (const char **)(*(char ***)ptr2));
2041
2042                 case P_STRING:
2043                 case P_USTRING:
2044                 {
2045                         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
2046                         if (p1 && !*p1)
2047                                 p1 = NULL;
2048                         if (p2 && !*p2)
2049                                 p2 = NULL;
2050                         return (p1 == p2 || strequal(p1, p2));
2051                 }
2052                 case P_SEP:
2053                         break;
2054         }
2055         return (False);
2056 }
2057
2058 /***************************************************************************
2059  Process a new section (service). At this stage all sections are services.
2060  Later we'll have special sections that permit server parameters to be set.
2061  Returns True on success, False on failure. 
2062 ***************************************************************************/
2063
2064 static BOOL do_section(const char *pszSectionName, void *userdata)
2065 {
2066         BOOL bRetval;
2067         BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
2068                          (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
2069         bRetval = False;
2070
2071         /* if we've just struck a global section, note the fact. */
2072         bInGlobalSection = isglobal;
2073
2074         /* check for multiple global sections */
2075         if (bInGlobalSection) {
2076                 DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
2077                 return (True);
2078         }
2079
2080         /* if we have a current service, tidy it up before moving on */
2081         bRetval = True;
2082
2083         if (iServiceIndex >= 0)
2084                 bRetval = service_ok(iServiceIndex);
2085
2086         /* if all is still well, move to the next record in the services array */
2087         if (bRetval) {
2088                 /* We put this here to avoid an odd message order if messages are */
2089                 /* issued by the post-processing of a previous section. */
2090                 DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
2091
2092                 if ((iServiceIndex = add_a_service(&sDefault, pszSectionName))
2093                     < 0) {
2094                         DEBUG(0, ("Failed to add a new service\n"));
2095                         return (False);
2096                 }
2097         }
2098
2099         return (bRetval);
2100 }
2101
2102
2103 /***************************************************************************
2104  Determine if a partcular base parameter is currentl set to the default value.
2105 ***************************************************************************/
2106
2107 static BOOL is_default(int i)
2108 {
2109         if (!defaults_saved)
2110                 return False;
2111         switch (parm_table[i].type) {
2112                 case P_LIST:
2113                         return str_list_equal((const char **)parm_table[i].def.lvalue, 
2114                                               (const char **)(*(char ***)parm_table[i].ptr));
2115                 case P_STRING:
2116                 case P_USTRING:
2117                         return strequal(parm_table[i].def.svalue,
2118                                         *(char **)parm_table[i].ptr);
2119                 case P_BOOL:
2120                         return parm_table[i].def.bvalue ==
2121                                 *(BOOL *)parm_table[i].ptr;
2122                 case P_INTEGER:
2123                 case P_ENUM:
2124                         return parm_table[i].def.ivalue ==
2125                                 *(int *)parm_table[i].ptr;
2126                 case P_SEP:
2127                         break;
2128         }
2129         return False;
2130 }
2131
2132 /***************************************************************************
2133 Display the contents of the global structure.
2134 ***************************************************************************/
2135
2136 static void dump_globals(FILE *f, BOOL show_defaults)
2137 {
2138         int i;
2139         struct param_opt *data;
2140         
2141         fprintf(f, "# Global parameters\n[global]\n");
2142
2143         for (i = 0; parm_table[i].label; i++)
2144                 if (parm_table[i].class == P_GLOBAL &&
2145                     parm_table[i].ptr &&
2146                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2147                         if (!show_defaults && (parm_table[i].flags & FLAG_DEFAULT)) 
2148                                 continue;
2149                         fprintf(f, "\t%s = ", parm_table[i].label);
2150                         print_parameter(&parm_table[i], parm_table[i].ptr, f);
2151                         fprintf(f, "\n");
2152         }
2153         if (Globals.param_opt != NULL) {
2154                 data = Globals.param_opt;
2155                 while(data) {
2156                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2157                         data = data->next;
2158                 }
2159         }
2160
2161 }
2162
2163 /***************************************************************************
2164  Display the contents of a single services record.
2165 ***************************************************************************/
2166
2167 static void dump_a_service(service * pService, FILE * f)
2168 {
2169         int i;
2170         struct param_opt *data;
2171         
2172         if (pService != &sDefault)
2173                 fprintf(f, "\n[%s]\n", pService->szService);
2174
2175         for (i = 0; parm_table[i].label; i++)
2176                 if (parm_table[i].class == P_LOCAL &&
2177                     parm_table[i].ptr &&
2178                     (*parm_table[i].label != '-') &&
2179                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2180                         int pdiff = PTR_DIFF(parm_table[i].ptr, &sDefault);
2181
2182                         if (pService == &sDefault) {
2183                                 if (defaults_saved && is_default(i))
2184                                         continue;
2185                         } else {
2186                                 if (equal_parameter(parm_table[i].type,
2187                                                     ((char *)pService) +
2188                                                     pdiff,
2189                                                     ((char *)&sDefault) +
2190                                                     pdiff))
2191                                         continue;
2192                         }
2193
2194                         fprintf(f, "\t%s = ", parm_table[i].label);
2195                         print_parameter(&parm_table[i],
2196                                         ((char *)pService) + pdiff, f);
2197                         fprintf(f, "\n");
2198         }
2199         if (pService->param_opt != NULL) {
2200                 data = pService->param_opt;
2201                 while(data) {
2202                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2203                         data = data->next;
2204                 }
2205         }
2206 }
2207
2208 BOOL lp_dump_a_parameter(int snum, char *parm_name, FILE * f, BOOL isGlobal)
2209 {
2210         service * pService = ServicePtrs[snum];
2211         parm_class p_class;
2212         unsigned flag = 0;
2213         struct parm_struct *parm;
2214         void *ptr;
2215         if (isGlobal) {
2216                 p_class = P_GLOBAL;
2217                 flag = FLAG_GLOBAL;
2218         } else
2219                 p_class = P_LOCAL;
2220         
2221         parm = lp_parm_struct(parm_name);
2222         if (!parm) {
2223                 return False;
2224         }
2225         
2226         if (isGlobal)
2227                 ptr = parm->ptr;
2228         else
2229                 ptr = ((char *)pService) +
2230                         PTR_DIFF(parm->ptr, &sDefault);
2231         
2232         print_parameter(parm,
2233                         ptr, f);
2234         fprintf(f, "\n");
2235         return True;
2236 }
2237
2238 /***************************************************************************
2239  Return info about the next service  in a service. snum==-1 gives the globals.
2240  Return NULL when out of parameters.
2241 ***************************************************************************/
2242
2243 struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
2244 {
2245         if (snum == -1) {
2246                 /* do the globals */
2247                 for (; parm_table[*i].label; (*i)++) {
2248                         if (parm_table[*i].class == P_SEPARATOR)
2249                                 return &parm_table[(*i)++];
2250
2251                         if (!parm_table[*i].ptr
2252                             || (*parm_table[*i].label == '-'))
2253                                 continue;
2254
2255                         if ((*i) > 0
2256                             && (parm_table[*i].ptr ==
2257                                 parm_table[(*i) - 1].ptr))
2258                                 continue;
2259
2260                         return &parm_table[(*i)++];
2261                 }
2262         } else {
2263                 service *pService = ServicePtrs[snum];
2264
2265                 for (; parm_table[*i].label; (*i)++) {
2266                         if (parm_table[*i].class == P_SEPARATOR)
2267                                 return &parm_table[(*i)++];
2268
2269                         if (parm_table[*i].class == P_LOCAL &&
2270                             parm_table[*i].ptr &&
2271                             (*parm_table[*i].label != '-') &&
2272                             ((*i) == 0 ||
2273                              (parm_table[*i].ptr !=
2274                               parm_table[(*i) - 1].ptr)))
2275                         {
2276                                 int pdiff =
2277                                         PTR_DIFF(parm_table[*i].ptr,
2278                                                  &sDefault);
2279
2280                                 if (allparameters ||
2281                                     !equal_parameter(parm_table[*i].type,
2282                                                      ((char *)pService) +
2283                                                      pdiff,
2284                                                      ((char *)&sDefault) +
2285                                                      pdiff))
2286                                 {
2287                                         return &parm_table[(*i)++];
2288                                 }
2289                         }
2290                 }
2291         }
2292
2293         return NULL;
2294 }
2295
2296
2297 /***************************************************************************
2298  Return TRUE if the passed service number is within range.
2299 ***************************************************************************/
2300
2301 BOOL lp_snum_ok(int iService)
2302 {
2303         return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
2304 }
2305
2306 /***************************************************************************
2307  Auto-load some home services.
2308 ***************************************************************************/
2309
2310 static void lp_add_auto_services(const char *str)
2311 {
2312         return;
2313 }
2314
2315 /***************************************************************************
2316  Announce ourselves as a print server.
2317 ***************************************************************************/
2318
2319 void update_server_announce_as_printserver(void)
2320 {
2321         default_server_announce |= SV_TYPE_PRINTQ_SERVER;       
2322 }
2323
2324 /***************************************************************************
2325  Have we loaded a services file yet?
2326 ***************************************************************************/
2327
2328 BOOL lp_loaded(void)
2329 {
2330         return (bLoaded);
2331 }
2332
2333 /***************************************************************************
2334  Unload unused services.
2335 ***************************************************************************/
2336
2337 void lp_killunused(struct smbsrv_connection *smb, BOOL (*snumused) (struct smbsrv_connection *, int))
2338 {
2339         int i;
2340         for (i = 0; i < iNumServices; i++) {
2341                 if (!VALID(i))
2342                         continue;
2343
2344                 if (!snumused || !snumused(smb, i)) {
2345                         ServicePtrs[i]->valid = False;
2346                         free_service(ServicePtrs[i]);
2347                 }
2348         }
2349 }
2350
2351 /***************************************************************************
2352  Unload a service.
2353 ***************************************************************************/
2354
2355 void lp_killservice(int iServiceIn)
2356 {
2357         if (VALID(iServiceIn)) {
2358                 ServicePtrs[iServiceIn]->valid = False;
2359                 free_service(ServicePtrs[iServiceIn]);
2360         }
2361 }
2362
2363 /***************************************************************************
2364  Load the services array from the services file. Return True on success, 
2365  False on failure.
2366 ***************************************************************************/
2367
2368 BOOL lp_load(void)
2369 {
2370         pstring n2;
2371         BOOL bRetval;
2372         struct param_opt *data;
2373
2374         bRetval = False;
2375
2376         bInGlobalSection = True;
2377
2378         if (Globals.param_opt != NULL) {
2379                 struct param_opt *next;
2380                 for (data=Globals.param_opt; data; data=next) {
2381                         next = data->next;
2382                         if (data->flags & FLAG_CMDLINE) continue;
2383                         free(data->key);
2384                         free(data->value);
2385                         DLIST_REMOVE(Globals.param_opt, data);
2386                         free(data);
2387                 }
2388         }
2389         
2390         init_globals();
2391
2392         pstrcpy(n2, lp_configfile());
2393         standard_sub_basic(n2,sizeof(n2));
2394         DEBUG(2, ("lp_load: refreshing parameters from %s\n", n2));
2395         
2396         add_to_file_list(lp_configfile(), n2);
2397
2398         /* We get sections first, so have to start 'behind' to make up */
2399         iServiceIndex = -1;
2400         bRetval = pm_process(n2, do_section, do_parameter, NULL);
2401
2402         /* finish up the last section */
2403         DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
2404         if (bRetval)
2405                 if (iServiceIndex >= 0)
2406                         bRetval = service_ok(iServiceIndex);
2407
2408         lp_add_auto_services(lp_auto_services());
2409
2410         lp_add_hidden("IPC$", "IPC");
2411         lp_add_hidden("ADMIN$", "DISK");
2412
2413         set_default_server_announce_type();
2414
2415         bLoaded = True;
2416
2417         if (!Globals.szWINSservers && Globals.bWINSsupport) {
2418                 lp_do_parameter(-1, "wins server", "127.0.0.1");
2419         }
2420
2421         init_iconv();
2422
2423         return (bRetval);
2424 }
2425
2426 /***************************************************************************
2427  Reset the max number of services.
2428 ***************************************************************************/
2429
2430 void lp_resetnumservices(void)
2431 {
2432         iNumServices = 0;
2433 }
2434
2435 /***************************************************************************
2436  Return the max number of services.
2437 ***************************************************************************/
2438
2439 int lp_numservices(void)
2440 {
2441         return (iNumServices);
2442 }
2443
2444 /***************************************************************************
2445 Display the contents of the services array in human-readable form.
2446 ***************************************************************************/
2447
2448 void lp_dump(FILE *f, BOOL show_defaults, int maxtoprint)
2449 {
2450         int iService;
2451
2452         if (show_defaults)
2453                 defaults_saved = False;
2454
2455         dump_globals(f, show_defaults);
2456
2457         dump_a_service(&sDefault, f);
2458
2459         for (iService = 0; iService < maxtoprint; iService++)
2460                 lp_dump_one(f, show_defaults, iService);
2461 }
2462
2463 /***************************************************************************
2464 Display the contents of one service in human-readable form.
2465 ***************************************************************************/
2466
2467 void lp_dump_one(FILE * f, BOOL show_defaults, int snum)
2468 {
2469         if (VALID(snum)) {
2470                 if (ServicePtrs[snum]->szService[0] == '\0')
2471                         return;
2472                 dump_a_service(ServicePtrs[snum], f);
2473         }
2474 }
2475
2476 /***************************************************************************
2477 Return the number of the service with the given name, or -1 if it doesn't
2478 exist. Note that this is a DIFFERENT ANIMAL from the internal function
2479 getservicebyname()! This works ONLY if all services have been loaded, and
2480 does not copy the found service.
2481 ***************************************************************************/
2482
2483 int lp_servicenumber(const char *pszServiceName)
2484 {
2485         int iService;
2486         fstring serviceName;
2487  
2488  
2489         for (iService = iNumServices - 1; iService >= 0; iService--) {
2490                 if (VALID(iService) && ServicePtrs[iService]->szService) {
2491                         /*
2492                          * The substitution here is used to support %U is
2493                          * service names
2494                          */
2495                         fstrcpy(serviceName, ServicePtrs[iService]->szService);
2496                         standard_sub_basic(serviceName,sizeof(serviceName));
2497                         if (strequal(serviceName, pszServiceName))
2498                                 break;
2499                 }
2500         }
2501
2502         if (iService < 0)
2503                 DEBUG(7,("lp_servicenumber: couldn't find %s\n", pszServiceName));
2504
2505         return (iService);
2506 }
2507
2508 /*******************************************************************
2509  A useful volume label function. 
2510 ********************************************************************/
2511 const char *volume_label(int snum)
2512 {
2513         const char *ret = lp_volume(snum);
2514         if (!*ret)
2515                 return lp_servicename(snum);
2516         return (ret);
2517 }
2518
2519
2520 /*******************************************************************
2521  Set the server type we will announce as via nmbd.
2522 ********************************************************************/
2523
2524 static void set_default_server_announce_type(void)
2525 {
2526         default_server_announce = 0;
2527         default_server_announce |= SV_TYPE_WORKSTATION;
2528         default_server_announce |= SV_TYPE_SERVER;
2529         default_server_announce |= SV_TYPE_SERVER_UNIX;
2530
2531         switch (lp_announce_as()) {
2532                 case ANNOUNCE_AS_NT_SERVER:
2533                         default_server_announce |= SV_TYPE_SERVER_NT;
2534                         /* fall through... */
2535                 case ANNOUNCE_AS_NT_WORKSTATION:
2536                         default_server_announce |= SV_TYPE_NT;
2537                         break;
2538                 case ANNOUNCE_AS_WIN95:
2539                         default_server_announce |= SV_TYPE_WIN95_PLUS;
2540                         break;
2541                 case ANNOUNCE_AS_WFW:
2542                         default_server_announce |= SV_TYPE_WFW;
2543                         break;
2544                 default:
2545                         break;
2546         }
2547
2548         switch (lp_server_role()) {
2549                 case ROLE_DOMAIN_MEMBER:
2550                         default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
2551                         break;
2552                 case ROLE_DOMAIN_PDC:
2553                         default_server_announce |= SV_TYPE_DOMAIN_CTRL;
2554                         break;
2555                 case ROLE_DOMAIN_BDC:
2556                         default_server_announce |= SV_TYPE_DOMAIN_BAKCTRL;
2557                         break;
2558                 case ROLE_STANDALONE:
2559                 default:
2560                         break;
2561         }
2562         if (lp_time_server())
2563                 default_server_announce |= SV_TYPE_TIME_SOURCE;
2564
2565         if (lp_host_msdfs())
2566                 default_server_announce |= SV_TYPE_DFS_SERVER;
2567
2568         /* TODO: only announce us as print server when we are a print server */
2569         default_server_announce |= SV_TYPE_PRINTQ_SERVER;
2570 }
2571
2572 /***********************************************************
2573  If we are PDC then prefer us as DMB
2574 ************************************************************/
2575
2576 BOOL lp_domain_master(void)
2577 {
2578         return (lp_server_role() == ROLE_DOMAIN_PDC);
2579 }
2580
2581 /***********************************************************
2582  If we are PDC then prefer us as DMB
2583 ************************************************************/
2584
2585 BOOL lp_domain_logons(void)
2586 {
2587         return (lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role() == ROLE_DOMAIN_BDC);
2588 }
2589
2590 /***********************************************************
2591  If we are DMB then prefer us as LMB
2592 ************************************************************/
2593
2594 BOOL lp_preferred_master(void)
2595 {
2596         return (lp_local_master() && lp_domain_master());
2597 }
2598
2599 /*******************************************************************
2600  Remove a service.
2601 ********************************************************************/
2602
2603 void lp_remove_service(int snum)
2604 {
2605         ServicePtrs[snum]->valid = False;
2606 }
2607
2608 /*******************************************************************
2609  Copy a service.
2610 ********************************************************************/
2611
2612 void lp_copy_service(int snum, const char *new_name)
2613 {
2614         const char *oldname = lp_servicename(snum);
2615         do_section(new_name, NULL);
2616         if (snum >= 0) {
2617                 snum = lp_servicenumber(new_name);
2618                 if (snum >= 0)
2619                         lp_do_parameter(snum, "copy", oldname);
2620         }
2621 }
2622
2623
2624 /*******************************************************************
2625  Get the default server type we will announce as via nmbd.
2626 ********************************************************************/
2627 int lp_default_server_announce(void)
2628 {
2629         return default_server_announce;
2630 }
2631
2632 const char *lp_printername(int snum)
2633 {
2634         const char *ret = _lp_printername(snum);
2635         if (ret == NULL || (ret != NULL && *ret == '\0'))
2636                 ret = lp_const_servicename(snum);
2637
2638         return ret;
2639 }
2640
2641
2642 /*******************************************************************
2643  Return the max print jobs per queue.
2644 ********************************************************************/
2645
2646 int lp_maxprintjobs(int snum)
2647 {
2648         int maxjobs = LP_SNUM_OK(snum) ? ServicePtrs[snum]->iMaxPrintJobs : sDefault.iMaxPrintJobs;
2649         if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
2650                 maxjobs = PRINT_MAX_JOBID - 1;
2651
2652         return maxjobs;
2653 }