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