1ecc53fac0cfacac8c716630a2d14d9e5ca471ba
[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 "dynconfig.h"
57 #include "system/time.h"
58 #include "system/iconv.h"
59 #include "system/network.h"
60 #include "system/printing.h"
61 #include "librpc/gen_ndr/ndr_svcctl.h"
62 #include "dlinklist.h"
63
64 BOOL in_client = False;         /* Not in the client by default */
65 static BOOL bLoaded = False;
66
67 #ifndef GLOBAL_NAME
68 #define GLOBAL_NAME "global"
69 #endif
70
71 #ifndef PRINTERS_NAME
72 #define PRINTERS_NAME "printers"
73 #endif
74
75 #ifndef HOMES_NAME
76 #define HOMES_NAME "homes"
77 #endif
78
79 /* some helpful bits */
80 #define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && ServicePtrs[(i)]->valid)
81 #define VALID(i) ServicePtrs[i]->valid
82
83 static BOOL do_parameter(const char *, const char *);
84 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...);
85
86 static BOOL defaults_saved = False;
87
88
89 #define FLAG_BASIC      0x0001 /* fundamental options */
90 #define FLAG_SHARE      0x0002 /* file sharing options */
91 #define FLAG_PRINT      0x0004 /* printing options */
92 #define FLAG_GLOBAL     0x0008 /* local options that should be globally settable in SWAT */
93 #define FLAG_WIZARD     0x0010 /* Parameters that the wizard will operate on */
94 #define FLAG_ADVANCED   0x0020 /* Parameters that the wizard will operate on */
95 #define FLAG_DEVELOPER  0x0040 /* Parameters that the wizard will operate on */
96 #define FLAG_DEPRECATED 0x1000 /* options that should no longer be used */
97 #define FLAG_HIDE       0x2000 /* options that should be hidden in SWAT */
98 #define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
99 #define FLAG_CMDLINE    0x8000 /* this option was set from the command line */
100
101
102 /* the following are used by loadparm for option lists */
103 typedef enum
104 {
105   P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
106   P_STRING,P_USTRING,P_ENUM,P_SEP
107 } parm_type;
108
109 typedef enum
110 {
111   P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
112 } parm_class;
113
114 struct enum_list {
115         int value;
116         const char *name;
117 };
118
119 struct parm_struct
120 {
121         const char *label;
122         parm_type type;
123         parm_class class;
124         void *ptr;
125         BOOL (*special)(const char *, char **);
126         const struct enum_list *enum_list;
127         uint_t flags;
128         union {
129                 BOOL bvalue;
130                 int ivalue;
131                 char *svalue;
132                 char cvalue;
133                 char **lvalue;
134         } def;
135 };
136
137
138 struct param_opt {
139         struct param_opt *prev, *next;
140         char *key;
141         char *value;
142         int flags;
143 };
144
145 /* 
146  * This structure describes global (ie., server-wide) parameters.
147  */
148 typedef struct
149 {
150         char **smb_ports;
151         char *dos_charset;
152         char *unix_charset;
153         char *ncalrpc_dir;
154         char *display_charset;
155         char *szPrintcapname;
156         char *szLockDir;
157         char *szPidDir;
158         char *szRootdir;
159         char *szDefaultService;
160         char *szHostsEquiv;
161         char *szServerString;
162         char *szAutoServices;
163         char *szPasswdProgram;
164         char *szPasswdChat;
165         char *szLogFile;
166         char *szConfigFile;
167         char *szSMBPasswdFile;
168         char *szSAM_URL;
169         char *szSPOOLSS_URL;
170         char *szPrivateDir;
171         char **szPreloadModules;
172         char *szPasswordServer;
173         char *szSocketOptions;
174         char *szRealm;
175         char *szADSserver;
176         char *szLogonScript;
177         char *szLogonPath;
178         char *szLogonDrive;
179         char *szLogonHome;
180         char **szWINSservers;
181         char **szInterfaces;
182         char *szRemoteAnnounce;
183         char *szRemoteBrowseSync;
184         char *szSocketAddress;
185         char *szAnnounceVersion;        /* This is initialised in init_globals */
186         char *szWorkgroup;
187         char *szNetbiosName;
188         char **szNetbiosAliases;
189         char *szNetbiosScope;
190         char *szDomainOtherSIDs;
191         char *szNameResolveOrder;
192         char *szPanicAction;
193         char *szAddUserScript; 
194         char *szAddMachineScript;
195         char *szWINSHook;
196         char *szWINSPartners;
197         char **dcerpc_ep_servers;
198         char **server_services;
199         char *szWinbindUID;
200         char *szWinbindGID;
201         char *szNonUnixAccountRange;
202         char *szTemplateHomedir;
203         char *szTemplateShell;
204         char *szWinbindSeparator;
205         BOOL bWinbindEnumUsers;
206         BOOL bWinbindEnumGroups;
207         BOOL bWinbindUseDefaultDomain;
208         char *szIDMapBackend;
209         char *szGuestaccount;
210         int max_mux;
211         int max_xmit;
212         int pwordlevel;
213         int unamelevel;
214         int maxprotocol;
215         int minprotocol;
216         int security;
217         char **AuthMethods;
218         BOOL paranoid_server_security;
219         int lpqcachetime;
220         BOOL bDisableSpoolss;
221         int os_level;
222         int enhanced_browsing;
223         int time_offset;
224         int max_ttl;
225         int max_wins_ttl;
226         int min_wins_ttl;
227         int lm_announce;
228         int lm_interval;
229         int announce_as;        /* This is initialised in init_globals */
230         int machine_password_timeout;
231         int winbind_cache_time;
232         int iLockSpinCount;
233         int iLockSpinTime;
234         char *socket_options;
235         BOOL bDNSproxy;
236         BOOL bWINSsupport;
237         BOOL bWINSproxy;
238         BOOL bLocalMaster;
239         BOOL bPreferredMaster;
240         BOOL bDomainMaster;
241         BOOL bDomainLogons;
242         BOOL bEncryptPasswords;
243         BOOL bNullPasswords;
244         BOOL bObeyPamRestrictions;
245         BOOL bLoadPrinters;
246         BOOL bLargeReadwrite;
247         BOOL bReadRaw;
248         BOOL bWriteRaw;
249         BOOL bTimeServer;
250         BOOL bBindInterfacesOnly;
251         BOOL bPamPasswordChange;
252         BOOL bNTSmbSupport;
253         BOOL bNTStatusSupport;
254         BOOL bAllowTrustedDomains;
255         BOOL bLanmanAuth;
256         BOOL bNTLMAuth;
257         BOOL bUseSpnego;
258         int  server_signing;
259         int  client_signing;
260         BOOL bClientLanManAuth;
261         BOOL bClientNTLMv2Auth;
262         BOOL bHostMSDfs;
263         BOOL bHideLocalUsers;
264         BOOL bUnicode;
265         BOOL bUseMmap;
266         BOOL bHostnameLookups;
267         BOOL bUnixExtensions;
268         BOOL bDisableNetbios;
269         BOOL bRpcBigEndian;
270         int restrict_anonymous;
271         int name_cache_timeout;
272         struct param_opt *param_opt;
273 }
274 global;
275
276 static global Globals;
277
278 /* 
279  * This structure describes a single service. 
280  */
281 typedef struct
282 {
283         BOOL valid;
284         BOOL autoloaded;
285         char *szService;
286         char *szPath;
287         char *szUsername;
288         char **szInvalidUsers;
289         char **szValidUsers;
290         char **szAdminUsers;
291         char *szCopy;
292         char *szInclude;
293         char *szPrintcommand;
294         char *szLpqcommand;
295         char *szLprmcommand;
296         char *szLppausecommand;
297         char *szLpresumecommand;
298         char *szQueuepausecommand;
299         char *szQueueresumecommand;
300         char *szPrintername;
301         char **szHostsallow;
302         char **szHostsdeny;
303         char *comment;
304         char *volume;
305         char *fstype;
306         char *szMSDfsProxy;
307         char **ntvfs_handler;
308         int iMinPrintSpace;
309         int iMaxPrintJobs;
310         int iMaxConnections;
311         int iPrinting;
312         int iCSCPolicy;
313         BOOL bAvailable;
314         BOOL bBrowseable;
315         BOOL bRead_only;
316         BOOL bPrint_ok;
317         BOOL bMap_system;
318         BOOL bMap_hidden;
319         BOOL bMap_archive;
320         BOOL bLocking;
321         BOOL bStrictLocking;
322         BOOL bPosixLocking;
323         BOOL bOpLocks;
324         BOOL bLevel2OpLocks;
325         BOOL bOnlyUser;
326         BOOL bGuest_only;
327         BOOL bGuest_ok;
328         BOOL *copymap;
329         BOOL bMSDfsRoot;
330         BOOL bShareModes;
331         BOOL bStrictSync;
332         BOOL bCIFileSystem;
333         struct param_opt *param_opt;
334
335         char dummy[3];          /* for alignment */
336 }
337 service;
338
339
340 /* This is a default service used to prime a services structure */
341 static service sDefault = {
342         True,                   /* valid */
343         False,                  /* not autoloaded */
344         NULL,                   /* szService */
345         NULL,                   /* szPath */
346         NULL,                   /* szUsername */
347         NULL,                   /* szInvalidUsers */
348         NULL,                   /* szValidUsers */
349         NULL,                   /* szAdminUsers */
350         NULL,                   /* szCopy */
351         NULL,                   /* szInclude */
352         NULL,                   /* szPrintcommand */
353         NULL,                   /* szLpqcommand */
354         NULL,                   /* szLprmcommand */
355         NULL,                   /* szLppausecommand */
356         NULL,                   /* szLpresumecommand */
357         NULL,                   /* szQueuepausecommand */
358         NULL,                   /* szQueueresumecommand */
359         NULL,                   /* szPrintername */
360         NULL,                   /* szHostsallow */
361         NULL,                   /* szHostsdeny */
362         NULL,                   /* comment */
363         NULL,                   /* volume */
364         NULL,                   /* fstype */
365         NULL,                   /* szMSDfsProxy */
366         NULL,                   /* ntvfs_handler */
367         0,                      /* iMinPrintSpace */
368         1000,                   /* iMaxPrintJobs */
369         0,                      /* iMaxConnections */
370         DEFAULT_PRINTING,       /* iPrinting */
371         0,                      /* iCSCPolicy */
372         True,                   /* bAvailable */
373         True,                   /* bBrowseable */
374         True,                   /* bRead_only */
375         False,                  /* bPrint_ok */
376         False,                  /* bMap_system */
377         False,                  /* bMap_hidden */
378         True,                   /* bMap_archive */
379         True,                   /* bLocking */
380         True,                   /* bStrictLocking */
381         True,                   /* bPosixLocking */
382         True,                   /* bOpLocks */
383         True,                   /* bLevel2OpLocks */
384         False,                  /* bOnlyUser */
385         False,                  /* bGuest_only */
386         False,                  /* bGuest_ok */
387         NULL,                   /* copymap */
388         False,                  /* bMSDfsRoot */
389         True,                   /* bShareModes */
390         False,                  /* bStrictSync */
391         False,                  /* bCIFileSystem */
392         NULL,                   /* Parametric options */
393
394         ""                      /* dummy */
395 };
396
397 /* local variables */
398 static service **ServicePtrs = NULL;
399 static int iNumServices = 0;
400 static int iServiceIndex = 0;
401 static BOOL bInGlobalSection = True;
402 static BOOL bGlobalOnly = False;
403 static int server_role;
404 static int default_server_announce;
405
406 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
407
408 /* prototypes for the special type handlers */
409 static BOOL handle_include(const char *pszParmValue, char **ptr);
410 static BOOL handle_copy(const char *pszParmValue, char **ptr);
411 static BOOL handle_winbind_uid(const char *pszParmValue, char **ptr);
412 static BOOL handle_winbind_gid(const char *pszParmValue, char **ptr);
413 static BOOL handle_non_unix_account_range(const char *pszParmValue, char **ptr);
414
415 static void set_server_role(void);
416 static void set_default_server_announce_type(void);
417
418 static const struct enum_list enum_protocol[] = {
419         {PROTOCOL_NT1, "NT1"},
420         {PROTOCOL_LANMAN2, "LANMAN2"},
421         {PROTOCOL_LANMAN1, "LANMAN1"},
422         {PROTOCOL_CORE, "CORE"},
423         {PROTOCOL_COREPLUS, "COREPLUS"},
424         {PROTOCOL_COREPLUS, "CORE+"},
425         {-1, NULL}
426 };
427
428 static const struct enum_list enum_security[] = {
429         {SEC_SHARE, "SHARE"},
430         {SEC_USER, "USER"},
431         {SEC_SERVER, "SERVER"},
432         {SEC_DOMAIN, "DOMAIN"},
433 #ifdef HAVE_ADS
434         {SEC_ADS, "ADS"},
435 #endif
436         {-1, NULL}
437 };
438
439 static const struct enum_list enum_printing[] = {
440         {PRINT_SYSV, "sysv"},
441         {PRINT_AIX, "aix"},
442         {PRINT_HPUX, "hpux"},
443         {PRINT_BSD, "bsd"},
444         {PRINT_QNX, "qnx"},
445         {PRINT_PLP, "plp"},
446         {PRINT_LPRNG, "lprng"},
447         {PRINT_SOFTQ, "softq"},
448         {PRINT_CUPS, "cups"},
449         {PRINT_LPRNT, "nt"},
450         {PRINT_LPROS2, "os2"},
451 #ifdef DEVELOPER
452         {PRINT_TEST, "test"},
453         {PRINT_VLP, "vlp"},
454 #endif /* DEVELOPER */
455         {-1, NULL}
456 };
457
458 /* Types of machine we can announce as. */
459 #define ANNOUNCE_AS_NT_SERVER 1
460 #define ANNOUNCE_AS_WIN95 2
461 #define ANNOUNCE_AS_WFW 3
462 #define ANNOUNCE_AS_NT_WORKSTATION 4
463
464 static const struct enum_list enum_announce_as[] = {
465         {ANNOUNCE_AS_NT_SERVER, "NT"},
466         {ANNOUNCE_AS_NT_SERVER, "NT Server"},
467         {ANNOUNCE_AS_NT_WORKSTATION, "NT Workstation"},
468         {ANNOUNCE_AS_WIN95, "win95"},
469         {ANNOUNCE_AS_WFW, "WfW"},
470         {-1, NULL}
471 };
472
473 static const struct enum_list enum_bool_auto[] = {
474         {False, "No"},
475         {False, "False"},
476         {False, "0"},
477         {True, "Yes"},
478         {True, "True"},
479         {True, "1"},
480         {Auto, "Auto"},
481         {-1, NULL}
482 };
483
484 /* Client-side offline caching policy types */
485 #define CSC_POLICY_MANUAL 0
486 #define CSC_POLICY_DOCUMENTS 1
487 #define CSC_POLICY_PROGRAMS 2
488 #define CSC_POLICY_DISABLE 3
489
490 static const struct enum_list enum_csc_policy[] = {
491         {CSC_POLICY_MANUAL, "manual"},
492         {CSC_POLICY_DOCUMENTS, "documents"},
493         {CSC_POLICY_PROGRAMS, "programs"},
494         {CSC_POLICY_DISABLE, "disable"},
495         {-1, NULL}
496 };
497
498 /* SMB signing types. */
499 static const struct enum_list enum_smb_signing_vals[] = {
500         {SMB_SIGNING_OFF, "No"},
501         {SMB_SIGNING_OFF, "False"},
502         {SMB_SIGNING_OFF, "0"},
503         {SMB_SIGNING_OFF, "Off"},
504         {SMB_SIGNING_OFF, "disabled"},
505         {SMB_SIGNING_SUPPORTED, "Yes"},
506         {SMB_SIGNING_SUPPORTED, "True"},
507         {SMB_SIGNING_SUPPORTED, "1"},
508         {SMB_SIGNING_SUPPORTED, "On"},
509         {SMB_SIGNING_SUPPORTED, "enabled"},
510         {SMB_SIGNING_REQUIRED, "required"},
511         {SMB_SIGNING_REQUIRED, "mandatory"},
512         {SMB_SIGNING_REQUIRED, "force"},
513         {SMB_SIGNING_REQUIRED, "forced"},
514         {SMB_SIGNING_REQUIRED, "enforced"},
515         {SMB_SIGNING_AUTO, "auto"},
516         {-1, NULL}
517 };
518
519
520 /* Note: We do not initialise the defaults union - it is not allowed in ANSI C
521  *
522  * Note: We have a flag called FLAG_DEVELOPER but is not used at this time, it
523  * is implied in current control logic. This may change at some later time. A
524  * flag value of 0 means - show as development option only.
525  *
526  * The FLAG_HIDE is explicit. Paramters set this way do NOT appear in any edit
527  * screen in SWAT. This is used to exclude parameters as well as to squash all
528  * parameters that have been duplicated by pseudonyms.
529  */
530 static struct parm_struct parm_table[] = {
531         {"Base Options", P_SEP, P_SEPARATOR},
532
533         {"dos charset", P_STRING, P_GLOBAL, &Globals.dos_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
534         {"unix charset", P_STRING, P_GLOBAL, &Globals.unix_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
535         {"ncalrpc dir", P_STRING, P_GLOBAL, &Globals.ncalrpc_dir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
536         {"display charset", P_STRING, P_GLOBAL, &Globals.display_charset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
537         {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
538         {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
539         {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_HIDE},
540         {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkgroup, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
541         {"realm", P_USTRING, P_GLOBAL, &Globals.szRealm, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
542         {"ADS server", P_STRING, P_GLOBAL, &Globals.szADSserver, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
543         {"netbios name", P_USTRING, P_GLOBAL, &Globals.szNetbiosName, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
544         {"netbios aliases", P_LIST, P_GLOBAL, &Globals.szNetbiosAliases, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
545         {"netbios scope", P_USTRING, P_GLOBAL, &Globals.szNetbiosScope, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
546         {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED  | FLAG_DEVELOPER},
547         {"interfaces", P_LIST, P_GLOBAL, &Globals.szInterfaces, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
548         {"bind interfaces only", P_BOOL, P_GLOBAL, &Globals.bBindInterfacesOnly, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
549         {"ntvfs handler", P_LIST, P_LOCAL, &sDefault.ntvfs_handler, NULL, NULL, FLAG_ADVANCED},
550         {"dcerpc endpoint servers", P_LIST, P_GLOBAL, &Globals.dcerpc_ep_servers, NULL, NULL, FLAG_ADVANCED},
551         {"server services", P_LIST, P_GLOBAL, &Globals.server_services, NULL, NULL, FLAG_ADVANCED},
552
553         {"Security Options", P_SEP, P_SEPARATOR},
554         
555         {"security", P_ENUM, P_GLOBAL, &Globals.security, NULL, enum_security, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
556         {"auth methods", P_LIST, P_GLOBAL, &Globals.AuthMethods, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
557         {"encrypt passwords", P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
558         {"allow trusted domains", P_BOOL, P_GLOBAL, &Globals.bAllowTrustedDomains, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
559         {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
560         {"idmap backend", P_STRING, P_GLOBAL, &Globals.szIDMapBackend, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
561         {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
562         {"obey pam restrictions", P_BOOL, P_GLOBAL, &Globals.bObeyPamRestrictions, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
563         {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
564         {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
565         {"sam database", P_STRING, P_GLOBAL, &Globals.szSAM_URL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
566         {"spoolss database", P_STRING, P_GLOBAL, &Globals.szSPOOLSS_URL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
567         {"private dir", P_STRING, P_GLOBAL, &Globals.szPrivateDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
568         {"non unix account range", P_STRING, P_GLOBAL, &Globals.szNonUnixAccountRange, handle_non_unix_account_range, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
569         {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
570         {"root dir", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
571         {"root", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, FLAG_HIDE | FLAG_DEVELOPER},
572         {"guest account", P_STRING, P_GLOBAL, &Globals.szGuestaccount, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
573         
574         {"pam password change", P_BOOL, P_GLOBAL, &Globals.bPamPasswordChange, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
575         {"passwd program", P_STRING, P_GLOBAL, &Globals.szPasswdProgram, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
576         {"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
577         {"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
578         {"username level", P_INTEGER, P_GLOBAL, &Globals.unamelevel, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
579         {"restrict anonymous", P_INTEGER, P_GLOBAL, &Globals.restrict_anonymous, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
580         {"lanman auth", P_BOOL, P_GLOBAL, &Globals.bLanmanAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
581         {"ntlm auth", P_BOOL, P_GLOBAL, &Globals.bNTLMAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
582         {"client NTLMv2 auth", P_BOOL, P_GLOBAL, &Globals.bClientNTLMv2Auth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
583         {"client lanman auth", P_BOOL, P_GLOBAL, &Globals.bClientLanManAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
584         
585         {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
586         {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_HIDE},
587         {"users", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_HIDE},
588         
589         {"invalid users", P_LIST, P_LOCAL, &sDefault.szInvalidUsers, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
590         {"valid users", P_LIST, P_LOCAL, &sDefault.szValidUsers, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
591         {"admin users", P_LIST, P_LOCAL, &sDefault.szAdminUsers, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
592         
593         {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE},
594
595         {"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, FLAG_SHARE},
596
597         {"guest ok", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
598
599         {"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL, NULL, FLAG_SHARE},
600         {"hosts allow", P_LIST, P_LOCAL, &sDefault.szHostsallow, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
601         {"hosts deny", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
602         {"preload modules", P_LIST, P_GLOBAL, &Globals.szPreloadModules, NULL, NULL, FLAG_BASIC | FLAG_GLOBAL},
603
604         {"Logging Options", P_SEP, P_SEPARATOR},
605
606         {"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
607         {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL, FLAG_HIDE},
608         {"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
609         
610         {"Protocol Options", P_SEP, P_SEPARATOR},
611         
612         {"smb ports", P_LIST, P_GLOBAL, &Globals.smb_ports, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
613         {"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, FLAG_DEVELOPER},
614         {"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
615         {"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
616         {"unicode", P_BOOL, P_GLOBAL, &Globals.bUnicode, NULL, NULL, FLAG_DEVELOPER},
617         {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL, NULL, FLAG_DEVELOPER},
618         {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL, NULL, FLAG_DEVELOPER},
619         {"disable netbios", P_BOOL, P_GLOBAL, &Globals.bDisableNetbios, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
620         
621         {"nt status support", P_BOOL, P_GLOBAL, &Globals.bNTStatusSupport, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
622
623         {"announce version", P_STRING, P_GLOBAL, &Globals.szAnnounceVersion, NULL, NULL, FLAG_DEVELOPER},
624         {"announce as", P_ENUM, P_GLOBAL, &Globals.announce_as, NULL, enum_announce_as, FLAG_DEVELOPER},
625         {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
626         {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
627
628         {"name resolve order", P_STRING, P_GLOBAL, &Globals.szNameResolveOrder, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
629         {"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, 
630         {"max wins ttl", P_INTEGER, P_GLOBAL, &Globals.max_wins_ttl, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
631         {"min wins ttl", P_INTEGER, P_GLOBAL, &Globals.min_wins_ttl, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
632         {"time server", P_BOOL, P_GLOBAL, &Globals.bTimeServer, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
633         {"unix extensions", P_BOOL, P_GLOBAL, &Globals.bUnixExtensions, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
634         {"use spnego", P_BOOL, P_GLOBAL, &Globals.bUseSpnego, NULL, NULL, FLAG_DEVELOPER},
635         {"server signing", P_ENUM, P_GLOBAL, &Globals.server_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED}, 
636         {"client signing", P_ENUM, P_GLOBAL, &Globals.client_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED}, 
637         {"rpc big endian", P_BOOL, P_GLOBAL, &Globals.bRpcBigEndian, NULL, NULL, FLAG_DEVELOPER},
638
639         {"Tuning Options", P_SEP, P_SEPARATOR},
640                 
641         {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL, NULL, FLAG_DEVELOPER},
642         {"max connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL, NULL, FLAG_SHARE},
643         {"paranoid server security", P_BOOL, P_GLOBAL, &Globals.paranoid_server_security, NULL, NULL, FLAG_DEVELOPER},
644         {"min print space", P_INTEGER, P_LOCAL, &sDefault.iMinPrintSpace, NULL, NULL, FLAG_PRINT},
645         
646         {"socket options", P_STRING, P_GLOBAL, &Globals.socket_options, NULL, NULL, FLAG_DEVELOPER},
647         {"use mmap", P_BOOL, P_GLOBAL, &Globals.bUseMmap, NULL, NULL, FLAG_DEVELOPER},
648         {"hostname lookups", P_BOOL, P_GLOBAL, &Globals.bHostnameLookups, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
649
650         {"name cache timeout", P_INTEGER, P_GLOBAL, &Globals.name_cache_timeout, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
651         {"strict sync", P_BOOL, P_LOCAL, &sDefault.bStrictSync, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
652         {"case insensitive filesystem", P_BOOL, P_LOCAL, &sDefault.bCIFileSystem, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
653
654         {"Printing Options", P_SEP, P_SEPARATOR},
655         
656         {"max print jobs", P_INTEGER, P_LOCAL, &sDefault.iMaxPrintJobs, NULL, NULL, FLAG_PRINT},
657         {"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL, NULL, FLAG_PRINT},
658         {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL, FLAG_PRINT | FLAG_DEVELOPER},
659         {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL, FLAG_HIDE},
660         {"printable", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_PRINT},
661         {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_HIDE},
662         {"printing", P_ENUM, P_LOCAL, &sDefault.iPrinting, NULL, enum_printing, FLAG_PRINT | FLAG_GLOBAL},
663         {"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
664         {"disable spoolss", P_BOOL, P_GLOBAL, &Globals.bDisableSpoolss, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
665         {"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
666         {"lprm command", P_STRING, P_LOCAL, &sDefault.szLprmcommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
667         {"lppause command", P_STRING, P_LOCAL, &sDefault.szLppausecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
668         {"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
669         {"queuepause command", P_STRING, P_LOCAL, &sDefault.szQueuepausecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
670         {"queueresume command", P_STRING, P_LOCAL, &sDefault.szQueueresumecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
671         
672         {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_PRINT},
673         {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_HIDE},
674
675         {"Filename Handling", P_SEP, P_SEPARATOR},
676         
677         {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
678         {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
679         {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
680
681         {"Domain Options", P_SEP, P_SEPARATOR},
682         
683         {"machine password timeout", P_INTEGER, P_GLOBAL, &Globals.machine_password_timeout, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
684
685         {"Logon Options", P_SEP, P_SEPARATOR},
686
687         {"add user script", P_STRING, P_GLOBAL, &Globals.szAddUserScript, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
688         {"add machine script", P_STRING, P_GLOBAL, &Globals.szAddMachineScript, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
689
690         {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
691         {"logon path", P_STRING, P_GLOBAL, &Globals.szLogonPath, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
692         {"logon drive", P_STRING, P_GLOBAL, &Globals.szLogonDrive, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
693         {"logon home", P_STRING, P_GLOBAL, &Globals.szLogonHome, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
694         {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
695
696         {"Browse Options", P_SEP, P_SEPARATOR},
697         
698         {"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
699         {"lm announce", P_ENUM, P_GLOBAL, &Globals.lm_announce, NULL, enum_bool_auto, FLAG_ADVANCED | FLAG_DEVELOPER},
700         {"lm interval", P_INTEGER, P_GLOBAL, &Globals.lm_interval, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
701         {"preferred master", P_ENUM, P_GLOBAL, &Globals.bPreferredMaster, NULL, enum_bool_auto, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
702         {"prefered master", P_ENUM, P_GLOBAL, &Globals.bPreferredMaster, NULL, enum_bool_auto, FLAG_HIDE},
703         {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
704         {"domain master", P_ENUM, P_GLOBAL, &Globals.bDomainMaster, NULL, enum_bool_auto, FLAG_BASIC | FLAG_ADVANCED | FLAG_DEVELOPER},
705         {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT | FLAG_DEVELOPER},
706         {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, FLAG_HIDE},
707         {"enhanced browsing", P_BOOL, P_GLOBAL, &Globals.enhanced_browsing, NULL, NULL, FLAG_DEVELOPER | FLAG_ADVANCED},
708
709         {"WINS Options", P_SEP, P_SEPARATOR},
710         {"dns proxy", P_BOOL, P_GLOBAL, &Globals.bDNSproxy, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
711         {"wins proxy", P_BOOL, P_GLOBAL, &Globals.bWINSproxy, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
712         
713         {"wins server", P_LIST, P_GLOBAL, &Globals.szWINSservers, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
714         {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
715         {"wins hook", P_STRING, P_GLOBAL, &Globals.szWINSHook, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
716         {"wins partners", P_STRING, P_GLOBAL, &Globals.szWINSPartners, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
717
718         {"Locking Options", P_SEP, P_SEPARATOR},
719         
720         {"csc policy", P_ENUM, P_LOCAL, &sDefault.iCSCPolicy, NULL, enum_csc_policy, FLAG_SHARE | FLAG_GLOBAL},
721         {"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
722         {"lock spin count", P_INTEGER, P_GLOBAL, &Globals.iLockSpinCount, NULL, NULL, FLAG_GLOBAL},
723         {"lock spin time", P_INTEGER, P_GLOBAL, &Globals.iLockSpinTime, NULL, NULL, FLAG_GLOBAL},
724         
725         {"oplocks", P_BOOL, P_LOCAL, &sDefault.bOpLocks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
726         {"level2 oplocks", P_BOOL, P_LOCAL, &sDefault.bLevel2OpLocks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
727         {"posix locking", P_BOOL, P_LOCAL, &sDefault.bPosixLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
728         {"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
729         {"share modes", P_BOOL, P_LOCAL,  &sDefault.bShareModes, NULL, NULL, FLAG_SHARE|FLAG_GLOBAL},
730
731         {"Miscellaneous Options", P_SEP, P_SEPARATOR},
732         
733         {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL, NULL, FLAG_HIDE},
734         {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
735         {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
736         {"lock dir", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL, FLAG_HIDE}, 
737         {"lock directory", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
738         {"pid directory", P_STRING, P_GLOBAL, &Globals.szPidDir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, 
739         
740         {"default service", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
741         {"default", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL,  FLAG_DEVELOPER},
742         {"remote announce", P_STRING, P_GLOBAL, &Globals.szRemoteAnnounce, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
743         {"remote browse sync", P_STRING, P_GLOBAL, &Globals.szRemoteBrowseSync, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
744         {"socket address", P_STRING, P_GLOBAL, &Globals.szSocketAddress, NULL, NULL, FLAG_DEVELOPER},
745         {"time offset", P_INTEGER, P_GLOBAL, &Globals.time_offset, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
746         {"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL, NULL, FLAG_HIDE},
747         
748         {"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy, NULL, FLAG_HIDE},
749         {"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include, NULL, FLAG_HIDE},
750         
751         {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
752         {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL, FLAG_SHARE },
753         {"fstype", P_STRING, P_LOCAL, &sDefault.fstype, NULL, NULL, FLAG_SHARE},
754
755         {"panic action", P_STRING, P_GLOBAL, &Globals.szPanicAction, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
756         {"hide local users", P_BOOL, P_GLOBAL, &Globals.bHideLocalUsers, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
757
758         {"msdfs root", P_BOOL, P_LOCAL, &sDefault.bMSDfsRoot, NULL, NULL, FLAG_SHARE},
759         {"msdfs proxy", P_STRING, P_LOCAL, &sDefault.szMSDfsProxy, NULL, NULL, FLAG_SHARE},
760         {"host msdfs", P_BOOL, P_GLOBAL, &Globals.bHostMSDfs, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
761         {"Winbind options", P_SEP, P_SEPARATOR},
762
763         {"winbind uid", P_STRING, P_GLOBAL, &Globals.szWinbindUID, handle_winbind_uid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
764         {"winbind gid", P_STRING, P_GLOBAL, &Globals.szWinbindGID, handle_winbind_gid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
765         {"template homedir", P_STRING, P_GLOBAL, &Globals.szTemplateHomedir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
766         {"template shell", P_STRING, P_GLOBAL, &Globals.szTemplateShell, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
767         {"winbind separator", P_STRING, P_GLOBAL, &Globals.szWinbindSeparator, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
768         {"winbind cache time", P_INTEGER, P_GLOBAL, &Globals.winbind_cache_time, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
769         {"winbind enum users", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumUsers, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
770         {"winbind enum groups", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumGroups, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
771         {"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
772
773         {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
774 };
775
776 /***************************************************************************
777  Initialise the sDefault parameter structure for the printer values.
778 ***************************************************************************/
779
780 static void init_printer_values(void)
781 {
782         /* choose defaults depending on the type of printing */
783         switch (sDefault.iPrinting) {
784                 case PRINT_BSD:
785                 case PRINT_AIX:
786                 case PRINT_LPRNT:
787                 case PRINT_LPROS2:
788                         do_parameter("Lpqcommand", "lpq -P'%p'");
789                         do_parameter("Lprmcommand", "lprm -P'%p' %j");
790                         do_parameter("Printcommand",
791                                    "lpr -r -P'%p' %s");
792                         break;
793
794                 case PRINT_LPRNG:
795                 case PRINT_PLP:
796                         do_parameter("Lpqcommand", "lpq -P'%p'");
797                         do_parameter("Lprmcommand", "lprm -P'%p' %j");
798                         do_parameter("Printcommand",
799                                    "lpr -r -P'%p' %s");
800                         do_parameter("Queuepausecommand",
801                                    "lpc stop '%p'");
802                         do_parameter("Queueresumecommand",
803                                    "lpc start '%p'");
804                         do_parameter("Lppausecommand",
805                                    "lpc hold '%p' %j");
806                         do_parameter("Lpresumecommand",
807                                    "lpc release '%p' %j");
808                         break;
809
810                 case PRINT_CUPS:
811 #ifdef HAVE_CUPS
812                         do_parameter("Lpqcommand", "");
813                         do_parameter("Lprmcommand", "");
814                         do_parameter("Printcommand", "");
815                         do_parameter("Lppausecommand", "");
816                         do_parameter("Lpresumecommand", "");
817                         do_parameter("Queuepausecommand", "");
818                         do_parameter("Queueresumecommand", "");
819
820                         do_parameter("Printcapname", "cups");
821 #else
822                         do_parameter("Lpqcommand",
823                                    "/usr/bin/lpstat -o '%p'");
824                         do_parameter("Lprmcommand",
825                                    "/usr/bin/cancel '%p-%j'");
826                         do_parameter("Printcommand",
827                                    "/usr/bin/lp -d '%p' %s; rm %s");
828                         do_parameter("Lppausecommand",
829                                    "lp -i '%p-%j' -H hold");
830                         do_parameter("Lpresumecommand",
831                                    "lp -i '%p-%j' -H resume");
832                         do_parameter("Queuepausecommand",
833                                    "/usr/bin/disable '%p'");
834                         do_parameter("Queueresumecommand",
835                                    "/usr/bin/enable '%p'");
836                         do_parameter("Printcapname", "lpstat");
837 #endif /* HAVE_CUPS */
838                         break;
839
840                 case PRINT_SYSV:
841                 case PRINT_HPUX:
842                         do_parameter("Lpqcommand", "lpstat -o%p");
843                         do_parameter("Lprmcommand", "cancel %p-%j");
844                         do_parameter("Printcommand",
845                                    "lp -c -d%p %s; rm %s");
846                         do_parameter("Queuepausecommand",
847                                    "disable %p");
848                         do_parameter("Queueresumecommand",
849                                    "enable %p");
850 #ifndef HPUX
851                         do_parameter("Lppausecommand",
852                                    "lp -i %p-%j -H hold");
853                         do_parameter("Lpresumecommand",
854                                    "lp -i %p-%j -H resume");
855 #endif /* HPUX */
856                         break;
857
858                 case PRINT_QNX:
859                         do_parameter("Lpqcommand", "lpq -P%p");
860                         do_parameter("Lprmcommand", "lprm -P%p %j");
861                         do_parameter("Printcommand", "lp -r -P%p %s");
862                         break;
863
864                 case PRINT_SOFTQ:
865                         do_parameter("Lpqcommand", "qstat -l -d%p");
866                         do_parameter("Lprmcommand",
867                                    "qstat -s -j%j -c");
868                         do_parameter("Printcommand",
869                                    "lp -d%p -s %s; rm %s");
870                         do_parameter("Lppausecommand",
871                                    "qstat -s -j%j -h");
872                         do_parameter("Lpresumecommand",
873                                    "qstat -s -j%j -r");
874                         break;
875 #ifdef DEVELOPER
876         case PRINT_TEST:
877         case PRINT_VLP:
878                 do_parameter("Printcommand", "vlp print %p %s");
879                 do_parameter("Lpqcommand", "vlp lpq %p");
880                 do_parameter("Lprmcommand", "vlp lprm %p %j");
881                 do_parameter("Lppausecommand", "vlp lppause %p %j");
882                 do_parameter("Lpresumecommand", "vlp lpresum %p %j");
883                 do_parameter("Queuepausecommand", "vlp queuepause %p");
884                 do_parameter("Queueresumecommand", "vlp queueresume %p");
885                 break;
886 #endif /* DEVELOPER */
887
888         }
889 }
890
891
892 /***************************************************************************
893  Initialise the global parameter structure.
894 ***************************************************************************/
895 static void init_globals(void)
896 {
897         int i;
898         char *myname;
899
900         DEBUG(3, ("Initialising global parameters\n"));
901
902         for (i = 0; parm_table[i].label; i++) {
903                 if ((parm_table[i].type == P_STRING ||
904                      parm_table[i].type == P_USTRING) &&
905                     parm_table[i].ptr &&
906                     !(parm_table[i].flags & FLAG_CMDLINE)) {
907                         string_set(parm_table[i].ptr, "");
908                 }
909         }
910
911         /* options that can be set on the command line must be initialised via
912            the slower do_parameter() to ensure that FLAG_CMDLINE is obeyed */
913 #ifdef TCP_NODELAY
914         do_parameter("socket options", "TCP_NODELAY");
915 #endif
916         do_parameter("workgroup", DEFAULT_WORKGROUP);
917         myname = get_myname();
918         do_parameter("netbios name", myname);
919         SAFE_FREE(myname);
920         do_parameter("max protocol", "NT1");
921         do_parameter("name resolve order", "lmhosts wins host bcast");
922
923         init_printer_values();
924
925         do_parameter("fstype", FSTYPE_STRING);
926         do_parameter("ntvfs handler", "unixuid default");
927
928         do_parameter("dcerpc endpoint servers", "epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi winreg IOXIDResolver IRemoteActivation");
929         do_parameter("server services", "smb rpc");
930         do_parameter("auth methods", "anonymous sam_ignoredomain");
931         do_parameter("smb passwd file", dyn_SMB_PASSWD_FILE);
932         do_parameter("private dir", dyn_PRIVATE_DIR);
933         do_parameter_var("sam database", "tdb://%s/sam.ldb", dyn_PRIVATE_DIR);
934         do_parameter_var("spoolss database", "tdb://%s/spoolss.ldb", dyn_PRIVATE_DIR);
935         do_parameter("guest account", GUEST_ACCOUNT);
936
937         /* using UTF8 by default allows us to support all chars */
938         do_parameter("unix charset", "UTF8");
939
940         /* Use codepage 850 as a default for the dos character set */
941         do_parameter("dos charset", "CP850");
942
943         /*
944          * Allow the default PASSWD_CHAT to be overridden in local.h.
945          */
946         do_parameter("passwd chat", DEFAULT_PASSWD_CHAT);
947
948         do_parameter("passwd program", "");
949         do_parameter("printcap name", PRINTCAP_NAME);
950         
951         do_parameter("pid directory", dyn_PIDDIR);
952         do_parameter("lock dir", dyn_LOCKDIR);
953         do_parameter("ncalrpc dir", dyn_NCALRPCDIR);
954
955         do_parameter("socket address", "0.0.0.0");
956         do_parameter_var("server string", "Samba %s", SAMBA_VERSION_STRING);
957
958         do_parameter_var("announce version", "%d.%d", 
959                          DEFAULT_MAJOR_VERSION,
960                          DEFAULT_MINOR_VERSION);
961
962         do_parameter("logon drive", "");
963
964         do_parameter("logon home", "\\\\%N\\%U");
965         do_parameter("logon path", "\\\\%N\\%U\\profile");
966         do_parameter("password server", "*");
967
968         do_parameter("load printers", "True");
969
970         do_parameter("max mux", "50");
971         do_parameter("max xmit", "12288");
972         do_parameter("lpqcachetime", "10");
973         do_parameter("DisableSpoolss", "False");
974         do_parameter("password level", "0");
975         do_parameter("username level", "0");
976         do_parameter("LargeReadwrite", "True");
977         do_parameter("minprotocol", "CORE");
978         do_parameter("security", "USER");
979         do_parameter("paranoid server security", "True");
980         do_parameter("EncryptPasswords", "True");
981         do_parameter("ReadRaw", "True");
982         do_parameter("WriteRaw", "True");
983         do_parameter("NullPasswords", "False");
984         do_parameter("ObeyPamRestrictions", "False");
985         do_parameter("lm announce", "Auto");    
986         do_parameter("lm interval", "60");
987         do_parameter("announce as", "NT SERVER");
988
989         do_parameter("TimeServer", "False");
990         do_parameter("BindInterfacesOnly", "False");
991         do_parameter("PamPasswordChange", "False");
992         do_parameter("Unicode", "True");
993         do_parameter("restrict anonymous", "0");
994         do_parameter("ClientLanManAuth", "True");
995         do_parameter("LanmanAuth", "True");
996         do_parameter("NTLMAuth", "True");
997         
998         do_parameter("enhanced browsing", "True"); 
999         do_parameter("LockSpinCount", "3");
1000         do_parameter("LockSpinTime", "10");
1001 #ifdef MMAP_BLACKLIST
1002         do_parameter("UseMmap", "False");
1003 #else
1004         do_parameter("UseMmap", "True");
1005 #endif
1006         do_parameter("UnixExtensions", "False");
1007
1008         /* hostname lookups can be very expensive and are broken on
1009            a large number of sites (tridge) */
1010         do_parameter("HostnameLookups", "False");
1011
1012         do_parameter("PreferredMaster", "Auto");
1013         do_parameter("os level", "20");
1014         do_parameter("LocalMaster", "True");
1015         do_parameter("DomainMaster", "Auto");   /* depending on bDomainLogons */
1016         do_parameter("DomainLogons", "False");
1017         do_parameter("WINSsupport", "False");
1018         do_parameter("WINSproxy", "False");
1019
1020         do_parameter("DNSproxy", "True");
1021
1022         do_parameter("AllowTrustedDomains", "True");
1023
1024         do_parameter("TemplateShell", "/bin/false");
1025         do_parameter("TemplateHomedir", "/home/%D/%U");
1026         do_parameter("WinbindSeparator", "\\");
1027
1028         do_parameter("winbind cache time", "15");
1029         do_parameter("WinbindEnumUsers", "True");
1030         do_parameter("WinbindEnumGroups", "True");
1031         do_parameter("WinbindUseDefaultDomain", "False");
1032
1033         do_parameter("IDMapBackend", "tdb");
1034
1035         do_parameter("name cache timeout", "660"); /* In seconds */
1036
1037         do_parameter("client signing", "Yes");
1038         do_parameter("server signing", "auto");
1039
1040         do_parameter("use spnego", "True");
1041
1042         do_parameter("smb ports", SMB_PORTS);
1043
1044         do_parameter("nt status support", "True");
1045 }
1046
1047 static TALLOC_CTX *lp_talloc;
1048
1049 /******************************************************************* a
1050  Free up temporary memory - called from the main loop.
1051 ********************************************************************/
1052
1053 void lp_talloc_free(void)
1054 {
1055         if (!lp_talloc)
1056                 return;
1057         talloc_free(lp_talloc);
1058         lp_talloc = NULL;
1059 }
1060
1061 /*******************************************************************
1062  Convenience routine to grab string parameters into temporary memory
1063  and run standard_sub_basic on them. The buffers can be written to by
1064  callers without affecting the source string.
1065 ********************************************************************/
1066
1067 static const char *lp_string(const char *s)
1068 {
1069 #if 0  /* until REWRITE done to make thread-safe */
1070         size_t len = s ? strlen(s) : 0;
1071         char *ret;
1072 #endif
1073
1074         /* The follow debug is useful for tracking down memory problems
1075            especially if you have an inner loop that is calling a lp_*()
1076            function that returns a string.  Perhaps this debug should be
1077            present all the time? */
1078
1079 #if 0
1080         DEBUG(10, ("lp_string(%s)\n", s));
1081 #endif
1082
1083 #if 0  /* until REWRITE done to make thread-safe */
1084         if (!lp_talloc)
1085                 lp_talloc = talloc_init("lp_talloc");
1086
1087         ret = (char *)talloc(lp_talloc, len + 100);     /* leave room for substitution */
1088
1089         if (!ret)
1090                 return NULL;
1091
1092         if (!s)
1093                 *ret = 0;
1094         else
1095                 StrnCpy(ret, s, len);
1096
1097         if (trim_string(ret, "\"", "\"")) {
1098                 if (strchr(ret,'"') != NULL)
1099                         StrnCpy(ret, s, len);
1100         }
1101
1102         standard_sub_basic(ret,len+100);
1103         return (ret);
1104 #endif
1105         return s;
1106 }
1107
1108 /*
1109    In this section all the functions that are used to access the 
1110    parameters from the rest of the program are defined 
1111 */
1112
1113 #define FN_GLOBAL_STRING(fn_name,ptr) \
1114  const char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
1115 #define FN_GLOBAL_CONST_STRING(fn_name,ptr) \
1116  const char *fn_name(void) {return(*(const char **)(ptr) ? *(const char **)(ptr) : "");}
1117 #define FN_GLOBAL_LIST(fn_name,ptr) \
1118  const char **fn_name(void) {return(*(const char ***)(ptr));}
1119 #define FN_GLOBAL_BOOL(fn_name,ptr) \
1120  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
1121 #define FN_GLOBAL_CHAR(fn_name,ptr) \
1122  char fn_name(void) {return(*(char *)(ptr));}
1123 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
1124  int fn_name(void) {return(*(int *)(ptr));}
1125
1126 #define FN_LOCAL_STRING(fn_name,val) \
1127  const char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val));}
1128 #define FN_LOCAL_CONST_STRING(fn_name,val) \
1129  const char *fn_name(int i) {return (const char *)((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val);}
1130 #define FN_LOCAL_LIST(fn_name,val) \
1131  const char **fn_name(int i) {return(const char **)(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1132 #define FN_LOCAL_BOOL(fn_name,val) \
1133  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1134 #define FN_LOCAL_CHAR(fn_name,val) \
1135  char fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1136 #define FN_LOCAL_INTEGER(fn_name,val) \
1137  int fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1138
1139 FN_GLOBAL_LIST(lp_smb_ports, &Globals.smb_ports)
1140 FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
1141 FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
1142 FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)
1143 FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)
1144 FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
1145 FN_GLOBAL_STRING(lp_smb_passwd_file, &Globals.szSMBPasswdFile)
1146 FN_GLOBAL_STRING(lp_sam_url, &Globals.szSAM_URL)
1147 FN_GLOBAL_STRING(lp_spoolss_url, &Globals.szSPOOLSS_URL)
1148 FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir)
1149 FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
1150 FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname)
1151 FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
1152 FN_GLOBAL_STRING(lp_ncalrpc_dir, &Globals.ncalrpc_dir)
1153 FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir)
1154 FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers)
1155 FN_GLOBAL_LIST(lp_server_services, &Globals.server_services)
1156 FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir)
1157 FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
1158 FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv)
1159 FN_GLOBAL_STRING(lp_auto_services, &Globals.szAutoServices)
1160 FN_GLOBAL_STRING(lp_passwd_program, &Globals.szPasswdProgram)
1161 FN_GLOBAL_STRING(lp_passwd_chat, &Globals.szPasswdChat)
1162 FN_GLOBAL_STRING(lp_passwordserver, &Globals.szPasswordServer)
1163 FN_GLOBAL_STRING(lp_name_resolve_order, &Globals.szNameResolveOrder)
1164 FN_GLOBAL_STRING(lp_realm, &Globals.szRealm)
1165 FN_GLOBAL_STRING(lp_ads_server, &Globals.szADSserver)
1166 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
1167 FN_GLOBAL_STRING(lp_workgroup, &Globals.szWorkgroup)
1168 FN_GLOBAL_STRING(lp_netbios_name, &Globals.szNetbiosName)
1169 FN_GLOBAL_STRING(lp_netbios_scope, &Globals.szNetbiosScope)
1170 FN_GLOBAL_CONST_STRING(lp_logon_script, &Globals.szLogonScript)
1171 FN_GLOBAL_CONST_STRING(lp_logon_path, &Globals.szLogonPath)
1172 FN_GLOBAL_CONST_STRING(lp_logon_drive, &Globals.szLogonDrive)
1173 FN_GLOBAL_CONST_STRING(lp_logon_home, &Globals.szLogonHome)
1174 FN_GLOBAL_STRING(lp_remote_announce, &Globals.szRemoteAnnounce)
1175 FN_GLOBAL_STRING(lp_remote_browse_sync, &Globals.szRemoteBrowseSync)
1176 FN_GLOBAL_LIST(lp_wins_server_list, &Globals.szWINSservers)
1177 FN_GLOBAL_LIST(lp_interfaces, &Globals.szInterfaces)
1178 FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
1179 FN_GLOBAL_LIST(lp_netbios_aliases, &Globals.szNetbiosAliases)
1180 FN_GLOBAL_LIST(lp_preload_modules, &Globals.szPreloadModules)
1181 FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction)
1182 FN_GLOBAL_STRING(lp_adduser_script, &Globals.szAddUserScript)
1183
1184 FN_GLOBAL_CONST_STRING(lp_guestaccount, &Globals.szGuestaccount)
1185
1186 FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript)
1187
1188 FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
1189 FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners)
1190 FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
1191 FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell)
1192 FN_GLOBAL_CONST_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
1193 FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
1194 FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
1195 FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
1196 FN_GLOBAL_STRING(lp_idmap_backend, &Globals.szIDMapBackend)
1197
1198 FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios)
1199 FN_GLOBAL_BOOL(lp_dns_proxy, &Globals.bDNSproxy)
1200 FN_GLOBAL_BOOL(lp_wins_support, &Globals.bWINSsupport)
1201 FN_GLOBAL_BOOL(lp_we_are_a_wins_server, &Globals.bWINSsupport)
1202 FN_GLOBAL_BOOL(lp_wins_proxy, &Globals.bWINSproxy)
1203 FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster)
1204 FN_GLOBAL_BOOL(lp_domain_logons, &Globals.bDomainLogons)
1205 FN_GLOBAL_BOOL(lp_load_printers, &Globals.bLoadPrinters)
1206 FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw)
1207 FN_GLOBAL_BOOL(lp_large_readwrite, &Globals.bLargeReadwrite)
1208 FN_GLOBAL_BOOL(lp_writeraw, &Globals.bWriteRaw)
1209 FN_GLOBAL_BOOL(lp_null_passwords, &Globals.bNullPasswords)
1210 FN_GLOBAL_BOOL(lp_obey_pam_restrictions, &Globals.bObeyPamRestrictions)
1211 FN_GLOBAL_BOOL(lp_encrypted_passwords, &Globals.bEncryptPasswords)
1212 static FN_GLOBAL_BOOL(lp_time_server, &Globals.bTimeServer)
1213 FN_GLOBAL_BOOL(lp_bind_interfaces_only, &Globals.bBindInterfacesOnly)
1214 FN_GLOBAL_BOOL(lp_pam_password_change, &Globals.bPamPasswordChange)
1215 FN_GLOBAL_BOOL(lp_unicode, &Globals.bUnicode)
1216 FN_GLOBAL_BOOL(lp_nt_status_support, &Globals.bNTStatusSupport)
1217 FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)
1218 FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous)
1219 FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
1220 FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
1221 FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
1222 FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
1223 FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
1224 FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing)
1225 FN_GLOBAL_BOOL(lp_use_mmap, &Globals.bUseMmap)
1226 FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions)
1227 FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
1228 FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
1229 FN_GLOBAL_BOOL(lp_rpc_big_endian, &Globals.bRpcBigEndian)
1230 FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
1231 FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
1232 FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
1233 FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.min_wins_ttl)
1234 FN_GLOBAL_INTEGER(lp_time_offset, &Globals.time_offset)
1235 FN_GLOBAL_INTEGER(lp_maxmux, &Globals.max_mux)
1236 FN_GLOBAL_INTEGER(lp_max_xmit, &Globals.max_xmit)
1237 FN_GLOBAL_INTEGER(lp_passwordlevel, &Globals.pwordlevel)
1238 FN_GLOBAL_INTEGER(lp_usernamelevel, &Globals.unamelevel)
1239 FN_GLOBAL_INTEGER(lp_maxprotocol, &Globals.maxprotocol)
1240 FN_GLOBAL_INTEGER(lp_minprotocol, &Globals.minprotocol)
1241 FN_GLOBAL_INTEGER(lp_security, &Globals.security)
1242 FN_GLOBAL_LIST(lp_auth_methods, &Globals.AuthMethods)
1243 FN_GLOBAL_BOOL(lp_paranoid_server_security, &Globals.paranoid_server_security)
1244 FN_GLOBAL_INTEGER(lp_lpqcachetime, &Globals.lpqcachetime)
1245 FN_GLOBAL_INTEGER(lp_disable_spoolss, &Globals.bDisableSpoolss)
1246 static FN_GLOBAL_INTEGER(lp_announce_as, &Globals.announce_as)
1247 FN_GLOBAL_INTEGER(lp_lm_announce, &Globals.lm_announce)
1248 FN_GLOBAL_INTEGER(lp_lm_interval, &Globals.lm_interval)
1249 FN_GLOBAL_INTEGER(lp_machine_password_timeout, &Globals.machine_password_timeout)
1250 FN_GLOBAL_INTEGER(lp_lock_spin_count, &Globals.iLockSpinCount)
1251 FN_GLOBAL_INTEGER(lp_lock_sleep_time, &Globals.iLockSpinTime)
1252 FN_LOCAL_STRING(lp_servicename, szService)
1253 FN_LOCAL_CONST_STRING(lp_const_servicename, szService)
1254 FN_LOCAL_STRING(lp_pathname, szPath)
1255 FN_LOCAL_STRING(lp_username, szUsername)
1256 FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers)
1257 FN_LOCAL_LIST(lp_valid_users, szValidUsers)
1258 FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
1259 FN_LOCAL_STRING(lp_printcommand, szPrintcommand)
1260 FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand)
1261 FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand)
1262 FN_LOCAL_STRING(lp_lppausecommand, szLppausecommand)
1263 FN_LOCAL_STRING(lp_lpresumecommand, szLpresumecommand)
1264 FN_LOCAL_STRING(lp_queuepausecommand, szQueuepausecommand)
1265 FN_LOCAL_STRING(lp_queueresumecommand, szQueueresumecommand)
1266 static FN_LOCAL_STRING(_lp_printername, szPrintername)
1267 FN_LOCAL_LIST(lp_hostsallow, szHostsallow)
1268 FN_LOCAL_LIST(lp_hostsdeny, szHostsdeny)
1269 FN_LOCAL_STRING(lp_comment, comment)
1270 FN_LOCAL_STRING(lp_fstype, fstype)
1271 FN_LOCAL_STRING(lp_msdfs_proxy, szMSDfsProxy)
1272 static FN_LOCAL_STRING(lp_volume, volume)
1273 FN_LOCAL_LIST(lp_ntvfs_handler, ntvfs_handler)
1274 FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
1275 FN_LOCAL_BOOL(lp_autoloaded, autoloaded)
1276 FN_LOCAL_BOOL(lp_browseable, bBrowseable)
1277 FN_LOCAL_BOOL(lp_readonly, bRead_only)
1278 FN_LOCAL_BOOL(lp_guest_ok, bGuest_ok)
1279 FN_LOCAL_BOOL(lp_guest_only, bGuest_only)
1280 FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
1281 FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
1282 FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
1283 FN_LOCAL_BOOL(lp_locking, bLocking)
1284 FN_LOCAL_BOOL(lp_strict_locking, bStrictLocking)
1285 FN_LOCAL_BOOL(lp_posix_locking, bPosixLocking)
1286 FN_LOCAL_BOOL(lp_strict_sync, bStrictSync)
1287 FN_LOCAL_BOOL(lp_ci_filesystem, bCIFileSystem)
1288 FN_LOCAL_BOOL(lp_share_modes, bShareModes)
1289 FN_LOCAL_BOOL(lp_oplocks, bOpLocks)
1290 FN_LOCAL_BOOL(lp_level2_oplocks, bLevel2OpLocks)
1291 FN_LOCAL_BOOL(lp_onlyuser, bOnlyUser)
1292 FN_LOCAL_BOOL(lp_map_system, bMap_system)
1293 FN_LOCAL_INTEGER(lp_max_connections, iMaxConnections)
1294 FN_LOCAL_INTEGER(lp_minprintspace, iMinPrintSpace)
1295 FN_LOCAL_INTEGER(lp_printing, iPrinting)
1296 FN_LOCAL_INTEGER(lp_csc_policy, iCSCPolicy)
1297 FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
1298 FN_GLOBAL_BOOL(lp_hide_local_users, &Globals.bHideLocalUsers)
1299 FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
1300 FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
1301 FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
1302
1303 /* local prototypes */
1304
1305 static int map_parameter(const char *pszParmName);
1306 static BOOL set_boolean(BOOL *pb, const char *pszParmValue);
1307 static int getservicebyname(const char *pszServiceName,
1308                             service * pserviceDest);
1309 static void copy_service(service * pserviceDest,
1310                          service * pserviceSource, BOOL *pcopymapDest);
1311 static BOOL service_ok(int iService);
1312 static BOOL do_section(const char *pszSectionName);
1313 static void init_copymap(service * pservice);
1314
1315 /* This is a helper function for parametrical options support. */
1316 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
1317 /* Actual parametrical functions are quite simple */
1318 static const char *get_parametrics(int lookup_service, const char *type, const char *option)
1319 {
1320         char *vfskey;
1321         struct param_opt *data;
1322         
1323         if (lookup_service >= iNumServices) return NULL;
1324         
1325         data = (lookup_service < 0) ? 
1326                 Globals.param_opt : ServicePtrs[lookup_service]->param_opt;
1327     
1328         asprintf(&vfskey, "%s:%s", type, option);
1329         strlower(vfskey);
1330
1331         while (data) {
1332                 if (strcmp(data->key, vfskey) == 0) {
1333                         free(vfskey);
1334                         return data->value;
1335                 }
1336                 data = data->next;
1337         }
1338
1339         if (lookup_service >= 0) {
1340                 /* Try to fetch the same option but from globals */
1341                 /* but only if we are not already working with Globals */
1342                 data = Globals.param_opt;
1343                 while (data) {
1344                         if (strcmp(data->key, vfskey) == 0) {
1345                                 free(vfskey);
1346                                 return data->value;
1347                         }
1348                         data = data->next;
1349                 }
1350         }
1351
1352         free(vfskey);
1353         
1354         return NULL;
1355 }
1356
1357
1358 /*******************************************************************
1359 convenience routine to return int parameters.
1360 ********************************************************************/
1361 static int lp_int(const char *s)
1362 {
1363
1364         if (!s) {
1365                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
1366                 return (-1);
1367         }
1368
1369         return atoi(s); 
1370 }
1371
1372 /*******************************************************************
1373 convenience routine to return unsigned long parameters.
1374 ********************************************************************/
1375 static int lp_ulong(const char *s)
1376 {
1377
1378         if (!s) {
1379                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
1380                 return (-1);
1381         }
1382
1383         return strtoul(s, NULL, 10);
1384 }
1385
1386 /*******************************************************************
1387 convenience routine to return boolean parameters.
1388 ********************************************************************/
1389 static BOOL lp_bool(const char *s)
1390 {
1391         BOOL ret = False;
1392
1393         if (!s) {
1394                 DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
1395                 return False;
1396         }
1397         
1398         if (!set_boolean(&ret,s)) {
1399                 DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
1400                 return False;
1401         }
1402
1403         return ret;
1404 }
1405
1406
1407 /* Return parametric option from a given service. Type is a part of option before ':' */
1408 /* Parametric option has following syntax: 'Type: option = value' */
1409 /* Returned value is allocated in 'lp_talloc' context */
1410
1411 const char *lp_parm_string(int lookup_service, const char *type, const char *option)
1412 {
1413         const char *value = get_parametrics(lookup_service, type, option);
1414         
1415         if (value)
1416                 return lp_string(value);
1417
1418         return NULL;
1419 }
1420
1421 /* Return parametric option from a given service. Type is a part of option before ':' */
1422 /* Parametric option has following syntax: 'Type: option = value' */
1423 /* Returned value is allocated in 'lp_talloc' context */
1424
1425 char **lp_parm_string_list(int lookup_service, const char *type, const char *option,
1426                            const char *separator)
1427 {
1428         const char *value = get_parametrics(lookup_service, type, option);
1429         
1430         if (value)
1431                 return str_list_make(value, separator);
1432
1433         return NULL;
1434 }
1435
1436 /* Return parametric option from a given service. Type is a part of option before ':' */
1437 /* Parametric option has following syntax: 'Type: option = value' */
1438
1439 int lp_parm_int(int lookup_service, const char *type, const char *option)
1440 {
1441         const char *value = get_parametrics(lookup_service, type, option);
1442         
1443         if (value)
1444                 return lp_int(value);
1445
1446         return (-1);
1447 }
1448
1449 /* Return parametric option from a given service. Type is a part of option before ':' */
1450 /* Parametric option has following syntax: 'Type: option = value' */
1451
1452 unsigned long lp_parm_ulong(int lookup_service, const char *type, const char *option)
1453 {
1454         const char *value = get_parametrics(lookup_service, type, option);
1455         
1456         if (value)
1457                 return lp_ulong(value);
1458
1459         return (0);
1460 }
1461
1462 /* Return parametric option from a given service. Type is a part of option before ':' */
1463 /* Parametric option has following syntax: 'Type: option = value' */
1464
1465 BOOL lp_parm_bool(int lookup_service, const char *type, const char *option, BOOL default_v)
1466 {
1467         const char *value = get_parametrics(lookup_service, type, option);
1468         
1469         if (value)
1470                 return lp_bool(value);
1471
1472         return default_v;
1473 }
1474
1475
1476 /***************************************************************************
1477  Initialise a service to the defaults.
1478 ***************************************************************************/
1479
1480 static void init_service(service * pservice)
1481 {
1482         memset((char *)pservice, '\0', sizeof(service));
1483         copy_service(pservice, &sDefault, NULL);
1484 }
1485
1486 /***************************************************************************
1487  Free the dynamically allocated parts of a service struct.
1488 ***************************************************************************/
1489
1490 static void free_service(service *pservice)
1491 {
1492         int i;
1493         struct param_opt *data, *pdata;
1494         if (!pservice)
1495                 return;
1496
1497         if (pservice->szService)
1498                 DEBUG(5, ("free_service: Freeing service %s\n",
1499                        pservice->szService));
1500
1501         string_free(&pservice->szService);
1502         SAFE_FREE(pservice->copymap);
1503
1504         for (i = 0; parm_table[i].label; i++) {
1505                 if ((parm_table[i].type == P_STRING ||
1506                      parm_table[i].type == P_USTRING) &&
1507                     parm_table[i].class == P_LOCAL)
1508                         string_free((char **)
1509                                     (((char *)pservice) +
1510                                      PTR_DIFF(parm_table[i].ptr, &sDefault)));
1511                 else if (parm_table[i].type == P_LIST &&
1512                          parm_table[i].class == P_LOCAL)
1513                              str_list_free((char ***)
1514                                             (((char *)pservice) +
1515                                              PTR_DIFF(parm_table[i].ptr, &sDefault)));
1516         }
1517                                 
1518         DEBUG(5,("Freeing parametrics:\n"));
1519         data = pservice->param_opt;
1520         while (data) {
1521                 DEBUG(5,("[%s = %s]\n", data->key, data->value));
1522                 string_free(&data->key);
1523                 string_free(&data->value);
1524                 pdata = data->next;
1525                 SAFE_FREE(data);
1526                 data = pdata;
1527         }
1528
1529         ZERO_STRUCTP(pservice);
1530 }
1531
1532 /***************************************************************************
1533  Add a new service to the services array initialising it with the given 
1534  service. 
1535 ***************************************************************************/
1536
1537 static int add_a_service(const service *pservice, const char *name)
1538 {
1539         int i;
1540         service tservice;
1541         int num_to_alloc = iNumServices + 1;
1542         struct param_opt *data, *pdata;
1543
1544         tservice = *pservice;
1545
1546         /* it might already exist */
1547         if (name) {
1548                 i = getservicebyname(name, NULL);
1549                 if (i >= 0) {
1550                         /* Clean all parametric options for service */
1551                         /* They will be added during parsing again */
1552                         data = ServicePtrs[i]->param_opt;
1553                         while (data) {
1554                                 string_free(&data->key);
1555                                 string_free(&data->value);
1556                                 pdata = data->next;
1557                                 SAFE_FREE(data);
1558                                 data = pdata;
1559                         }
1560                         ServicePtrs[i]->param_opt = NULL;
1561                         return (i);
1562                 }
1563         }
1564
1565         /* find an invalid one */
1566         for (i = 0; i < iNumServices; i++)
1567                 if (!ServicePtrs[i]->valid)
1568                         break;
1569
1570         /* if not, then create one */
1571         if (i == iNumServices) {
1572                 service **tsp;
1573                 
1574                 tsp = realloc_p(ServicePtrs, service *, num_to_alloc);
1575                                            
1576                 if (!tsp) {
1577                         DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
1578                         return (-1);
1579                 }
1580                 else {
1581                         ServicePtrs = tsp;
1582                         ServicePtrs[iNumServices] = malloc_p(service);
1583                 }
1584                 if (!ServicePtrs[iNumServices]) {
1585                         DEBUG(0,("add_a_service: out of memory!\n"));
1586                         return (-1);
1587                 }
1588
1589                 iNumServices++;
1590         } else
1591                 free_service(ServicePtrs[i]);
1592
1593         ServicePtrs[i]->valid = True;
1594
1595         init_service(ServicePtrs[i]);
1596         copy_service(ServicePtrs[i], &tservice, NULL);
1597         if (name)
1598                 string_set(&ServicePtrs[i]->szService, name);
1599         return (i);
1600 }
1601
1602 /***************************************************************************
1603  Add a new home service, with the specified home directory, defaults coming 
1604  from service ifrom.
1605 ***************************************************************************/
1606
1607 BOOL lp_add_home(const char *pszHomename, int iDefaultService, 
1608                  const char *user, const char *pszHomedir)
1609 {
1610         int i;
1611         pstring newHomedir;
1612
1613         i = add_a_service(ServicePtrs[iDefaultService], pszHomename);
1614
1615         if (i < 0)
1616                 return (False);
1617
1618         if (!(*(ServicePtrs[iDefaultService]->szPath))
1619             || strequal(ServicePtrs[iDefaultService]->szPath, lp_pathname(-1))) {
1620                 pstrcpy(newHomedir, pszHomedir);
1621         } else {
1622                 pstrcpy(newHomedir, lp_pathname(iDefaultService));
1623                 string_sub(newHomedir,"%H", pszHomedir, sizeof(newHomedir)); 
1624         }
1625
1626         string_set(&ServicePtrs[i]->szPath, newHomedir);
1627
1628         if (!(*(ServicePtrs[i]->comment))) {
1629                 pstring comment;
1630                 slprintf(comment, sizeof(comment) - 1,
1631                          "Home directory of %s", user);
1632                 string_set(&ServicePtrs[i]->comment, comment);
1633         }
1634         ServicePtrs[i]->bAvailable = sDefault.bAvailable;
1635         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1636
1637         DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename, 
1638                user, newHomedir));
1639         
1640         return (True);
1641 }
1642
1643 /***************************************************************************
1644  Add a new service, based on an old one.
1645 ***************************************************************************/
1646
1647 int lp_add_service(const char *pszService, int iDefaultService)
1648 {
1649         return (add_a_service(ServicePtrs[iDefaultService], pszService));
1650 }
1651
1652 /***************************************************************************
1653  Add the IPC service.
1654 ***************************************************************************/
1655
1656 static BOOL lp_add_ipc(const char *ipc_name, BOOL guest_ok)
1657 {
1658         pstring comment;
1659         int i = add_a_service(&sDefault, ipc_name);
1660
1661         if (i < 0)
1662                 return (False);
1663
1664         slprintf(comment, sizeof(comment) - 1,
1665                  "IPC Service (%s)", Globals.szServerString);
1666
1667         string_set(&ServicePtrs[i]->szPath, tmpdir());
1668         string_set(&ServicePtrs[i]->szUsername, "");
1669         string_set(&ServicePtrs[i]->comment, comment);
1670         string_set(&ServicePtrs[i]->fstype, "IPC");
1671         ServicePtrs[i]->iMaxConnections = 0;
1672         ServicePtrs[i]->bAvailable = True;
1673         ServicePtrs[i]->bRead_only = True;
1674         ServicePtrs[i]->bGuest_only = False;
1675         ServicePtrs[i]->bGuest_ok = guest_ok;
1676         ServicePtrs[i]->bPrint_ok = False;
1677         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1678
1679         lp_do_parameter(i, "ntvfs handler", "default");
1680
1681         DEBUG(3, ("adding IPC service\n"));
1682
1683         return (True);
1684 }
1685
1686 /***************************************************************************
1687  Add a new printer service, with defaults coming from service iFrom.
1688 ***************************************************************************/
1689
1690 BOOL lp_add_printer(const char *pszPrintername, int iDefaultService)
1691 {
1692         const char *comment = "From Printcap";
1693         int i = add_a_service(ServicePtrs[iDefaultService], pszPrintername);
1694
1695         if (i < 0)
1696                 return (False);
1697
1698         /* note that we do NOT default the availability flag to True - */
1699         /* we take it from the default service passed. This allows all */
1700         /* dynamic printers to be disabled by disabling the [printers] */
1701         /* entry (if/when the 'available' keyword is implemented!).    */
1702
1703         /* the printer name is set to the service name. */
1704         string_set(&ServicePtrs[i]->szPrintername, pszPrintername);
1705         string_set(&ServicePtrs[i]->comment, comment);
1706         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1707         /* Printers cannot be read_only. */
1708         ServicePtrs[i]->bRead_only = False;
1709         /* No share modes on printer services. */
1710         ServicePtrs[i]->bShareModes = False;
1711         /* No oplocks on printer services. */
1712         ServicePtrs[i]->bOpLocks = False;
1713         /* Printer services must be printable. */
1714         ServicePtrs[i]->bPrint_ok = True;
1715
1716         DEBUG(3, ("adding printer service %s\n", pszPrintername));
1717
1718         update_server_announce_as_printserver();
1719
1720         return (True);
1721 }
1722
1723 /***************************************************************************
1724  Map a parameter's string representation to something we can use. 
1725  Returns False if the parameter string is not recognised, else TRUE.
1726 ***************************************************************************/
1727
1728 static int map_parameter(const char *pszParmName)
1729 {
1730         int iIndex;
1731
1732         if (*pszParmName == '-')
1733                 return (-1);
1734
1735         for (iIndex = 0; parm_table[iIndex].label; iIndex++)
1736                 if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1737                         return (iIndex);
1738
1739         /* Warn only if it isn't parametric option */
1740         if (strchr(pszParmName, ':') == NULL)
1741                 DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
1742         /* We do return 'fail' for parametric options as well because they are
1743            stored in different storage
1744          */
1745         return (-1);
1746 }
1747
1748 /***************************************************************************
1749  Set a boolean variable from the text value stored in the passed string.
1750  Returns True in success, False if the passed string does not correctly 
1751  represent a boolean.
1752 ***************************************************************************/
1753
1754 static BOOL set_boolean(BOOL *pb, const char *pszParmValue)
1755 {
1756         BOOL bRetval;
1757
1758         bRetval = True;
1759         if (strwicmp(pszParmValue, "yes") == 0 ||
1760             strwicmp(pszParmValue, "true") == 0 ||
1761             strwicmp(pszParmValue, "1") == 0)
1762                 *pb = True;
1763         else if (strwicmp(pszParmValue, "no") == 0 ||
1764                     strwicmp(pszParmValue, "False") == 0 ||
1765                     strwicmp(pszParmValue, "0") == 0)
1766                 *pb = False;
1767         else {
1768                 DEBUG(0,
1769                       ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
1770                        pszParmValue));
1771                 bRetval = False;
1772         }
1773         return (bRetval);
1774 }
1775
1776 /***************************************************************************
1777 Find a service by name. Otherwise works like get_service.
1778 ***************************************************************************/
1779
1780 static int getservicebyname(const char *pszServiceName, service * pserviceDest)
1781 {
1782         int iService;
1783
1784         for (iService = iNumServices - 1; iService >= 0; iService--)
1785                 if (VALID(iService) &&
1786                     strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0) {
1787                         if (pserviceDest != NULL)
1788                                 copy_service(pserviceDest, ServicePtrs[iService], NULL);
1789                         break;
1790                 }
1791
1792         return (iService);
1793 }
1794
1795 /***************************************************************************
1796  Copy a service structure to another.
1797  If pcopymapDest is NULL then copy all fields
1798 ***************************************************************************/
1799
1800 static void copy_service(service * pserviceDest, service * pserviceSource, BOOL *pcopymapDest)
1801 {
1802         int i;
1803         BOOL bcopyall = (pcopymapDest == NULL);
1804         struct param_opt *data, *pdata, *paramo;
1805         BOOL not_added;
1806
1807         for (i = 0; parm_table[i].label; i++)
1808                 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL &&
1809                     (bcopyall || pcopymapDest[i])) {
1810                         void *def_ptr = parm_table[i].ptr;
1811                         void *src_ptr =
1812                                 ((char *)pserviceSource) + PTR_DIFF(def_ptr,
1813                                                                     &sDefault);
1814                         void *dest_ptr =
1815                                 ((char *)pserviceDest) + PTR_DIFF(def_ptr,
1816                                                                   &sDefault);
1817
1818                         switch (parm_table[i].type) {
1819                                 case P_BOOL:
1820                                 case P_BOOLREV:
1821                                         *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1822                                         break;
1823
1824                                 case P_INTEGER:
1825                                 case P_ENUM:
1826                                 case P_OCTAL:
1827                                         *(int *)dest_ptr = *(int *)src_ptr;
1828                                         break;
1829
1830                                 case P_CHAR:
1831                                         *(char *)dest_ptr = *(char *)src_ptr;
1832                                         break;
1833
1834                                 case P_STRING:
1835                                         string_set(dest_ptr,
1836                                                    *(char **)src_ptr);
1837                                         break;
1838
1839                                 case P_USTRING:
1840                                         string_set(dest_ptr,
1841                                                    *(char **)src_ptr);
1842                                         strupper(*(char **)dest_ptr);
1843                                         break;
1844                                 case P_LIST:
1845                                         str_list_copy((char ***)dest_ptr, *(const char ***)src_ptr);
1846                                         break;
1847                                 default:
1848                                         break;
1849                         }
1850                 }
1851
1852         if (bcopyall) {
1853                 init_copymap(pserviceDest);
1854                 if (pserviceSource->copymap)
1855                         memcpy((void *)pserviceDest->copymap,
1856                                (void *)pserviceSource->copymap,
1857                                sizeof(BOOL) * NUMPARAMETERS);
1858         }
1859         
1860         data = pserviceSource->param_opt;
1861         while (data) {
1862                 not_added = True;
1863                 pdata = pserviceDest->param_opt;
1864                 /* Traverse destination */
1865                 while (pdata) {
1866                         /* If we already have same option, override it */
1867                         if (strcmp(pdata->key, data->key) == 0) {
1868                                 string_free(&pdata->value);
1869                                 pdata->value = strdup(data->value);
1870                                 not_added = False;
1871                                 break;
1872                         }
1873                         pdata = pdata->next;
1874                 }
1875                 if (not_added) {
1876                         paramo = smb_xmalloc_p(struct param_opt);
1877                         paramo->key = strdup(data->key);
1878                         paramo->value = strdup(data->value);
1879                         DLIST_ADD(pserviceDest->param_opt, paramo);
1880                 }
1881                 data = data->next;
1882         }
1883 }
1884
1885 /***************************************************************************
1886 Check a service for consistency. Return False if the service is in any way
1887 incomplete or faulty, else True.
1888 ***************************************************************************/
1889
1890 static BOOL service_ok(int iService)
1891 {
1892         BOOL bRetval;
1893
1894         bRetval = True;
1895         if (ServicePtrs[iService]->szService[0] == '\0') {
1896                 DEBUG(0, ("The following message indicates an internal error:\n"));
1897                 DEBUG(0, ("No service name in service entry.\n"));
1898                 bRetval = False;
1899         }
1900
1901         /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1902         /* I can't see why you'd want a non-printable printer service...        */
1903         if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
1904                 if (!ServicePtrs[iService]->bPrint_ok) {
1905                         DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
1906                                ServicePtrs[iService]->szService));
1907                         ServicePtrs[iService]->bPrint_ok = True;
1908                 }
1909                 /* [printers] service must also be non-browsable. */
1910                 if (ServicePtrs[iService]->bBrowseable)
1911                         ServicePtrs[iService]->bBrowseable = False;
1912         }
1913
1914         /* If a service is flagged unavailable, log the fact at level 0. */
1915         if (!ServicePtrs[iService]->bAvailable)
1916                 DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
1917                           ServicePtrs[iService]->szService));
1918
1919         return (bRetval);
1920 }
1921
1922 static struct file_lists {
1923         struct file_lists *next;
1924         char *name;
1925         char *subfname;
1926         time_t modtime;
1927 } *file_lists = NULL;
1928
1929 /*******************************************************************
1930  Keep a linked list of all config files so we know when one has changed 
1931  it's date and needs to be reloaded.
1932 ********************************************************************/
1933
1934 static void add_to_file_list(const char *fname, const char *subfname)
1935 {
1936         struct file_lists *f = file_lists;
1937
1938         while (f) {
1939                 if (f->name && !strcmp(f->name, fname))
1940                         break;
1941                 f = f->next;
1942         }
1943
1944         if (!f) {
1945                 f = malloc_p(struct file_lists);
1946                 if (!f)
1947                         return;
1948                 f->next = file_lists;
1949                 f->name = strdup(fname);
1950                 if (!f->name) {
1951                         SAFE_FREE(f);
1952                         return;
1953                 }
1954                 f->subfname = strdup(subfname);
1955                 if (!f->subfname) {
1956                         SAFE_FREE(f);
1957                         return;
1958                 }
1959                 file_lists = f;
1960                 f->modtime = file_modtime(subfname);
1961         } else {
1962                 time_t t = file_modtime(subfname);
1963                 if (t)
1964                         f->modtime = t;
1965         }
1966 }
1967
1968 /*******************************************************************
1969  Check if a config file has changed date.
1970 ********************************************************************/
1971
1972 BOOL lp_file_list_changed(void)
1973 {
1974         struct file_lists *f = file_lists;
1975         DEBUG(6, ("lp_file_list_changed()\n"));
1976
1977         while (f) {
1978                 pstring n2;
1979                 time_t mod_time;
1980
1981                 pstrcpy(n2, f->name);
1982                 standard_sub_basic(n2,sizeof(n2));
1983
1984                 DEBUGADD(6, ("file %s -> %s  last mod_time: %s\n",
1985                              f->name, n2, ctime(&f->modtime)));
1986
1987                 mod_time = file_modtime(n2);
1988
1989                 if (mod_time && ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))) {
1990                         DEBUGADD(6,
1991                                  ("file %s modified: %s\n", n2,
1992                                   ctime(&mod_time)));
1993                         f->modtime = mod_time;
1994                         SAFE_FREE(f->subfname);
1995                         f->subfname = strdup(n2);
1996                         return (True);
1997                 }
1998                 f = f->next;
1999         }
2000         return (False);
2001 }
2002
2003 /***************************************************************************
2004  Handle the include operation.
2005 ***************************************************************************/
2006
2007 static BOOL handle_include(const char *pszParmValue, char **ptr)
2008 {
2009         pstring fname;
2010         pstrcpy(fname, pszParmValue);
2011
2012         standard_sub_basic(fname,sizeof(fname));
2013
2014         add_to_file_list(pszParmValue, fname);
2015
2016         string_set(ptr, fname);
2017
2018         if (file_exist(fname, NULL))
2019                 return (pm_process(fname, do_section, do_parameter));
2020
2021         DEBUG(2, ("Can't find include file %s\n", fname));
2022
2023         return (False);
2024 }
2025
2026 /***************************************************************************
2027  Handle the interpretation of the copy parameter.
2028 ***************************************************************************/
2029
2030 static BOOL handle_copy(const char *pszParmValue, char **ptr)
2031 {
2032         BOOL bRetval;
2033         int iTemp;
2034         service serviceTemp;
2035
2036         string_set(ptr, pszParmValue);
2037
2038         init_service(&serviceTemp);
2039
2040         bRetval = False;
2041
2042         DEBUG(3, ("Copying service from service %s\n", pszParmValue));
2043
2044         if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0) {
2045                 if (iTemp == iServiceIndex) {
2046                         DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
2047                 } else {
2048                         copy_service(ServicePtrs[iServiceIndex],
2049                                      &serviceTemp,
2050                                      ServicePtrs[iServiceIndex]->copymap);
2051                         bRetval = True;
2052                 }
2053         } else {
2054                 DEBUG(0, ("Unable to copy service - source not found: %s\n", pszParmValue));
2055                 bRetval = False;
2056         }
2057
2058         free_service(&serviceTemp);
2059         return (bRetval);
2060 }
2061
2062 /***************************************************************************
2063  Handle winbind/non unix account uid and gid allocation parameters.  The format of these
2064  parameters is:
2065
2066  [global]
2067
2068         winbind uid = 1000-1999
2069         winbind gid = 700-899
2070
2071  We only do simple parsing checks here.  The strings are parsed into useful
2072  structures in the winbind daemon code.
2073
2074 ***************************************************************************/
2075
2076 /* Some lp_ routines to return winbind [ug]id information */
2077
2078 static uid_t winbind_uid_low, winbind_uid_high;
2079 static gid_t winbind_gid_low, winbind_gid_high;
2080 static uint32_t non_unix_account_low, non_unix_account_high;
2081
2082 BOOL lp_winbind_uid(uid_t *low, uid_t *high)
2083 {
2084         if (winbind_uid_low == 0 || winbind_uid_high == 0)
2085                 return False;
2086
2087         if (low)
2088                 *low = winbind_uid_low;
2089
2090         if (high)
2091                 *high = winbind_uid_high;
2092
2093         return True;
2094 }
2095
2096 BOOL lp_winbind_gid(gid_t *low, gid_t *high)
2097 {
2098         if (winbind_gid_low == 0 || winbind_gid_high == 0)
2099                 return False;
2100
2101         if (low)
2102                 *low = winbind_gid_low;
2103
2104         if (high)
2105                 *high = winbind_gid_high;
2106
2107         return True;
2108 }
2109
2110 BOOL lp_non_unix_account_range(uint32_t *low, uint32_t *high)
2111 {
2112         if (non_unix_account_low == 0 || non_unix_account_high == 0)
2113                 return False;
2114
2115         if (low)
2116                 *low = non_unix_account_low;
2117
2118         if (high)
2119                 *high = non_unix_account_high;
2120
2121         return True;
2122 }
2123
2124 /* Do some simple checks on "winbind [ug]id" parameter values */
2125
2126 static BOOL handle_winbind_uid(const char *pszParmValue, char **ptr)
2127 {
2128         uint32_t low, high;
2129
2130         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2131                 return False;
2132
2133         /* Parse OK */
2134
2135         string_set(ptr, pszParmValue);
2136
2137         winbind_uid_low = low;
2138         winbind_uid_high = high;
2139
2140         return True;
2141 }
2142
2143 static BOOL handle_winbind_gid(const char *pszParmValue, char **ptr)
2144 {
2145         uint32_t low, high;
2146
2147         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2148                 return False;
2149
2150         /* Parse OK */
2151
2152         string_set(ptr, pszParmValue);
2153
2154         winbind_gid_low = low;
2155         winbind_gid_high = high;
2156
2157         return True;
2158 }
2159
2160 /***************************************************************************
2161  Do some simple checks on "non unix account range" parameter values.
2162 ***************************************************************************/
2163
2164 static BOOL handle_non_unix_account_range(const char *pszParmValue, char **ptr)
2165 {
2166         uint32_t low, high;
2167
2168         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2169                 return False;
2170
2171         /* Parse OK */
2172
2173         string_set(ptr, pszParmValue);
2174
2175         non_unix_account_low = low;
2176         non_unix_account_high = high;
2177
2178         return True;
2179 }
2180
2181
2182 /***************************************************************************
2183  Initialise a copymap.
2184 ***************************************************************************/
2185
2186 static void init_copymap(service * pservice)
2187 {
2188         int i;
2189         SAFE_FREE(pservice->copymap);
2190         pservice->copymap = malloc_array_p(BOOL, NUMPARAMETERS);
2191         if (!pservice->copymap)
2192                 DEBUG(0,
2193                       ("Couldn't allocate copymap!! (size %d)\n",
2194                        (int)NUMPARAMETERS));
2195         else
2196                 for (i = 0; i < NUMPARAMETERS; i++)
2197                         pservice->copymap[i] = True;
2198 }
2199
2200 /***************************************************************************
2201  Return the local pointer to a parameter given the service number and the 
2202  pointer into the default structure.
2203 ***************************************************************************/
2204
2205 void *lp_local_ptr(int snum, void *ptr)
2206 {
2207         return (void *)(((char *)ServicePtrs[snum]) + PTR_DIFF(ptr, &sDefault));
2208 }
2209
2210
2211 /***************************************************************************
2212  Process a parametric option
2213 ***************************************************************************/
2214 static BOOL lp_do_parameter_parametric(int snum, const char *pszParmName, const char *pszParmValue, int flags)
2215 {
2216         struct param_opt *paramo, *data;
2217         char *name;
2218
2219         while (isspace(*pszParmName)) {
2220                 pszParmName++;
2221         }
2222
2223         name = strdup(pszParmName);
2224         if (!name) return False;
2225
2226         strlower(name);
2227
2228         if (snum < 0) {
2229                 data = Globals.param_opt;
2230         } else {
2231                 data = ServicePtrs[snum]->param_opt;
2232         }
2233
2234         /* Traverse destination */
2235         for (paramo=data; paramo; paramo=paramo->next) {
2236                 /* If we already have the option set, override it unless
2237                    it was a command line option and the new one isn't */
2238                 if (strcmp(paramo->key, name) == 0) {
2239                         if ((paramo->flags & FLAG_CMDLINE) &&
2240                             !(flags & FLAG_CMDLINE)) {
2241                                 return True;
2242                         }
2243
2244                         free(paramo->value);
2245                         paramo->value = strdup(pszParmValue);
2246                         paramo->flags = flags;
2247                         free(name);
2248                         return True;
2249                 }
2250         }
2251
2252         paramo = smb_xmalloc_p(struct param_opt);
2253         paramo->key = strdup(name);
2254         paramo->value = strdup(pszParmValue);
2255         paramo->flags = flags;
2256         if (snum < 0) {
2257                 DLIST_ADD(Globals.param_opt, paramo);
2258         } else {
2259                 DLIST_ADD(ServicePtrs[snum]->param_opt, paramo);
2260         }
2261
2262         free(name);
2263         
2264         return True;
2265 }
2266
2267 /***************************************************************************
2268  Process a parameter for a particular service number. If snum < 0
2269  then assume we are in the globals.
2270 ***************************************************************************/
2271 BOOL lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue)
2272 {
2273         int parmnum, i;
2274         void *parm_ptr = NULL;  /* where we are going to store the result */
2275         void *def_ptr = NULL;
2276
2277         parmnum = map_parameter(pszParmName);
2278
2279         if (parmnum < 0) {
2280                 if (strchr(pszParmName, ':')) {
2281                         return lp_do_parameter_parametric(snum, pszParmName, pszParmValue, 0);
2282                 }
2283                 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
2284                 return (True);
2285         }
2286
2287         if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
2288                 DEBUG(1, ("WARNING: The \"%s\" option is deprecated\n",
2289                           pszParmName));
2290         }
2291
2292         /* if the flag has been set on the command line, then don't allow override,
2293            but don't report an error */
2294         if (parm_table[parmnum].flags & FLAG_CMDLINE) {
2295                 return True;
2296         }
2297
2298         def_ptr = parm_table[parmnum].ptr;
2299
2300         /* we might point at a service, the default service or a global */
2301         if (snum < 0) {
2302                 parm_ptr = def_ptr;
2303         } else {
2304                 if (parm_table[parmnum].class == P_GLOBAL) {
2305                         DEBUG(0,
2306                               ("Global parameter %s found in service section!\n",
2307                                pszParmName));
2308                         return (True);
2309                 }
2310                 parm_ptr =
2311                         ((char *)ServicePtrs[snum]) + PTR_DIFF(def_ptr,
2312                                                             &sDefault);
2313         }
2314
2315         if (snum >= 0) {
2316                 if (!ServicePtrs[snum]->copymap)
2317                         init_copymap(ServicePtrs[snum]);
2318
2319                 /* this handles the aliases - set the copymap for other entries with
2320                    the same data pointer */
2321                 for (i = 0; parm_table[i].label; i++)
2322                         if (parm_table[i].ptr == parm_table[parmnum].ptr)
2323                                 ServicePtrs[snum]->copymap[i] = False;
2324         }
2325
2326         /* if it is a special case then go ahead */
2327         if (parm_table[parmnum].special) {
2328                 parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
2329                 return (True);
2330         }
2331
2332         /* now switch on the type of variable it is */
2333         switch (parm_table[parmnum].type)
2334         {
2335                 case P_BOOL:
2336                         set_boolean(parm_ptr, pszParmValue);
2337                         break;
2338
2339                 case P_BOOLREV:
2340                         set_boolean(parm_ptr, pszParmValue);
2341                         *(BOOL *)parm_ptr = !*(BOOL *)parm_ptr;
2342                         break;
2343
2344                 case P_INTEGER:
2345                         *(int *)parm_ptr = atoi(pszParmValue);
2346                         break;
2347
2348                 case P_CHAR:
2349                         *(char *)parm_ptr = *pszParmValue;
2350                         break;
2351
2352                 case P_OCTAL:
2353                         sscanf(pszParmValue, "%o", (int *)parm_ptr);
2354                         break;
2355
2356                 case P_LIST:
2357                         *(char ***)parm_ptr = str_list_make(pszParmValue, NULL);
2358                         break;
2359
2360                 case P_STRING:
2361                         string_set(parm_ptr, pszParmValue);
2362                         break;
2363
2364                 case P_USTRING:
2365                         string_set(parm_ptr, pszParmValue);
2366                         strupper(*(char **)parm_ptr);
2367                         break;
2368
2369                 case P_ENUM:
2370                         for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
2371                                 if (strequal
2372                                     (pszParmValue,
2373                                      parm_table[parmnum].enum_list[i].name)) {
2374                                         *(int *)parm_ptr =
2375                                                 parm_table[parmnum].
2376                                                 enum_list[i].value;
2377                                         break;
2378                                 }
2379                         }
2380                         if (!parm_table[parmnum].enum_list[i].name) {
2381                                 DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
2382                                          pszParmValue, pszParmName));
2383                                 return False;
2384                         }
2385                         break;
2386                 case P_SEP:
2387                         break;
2388         }
2389
2390         return (True);
2391 }
2392
2393 /***************************************************************************
2394  Process a parameter.
2395 ***************************************************************************/
2396
2397 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue)
2398 {
2399         if (!bInGlobalSection && bGlobalOnly)
2400                 return (True);
2401
2402         return (lp_do_parameter(bInGlobalSection ? -2 : iServiceIndex,
2403                                 pszParmName, pszParmValue));
2404 }
2405
2406 /*
2407   variable argument do parameter
2408 */
2409 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
2410
2411 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...)
2412 {
2413         char *s;
2414         BOOL ret;
2415         va_list ap;
2416
2417         va_start(ap, fmt);      
2418         s = talloc_vasprintf(NULL, fmt, ap);
2419         va_end(ap);
2420         ret = do_parameter(pszParmName, s);
2421         talloc_free(s);
2422         return ret;
2423 }
2424
2425
2426 /*
2427   set a parameter from the commandline - this is called from command line parameter
2428   parsing code. It sets the parameter then marks the parameter as unable to be modified
2429   by smb.conf processing
2430 */
2431 BOOL lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
2432 {
2433         int parmnum = map_parameter(pszParmName);
2434         int i;
2435
2436         while (isspace(*pszParmValue)) pszParmValue++;
2437
2438
2439         if (parmnum < 0 && strchr(pszParmName, ':')) {
2440                 /* set a parametric option */
2441                 return lp_do_parameter_parametric(-1, pszParmName, pszParmValue, FLAG_CMDLINE);
2442         }
2443
2444         if (parmnum < 0) {
2445                 DEBUG(0,("Unknown option '%s'\n", pszParmName));
2446                 return False;
2447         }
2448
2449         /* reset the CMDLINE flag in case this has been called before */
2450         parm_table[parmnum].flags &= ~FLAG_CMDLINE;
2451
2452         if (!lp_do_parameter(-2, pszParmName, pszParmValue)) {
2453                 return False;
2454         }
2455
2456         parm_table[parmnum].flags |= FLAG_CMDLINE;
2457
2458         /* we have to also set FLAG_CMDLINE on aliases */
2459         for (i=parmnum-1;i>=0 && parm_table[i].ptr == parm_table[parmnum].ptr;i--) {
2460                 parm_table[i].flags |= FLAG_CMDLINE;
2461         }
2462         for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].ptr == parm_table[parmnum].ptr;i++) {
2463                 parm_table[i].flags |= FLAG_CMDLINE;
2464         }
2465
2466         return True;
2467 }
2468
2469 /*
2470   set a option from the commandline in 'a=b' format. Use to support --option
2471 */
2472 BOOL lp_set_option(const char *option)
2473 {
2474         char *p, *s;
2475         BOOL ret;
2476
2477         s = strdup(option);
2478         if (!s) {
2479                 return False;
2480         }
2481
2482         p = strchr(s, '=');
2483         if (!p) {
2484                 free(s);
2485                 return False;
2486         }
2487
2488         *p = 0;
2489
2490         ret = lp_set_cmdline(s, p+1);
2491         free(s);
2492         return ret;
2493 }
2494
2495
2496 /***************************************************************************
2497  Print a parameter of the specified type.
2498 ***************************************************************************/
2499
2500 static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
2501 {
2502         int i;
2503         switch (p->type)
2504         {
2505                 case P_ENUM:
2506                         for (i = 0; p->enum_list[i].name; i++) {
2507                                 if (*(int *)ptr == p->enum_list[i].value) {
2508                                         fprintf(f, "%s",
2509                                                 p->enum_list[i].name);
2510                                         break;
2511                                 }
2512                         }
2513                         break;
2514
2515                 case P_BOOL:
2516                         fprintf(f, "%s", BOOLSTR(*(BOOL *)ptr));
2517                         break;
2518
2519                 case P_BOOLREV:
2520                         fprintf(f, "%s", BOOLSTR(!*(BOOL *)ptr));
2521                         break;
2522
2523                 case P_INTEGER:
2524                         fprintf(f, "%d", *(int *)ptr);
2525                         break;
2526
2527                 case P_CHAR:
2528                         fprintf(f, "%c", *(char *)ptr);
2529                         break;
2530
2531                 case P_OCTAL:
2532                         if (*(int *)ptr == -1) {
2533                                 fprintf(f, "-1");
2534                         } else {
2535                                 fprintf(f, "0%o", *(int *)ptr);
2536                         }
2537                         break;
2538
2539                 case P_LIST:
2540                         if ((char ***)ptr && *(char ***)ptr) {
2541                                 char **list = *(char ***)ptr;
2542                                 
2543                                 for (; *list; list++)
2544                                         fprintf(f, "%s%s", *list,
2545                                                 ((*(list+1))?", ":""));
2546                         }
2547                         break;
2548
2549                 case P_STRING:
2550                 case P_USTRING:
2551                         if (*(char **)ptr) {
2552                                 fprintf(f, "%s", *(char **)ptr);
2553                         }
2554                         break;
2555                 case P_SEP:
2556                         break;
2557         }
2558 }
2559
2560 /***************************************************************************
2561  Check if two parameters are equal.
2562 ***************************************************************************/
2563
2564 static BOOL equal_parameter(parm_type type, void *ptr1, void *ptr2)
2565 {
2566         switch (type) {
2567                 case P_BOOL:
2568                 case P_BOOLREV:
2569                         return (*((BOOL *)ptr1) == *((BOOL *)ptr2));
2570
2571                 case P_INTEGER:
2572                 case P_ENUM:
2573                 case P_OCTAL:
2574                         return (*((int *)ptr1) == *((int *)ptr2));
2575
2576                 case P_CHAR:
2577                         return (*((char *)ptr1) == *((char *)ptr2));
2578                 
2579                 case P_LIST:
2580                         return str_list_compare(*(char ***)ptr1, *(char ***)ptr2);
2581
2582                 case P_STRING:
2583                 case P_USTRING:
2584                 {
2585                         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
2586                         if (p1 && !*p1)
2587                                 p1 = NULL;
2588                         if (p2 && !*p2)
2589                                 p2 = NULL;
2590                         return (p1 == p2 || strequal(p1, p2));
2591                 }
2592                 case P_SEP:
2593                         break;
2594         }
2595         return (False);
2596 }
2597
2598 /***************************************************************************
2599  Process a new section (service). At this stage all sections are services.
2600  Later we'll have special sections that permit server parameters to be set.
2601  Returns True on success, False on failure. 
2602 ***************************************************************************/
2603
2604 static BOOL do_section(const char *pszSectionName)
2605 {
2606         BOOL bRetval;
2607         BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
2608                          (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
2609         bRetval = False;
2610
2611         /* if we've just struck a global section, note the fact. */
2612         bInGlobalSection = isglobal;
2613
2614         /* check for multiple global sections */
2615         if (bInGlobalSection) {
2616                 DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
2617                 return (True);
2618         }
2619
2620         if (!bInGlobalSection && bGlobalOnly)
2621                 return (True);
2622
2623         /* if we have a current service, tidy it up before moving on */
2624         bRetval = True;
2625
2626         if (iServiceIndex >= 0)
2627                 bRetval = service_ok(iServiceIndex);
2628
2629         /* if all is still well, move to the next record in the services array */
2630         if (bRetval) {
2631                 /* We put this here to avoid an odd message order if messages are */
2632                 /* issued by the post-processing of a previous section. */
2633                 DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
2634
2635                 if ((iServiceIndex = add_a_service(&sDefault, pszSectionName))
2636                     < 0) {
2637                         DEBUG(0, ("Failed to add a new service\n"));
2638                         return (False);
2639                 }
2640         }
2641
2642         return (bRetval);
2643 }
2644
2645
2646 /***************************************************************************
2647  Determine if a partcular base parameter is currentl set to the default value.
2648 ***************************************************************************/
2649
2650 static BOOL is_default(int i)
2651 {
2652         if (!defaults_saved)
2653                 return False;
2654         switch (parm_table[i].type) {
2655                 case P_LIST:
2656                         return str_list_compare (parm_table[i].def.lvalue, 
2657                                                 *(char ***)parm_table[i].ptr);
2658                 case P_STRING:
2659                 case P_USTRING:
2660                         return strequal(parm_table[i].def.svalue,
2661                                         *(char **)parm_table[i].ptr);
2662                 case P_BOOL:
2663                 case P_BOOLREV:
2664                         return parm_table[i].def.bvalue ==
2665                                 *(BOOL *)parm_table[i].ptr;
2666                 case P_CHAR:
2667                         return parm_table[i].def.cvalue ==
2668                                 *(char *)parm_table[i].ptr;
2669                 case P_INTEGER:
2670                 case P_OCTAL:
2671                 case P_ENUM:
2672                         return parm_table[i].def.ivalue ==
2673                                 *(int *)parm_table[i].ptr;
2674                 case P_SEP:
2675                         break;
2676         }
2677         return False;
2678 }
2679
2680 /***************************************************************************
2681 Display the contents of the global structure.
2682 ***************************************************************************/
2683
2684 static void dump_globals(FILE *f)
2685 {
2686         int i;
2687         struct param_opt *data;
2688         
2689         fprintf(f, "# Global parameters\n[global]\n");
2690
2691         for (i = 0; parm_table[i].label; i++)
2692                 if (parm_table[i].class == P_GLOBAL &&
2693                     parm_table[i].ptr &&
2694                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2695                         if (defaults_saved && is_default(i))
2696                                 continue;
2697                         fprintf(f, "\t%s = ", parm_table[i].label);
2698                         print_parameter(&parm_table[i], parm_table[i].ptr, f);
2699                         fprintf(f, "\n");
2700         }
2701         if (Globals.param_opt != NULL) {
2702                 data = Globals.param_opt;
2703                 while(data) {
2704                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2705                         data = data->next;
2706                 }
2707         }
2708
2709 }
2710
2711 /***************************************************************************
2712  Display the contents of a single services record.
2713 ***************************************************************************/
2714
2715 static void dump_a_service(service * pService, FILE * f)
2716 {
2717         int i;
2718         struct param_opt *data;
2719         
2720         if (pService != &sDefault)
2721                 fprintf(f, "\n[%s]\n", pService->szService);
2722
2723         for (i = 0; parm_table[i].label; i++)
2724                 if (parm_table[i].class == P_LOCAL &&
2725                     parm_table[i].ptr &&
2726                     (*parm_table[i].label != '-') &&
2727                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2728                         int pdiff = PTR_DIFF(parm_table[i].ptr, &sDefault);
2729
2730                         if (pService == &sDefault) {
2731                                 if (defaults_saved && is_default(i))
2732                                         continue;
2733                         } else {
2734                                 if (equal_parameter(parm_table[i].type,
2735                                                     ((char *)pService) +
2736                                                     pdiff,
2737                                                     ((char *)&sDefault) +
2738                                                     pdiff))
2739                                         continue;
2740                         }
2741
2742                         fprintf(f, "\t%s = ", parm_table[i].label);
2743                         print_parameter(&parm_table[i],
2744                                         ((char *)pService) + pdiff, f);
2745                         fprintf(f, "\n");
2746         }
2747         if (pService->param_opt != NULL) {
2748                 data = pService->param_opt;
2749                 while(data) {
2750                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2751                         data = data->next;
2752                 }
2753         }
2754 }
2755
2756
2757 /***************************************************************************
2758  Return info about the next service  in a service. snum==-1 gives the globals.
2759  Return NULL when out of parameters.
2760 ***************************************************************************/
2761
2762 struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
2763 {
2764         if (snum == -1) {
2765                 /* do the globals */
2766                 for (; parm_table[*i].label; (*i)++) {
2767                         if (parm_table[*i].class == P_SEPARATOR)
2768                                 return &parm_table[(*i)++];
2769
2770                         if (!parm_table[*i].ptr
2771                             || (*parm_table[*i].label == '-'))
2772                                 continue;
2773
2774                         if ((*i) > 0
2775                             && (parm_table[*i].ptr ==
2776                                 parm_table[(*i) - 1].ptr))
2777                                 continue;
2778
2779                         return &parm_table[(*i)++];
2780                 }
2781         } else {
2782                 service *pService = ServicePtrs[snum];
2783
2784                 for (; parm_table[*i].label; (*i)++) {
2785                         if (parm_table[*i].class == P_SEPARATOR)
2786                                 return &parm_table[(*i)++];
2787
2788                         if (parm_table[*i].class == P_LOCAL &&
2789                             parm_table[*i].ptr &&
2790                             (*parm_table[*i].label != '-') &&
2791                             ((*i) == 0 ||
2792                              (parm_table[*i].ptr !=
2793                               parm_table[(*i) - 1].ptr)))
2794                         {
2795                                 int pdiff =
2796                                         PTR_DIFF(parm_table[*i].ptr,
2797                                                  &sDefault);
2798
2799                                 if (allparameters ||
2800                                     !equal_parameter(parm_table[*i].type,
2801                                                      ((char *)pService) +
2802                                                      pdiff,
2803                                                      ((char *)&sDefault) +
2804                                                      pdiff))
2805                                 {
2806                                         return &parm_table[(*i)++];
2807                                 }
2808                         }
2809                 }
2810         }
2811
2812         return NULL;
2813 }
2814
2815
2816 /***************************************************************************
2817  Return TRUE if the passed service number is within range.
2818 ***************************************************************************/
2819
2820 BOOL lp_snum_ok(int iService)
2821 {
2822         return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
2823 }
2824
2825 /***************************************************************************
2826  Auto-load some home services.
2827 ***************************************************************************/
2828
2829 static void lp_add_auto_services(const char *str)
2830 {
2831         return;
2832 }
2833
2834 /***************************************************************************
2835  Auto-load one printer.
2836 ***************************************************************************/
2837
2838 void lp_add_one_printer(char *name, char *comment)
2839 {
2840         int printers = lp_servicenumber(PRINTERS_NAME);
2841         int i;
2842
2843         if (lp_servicenumber(name) < 0) {
2844                 lp_add_printer(name, printers);
2845                 if ((i = lp_servicenumber(name)) >= 0) {
2846                         string_set(&ServicePtrs[i]->comment, comment);
2847                         ServicePtrs[i]->autoloaded = True;
2848                 }
2849         }
2850 }
2851
2852 /***************************************************************************
2853  Announce ourselves as a print server.
2854 ***************************************************************************/
2855
2856 void update_server_announce_as_printserver(void)
2857 {
2858         default_server_announce |= SV_TYPE_PRINTQ_SERVER;       
2859 }
2860
2861 /***************************************************************************
2862  Have we loaded a services file yet?
2863 ***************************************************************************/
2864
2865 BOOL lp_loaded(void)
2866 {
2867         return (bLoaded);
2868 }
2869
2870 /***************************************************************************
2871  Unload unused services.
2872 ***************************************************************************/
2873
2874 void lp_killunused(struct smbsrv_connection *smb, BOOL (*snumused) (struct smbsrv_connection *, int))
2875 {
2876         int i;
2877         for (i = 0; i < iNumServices; i++) {
2878                 if (!VALID(i))
2879                         continue;
2880
2881                 if (!snumused || !snumused(smb, i)) {
2882                         ServicePtrs[i]->valid = False;
2883                         free_service(ServicePtrs[i]);
2884                 }
2885         }
2886 }
2887
2888 /***************************************************************************
2889  Unload a service.
2890 ***************************************************************************/
2891
2892 void lp_killservice(int iServiceIn)
2893 {
2894         if (VALID(iServiceIn)) {
2895                 ServicePtrs[iServiceIn]->valid = False;
2896                 free_service(ServicePtrs[iServiceIn]);
2897         }
2898 }
2899
2900 /***************************************************************************
2901  Save the curent values of all global and sDefault parameters into the 
2902  defaults union. This allows swat and testparm to show only the
2903  changed (ie. non-default) parameters.
2904 ***************************************************************************/
2905
2906 static void lp_save_defaults(void)
2907 {
2908         int i;
2909         for (i = 0; parm_table[i].label; i++) {
2910                 if (i > 0 && parm_table[i].ptr == parm_table[i - 1].ptr)
2911                         continue;
2912                 switch (parm_table[i].type) {
2913                         case P_LIST:
2914                                 str_list_copy(&(parm_table[i].def.lvalue),
2915                                             *(const char ***)parm_table[i].ptr);
2916                                 break;
2917                         case P_STRING:
2918                         case P_USTRING:
2919                                 if (parm_table[i].ptr) {
2920                                         parm_table[i].def.svalue = strdup(*(char **)parm_table[i].ptr);
2921                                 } else {
2922                                         parm_table[i].def.svalue = NULL;
2923                                 }
2924                                 break;
2925                         case P_BOOL:
2926                         case P_BOOLREV:
2927                                 parm_table[i].def.bvalue =
2928                                         *(BOOL *)parm_table[i].ptr;
2929                                 break;
2930                         case P_CHAR:
2931                                 parm_table[i].def.cvalue =
2932                                         *(char *)parm_table[i].ptr;
2933                                 break;
2934                         case P_INTEGER:
2935                         case P_OCTAL:
2936                         case P_ENUM:
2937                                 parm_table[i].def.ivalue =
2938                                         *(int *)parm_table[i].ptr;
2939                                 break;
2940                         case P_SEP:
2941                                 break;
2942                 }
2943         }
2944         defaults_saved = True;
2945 }
2946
2947 /*******************************************************************
2948  Set the server type we will announce as via nmbd.
2949 ********************************************************************/
2950
2951 static void set_server_role(void)
2952 {
2953         server_role = ROLE_STANDALONE;
2954
2955         switch (lp_security()) {
2956                 case SEC_SHARE:
2957                         if (lp_domain_logons())
2958                                 DEBUG(0, ("Server's Role (logon server) conflicts with share-level security\n"));
2959                         break;
2960                 case SEC_SERVER:
2961                 case SEC_DOMAIN:
2962                 case SEC_ADS:
2963                         if (lp_domain_logons()) {
2964                                 server_role = ROLE_DOMAIN_PDC;
2965                                 break;
2966                         }
2967                         server_role = ROLE_DOMAIN_MEMBER;
2968                         break;
2969                 case SEC_USER:
2970                         if (lp_domain_logons()) {
2971
2972                                 if (Globals.bDomainMaster) /* auto or yes */ 
2973                                         server_role = ROLE_DOMAIN_PDC;
2974                                 else
2975                                         server_role = ROLE_DOMAIN_BDC;
2976                         }
2977                         break;
2978                 default:
2979                         DEBUG(0, ("Server's Role undefined due to unknown security mode\n"));
2980                         break;
2981         }
2982
2983         DEBUG(10, ("set_server_role: role = "));
2984
2985         switch(server_role) {
2986         case ROLE_STANDALONE:
2987                 DEBUGADD(10, ("ROLE_STANDALONE\n"));
2988                 break;
2989         case ROLE_DOMAIN_MEMBER:
2990                 DEBUGADD(10, ("ROLE_DOMAIN_MEMBER\n"));
2991                 break;
2992         case ROLE_DOMAIN_BDC:
2993                 DEBUGADD(10, ("ROLE_DOMAIN_BDC\n"));
2994                 break;
2995         case ROLE_DOMAIN_PDC:
2996                 DEBUGADD(10, ("ROLE_DOMAIN_PDC\n"));
2997                 break;
2998         }
2999 }
3000
3001 /***************************************************************************
3002  Load the services array from the services file. Return True on success, 
3003  False on failure.
3004 ***************************************************************************/
3005
3006 BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
3007              BOOL add_ipc)
3008 {
3009         pstring n2;
3010         BOOL bRetval;
3011         struct param_opt *data;
3012
3013         pstrcpy(n2, pszFname);
3014         standard_sub_basic(n2,sizeof(n2));
3015
3016         add_to_file_list(pszFname, n2);
3017
3018         bRetval = False;
3019
3020         DEBUG(2, ("lp_load: refreshing parameters from %s\n", pszFname));
3021         
3022         bInGlobalSection = True;
3023         bGlobalOnly = global_only;
3024
3025         init_globals();
3026
3027         if (save_defaults)
3028         {
3029                 lp_save_defaults();
3030         }
3031
3032         if (Globals.param_opt != NULL) {
3033                 struct param_opt *next;
3034                 for (data=Globals.param_opt; data; data=next) {
3035                         next = data->next;
3036                         if (data->flags & FLAG_CMDLINE) continue;
3037                         free(data->key);
3038                         free(data->value);
3039                         DLIST_REMOVE(Globals.param_opt, data);
3040                         free(data);
3041                 }
3042         }
3043         
3044         /* We get sections first, so have to start 'behind' to make up */
3045         iServiceIndex = -1;
3046         bRetval = pm_process(n2, do_section, do_parameter);
3047
3048         /* finish up the last section */
3049         DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
3050         if (bRetval)
3051                 if (iServiceIndex >= 0)
3052                         bRetval = service_ok(iServiceIndex);
3053
3054         lp_add_auto_services(lp_auto_services());
3055
3056         if (add_ipc) {
3057                 /* When 'restrict anonymous = 2' guest connections to ipc$
3058                    are denied */
3059                 lp_add_ipc("IPC$", (lp_restrict_anonymous() < 2));
3060                 lp_add_ipc("ADMIN$", False);
3061         }
3062
3063         set_server_role();
3064         set_default_server_announce_type();
3065
3066         bLoaded = True;
3067
3068         /* Now we check bWINSsupport and set szWINSserver to 127.0.0.1 */
3069         /* if bWINSsupport is true and we are in the client            */
3070         if (in_client && Globals.bWINSsupport) {
3071                 lp_do_parameter(-1, "wins server", "127.0.0.1");
3072         }
3073
3074         lp_do_parameter(-1, "gensec:krb5", "False");
3075         lp_do_parameter(-1, "gensec:ms_krb5", "False");
3076
3077         init_iconv();
3078
3079         return (bRetval);
3080 }
3081
3082 /***************************************************************************
3083  Reset the max number of services.
3084 ***************************************************************************/
3085
3086 void lp_resetnumservices(void)
3087 {
3088         iNumServices = 0;
3089 }
3090
3091 /***************************************************************************
3092  Return the max number of services.
3093 ***************************************************************************/
3094
3095 int lp_numservices(void)
3096 {
3097         return (iNumServices);
3098 }
3099
3100 /***************************************************************************
3101 Display the contents of the services array in human-readable form.
3102 ***************************************************************************/
3103
3104 void lp_dump(FILE *f, BOOL show_defaults, int maxtoprint)
3105 {
3106         int iService;
3107
3108         if (show_defaults)
3109                 defaults_saved = False;
3110
3111         dump_globals(f);
3112
3113         dump_a_service(&sDefault, f);
3114
3115         for (iService = 0; iService < maxtoprint; iService++)
3116                 lp_dump_one(f, show_defaults, iService);
3117 }
3118
3119 /***************************************************************************
3120 Display the contents of one service in human-readable form.
3121 ***************************************************************************/
3122
3123 void lp_dump_one(FILE * f, BOOL show_defaults, int snum)
3124 {
3125         if (VALID(snum)) {
3126                 if (ServicePtrs[snum]->szService[0] == '\0')
3127                         return;
3128                 dump_a_service(ServicePtrs[snum], f);
3129         }
3130 }
3131
3132 /***************************************************************************
3133 Return the number of the service with the given name, or -1 if it doesn't
3134 exist. Note that this is a DIFFERENT ANIMAL from the internal function
3135 getservicebyname()! This works ONLY if all services have been loaded, and
3136 does not copy the found service.
3137 ***************************************************************************/
3138
3139 int lp_servicenumber(const char *pszServiceName)
3140 {
3141         int iService;
3142         fstring serviceName;
3143  
3144  
3145         for (iService = iNumServices - 1; iService >= 0; iService--) {
3146                 if (VALID(iService) && ServicePtrs[iService]->szService) {
3147                         /*
3148                          * The substitution here is used to support %U is
3149                          * service names
3150                          */
3151                         fstrcpy(serviceName, ServicePtrs[iService]->szService);
3152                         standard_sub_basic(serviceName,sizeof(serviceName));
3153                         if (strequal(serviceName, pszServiceName))
3154                                 break;
3155                 }
3156         }
3157
3158         if (iService < 0)
3159                 DEBUG(7,("lp_servicenumber: couldn't find %s\n", pszServiceName));
3160
3161         return (iService);
3162 }
3163
3164 /*******************************************************************
3165  A useful volume label function. 
3166 ********************************************************************/
3167 const char *volume_label(int snum)
3168 {
3169         const char *ret = lp_volume(snum);
3170         if (!*ret)
3171                 return lp_servicename(snum);
3172         return (ret);
3173 }
3174
3175
3176 /*******************************************************************
3177  Set the server type we will announce as via nmbd.
3178 ********************************************************************/
3179
3180 static void set_default_server_announce_type(void)
3181 {
3182         default_server_announce = 0;
3183         default_server_announce |= SV_TYPE_WORKSTATION;
3184         default_server_announce |= SV_TYPE_SERVER;
3185         default_server_announce |= SV_TYPE_SERVER_UNIX;
3186
3187         switch (lp_announce_as()) {
3188                 case ANNOUNCE_AS_NT_SERVER:
3189                         default_server_announce |= SV_TYPE_SERVER_NT;
3190                         /* fall through... */
3191                 case ANNOUNCE_AS_NT_WORKSTATION:
3192                         default_server_announce |= SV_TYPE_NT;
3193                         break;
3194                 case ANNOUNCE_AS_WIN95:
3195                         default_server_announce |= SV_TYPE_WIN95_PLUS;
3196                         break;
3197                 case ANNOUNCE_AS_WFW:
3198                         default_server_announce |= SV_TYPE_WFW;
3199                         break;
3200                 default:
3201                         break;
3202         }
3203
3204         switch (lp_server_role()) {
3205                 case ROLE_DOMAIN_MEMBER:
3206                         default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
3207                         break;
3208                 case ROLE_DOMAIN_PDC:
3209                         default_server_announce |= SV_TYPE_DOMAIN_CTRL;
3210                         break;
3211                 case ROLE_DOMAIN_BDC:
3212                         default_server_announce |= SV_TYPE_DOMAIN_BAKCTRL;
3213                         break;
3214                 case ROLE_STANDALONE:
3215                 default:
3216                         break;
3217         }
3218         if (lp_time_server())
3219                 default_server_announce |= SV_TYPE_TIME_SOURCE;
3220
3221         if (lp_host_msdfs())
3222                 default_server_announce |= SV_TYPE_DFS_SERVER;
3223 }
3224
3225 /***********************************************************
3226  returns role of Samba server
3227 ************************************************************/
3228
3229 int lp_server_role(void)
3230 {
3231         return server_role;
3232 }
3233
3234 /***********************************************************
3235  If we are PDC then prefer us as DMB
3236 ************************************************************/
3237
3238 BOOL lp_domain_master(void)
3239 {
3240         if (Globals.bDomainMaster == Auto)
3241                 return (lp_server_role() == ROLE_DOMAIN_PDC);
3242
3243         return Globals.bDomainMaster;
3244 }
3245
3246 /***********************************************************
3247  If we are DMB then prefer us as LMB
3248 ************************************************************/
3249
3250 BOOL lp_preferred_master(void)
3251 {
3252         if (Globals.bPreferredMaster == Auto)
3253                 return (lp_local_master() && lp_domain_master());
3254
3255         return Globals.bPreferredMaster;
3256 }
3257
3258 /*******************************************************************
3259  Remove a service.
3260 ********************************************************************/
3261
3262 void lp_remove_service(int snum)
3263 {
3264         ServicePtrs[snum]->valid = False;
3265 }
3266
3267 /*******************************************************************
3268  Copy a service.
3269 ********************************************************************/
3270
3271 void lp_copy_service(int snum, const char *new_name)
3272 {
3273         const char *oldname = lp_servicename(snum);
3274         do_section(new_name);
3275         if (snum >= 0) {
3276                 snum = lp_servicenumber(new_name);
3277                 if (snum >= 0)
3278                         lp_do_parameter(snum, "copy", oldname);
3279         }
3280 }
3281
3282
3283 /*******************************************************************
3284  Get the default server type we will announce as via nmbd.
3285 ********************************************************************/
3286 int lp_default_server_announce(void)
3287 {
3288         return default_server_announce;
3289 }
3290
3291 const char *lp_printername(int snum)
3292 {
3293         const char *ret = _lp_printername(snum);
3294         if (ret == NULL || (ret != NULL && *ret == '\0'))
3295                 ret = lp_const_servicename(snum);
3296
3297         return ret;
3298 }
3299
3300
3301 /*******************************************************************
3302  Return the max print jobs per queue.
3303 ********************************************************************/
3304
3305 int lp_maxprintjobs(int snum)
3306 {
3307         int maxjobs = LP_SNUM_OK(snum) ? ServicePtrs[snum]->iMaxPrintJobs : sDefault.iMaxPrintJobs;
3308         if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
3309                 maxjobs = PRINT_MAX_JOBID - 1;
3310
3311         return maxjobs;
3312 }