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