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