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