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