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