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