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