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