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