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