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