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