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