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