r4054: got rid of Realloc(), replacing it with the type safe macro realloc_p()
[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
899         DEBUG(3, ("Initialising global parameters\n"));
900
901         for (i = 0; parm_table[i].label; i++) {
902                 if ((parm_table[i].type == P_STRING ||
903                      parm_table[i].type == P_USTRING) &&
904                     parm_table[i].ptr &&
905                     !(parm_table[i].flags & FLAG_CMDLINE)) {
906                         string_set(parm_table[i].ptr, "");
907                 }
908         }
909
910         /* options that can be set on the command line must be initialised via
911            the slower do_parameter() to ensure that FLAG_CMDLINE is obeyed */
912 #ifdef TCP_NODELAY
913         do_parameter("socket options", "TCP_NODELAY");
914 #endif
915         do_parameter("workgroup", DEFAULT_WORKGROUP);
916         do_parameter("netbios name", get_myname());
917         do_parameter("max protocol", "NT1");
918         do_parameter("name resolve order", "lmhosts wins host bcast");
919
920         init_printer_values();
921
922         do_parameter("fstype", FSTYPE_STRING);
923         do_parameter("ntvfs handler", "unixuid default");
924
925         do_parameter("dcerpc endpoint servers", "epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi winreg IOXIDResolver IRemoteActivation");
926         do_parameter("server services", "smb rpc");
927         do_parameter("auth methods", "guest sam_ignoredomain");
928         do_parameter("smb passwd file", dyn_SMB_PASSWD_FILE);
929         do_parameter("private dir", dyn_PRIVATE_DIR);
930         do_parameter_var("sam database", "tdb://%s/sam.ldb", dyn_PRIVATE_DIR);
931         do_parameter_var("spoolss database", "tdb://%s/spoolss.ldb", dyn_PRIVATE_DIR);
932         do_parameter("guest account", GUEST_ACCOUNT);
933
934         /* using UTF8 by default allows us to support all chars */
935         do_parameter("unix charset", "UTF8");
936
937         /* Use codepage 850 as a default for the dos character set */
938         do_parameter("dos charset", "CP850");
939
940         /*
941          * Allow the default PASSWD_CHAT to be overridden in local.h.
942          */
943         do_parameter("passwd chat", DEFAULT_PASSWD_CHAT);
944
945         do_parameter("passwd program", "");
946         do_parameter("printcap name", PRINTCAP_NAME);
947         
948         do_parameter("pid directory", dyn_PIDDIR);
949         do_parameter("lock dir", dyn_LOCKDIR);
950         do_parameter("ncalrpc dir", dyn_NCALRPCDIR);
951
952         do_parameter("socket address", "0.0.0.0");
953         do_parameter_var("server string", "Samba %s", SAMBA_VERSION_STRING);
954
955         do_parameter_var("announce version", "%d.%d", 
956                          DEFAULT_MAJOR_VERSION,
957                          DEFAULT_MINOR_VERSION);
958
959         do_parameter("logon drive", "");
960
961         do_parameter("logon home", "\\\\%N\\%U");
962         do_parameter("logon path", "\\\\%N\\%U\\profile");
963         do_parameter("password server", "*");
964
965         do_parameter("load printers", "True");
966
967         do_parameter("max mux", "50");
968         do_parameter("max xmit", "12288");
969         do_parameter("lpqcachetime", "10");
970         do_parameter("DisableSpoolss", "False");
971         do_parameter("password level", "0");
972         do_parameter("username level", "0");
973         do_parameter("LargeReadwrite", "True");
974         do_parameter("minprotocol", "CORE");
975         do_parameter("security", "USER");
976         do_parameter("paranoid server security", "True");
977         do_parameter("EncryptPasswords", "True");
978         do_parameter("ReadRaw", "True");
979         do_parameter("WriteRaw", "True");
980         do_parameter("NullPasswords", "False");
981         do_parameter("ObeyPamRestrictions", "False");
982         do_parameter("lm announce", "Auto");    
983         do_parameter("lm interval", "60");
984         do_parameter("announce as", "NT SERVER");
985
986         do_parameter("TimeServer", "False");
987         do_parameter("BindInterfacesOnly", "False");
988         do_parameter("PamPasswordChange", "False");
989         do_parameter("Unicode", "True");
990         do_parameter("restrict anonymous", "0");
991         do_parameter("ClientLanManAuth", "True");
992         do_parameter("LanmanAuth", "True");
993         do_parameter("NTLMAuth", "True");
994         
995         do_parameter("enhanced browsing", "True"); 
996         do_parameter("LockSpinCount", "3");
997         do_parameter("LockSpinTime", "10");
998 #ifdef MMAP_BLACKLIST
999         do_parameter("UseMmap", "False");
1000 #else
1001         do_parameter("UseMmap", "True");
1002 #endif
1003         do_parameter("UnixExtensions", "False");
1004
1005         /* hostname lookups can be very expensive and are broken on
1006            a large number of sites (tridge) */
1007         do_parameter("HostnameLookups", "False");
1008
1009         do_parameter("PreferredMaster", "Auto");
1010         do_parameter("os level", "20");
1011         do_parameter("LocalMaster", "True");
1012         do_parameter("DomainMaster", "Auto");   /* depending on bDomainLogons */
1013         do_parameter("DomainLogons", "False");
1014         do_parameter("WINSsupport", "False");
1015         do_parameter("WINSproxy", "False");
1016
1017         do_parameter("DNSproxy", "True");
1018
1019         do_parameter("AllowTrustedDomains", "True");
1020
1021         do_parameter("TemplateShell", "/bin/false");
1022         do_parameter("TemplateHomedir", "/home/%D/%U");
1023         do_parameter("WinbindSeparator", "\\");
1024
1025         do_parameter("winbind cache time", "15");
1026         do_parameter("WinbindEnumUsers", "True");
1027         do_parameter("WinbindEnumGroups", "True");
1028         do_parameter("WinbindUseDefaultDomain", "False");
1029
1030         do_parameter("IDMapBackend", "tdb");
1031
1032         do_parameter("name cache timeout", "660"); /* In seconds */
1033
1034         do_parameter("client signing", "Yes");
1035         do_parameter("server signing", "auto");
1036
1037         do_parameter("use spnego", "True");
1038
1039         do_parameter("smb ports", SMB_PORTS);
1040
1041         do_parameter("nt status support", "True");
1042 }
1043
1044 static TALLOC_CTX *lp_talloc;
1045
1046 /******************************************************************* a
1047  Free up temporary memory - called from the main loop.
1048 ********************************************************************/
1049
1050 void lp_talloc_free(void)
1051 {
1052         if (!lp_talloc)
1053                 return;
1054         talloc_free(lp_talloc);
1055         lp_talloc = NULL;
1056 }
1057
1058 /*******************************************************************
1059  Convenience routine to grab string parameters into temporary memory
1060  and run standard_sub_basic on them. The buffers can be written to by
1061  callers without affecting the source string.
1062 ********************************************************************/
1063
1064 static const char *lp_string(const char *s)
1065 {
1066 #if 0  /* until REWRITE done to make thread-safe */
1067         size_t len = s ? strlen(s) : 0;
1068         char *ret;
1069 #endif
1070
1071         /* The follow debug is useful for tracking down memory problems
1072            especially if you have an inner loop that is calling a lp_*()
1073            function that returns a string.  Perhaps this debug should be
1074            present all the time? */
1075
1076 #if 0
1077         DEBUG(10, ("lp_string(%s)\n", s));
1078 #endif
1079
1080 #if 0  /* until REWRITE done to make thread-safe */
1081         if (!lp_talloc)
1082                 lp_talloc = talloc_init("lp_talloc");
1083
1084         ret = (char *)talloc(lp_talloc, len + 100);     /* leave room for substitution */
1085
1086         if (!ret)
1087                 return NULL;
1088
1089         if (!s)
1090                 *ret = 0;
1091         else
1092                 StrnCpy(ret, s, len);
1093
1094         if (trim_string(ret, "\"", "\"")) {
1095                 if (strchr(ret,'"') != NULL)
1096                         StrnCpy(ret, s, len);
1097         }
1098
1099         standard_sub_basic(ret,len+100);
1100         return (ret);
1101 #endif
1102         return s;
1103 }
1104
1105 /*
1106    In this section all the functions that are used to access the 
1107    parameters from the rest of the program are defined 
1108 */
1109
1110 #define FN_GLOBAL_STRING(fn_name,ptr) \
1111  const char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
1112 #define FN_GLOBAL_CONST_STRING(fn_name,ptr) \
1113  const char *fn_name(void) {return(*(const char **)(ptr) ? *(const char **)(ptr) : "");}
1114 #define FN_GLOBAL_LIST(fn_name,ptr) \
1115  const char **fn_name(void) {return(*(const char ***)(ptr));}
1116 #define FN_GLOBAL_BOOL(fn_name,ptr) \
1117  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
1118 #define FN_GLOBAL_CHAR(fn_name,ptr) \
1119  char fn_name(void) {return(*(char *)(ptr));}
1120 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
1121  int fn_name(void) {return(*(int *)(ptr));}
1122
1123 #define FN_LOCAL_STRING(fn_name,val) \
1124  const char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val));}
1125 #define FN_LOCAL_CONST_STRING(fn_name,val) \
1126  const char *fn_name(int i) {return (const char *)((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val);}
1127 #define FN_LOCAL_LIST(fn_name,val) \
1128  const char **fn_name(int i) {return(const char **)(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1129 #define FN_LOCAL_BOOL(fn_name,val) \
1130  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1131 #define FN_LOCAL_CHAR(fn_name,val) \
1132  char fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1133 #define FN_LOCAL_INTEGER(fn_name,val) \
1134  int fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
1135
1136 FN_GLOBAL_LIST(lp_smb_ports, &Globals.smb_ports)
1137 FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
1138 FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
1139 FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)
1140 FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)
1141 FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
1142 FN_GLOBAL_STRING(lp_smb_passwd_file, &Globals.szSMBPasswdFile)
1143 FN_GLOBAL_STRING(lp_sam_url, &Globals.szSAM_URL)
1144 FN_GLOBAL_STRING(lp_spoolss_url, &Globals.szSPOOLSS_URL)
1145 FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir)
1146 FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
1147 FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname)
1148 FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
1149 FN_GLOBAL_STRING(lp_ncalrpc_dir, &Globals.ncalrpc_dir)
1150 FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir)
1151 FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers)
1152 FN_GLOBAL_LIST(lp_server_services, &Globals.server_services)
1153 FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir)
1154 FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
1155 FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv)
1156 FN_GLOBAL_STRING(lp_auto_services, &Globals.szAutoServices)
1157 FN_GLOBAL_STRING(lp_passwd_program, &Globals.szPasswdProgram)
1158 FN_GLOBAL_STRING(lp_passwd_chat, &Globals.szPasswdChat)
1159 FN_GLOBAL_STRING(lp_passwordserver, &Globals.szPasswordServer)
1160 FN_GLOBAL_STRING(lp_name_resolve_order, &Globals.szNameResolveOrder)
1161 FN_GLOBAL_STRING(lp_realm, &Globals.szRealm)
1162 FN_GLOBAL_STRING(lp_ads_server, &Globals.szADSserver)
1163 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
1164 FN_GLOBAL_STRING(lp_workgroup, &Globals.szWorkgroup)
1165 FN_GLOBAL_STRING(lp_netbios_name, &Globals.szNetbiosName)
1166 FN_GLOBAL_STRING(lp_netbios_scope, &Globals.szNetbiosScope)
1167 FN_GLOBAL_CONST_STRING(lp_logon_script, &Globals.szLogonScript)
1168 FN_GLOBAL_CONST_STRING(lp_logon_path, &Globals.szLogonPath)
1169 FN_GLOBAL_CONST_STRING(lp_logon_drive, &Globals.szLogonDrive)
1170 FN_GLOBAL_CONST_STRING(lp_logon_home, &Globals.szLogonHome)
1171 FN_GLOBAL_STRING(lp_remote_announce, &Globals.szRemoteAnnounce)
1172 FN_GLOBAL_STRING(lp_remote_browse_sync, &Globals.szRemoteBrowseSync)
1173 FN_GLOBAL_LIST(lp_wins_server_list, &Globals.szWINSservers)
1174 FN_GLOBAL_LIST(lp_interfaces, &Globals.szInterfaces)
1175 FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
1176 FN_GLOBAL_LIST(lp_netbios_aliases, &Globals.szNetbiosAliases)
1177 FN_GLOBAL_LIST(lp_preload_modules, &Globals.szPreloadModules)
1178 FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction)
1179 FN_GLOBAL_STRING(lp_adduser_script, &Globals.szAddUserScript)
1180
1181 FN_GLOBAL_CONST_STRING(lp_guestaccount, &Globals.szGuestaccount)
1182
1183 FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript)
1184
1185 FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
1186 FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners)
1187 FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
1188 FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell)
1189 FN_GLOBAL_CONST_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
1190 FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
1191 FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
1192 FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
1193 FN_GLOBAL_STRING(lp_idmap_backend, &Globals.szIDMapBackend)
1194
1195 FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios)
1196 FN_GLOBAL_BOOL(lp_dns_proxy, &Globals.bDNSproxy)
1197 FN_GLOBAL_BOOL(lp_wins_support, &Globals.bWINSsupport)
1198 FN_GLOBAL_BOOL(lp_we_are_a_wins_server, &Globals.bWINSsupport)
1199 FN_GLOBAL_BOOL(lp_wins_proxy, &Globals.bWINSproxy)
1200 FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster)
1201 FN_GLOBAL_BOOL(lp_domain_logons, &Globals.bDomainLogons)
1202 FN_GLOBAL_BOOL(lp_load_printers, &Globals.bLoadPrinters)
1203 FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw)
1204 FN_GLOBAL_BOOL(lp_large_readwrite, &Globals.bLargeReadwrite)
1205 FN_GLOBAL_BOOL(lp_writeraw, &Globals.bWriteRaw)
1206 FN_GLOBAL_BOOL(lp_null_passwords, &Globals.bNullPasswords)
1207 FN_GLOBAL_BOOL(lp_obey_pam_restrictions, &Globals.bObeyPamRestrictions)
1208 FN_GLOBAL_BOOL(lp_encrypted_passwords, &Globals.bEncryptPasswords)
1209 static FN_GLOBAL_BOOL(lp_time_server, &Globals.bTimeServer)
1210 FN_GLOBAL_BOOL(lp_bind_interfaces_only, &Globals.bBindInterfacesOnly)
1211 FN_GLOBAL_BOOL(lp_pam_password_change, &Globals.bPamPasswordChange)
1212 FN_GLOBAL_BOOL(lp_unicode, &Globals.bUnicode)
1213 FN_GLOBAL_BOOL(lp_nt_status_support, &Globals.bNTStatusSupport)
1214 FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)
1215 FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous)
1216 FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
1217 FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
1218 FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
1219 FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
1220 FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
1221 FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing)
1222 FN_GLOBAL_BOOL(lp_use_mmap, &Globals.bUseMmap)
1223 FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions)
1224 FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
1225 FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
1226 FN_GLOBAL_BOOL(lp_rpc_big_endian, &Globals.bRpcBigEndian)
1227 FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
1228 FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
1229 FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
1230 FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.min_wins_ttl)
1231 FN_GLOBAL_INTEGER(lp_time_offset, &Globals.time_offset)
1232 FN_GLOBAL_INTEGER(lp_maxmux, &Globals.max_mux)
1233 FN_GLOBAL_INTEGER(lp_max_xmit, &Globals.max_xmit)
1234 FN_GLOBAL_INTEGER(lp_passwordlevel, &Globals.pwordlevel)
1235 FN_GLOBAL_INTEGER(lp_usernamelevel, &Globals.unamelevel)
1236 FN_GLOBAL_INTEGER(lp_maxprotocol, &Globals.maxprotocol)
1237 FN_GLOBAL_INTEGER(lp_minprotocol, &Globals.minprotocol)
1238 FN_GLOBAL_INTEGER(lp_security, &Globals.security)
1239 FN_GLOBAL_LIST(lp_auth_methods, &Globals.AuthMethods)
1240 FN_GLOBAL_BOOL(lp_paranoid_server_security, &Globals.paranoid_server_security)
1241 FN_GLOBAL_INTEGER(lp_lpqcachetime, &Globals.lpqcachetime)
1242 FN_GLOBAL_INTEGER(lp_disable_spoolss, &Globals.bDisableSpoolss)
1243 static FN_GLOBAL_INTEGER(lp_announce_as, &Globals.announce_as)
1244 FN_GLOBAL_INTEGER(lp_lm_announce, &Globals.lm_announce)
1245 FN_GLOBAL_INTEGER(lp_lm_interval, &Globals.lm_interval)
1246 FN_GLOBAL_INTEGER(lp_machine_password_timeout, &Globals.machine_password_timeout)
1247 FN_GLOBAL_INTEGER(lp_lock_spin_count, &Globals.iLockSpinCount)
1248 FN_GLOBAL_INTEGER(lp_lock_sleep_time, &Globals.iLockSpinTime)
1249 FN_LOCAL_STRING(lp_servicename, szService)
1250 FN_LOCAL_CONST_STRING(lp_const_servicename, szService)
1251 FN_LOCAL_STRING(lp_pathname, szPath)
1252 FN_LOCAL_STRING(lp_username, szUsername)
1253 FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers)
1254 FN_LOCAL_LIST(lp_valid_users, szValidUsers)
1255 FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
1256 FN_LOCAL_STRING(lp_printcommand, szPrintcommand)
1257 FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand)
1258 FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand)
1259 FN_LOCAL_STRING(lp_lppausecommand, szLppausecommand)
1260 FN_LOCAL_STRING(lp_lpresumecommand, szLpresumecommand)
1261 FN_LOCAL_STRING(lp_queuepausecommand, szQueuepausecommand)
1262 FN_LOCAL_STRING(lp_queueresumecommand, szQueueresumecommand)
1263 static FN_LOCAL_STRING(_lp_printername, szPrintername)
1264 FN_LOCAL_LIST(lp_hostsallow, szHostsallow)
1265 FN_LOCAL_LIST(lp_hostsdeny, szHostsdeny)
1266 FN_LOCAL_STRING(lp_comment, comment)
1267 FN_LOCAL_STRING(lp_fstype, fstype)
1268 FN_LOCAL_STRING(lp_msdfs_proxy, szMSDfsProxy)
1269 static FN_LOCAL_STRING(lp_volume, volume)
1270 FN_LOCAL_LIST(lp_ntvfs_handler, ntvfs_handler)
1271 FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
1272 FN_LOCAL_BOOL(lp_autoloaded, autoloaded)
1273 FN_LOCAL_BOOL(lp_browseable, bBrowseable)
1274 FN_LOCAL_BOOL(lp_readonly, bRead_only)
1275 FN_LOCAL_BOOL(lp_guest_ok, bGuest_ok)
1276 FN_LOCAL_BOOL(lp_guest_only, bGuest_only)
1277 FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
1278 FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
1279 FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
1280 FN_LOCAL_BOOL(lp_locking, bLocking)
1281 FN_LOCAL_BOOL(lp_strict_locking, bStrictLocking)
1282 FN_LOCAL_BOOL(lp_posix_locking, bPosixLocking)
1283 FN_LOCAL_BOOL(lp_strict_sync, bStrictSync)
1284 FN_LOCAL_BOOL(lp_ci_filesystem, bCIFileSystem)
1285 FN_LOCAL_BOOL(lp_share_modes, bShareModes)
1286 FN_LOCAL_BOOL(lp_oplocks, bOpLocks)
1287 FN_LOCAL_BOOL(lp_level2_oplocks, bLevel2OpLocks)
1288 FN_LOCAL_BOOL(lp_onlyuser, bOnlyUser)
1289 FN_LOCAL_BOOL(lp_map_system, bMap_system)
1290 FN_LOCAL_INTEGER(lp_max_connections, iMaxConnections)
1291 FN_LOCAL_INTEGER(lp_minprintspace, iMinPrintSpace)
1292 FN_LOCAL_INTEGER(lp_printing, iPrinting)
1293 FN_LOCAL_INTEGER(lp_csc_policy, iCSCPolicy)
1294 FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
1295 FN_GLOBAL_BOOL(lp_hide_local_users, &Globals.bHideLocalUsers)
1296 FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
1297 FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
1298 FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
1299
1300 /* local prototypes */
1301
1302 static int map_parameter(const char *pszParmName);
1303 static BOOL set_boolean(BOOL *pb, const char *pszParmValue);
1304 static int getservicebyname(const char *pszServiceName,
1305                             service * pserviceDest);
1306 static void copy_service(service * pserviceDest,
1307                          service * pserviceSource, BOOL *pcopymapDest);
1308 static BOOL service_ok(int iService);
1309 static BOOL do_section(const char *pszSectionName);
1310 static void init_copymap(service * pservice);
1311
1312 /* This is a helper function for parametrical options support. */
1313 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
1314 /* Actual parametrical functions are quite simple */
1315 static const char *get_parametrics(int lookup_service, const char *type, const char *option)
1316 {
1317         char *vfskey;
1318         struct param_opt *data;
1319         
1320         if (lookup_service >= iNumServices) return NULL;
1321         
1322         data = (lookup_service < 0) ? 
1323                 Globals.param_opt : ServicePtrs[lookup_service]->param_opt;
1324     
1325         asprintf(&vfskey, "%s:%s", type, option);
1326         strlower(vfskey);
1327
1328         while (data) {
1329                 if (strcmp(data->key, vfskey) == 0) {
1330                         free(vfskey);
1331                         return data->value;
1332                 }
1333                 data = data->next;
1334         }
1335
1336         if (lookup_service >= 0) {
1337                 /* Try to fetch the same option but from globals */
1338                 /* but only if we are not already working with Globals */
1339                 data = Globals.param_opt;
1340                 while (data) {
1341                         if (strcmp(data->key, vfskey) == 0) {
1342                                 free(vfskey);
1343                                 return data->value;
1344                         }
1345                         data = data->next;
1346                 }
1347         }
1348
1349         free(vfskey);
1350         
1351         return NULL;
1352 }
1353
1354
1355 /*******************************************************************
1356 convenience routine to return int parameters.
1357 ********************************************************************/
1358 static int lp_int(const char *s)
1359 {
1360
1361         if (!s) {
1362                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
1363                 return (-1);
1364         }
1365
1366         return atoi(s); 
1367 }
1368
1369 /*******************************************************************
1370 convenience routine to return unsigned long parameters.
1371 ********************************************************************/
1372 static int lp_ulong(const char *s)
1373 {
1374
1375         if (!s) {
1376                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
1377                 return (-1);
1378         }
1379
1380         return strtoul(s, NULL, 10);
1381 }
1382
1383 /*******************************************************************
1384 convenience routine to return boolean parameters.
1385 ********************************************************************/
1386 static BOOL lp_bool(const char *s)
1387 {
1388         BOOL ret = False;
1389
1390         if (!s) {
1391                 DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
1392                 return False;
1393         }
1394         
1395         if (!set_boolean(&ret,s)) {
1396                 DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
1397                 return False;
1398         }
1399
1400         return ret;
1401 }
1402
1403
1404 /* Return parametric option from a given service. Type is a part of option before ':' */
1405 /* Parametric option has following syntax: 'Type: option = value' */
1406 /* Returned value is allocated in 'lp_talloc' context */
1407
1408 const char *lp_parm_string(int lookup_service, const char *type, const char *option)
1409 {
1410         const char *value = get_parametrics(lookup_service, type, option);
1411         
1412         if (value)
1413                 return lp_string(value);
1414
1415         return NULL;
1416 }
1417
1418 /* Return parametric option from a given service. Type is a part of option before ':' */
1419 /* Parametric option has following syntax: 'Type: option = value' */
1420 /* Returned value is allocated in 'lp_talloc' context */
1421
1422 char **lp_parm_string_list(int lookup_service, const char *type, const char *option,
1423                            const char *separator)
1424 {
1425         const char *value = get_parametrics(lookup_service, type, option);
1426         
1427         if (value)
1428                 return str_list_make(value, separator);
1429
1430         return NULL;
1431 }
1432
1433 /* Return parametric option from a given service. Type is a part of option before ':' */
1434 /* Parametric option has following syntax: 'Type: option = value' */
1435
1436 int lp_parm_int(int lookup_service, const char *type, const char *option)
1437 {
1438         const char *value = get_parametrics(lookup_service, type, option);
1439         
1440         if (value)
1441                 return lp_int(value);
1442
1443         return (-1);
1444 }
1445
1446 /* Return parametric option from a given service. Type is a part of option before ':' */
1447 /* Parametric option has following syntax: 'Type: option = value' */
1448
1449 unsigned long lp_parm_ulong(int lookup_service, const char *type, const char *option)
1450 {
1451         const char *value = get_parametrics(lookup_service, type, option);
1452         
1453         if (value)
1454                 return lp_ulong(value);
1455
1456         return (0);
1457 }
1458
1459 /* Return parametric option from a given service. Type is a part of option before ':' */
1460 /* Parametric option has following syntax: 'Type: option = value' */
1461
1462 BOOL lp_parm_bool(int lookup_service, const char *type, const char *option, BOOL default_v)
1463 {
1464         const char *value = get_parametrics(lookup_service, type, option);
1465         
1466         if (value)
1467                 return lp_bool(value);
1468
1469         return default_v;
1470 }
1471
1472
1473 /***************************************************************************
1474  Initialise a service to the defaults.
1475 ***************************************************************************/
1476
1477 static void init_service(service * pservice)
1478 {
1479         memset((char *)pservice, '\0', sizeof(service));
1480         copy_service(pservice, &sDefault, NULL);
1481 }
1482
1483 /***************************************************************************
1484  Free the dynamically allocated parts of a service struct.
1485 ***************************************************************************/
1486
1487 static void free_service(service *pservice)
1488 {
1489         int i;
1490         struct param_opt *data, *pdata;
1491         if (!pservice)
1492                 return;
1493
1494         if (pservice->szService)
1495                 DEBUG(5, ("free_service: Freeing service %s\n",
1496                        pservice->szService));
1497
1498         string_free(&pservice->szService);
1499         SAFE_FREE(pservice->copymap);
1500
1501         for (i = 0; parm_table[i].label; i++) {
1502                 if ((parm_table[i].type == P_STRING ||
1503                      parm_table[i].type == P_USTRING) &&
1504                     parm_table[i].class == P_LOCAL)
1505                         string_free((char **)
1506                                     (((char *)pservice) +
1507                                      PTR_DIFF(parm_table[i].ptr, &sDefault)));
1508                 else if (parm_table[i].type == P_LIST &&
1509                          parm_table[i].class == P_LOCAL)
1510                              str_list_free((char ***)
1511                                             (((char *)pservice) +
1512                                              PTR_DIFF(parm_table[i].ptr, &sDefault)));
1513         }
1514                                 
1515         DEBUG(5,("Freeing parametrics:\n"));
1516         data = pservice->param_opt;
1517         while (data) {
1518                 DEBUG(5,("[%s = %s]\n", data->key, data->value));
1519                 string_free(&data->key);
1520                 string_free(&data->value);
1521                 pdata = data->next;
1522                 SAFE_FREE(data);
1523                 data = pdata;
1524         }
1525
1526         ZERO_STRUCTP(pservice);
1527 }
1528
1529 /***************************************************************************
1530  Add a new service to the services array initialising it with the given 
1531  service. 
1532 ***************************************************************************/
1533
1534 static int add_a_service(const service *pservice, const char *name)
1535 {
1536         int i;
1537         service tservice;
1538         int num_to_alloc = iNumServices + 1;
1539         struct param_opt *data, *pdata;
1540
1541         tservice = *pservice;
1542
1543         /* it might already exist */
1544         if (name) {
1545                 i = getservicebyname(name, NULL);
1546                 if (i >= 0) {
1547                         /* Clean all parametric options for service */
1548                         /* They will be added during parsing again */
1549                         data = ServicePtrs[i]->param_opt;
1550                         while (data) {
1551                                 string_free(&data->key);
1552                                 string_free(&data->value);
1553                                 pdata = data->next;
1554                                 SAFE_FREE(data);
1555                                 data = pdata;
1556                         }
1557                         ServicePtrs[i]->param_opt = NULL;
1558                         return (i);
1559                 }
1560         }
1561
1562         /* find an invalid one */
1563         for (i = 0; i < iNumServices; i++)
1564                 if (!ServicePtrs[i]->valid)
1565                         break;
1566
1567         /* if not, then create one */
1568         if (i == iNumServices) {
1569                 service **tsp;
1570                 
1571                 tsp = realloc_p(ServicePtrs, service *, num_to_alloc);
1572                                            
1573                 if (!tsp) {
1574                         DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
1575                         return (-1);
1576                 }
1577                 else {
1578                         ServicePtrs = tsp;
1579                         ServicePtrs[iNumServices] =
1580                                 (service *) malloc(sizeof(service));
1581                 }
1582                 if (!ServicePtrs[iNumServices]) {
1583                         DEBUG(0,("add_a_service: out of memory!\n"));
1584                         return (-1);
1585                 }
1586
1587                 iNumServices++;
1588         } else
1589                 free_service(ServicePtrs[i]);
1590
1591         ServicePtrs[i]->valid = True;
1592
1593         init_service(ServicePtrs[i]);
1594         copy_service(ServicePtrs[i], &tservice, NULL);
1595         if (name)
1596                 string_set(&ServicePtrs[i]->szService, name);
1597         return (i);
1598 }
1599
1600 /***************************************************************************
1601  Add a new home service, with the specified home directory, defaults coming 
1602  from service ifrom.
1603 ***************************************************************************/
1604
1605 BOOL lp_add_home(const char *pszHomename, int iDefaultService, 
1606                  const char *user, const char *pszHomedir)
1607 {
1608         int i;
1609         pstring newHomedir;
1610
1611         i = add_a_service(ServicePtrs[iDefaultService], pszHomename);
1612
1613         if (i < 0)
1614                 return (False);
1615
1616         if (!(*(ServicePtrs[iDefaultService]->szPath))
1617             || strequal(ServicePtrs[iDefaultService]->szPath, lp_pathname(-1))) {
1618                 pstrcpy(newHomedir, pszHomedir);
1619         } else {
1620                 pstrcpy(newHomedir, lp_pathname(iDefaultService));
1621                 string_sub(newHomedir,"%H", pszHomedir, sizeof(newHomedir)); 
1622         }
1623
1624         string_set(&ServicePtrs[i]->szPath, newHomedir);
1625
1626         if (!(*(ServicePtrs[i]->comment))) {
1627                 pstring comment;
1628                 slprintf(comment, sizeof(comment) - 1,
1629                          "Home directory of %s", user);
1630                 string_set(&ServicePtrs[i]->comment, comment);
1631         }
1632         ServicePtrs[i]->bAvailable = sDefault.bAvailable;
1633         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1634
1635         DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename, 
1636                user, newHomedir));
1637         
1638         return (True);
1639 }
1640
1641 /***************************************************************************
1642  Add a new service, based on an old one.
1643 ***************************************************************************/
1644
1645 int lp_add_service(const char *pszService, int iDefaultService)
1646 {
1647         return (add_a_service(ServicePtrs[iDefaultService], pszService));
1648 }
1649
1650 /***************************************************************************
1651  Add the IPC service.
1652 ***************************************************************************/
1653
1654 static BOOL lp_add_ipc(const char *ipc_name, BOOL guest_ok)
1655 {
1656         pstring comment;
1657         int i = add_a_service(&sDefault, ipc_name);
1658
1659         if (i < 0)
1660                 return (False);
1661
1662         slprintf(comment, sizeof(comment) - 1,
1663                  "IPC Service (%s)", Globals.szServerString);
1664
1665         string_set(&ServicePtrs[i]->szPath, tmpdir());
1666         string_set(&ServicePtrs[i]->szUsername, "");
1667         string_set(&ServicePtrs[i]->comment, comment);
1668         string_set(&ServicePtrs[i]->fstype, "IPC");
1669         ServicePtrs[i]->iMaxConnections = 0;
1670         ServicePtrs[i]->bAvailable = True;
1671         ServicePtrs[i]->bRead_only = True;
1672         ServicePtrs[i]->bGuest_only = False;
1673         ServicePtrs[i]->bGuest_ok = guest_ok;
1674         ServicePtrs[i]->bPrint_ok = False;
1675         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1676
1677         lp_do_parameter(i, "ntvfs handler", "default");
1678
1679         DEBUG(3, ("adding IPC service\n"));
1680
1681         return (True);
1682 }
1683
1684 /***************************************************************************
1685  Add a new printer service, with defaults coming from service iFrom.
1686 ***************************************************************************/
1687
1688 BOOL lp_add_printer(const char *pszPrintername, int iDefaultService)
1689 {
1690         const char *comment = "From Printcap";
1691         int i = add_a_service(ServicePtrs[iDefaultService], pszPrintername);
1692
1693         if (i < 0)
1694                 return (False);
1695
1696         /* note that we do NOT default the availability flag to True - */
1697         /* we take it from the default service passed. This allows all */
1698         /* dynamic printers to be disabled by disabling the [printers] */
1699         /* entry (if/when the 'available' keyword is implemented!).    */
1700
1701         /* the printer name is set to the service name. */
1702         string_set(&ServicePtrs[i]->szPrintername, pszPrintername);
1703         string_set(&ServicePtrs[i]->comment, comment);
1704         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1705         /* Printers cannot be read_only. */
1706         ServicePtrs[i]->bRead_only = False;
1707         /* No share modes on printer services. */
1708         ServicePtrs[i]->bShareModes = False;
1709         /* No oplocks on printer services. */
1710         ServicePtrs[i]->bOpLocks = False;
1711         /* Printer services must be printable. */
1712         ServicePtrs[i]->bPrint_ok = True;
1713
1714         DEBUG(3, ("adding printer service %s\n", pszPrintername));
1715
1716         update_server_announce_as_printserver();
1717
1718         return (True);
1719 }
1720
1721 /***************************************************************************
1722  Map a parameter's string representation to something we can use. 
1723  Returns False if the parameter string is not recognised, else TRUE.
1724 ***************************************************************************/
1725
1726 static int map_parameter(const char *pszParmName)
1727 {
1728         int iIndex;
1729
1730         if (*pszParmName == '-')
1731                 return (-1);
1732
1733         for (iIndex = 0; parm_table[iIndex].label; iIndex++)
1734                 if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1735                         return (iIndex);
1736
1737         /* Warn only if it isn't parametric option */
1738         if (strchr(pszParmName, ':') == NULL)
1739                 DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
1740         /* We do return 'fail' for parametric options as well because they are
1741            stored in different storage
1742          */
1743         return (-1);
1744 }
1745
1746 /***************************************************************************
1747  Set a boolean variable from the text value stored in the passed string.
1748  Returns True in success, False if the passed string does not correctly 
1749  represent a boolean.
1750 ***************************************************************************/
1751
1752 static BOOL set_boolean(BOOL *pb, const char *pszParmValue)
1753 {
1754         BOOL bRetval;
1755
1756         bRetval = True;
1757         if (strwicmp(pszParmValue, "yes") == 0 ||
1758             strwicmp(pszParmValue, "true") == 0 ||
1759             strwicmp(pszParmValue, "1") == 0)
1760                 *pb = True;
1761         else if (strwicmp(pszParmValue, "no") == 0 ||
1762                     strwicmp(pszParmValue, "False") == 0 ||
1763                     strwicmp(pszParmValue, "0") == 0)
1764                 *pb = False;
1765         else {
1766                 DEBUG(0,
1767                       ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
1768                        pszParmValue));
1769                 bRetval = False;
1770         }
1771         return (bRetval);
1772 }
1773
1774 /***************************************************************************
1775 Find a service by name. Otherwise works like get_service.
1776 ***************************************************************************/
1777
1778 static int getservicebyname(const char *pszServiceName, service * pserviceDest)
1779 {
1780         int iService;
1781
1782         for (iService = iNumServices - 1; iService >= 0; iService--)
1783                 if (VALID(iService) &&
1784                     strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0) {
1785                         if (pserviceDest != NULL)
1786                                 copy_service(pserviceDest, ServicePtrs[iService], NULL);
1787                         break;
1788                 }
1789
1790         return (iService);
1791 }
1792
1793 /***************************************************************************
1794  Copy a service structure to another.
1795  If pcopymapDest is NULL then copy all fields
1796 ***************************************************************************/
1797
1798 static void copy_service(service * pserviceDest, service * pserviceSource, BOOL *pcopymapDest)
1799 {
1800         int i;
1801         BOOL bcopyall = (pcopymapDest == NULL);
1802         struct param_opt *data, *pdata, *paramo;
1803         BOOL not_added;
1804
1805         for (i = 0; parm_table[i].label; i++)
1806                 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL &&
1807                     (bcopyall || pcopymapDest[i])) {
1808                         void *def_ptr = parm_table[i].ptr;
1809                         void *src_ptr =
1810                                 ((char *)pserviceSource) + PTR_DIFF(def_ptr,
1811                                                                     &sDefault);
1812                         void *dest_ptr =
1813                                 ((char *)pserviceDest) + PTR_DIFF(def_ptr,
1814                                                                   &sDefault);
1815
1816                         switch (parm_table[i].type) {
1817                                 case P_BOOL:
1818                                 case P_BOOLREV:
1819                                         *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1820                                         break;
1821
1822                                 case P_INTEGER:
1823                                 case P_ENUM:
1824                                 case P_OCTAL:
1825                                         *(int *)dest_ptr = *(int *)src_ptr;
1826                                         break;
1827
1828                                 case P_CHAR:
1829                                         *(char *)dest_ptr = *(char *)src_ptr;
1830                                         break;
1831
1832                                 case P_STRING:
1833                                         string_set(dest_ptr,
1834                                                    *(char **)src_ptr);
1835                                         break;
1836
1837                                 case P_USTRING:
1838                                         string_set(dest_ptr,
1839                                                    *(char **)src_ptr);
1840                                         strupper(*(char **)dest_ptr);
1841                                         break;
1842                                 case P_LIST:
1843                                         str_list_copy((char ***)dest_ptr, *(const char ***)src_ptr);
1844                                         break;
1845                                 default:
1846                                         break;
1847                         }
1848                 }
1849
1850         if (bcopyall) {
1851                 init_copymap(pserviceDest);
1852                 if (pserviceSource->copymap)
1853                         memcpy((void *)pserviceDest->copymap,
1854                                (void *)pserviceSource->copymap,
1855                                sizeof(BOOL) * NUMPARAMETERS);
1856         }
1857         
1858         data = pserviceSource->param_opt;
1859         while (data) {
1860                 not_added = True;
1861                 pdata = pserviceDest->param_opt;
1862                 /* Traverse destination */
1863                 while (pdata) {
1864                         /* If we already have same option, override it */
1865                         if (strcmp(pdata->key, data->key) == 0) {
1866                                 string_free(&pdata->value);
1867                                 pdata->value = strdup(data->value);
1868                                 not_added = False;
1869                                 break;
1870                         }
1871                         pdata = pdata->next;
1872                 }
1873                 if (not_added) {
1874                         paramo = smb_xmalloc(sizeof(*paramo));
1875                         paramo->key = strdup(data->key);
1876                         paramo->value = strdup(data->value);
1877                         DLIST_ADD(pserviceDest->param_opt, paramo);
1878                 }
1879                 data = data->next;
1880         }
1881 }
1882
1883 /***************************************************************************
1884 Check a service for consistency. Return False if the service is in any way
1885 incomplete or faulty, else True.
1886 ***************************************************************************/
1887
1888 static BOOL service_ok(int iService)
1889 {
1890         BOOL bRetval;
1891
1892         bRetval = True;
1893         if (ServicePtrs[iService]->szService[0] == '\0') {
1894                 DEBUG(0, ("The following message indicates an internal error:\n"));
1895                 DEBUG(0, ("No service name in service entry.\n"));
1896                 bRetval = False;
1897         }
1898
1899         /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1900         /* I can't see why you'd want a non-printable printer service...        */
1901         if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
1902                 if (!ServicePtrs[iService]->bPrint_ok) {
1903                         DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
1904                                ServicePtrs[iService]->szService));
1905                         ServicePtrs[iService]->bPrint_ok = True;
1906                 }
1907                 /* [printers] service must also be non-browsable. */
1908                 if (ServicePtrs[iService]->bBrowseable)
1909                         ServicePtrs[iService]->bBrowseable = False;
1910         }
1911
1912         /* If a service is flagged unavailable, log the fact at level 0. */
1913         if (!ServicePtrs[iService]->bAvailable)
1914                 DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
1915                           ServicePtrs[iService]->szService));
1916
1917         return (bRetval);
1918 }
1919
1920 static struct file_lists {
1921         struct file_lists *next;
1922         char *name;
1923         char *subfname;
1924         time_t modtime;
1925 } *file_lists = NULL;
1926
1927 /*******************************************************************
1928  Keep a linked list of all config files so we know when one has changed 
1929  it's date and needs to be reloaded.
1930 ********************************************************************/
1931
1932 static void add_to_file_list(const char *fname, const char *subfname)
1933 {
1934         struct file_lists *f = file_lists;
1935
1936         while (f) {
1937                 if (f->name && !strcmp(f->name, fname))
1938                         break;
1939                 f = f->next;
1940         }
1941
1942         if (!f) {
1943                 f = (struct file_lists *)malloc(sizeof(file_lists[0]));
1944                 if (!f)
1945                         return;
1946                 f->next = file_lists;
1947                 f->name = strdup(fname);
1948                 if (!f->name) {
1949                         SAFE_FREE(f);
1950                         return;
1951                 }
1952                 f->subfname = strdup(subfname);
1953                 if (!f->subfname) {
1954                         SAFE_FREE(f);
1955                         return;
1956                 }
1957                 file_lists = f;
1958                 f->modtime = file_modtime(subfname);
1959         } else {
1960                 time_t t = file_modtime(subfname);
1961                 if (t)
1962                         f->modtime = t;
1963         }
1964 }
1965
1966 /*******************************************************************
1967  Check if a config file has changed date.
1968 ********************************************************************/
1969
1970 BOOL lp_file_list_changed(void)
1971 {
1972         struct file_lists *f = file_lists;
1973         DEBUG(6, ("lp_file_list_changed()\n"));
1974
1975         while (f) {
1976                 pstring n2;
1977                 time_t mod_time;
1978
1979                 pstrcpy(n2, f->name);
1980                 standard_sub_basic(n2,sizeof(n2));
1981
1982                 DEBUGADD(6, ("file %s -> %s  last mod_time: %s\n",
1983                              f->name, n2, ctime(&f->modtime)));
1984
1985                 mod_time = file_modtime(n2);
1986
1987                 if (mod_time && ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))) {
1988                         DEBUGADD(6,
1989                                  ("file %s modified: %s\n", n2,
1990                                   ctime(&mod_time)));
1991                         f->modtime = mod_time;
1992                         SAFE_FREE(f->subfname);
1993                         f->subfname = strdup(n2);
1994                         return (True);
1995                 }
1996                 f = f->next;
1997         }
1998         return (False);
1999 }
2000
2001 /***************************************************************************
2002  Handle the include operation.
2003 ***************************************************************************/
2004
2005 static BOOL handle_include(const char *pszParmValue, char **ptr)
2006 {
2007         pstring fname;
2008         pstrcpy(fname, pszParmValue);
2009
2010         standard_sub_basic(fname,sizeof(fname));
2011
2012         add_to_file_list(pszParmValue, fname);
2013
2014         string_set(ptr, fname);
2015
2016         if (file_exist(fname, NULL))
2017                 return (pm_process(fname, do_section, do_parameter));
2018
2019         DEBUG(2, ("Can't find include file %s\n", fname));
2020
2021         return (False);
2022 }
2023
2024 /***************************************************************************
2025  Handle the interpretation of the copy parameter.
2026 ***************************************************************************/
2027
2028 static BOOL handle_copy(const char *pszParmValue, char **ptr)
2029 {
2030         BOOL bRetval;
2031         int iTemp;
2032         service serviceTemp;
2033
2034         string_set(ptr, pszParmValue);
2035
2036         init_service(&serviceTemp);
2037
2038         bRetval = False;
2039
2040         DEBUG(3, ("Copying service from service %s\n", pszParmValue));
2041
2042         if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0) {
2043                 if (iTemp == iServiceIndex) {
2044                         DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
2045                 } else {
2046                         copy_service(ServicePtrs[iServiceIndex],
2047                                      &serviceTemp,
2048                                      ServicePtrs[iServiceIndex]->copymap);
2049                         bRetval = True;
2050                 }
2051         } else {
2052                 DEBUG(0, ("Unable to copy service - source not found: %s\n", pszParmValue));
2053                 bRetval = False;
2054         }
2055
2056         free_service(&serviceTemp);
2057         return (bRetval);
2058 }
2059
2060 /***************************************************************************
2061  Handle winbind/non unix account uid and gid allocation parameters.  The format of these
2062  parameters is:
2063
2064  [global]
2065
2066         winbind uid = 1000-1999
2067         winbind gid = 700-899
2068
2069  We only do simple parsing checks here.  The strings are parsed into useful
2070  structures in the winbind daemon code.
2071
2072 ***************************************************************************/
2073
2074 /* Some lp_ routines to return winbind [ug]id information */
2075
2076 static uid_t winbind_uid_low, winbind_uid_high;
2077 static gid_t winbind_gid_low, winbind_gid_high;
2078 static uint32_t non_unix_account_low, non_unix_account_high;
2079
2080 BOOL lp_winbind_uid(uid_t *low, uid_t *high)
2081 {
2082         if (winbind_uid_low == 0 || winbind_uid_high == 0)
2083                 return False;
2084
2085         if (low)
2086                 *low = winbind_uid_low;
2087
2088         if (high)
2089                 *high = winbind_uid_high;
2090
2091         return True;
2092 }
2093
2094 BOOL lp_winbind_gid(gid_t *low, gid_t *high)
2095 {
2096         if (winbind_gid_low == 0 || winbind_gid_high == 0)
2097                 return False;
2098
2099         if (low)
2100                 *low = winbind_gid_low;
2101
2102         if (high)
2103                 *high = winbind_gid_high;
2104
2105         return True;
2106 }
2107
2108 BOOL lp_non_unix_account_range(uint32_t *low, uint32_t *high)
2109 {
2110         if (non_unix_account_low == 0 || non_unix_account_high == 0)
2111                 return False;
2112
2113         if (low)
2114                 *low = non_unix_account_low;
2115
2116         if (high)
2117                 *high = non_unix_account_high;
2118
2119         return True;
2120 }
2121
2122 /* Do some simple checks on "winbind [ug]id" parameter values */
2123
2124 static BOOL handle_winbind_uid(const char *pszParmValue, char **ptr)
2125 {
2126         uint32_t low, high;
2127
2128         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2129                 return False;
2130
2131         /* Parse OK */
2132
2133         string_set(ptr, pszParmValue);
2134
2135         winbind_uid_low = low;
2136         winbind_uid_high = high;
2137
2138         return True;
2139 }
2140
2141 static BOOL handle_winbind_gid(const char *pszParmValue, char **ptr)
2142 {
2143         uint32_t low, high;
2144
2145         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2146                 return False;
2147
2148         /* Parse OK */
2149
2150         string_set(ptr, pszParmValue);
2151
2152         winbind_gid_low = low;
2153         winbind_gid_high = high;
2154
2155         return True;
2156 }
2157
2158 /***************************************************************************
2159  Do some simple checks on "non unix account range" parameter values.
2160 ***************************************************************************/
2161
2162 static BOOL handle_non_unix_account_range(const char *pszParmValue, char **ptr)
2163 {
2164         uint32_t low, high;
2165
2166         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2167                 return False;
2168
2169         /* Parse OK */
2170
2171         string_set(ptr, pszParmValue);
2172
2173         non_unix_account_low = low;
2174         non_unix_account_high = high;
2175
2176         return True;
2177 }
2178
2179
2180 /***************************************************************************
2181  Initialise a copymap.
2182 ***************************************************************************/
2183
2184 static void init_copymap(service * pservice)
2185 {
2186         int i;
2187         SAFE_FREE(pservice->copymap);
2188         pservice->copymap = (BOOL *)malloc(sizeof(BOOL) * NUMPARAMETERS);
2189         if (!pservice->copymap)
2190                 DEBUG(0,
2191                       ("Couldn't allocate copymap!! (size %d)\n",
2192                        (int)NUMPARAMETERS));
2193         else
2194                 for (i = 0; i < NUMPARAMETERS; i++)
2195                         pservice->copymap[i] = True;
2196 }
2197
2198 /***************************************************************************
2199  Return the local pointer to a parameter given the service number and the 
2200  pointer into the default structure.
2201 ***************************************************************************/
2202
2203 void *lp_local_ptr(int snum, void *ptr)
2204 {
2205         return (void *)(((char *)ServicePtrs[snum]) + PTR_DIFF(ptr, &sDefault));
2206 }
2207
2208
2209 /***************************************************************************
2210  Process a parametric option
2211 ***************************************************************************/
2212 static BOOL lp_do_parameter_parametric(int snum, const char *pszParmName, const char *pszParmValue, int flags)
2213 {
2214         struct param_opt *paramo, *data;
2215         char *name;
2216
2217         while (isspace(*pszParmName)) {
2218                 pszParmName++;
2219         }
2220
2221         name = strdup(pszParmName);
2222         if (!name) return False;
2223
2224         strlower(name);
2225
2226         if (snum < 0) {
2227                 data = Globals.param_opt;
2228         } else {
2229                 data = ServicePtrs[snum]->param_opt;
2230         }
2231
2232         /* Traverse destination */
2233         for (paramo=data; paramo; paramo=paramo->next) {
2234                 /* If we already have the option set, override it unless
2235                    it was a command line option and the new one isn't */
2236                 if (strcmp(paramo->key, name) == 0) {
2237                         if ((paramo->flags & FLAG_CMDLINE) &&
2238                             !(flags & FLAG_CMDLINE)) {
2239                                 return True;
2240                         }
2241
2242                         free(paramo->value);
2243                         paramo->value = strdup(pszParmValue);
2244                         paramo->flags = flags;
2245                         free(name);
2246                         return True;
2247                 }
2248         }
2249
2250         paramo = smb_xmalloc(sizeof(*paramo));
2251         paramo->key = strdup(name);
2252         paramo->value = strdup(pszParmValue);
2253         paramo->flags = flags;
2254         if (snum < 0) {
2255                 DLIST_ADD(Globals.param_opt, paramo);
2256         } else {
2257                 DLIST_ADD(ServicePtrs[snum]->param_opt, paramo);
2258         }
2259
2260         free(name);
2261         
2262         return True;
2263 }
2264
2265 /***************************************************************************
2266  Process a parameter for a particular service number. If snum < 0
2267  then assume we are in the globals.
2268 ***************************************************************************/
2269 BOOL lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue)
2270 {
2271         int parmnum, i;
2272         void *parm_ptr = NULL;  /* where we are going to store the result */
2273         void *def_ptr = NULL;
2274
2275         parmnum = map_parameter(pszParmName);
2276
2277         if (parmnum < 0) {
2278                 if (strchr(pszParmName, ':')) {
2279                         return lp_do_parameter_parametric(snum, pszParmName, pszParmValue, 0);
2280                 }
2281                 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
2282                 return (True);
2283         }
2284
2285         if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
2286                 DEBUG(1, ("WARNING: The \"%s\" option is deprecated\n",
2287                           pszParmName));
2288         }
2289
2290         /* if the flag has been set on the command line, then don't allow override,
2291            but don't report an error */
2292         if (parm_table[parmnum].flags & FLAG_CMDLINE) {
2293                 return True;
2294         }
2295
2296         def_ptr = parm_table[parmnum].ptr;
2297
2298         /* we might point at a service, the default service or a global */
2299         if (snum < 0) {
2300                 parm_ptr = def_ptr;
2301         } else {
2302                 if (parm_table[parmnum].class == P_GLOBAL) {
2303                         DEBUG(0,
2304                               ("Global parameter %s found in service section!\n",
2305                                pszParmName));
2306                         return (True);
2307                 }
2308                 parm_ptr =
2309                         ((char *)ServicePtrs[snum]) + PTR_DIFF(def_ptr,
2310                                                             &sDefault);
2311         }
2312
2313         if (snum >= 0) {
2314                 if (!ServicePtrs[snum]->copymap)
2315                         init_copymap(ServicePtrs[snum]);
2316
2317                 /* this handles the aliases - set the copymap for other entries with
2318                    the same data pointer */
2319                 for (i = 0; parm_table[i].label; i++)
2320                         if (parm_table[i].ptr == parm_table[parmnum].ptr)
2321                                 ServicePtrs[snum]->copymap[i] = False;
2322         }
2323
2324         /* if it is a special case then go ahead */
2325         if (parm_table[parmnum].special) {
2326                 parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
2327                 return (True);
2328         }
2329
2330         /* now switch on the type of variable it is */
2331         switch (parm_table[parmnum].type)
2332         {
2333                 case P_BOOL:
2334                         set_boolean(parm_ptr, pszParmValue);
2335                         break;
2336
2337                 case P_BOOLREV:
2338                         set_boolean(parm_ptr, pszParmValue);
2339                         *(BOOL *)parm_ptr = !*(BOOL *)parm_ptr;
2340                         break;
2341
2342                 case P_INTEGER:
2343                         *(int *)parm_ptr = atoi(pszParmValue);
2344                         break;
2345
2346                 case P_CHAR:
2347                         *(char *)parm_ptr = *pszParmValue;
2348                         break;
2349
2350                 case P_OCTAL:
2351                         sscanf(pszParmValue, "%o", (int *)parm_ptr);
2352                         break;
2353
2354                 case P_LIST:
2355                         *(char ***)parm_ptr = str_list_make(pszParmValue, NULL);
2356                         break;
2357
2358                 case P_STRING:
2359                         string_set(parm_ptr, pszParmValue);
2360                         break;
2361
2362                 case P_USTRING:
2363                         string_set(parm_ptr, pszParmValue);
2364                         strupper(*(char **)parm_ptr);
2365                         break;
2366
2367                 case P_ENUM:
2368                         for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
2369                                 if (strequal
2370                                     (pszParmValue,
2371                                      parm_table[parmnum].enum_list[i].name)) {
2372                                         *(int *)parm_ptr =
2373                                                 parm_table[parmnum].
2374                                                 enum_list[i].value;
2375                                         break;
2376                                 }
2377                         }
2378                         if (!parm_table[parmnum].enum_list[i].name) {
2379                                 DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
2380                                          pszParmValue, pszParmName));
2381                                 return False;
2382                         }
2383                         break;
2384                 case P_SEP:
2385                         break;
2386         }
2387
2388         return (True);
2389 }
2390
2391 /***************************************************************************
2392  Process a parameter.
2393 ***************************************************************************/
2394
2395 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue)
2396 {
2397         if (!bInGlobalSection && bGlobalOnly)
2398                 return (True);
2399
2400         return (lp_do_parameter(bInGlobalSection ? -2 : iServiceIndex,
2401                                 pszParmName, pszParmValue));
2402 }
2403
2404 /*
2405   variable argument do parameter
2406 */
2407 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
2408
2409 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...)
2410 {
2411         char *s;
2412         BOOL ret;
2413         va_list ap;
2414
2415         va_start(ap, fmt);      
2416         s = talloc_vasprintf(NULL, fmt, ap);
2417         va_end(ap);
2418         ret = do_parameter(pszParmName, s);
2419         talloc_free(s);
2420         return ret;
2421 }
2422
2423
2424 /*
2425   set a parameter from the commandline - this is called from command line parameter
2426   parsing code. It sets the parameter then marks the parameter as unable to be modified
2427   by smb.conf processing
2428 */
2429 BOOL lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
2430 {
2431         int parmnum = map_parameter(pszParmName);
2432         int i;
2433
2434         while (isspace(*pszParmValue)) pszParmValue++;
2435
2436
2437         if (parmnum < 0 && strchr(pszParmName, ':')) {
2438                 /* set a parametric option */
2439                 return lp_do_parameter_parametric(-1, pszParmName, pszParmValue, FLAG_CMDLINE);
2440         }
2441
2442         if (parmnum < 0) {
2443                 DEBUG(0,("Unknown option '%s'\n", pszParmName));
2444                 return False;
2445         }
2446
2447         /* reset the CMDLINE flag in case this has been called before */
2448         parm_table[parmnum].flags &= ~FLAG_CMDLINE;
2449
2450         if (!lp_do_parameter(-2, pszParmName, pszParmValue)) {
2451                 return False;
2452         }
2453
2454         parm_table[parmnum].flags |= FLAG_CMDLINE;
2455
2456         /* we have to also set FLAG_CMDLINE on aliases */
2457         for (i=parmnum-1;i>=0 && parm_table[i].ptr == parm_table[parmnum].ptr;i--) {
2458                 parm_table[i].flags |= FLAG_CMDLINE;
2459         }
2460         for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].ptr == parm_table[parmnum].ptr;i++) {
2461                 parm_table[i].flags |= FLAG_CMDLINE;
2462         }
2463
2464         return True;
2465 }
2466
2467 /*
2468   set a option from the commandline in 'a=b' format. Use to support --option
2469 */
2470 BOOL lp_set_option(const char *option)
2471 {
2472         char *p, *s;
2473         BOOL ret;
2474
2475         s = strdup(option);
2476         if (!s) {
2477                 return False;
2478         }
2479
2480         p = strchr(s, '=');
2481         if (!p) {
2482                 free(s);
2483                 return False;
2484         }
2485
2486         *p = 0;
2487
2488         ret = lp_set_cmdline(s, p+1);
2489         free(s);
2490         return ret;
2491 }
2492
2493
2494 /***************************************************************************
2495  Print a parameter of the specified type.
2496 ***************************************************************************/
2497
2498 static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
2499 {
2500         int i;
2501         switch (p->type)
2502         {
2503                 case P_ENUM:
2504                         for (i = 0; p->enum_list[i].name; i++) {
2505                                 if (*(int *)ptr == p->enum_list[i].value) {
2506                                         fprintf(f, "%s",
2507                                                 p->enum_list[i].name);
2508                                         break;
2509                                 }
2510                         }
2511                         break;
2512
2513                 case P_BOOL:
2514                         fprintf(f, "%s", BOOLSTR(*(BOOL *)ptr));
2515                         break;
2516
2517                 case P_BOOLREV:
2518                         fprintf(f, "%s", BOOLSTR(!*(BOOL *)ptr));
2519                         break;
2520
2521                 case P_INTEGER:
2522                         fprintf(f, "%d", *(int *)ptr);
2523                         break;
2524
2525                 case P_CHAR:
2526                         fprintf(f, "%c", *(char *)ptr);
2527                         break;
2528
2529                 case P_OCTAL:
2530                         if (*(int *)ptr == -1) {
2531                                 fprintf(f, "-1");
2532                         } else {
2533                                 fprintf(f, "0%o", *(int *)ptr);
2534                         }
2535                         break;
2536
2537                 case P_LIST:
2538                         if ((char ***)ptr && *(char ***)ptr) {
2539                                 char **list = *(char ***)ptr;
2540                                 
2541                                 for (; *list; list++)
2542                                         fprintf(f, "%s%s", *list,
2543                                                 ((*(list+1))?", ":""));
2544                         }
2545                         break;
2546
2547                 case P_STRING:
2548                 case P_USTRING:
2549                         if (*(char **)ptr) {
2550                                 fprintf(f, "%s", *(char **)ptr);
2551                         }
2552                         break;
2553                 case P_SEP:
2554                         break;
2555         }
2556 }
2557
2558 /***************************************************************************
2559  Check if two parameters are equal.
2560 ***************************************************************************/
2561
2562 static BOOL equal_parameter(parm_type type, void *ptr1, void *ptr2)
2563 {
2564         switch (type) {
2565                 case P_BOOL:
2566                 case P_BOOLREV:
2567                         return (*((BOOL *)ptr1) == *((BOOL *)ptr2));
2568
2569                 case P_INTEGER:
2570                 case P_ENUM:
2571                 case P_OCTAL:
2572                         return (*((int *)ptr1) == *((int *)ptr2));
2573
2574                 case P_CHAR:
2575                         return (*((char *)ptr1) == *((char *)ptr2));
2576                 
2577                 case P_LIST:
2578                         return str_list_compare(*(char ***)ptr1, *(char ***)ptr2);
2579
2580                 case P_STRING:
2581                 case P_USTRING:
2582                 {
2583                         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
2584                         if (p1 && !*p1)
2585                                 p1 = NULL;
2586                         if (p2 && !*p2)
2587                                 p2 = NULL;
2588                         return (p1 == p2 || strequal(p1, p2));
2589                 }
2590                 case P_SEP:
2591                         break;
2592         }
2593         return (False);
2594 }
2595
2596 /***************************************************************************
2597  Process a new section (service). At this stage all sections are services.
2598  Later we'll have special sections that permit server parameters to be set.
2599  Returns True on success, False on failure. 
2600 ***************************************************************************/
2601
2602 static BOOL do_section(const char *pszSectionName)
2603 {
2604         BOOL bRetval;
2605         BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
2606                          (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
2607         bRetval = False;
2608
2609         /* if we've just struck a global section, note the fact. */
2610         bInGlobalSection = isglobal;
2611
2612         /* check for multiple global sections */
2613         if (bInGlobalSection) {
2614                 DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
2615                 return (True);
2616         }
2617
2618         if (!bInGlobalSection && bGlobalOnly)
2619                 return (True);
2620
2621         /* if we have a current service, tidy it up before moving on */
2622         bRetval = True;
2623
2624         if (iServiceIndex >= 0)
2625                 bRetval = service_ok(iServiceIndex);
2626
2627         /* if all is still well, move to the next record in the services array */
2628         if (bRetval) {
2629                 /* We put this here to avoid an odd message order if messages are */
2630                 /* issued by the post-processing of a previous section. */
2631                 DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
2632
2633                 if ((iServiceIndex = add_a_service(&sDefault, pszSectionName))
2634                     < 0) {
2635                         DEBUG(0, ("Failed to add a new service\n"));
2636                         return (False);
2637                 }
2638         }
2639
2640         return (bRetval);
2641 }
2642
2643
2644 /***************************************************************************
2645  Determine if a partcular base parameter is currentl set to the default value.
2646 ***************************************************************************/
2647
2648 static BOOL is_default(int i)
2649 {
2650         if (!defaults_saved)
2651                 return False;
2652         switch (parm_table[i].type) {
2653                 case P_LIST:
2654                         return str_list_compare (parm_table[i].def.lvalue, 
2655                                                 *(char ***)parm_table[i].ptr);
2656                 case P_STRING:
2657                 case P_USTRING:
2658                         return strequal(parm_table[i].def.svalue,
2659                                         *(char **)parm_table[i].ptr);
2660                 case P_BOOL:
2661                 case P_BOOLREV:
2662                         return parm_table[i].def.bvalue ==
2663                                 *(BOOL *)parm_table[i].ptr;
2664                 case P_CHAR:
2665                         return parm_table[i].def.cvalue ==
2666                                 *(char *)parm_table[i].ptr;
2667                 case P_INTEGER:
2668                 case P_OCTAL:
2669                 case P_ENUM:
2670                         return parm_table[i].def.ivalue ==
2671                                 *(int *)parm_table[i].ptr;
2672                 case P_SEP:
2673                         break;
2674         }
2675         return False;
2676 }
2677
2678 /***************************************************************************
2679 Display the contents of the global structure.
2680 ***************************************************************************/
2681
2682 static void dump_globals(FILE *f)
2683 {
2684         int i;
2685         struct param_opt *data;
2686         
2687         fprintf(f, "# Global parameters\n[global]\n");
2688
2689         for (i = 0; parm_table[i].label; i++)
2690                 if (parm_table[i].class == P_GLOBAL &&
2691                     parm_table[i].ptr &&
2692                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2693                         if (defaults_saved && is_default(i))
2694                                 continue;
2695                         fprintf(f, "\t%s = ", parm_table[i].label);
2696                         print_parameter(&parm_table[i], parm_table[i].ptr, f);
2697                         fprintf(f, "\n");
2698         }
2699         if (Globals.param_opt != NULL) {
2700                 data = Globals.param_opt;
2701                 while(data) {
2702                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2703                         data = data->next;
2704                 }
2705         }
2706
2707 }
2708
2709 /***************************************************************************
2710  Display the contents of a single services record.
2711 ***************************************************************************/
2712
2713 static void dump_a_service(service * pService, FILE * f)
2714 {
2715         int i;
2716         struct param_opt *data;
2717         
2718         if (pService != &sDefault)
2719                 fprintf(f, "\n[%s]\n", pService->szService);
2720
2721         for (i = 0; parm_table[i].label; i++)
2722                 if (parm_table[i].class == P_LOCAL &&
2723                     parm_table[i].ptr &&
2724                     (*parm_table[i].label != '-') &&
2725                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2726                         int pdiff = PTR_DIFF(parm_table[i].ptr, &sDefault);
2727
2728                         if (pService == &sDefault) {
2729                                 if (defaults_saved && is_default(i))
2730                                         continue;
2731                         } else {
2732                                 if (equal_parameter(parm_table[i].type,
2733                                                     ((char *)pService) +
2734                                                     pdiff,
2735                                                     ((char *)&sDefault) +
2736                                                     pdiff))
2737                                         continue;
2738                         }
2739
2740                         fprintf(f, "\t%s = ", parm_table[i].label);
2741                         print_parameter(&parm_table[i],
2742                                         ((char *)pService) + pdiff, f);
2743                         fprintf(f, "\n");
2744         }
2745         if (pService->param_opt != NULL) {
2746                 data = pService->param_opt;
2747                 while(data) {
2748                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2749                         data = data->next;
2750                 }
2751         }
2752 }
2753
2754
2755 /***************************************************************************
2756  Return info about the next service  in a service. snum==-1 gives the globals.
2757  Return NULL when out of parameters.
2758 ***************************************************************************/
2759
2760 struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
2761 {
2762         if (snum == -1) {
2763                 /* do the globals */
2764                 for (; parm_table[*i].label; (*i)++) {
2765                         if (parm_table[*i].class == P_SEPARATOR)
2766                                 return &parm_table[(*i)++];
2767
2768                         if (!parm_table[*i].ptr
2769                             || (*parm_table[*i].label == '-'))
2770                                 continue;
2771
2772                         if ((*i) > 0
2773                             && (parm_table[*i].ptr ==
2774                                 parm_table[(*i) - 1].ptr))
2775                                 continue;
2776
2777                         return &parm_table[(*i)++];
2778                 }
2779         } else {
2780                 service *pService = ServicePtrs[snum];
2781
2782                 for (; parm_table[*i].label; (*i)++) {
2783                         if (parm_table[*i].class == P_SEPARATOR)
2784                                 return &parm_table[(*i)++];
2785
2786                         if (parm_table[*i].class == P_LOCAL &&
2787                             parm_table[*i].ptr &&
2788                             (*parm_table[*i].label != '-') &&
2789                             ((*i) == 0 ||
2790                              (parm_table[*i].ptr !=
2791                               parm_table[(*i) - 1].ptr)))
2792                         {
2793                                 int pdiff =
2794                                         PTR_DIFF(parm_table[*i].ptr,
2795                                                  &sDefault);
2796
2797                                 if (allparameters ||
2798                                     !equal_parameter(parm_table[*i].type,
2799                                                      ((char *)pService) +
2800                                                      pdiff,
2801                                                      ((char *)&sDefault) +
2802                                                      pdiff))
2803                                 {
2804                                         return &parm_table[(*i)++];
2805                                 }
2806                         }
2807                 }
2808         }
2809
2810         return NULL;
2811 }
2812
2813
2814 /***************************************************************************
2815  Return TRUE if the passed service number is within range.
2816 ***************************************************************************/
2817
2818 BOOL lp_snum_ok(int iService)
2819 {
2820         return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
2821 }
2822
2823 /***************************************************************************
2824  Auto-load some home services.
2825 ***************************************************************************/
2826
2827 static void lp_add_auto_services(const char *str)
2828 {
2829         return;
2830 }
2831
2832 /***************************************************************************
2833  Auto-load one printer.
2834 ***************************************************************************/
2835
2836 void lp_add_one_printer(char *name, char *comment)
2837 {
2838         int printers = lp_servicenumber(PRINTERS_NAME);
2839         int i;
2840
2841         if (lp_servicenumber(name) < 0) {
2842                 lp_add_printer(name, printers);
2843                 if ((i = lp_servicenumber(name)) >= 0) {
2844                         string_set(&ServicePtrs[i]->comment, comment);
2845                         ServicePtrs[i]->autoloaded = True;
2846                 }
2847         }
2848 }
2849
2850 /***************************************************************************
2851  Announce ourselves as a print server.
2852 ***************************************************************************/
2853
2854 void update_server_announce_as_printserver(void)
2855 {
2856         default_server_announce |= SV_TYPE_PRINTQ_SERVER;       
2857 }
2858
2859 /***************************************************************************
2860  Have we loaded a services file yet?
2861 ***************************************************************************/
2862
2863 BOOL lp_loaded(void)
2864 {
2865         return (bLoaded);
2866 }
2867
2868 /***************************************************************************
2869  Unload unused services.
2870 ***************************************************************************/
2871
2872 void lp_killunused(struct smbsrv_connection *smb, BOOL (*snumused) (struct smbsrv_connection *, int))
2873 {
2874         int i;
2875         for (i = 0; i < iNumServices; i++) {
2876                 if (!VALID(i))
2877                         continue;
2878
2879                 if (!snumused || !snumused(smb, i)) {
2880                         ServicePtrs[i]->valid = False;
2881                         free_service(ServicePtrs[i]);
2882                 }
2883         }
2884 }
2885
2886 /***************************************************************************
2887  Unload a service.
2888 ***************************************************************************/
2889
2890 void lp_killservice(int iServiceIn)
2891 {
2892         if (VALID(iServiceIn)) {
2893                 ServicePtrs[iServiceIn]->valid = False;
2894                 free_service(ServicePtrs[iServiceIn]);
2895         }
2896 }
2897
2898 /***************************************************************************
2899  Save the curent values of all global and sDefault parameters into the 
2900  defaults union. This allows swat and testparm to show only the
2901  changed (ie. non-default) parameters.
2902 ***************************************************************************/
2903
2904 static void lp_save_defaults(void)
2905 {
2906         int i;
2907         for (i = 0; parm_table[i].label; i++) {
2908                 if (i > 0 && parm_table[i].ptr == parm_table[i - 1].ptr)
2909                         continue;
2910                 switch (parm_table[i].type) {
2911                         case P_LIST:
2912                                 str_list_copy(&(parm_table[i].def.lvalue),
2913                                             *(const char ***)parm_table[i].ptr);
2914                                 break;
2915                         case P_STRING:
2916                         case P_USTRING:
2917                                 if (parm_table[i].ptr) {
2918                                         parm_table[i].def.svalue = strdup(*(char **)parm_table[i].ptr);
2919                                 } else {
2920                                         parm_table[i].def.svalue = NULL;
2921                                 }
2922                                 break;
2923                         case P_BOOL:
2924                         case P_BOOLREV:
2925                                 parm_table[i].def.bvalue =
2926                                         *(BOOL *)parm_table[i].ptr;
2927                                 break;
2928                         case P_CHAR:
2929                                 parm_table[i].def.cvalue =
2930                                         *(char *)parm_table[i].ptr;
2931                                 break;
2932                         case P_INTEGER:
2933                         case P_OCTAL:
2934                         case P_ENUM:
2935                                 parm_table[i].def.ivalue =
2936                                         *(int *)parm_table[i].ptr;
2937                                 break;
2938                         case P_SEP:
2939                                 break;
2940                 }
2941         }
2942         defaults_saved = True;
2943 }
2944
2945 /*******************************************************************
2946  Set the server type we will announce as via nmbd.
2947 ********************************************************************/
2948
2949 static void set_server_role(void)
2950 {
2951         server_role = ROLE_STANDALONE;
2952
2953         switch (lp_security()) {
2954                 case SEC_SHARE:
2955                         if (lp_domain_logons())
2956                                 DEBUG(0, ("Server's Role (logon server) conflicts with share-level security\n"));
2957                         break;
2958                 case SEC_SERVER:
2959                 case SEC_DOMAIN:
2960                 case SEC_ADS:
2961                         if (lp_domain_logons()) {
2962                                 server_role = ROLE_DOMAIN_PDC;
2963                                 break;
2964                         }
2965                         server_role = ROLE_DOMAIN_MEMBER;
2966                         break;
2967                 case SEC_USER:
2968                         if (lp_domain_logons()) {
2969
2970                                 if (Globals.bDomainMaster) /* auto or yes */ 
2971                                         server_role = ROLE_DOMAIN_PDC;
2972                                 else
2973                                         server_role = ROLE_DOMAIN_BDC;
2974                         }
2975                         break;
2976                 default:
2977                         DEBUG(0, ("Server's Role undefined due to unknown security mode\n"));
2978                         break;
2979         }
2980
2981         DEBUG(10, ("set_server_role: role = "));
2982
2983         switch(server_role) {
2984         case ROLE_STANDALONE:
2985                 DEBUGADD(10, ("ROLE_STANDALONE\n"));
2986                 break;
2987         case ROLE_DOMAIN_MEMBER:
2988                 DEBUGADD(10, ("ROLE_DOMAIN_MEMBER\n"));
2989                 break;
2990         case ROLE_DOMAIN_BDC:
2991                 DEBUGADD(10, ("ROLE_DOMAIN_BDC\n"));
2992                 break;
2993         case ROLE_DOMAIN_PDC:
2994                 DEBUGADD(10, ("ROLE_DOMAIN_PDC\n"));
2995                 break;
2996         }
2997 }
2998
2999 /***************************************************************************
3000  Load the services array from the services file. Return True on success, 
3001  False on failure.
3002 ***************************************************************************/
3003
3004 BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
3005              BOOL add_ipc)
3006 {
3007         pstring n2;
3008         BOOL bRetval;
3009         struct param_opt *data;
3010
3011         pstrcpy(n2, pszFname);
3012         standard_sub_basic(n2,sizeof(n2));
3013
3014         add_to_file_list(pszFname, n2);
3015
3016         bRetval = False;
3017
3018         DEBUG(2, ("lp_load: refreshing parameters from %s\n", pszFname));
3019         
3020         bInGlobalSection = True;
3021         bGlobalOnly = global_only;
3022
3023         init_globals();
3024
3025         if (save_defaults)
3026         {
3027                 lp_save_defaults();
3028         }
3029
3030         if (Globals.param_opt != NULL) {
3031                 struct param_opt *next;
3032                 for (data=Globals.param_opt; data; data=next) {
3033                         next = data->next;
3034                         if (data->flags & FLAG_CMDLINE) continue;
3035                         free(data->key);
3036                         free(data->value);
3037                         DLIST_REMOVE(Globals.param_opt, data);
3038                         free(data);
3039                 }
3040         }
3041         
3042         /* We get sections first, so have to start 'behind' to make up */
3043         iServiceIndex = -1;
3044         bRetval = pm_process(n2, do_section, do_parameter);
3045
3046         /* finish up the last section */
3047         DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
3048         if (bRetval)
3049                 if (iServiceIndex >= 0)
3050                         bRetval = service_ok(iServiceIndex);
3051
3052         lp_add_auto_services(lp_auto_services());
3053
3054         if (add_ipc) {
3055                 /* When 'restrict anonymous = 2' guest connections to ipc$
3056                    are denied */
3057                 lp_add_ipc("IPC$", (lp_restrict_anonymous() < 2));
3058                 lp_add_ipc("ADMIN$", False);
3059         }
3060
3061         set_server_role();
3062         set_default_server_announce_type();
3063
3064         bLoaded = True;
3065
3066         /* Now we check bWINSsupport and set szWINSserver to 127.0.0.1 */
3067         /* if bWINSsupport is true and we are in the client            */
3068         if (in_client && Globals.bWINSsupport) {
3069                 lp_do_parameter(-1, "wins server", "127.0.0.1");
3070         }
3071
3072         lp_do_parameter(-1, "gensec:krb5", "False");
3073         lp_do_parameter(-1, "gensec:ms_krb5", "False");
3074
3075         init_iconv();
3076
3077         return (bRetval);
3078 }
3079
3080 /***************************************************************************
3081  Reset the max number of services.
3082 ***************************************************************************/
3083
3084 void lp_resetnumservices(void)
3085 {
3086         iNumServices = 0;
3087 }
3088
3089 /***************************************************************************
3090  Return the max number of services.
3091 ***************************************************************************/
3092
3093 int lp_numservices(void)
3094 {
3095         return (iNumServices);
3096 }
3097
3098 /***************************************************************************
3099 Display the contents of the services array in human-readable form.
3100 ***************************************************************************/
3101
3102 void lp_dump(FILE *f, BOOL show_defaults, int maxtoprint)
3103 {
3104         int iService;
3105
3106         if (show_defaults)
3107                 defaults_saved = False;
3108
3109         dump_globals(f);
3110
3111         dump_a_service(&sDefault, f);
3112
3113         for (iService = 0; iService < maxtoprint; iService++)
3114                 lp_dump_one(f, show_defaults, iService);
3115 }
3116
3117 /***************************************************************************
3118 Display the contents of one service in human-readable form.
3119 ***************************************************************************/
3120
3121 void lp_dump_one(FILE * f, BOOL show_defaults, int snum)
3122 {
3123         if (VALID(snum)) {
3124                 if (ServicePtrs[snum]->szService[0] == '\0')
3125                         return;
3126                 dump_a_service(ServicePtrs[snum], f);
3127         }
3128 }
3129
3130 /***************************************************************************
3131 Return the number of the service with the given name, or -1 if it doesn't
3132 exist. Note that this is a DIFFERENT ANIMAL from the internal function
3133 getservicebyname()! This works ONLY if all services have been loaded, and
3134 does not copy the found service.
3135 ***************************************************************************/
3136
3137 int lp_servicenumber(const char *pszServiceName)
3138 {
3139         int iService;
3140         fstring serviceName;
3141  
3142  
3143         for (iService = iNumServices - 1; iService >= 0; iService--) {
3144                 if (VALID(iService) && ServicePtrs[iService]->szService) {
3145                         /*
3146                          * The substitution here is used to support %U is
3147                          * service names
3148                          */
3149                         fstrcpy(serviceName, ServicePtrs[iService]->szService);
3150                         standard_sub_basic(serviceName,sizeof(serviceName));
3151                         if (strequal(serviceName, pszServiceName))
3152                                 break;
3153                 }
3154         }
3155
3156         if (iService < 0)
3157                 DEBUG(7,("lp_servicenumber: couldn't find %s\n", pszServiceName));
3158
3159         return (iService);
3160 }
3161
3162 /*******************************************************************
3163  A useful volume label function. 
3164 ********************************************************************/
3165 const char *volume_label(int snum)
3166 {
3167         const char *ret = lp_volume(snum);
3168         if (!*ret)
3169                 return lp_servicename(snum);
3170         return (ret);
3171 }
3172
3173
3174 /*******************************************************************
3175  Set the server type we will announce as via nmbd.
3176 ********************************************************************/
3177
3178 static void set_default_server_announce_type(void)
3179 {
3180         default_server_announce = 0;
3181         default_server_announce |= SV_TYPE_WORKSTATION;
3182         default_server_announce |= SV_TYPE_SERVER;
3183         default_server_announce |= SV_TYPE_SERVER_UNIX;
3184
3185         switch (lp_announce_as()) {
3186                 case ANNOUNCE_AS_NT_SERVER:
3187                         default_server_announce |= SV_TYPE_SERVER_NT;
3188                         /* fall through... */
3189                 case ANNOUNCE_AS_NT_WORKSTATION:
3190                         default_server_announce |= SV_TYPE_NT;
3191                         break;
3192                 case ANNOUNCE_AS_WIN95:
3193                         default_server_announce |= SV_TYPE_WIN95_PLUS;
3194                         break;
3195                 case ANNOUNCE_AS_WFW:
3196                         default_server_announce |= SV_TYPE_WFW;
3197                         break;
3198                 default:
3199                         break;
3200         }
3201
3202         switch (lp_server_role()) {
3203                 case ROLE_DOMAIN_MEMBER:
3204                         default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
3205                         break;
3206                 case ROLE_DOMAIN_PDC:
3207                         default_server_announce |= SV_TYPE_DOMAIN_CTRL;
3208                         break;
3209                 case ROLE_DOMAIN_BDC:
3210                         default_server_announce |= SV_TYPE_DOMAIN_BAKCTRL;
3211                         break;
3212                 case ROLE_STANDALONE:
3213                 default:
3214                         break;
3215         }
3216         if (lp_time_server())
3217                 default_server_announce |= SV_TYPE_TIME_SOURCE;
3218
3219         if (lp_host_msdfs())
3220                 default_server_announce |= SV_TYPE_DFS_SERVER;
3221 }
3222
3223 /***********************************************************
3224  returns role of Samba server
3225 ************************************************************/
3226
3227 int lp_server_role(void)
3228 {
3229         return server_role;
3230 }
3231
3232 /***********************************************************
3233  If we are PDC then prefer us as DMB
3234 ************************************************************/
3235
3236 BOOL lp_domain_master(void)
3237 {
3238         if (Globals.bDomainMaster == Auto)
3239                 return (lp_server_role() == ROLE_DOMAIN_PDC);
3240
3241         return Globals.bDomainMaster;
3242 }
3243
3244 /***********************************************************
3245  If we are DMB then prefer us as LMB
3246 ************************************************************/
3247
3248 BOOL lp_preferred_master(void)
3249 {
3250         if (Globals.bPreferredMaster == Auto)
3251                 return (lp_local_master() && lp_domain_master());
3252
3253         return Globals.bPreferredMaster;
3254 }
3255
3256 /*******************************************************************
3257  Remove a service.
3258 ********************************************************************/
3259
3260 void lp_remove_service(int snum)
3261 {
3262         ServicePtrs[snum]->valid = False;
3263 }
3264
3265 /*******************************************************************
3266  Copy a service.
3267 ********************************************************************/
3268
3269 void lp_copy_service(int snum, const char *new_name)
3270 {
3271         const char *oldname = lp_servicename(snum);
3272         do_section(new_name);
3273         if (snum >= 0) {
3274                 snum = lp_servicenumber(new_name);
3275                 if (snum >= 0)
3276                         lp_do_parameter(snum, "copy", oldname);
3277         }
3278 }
3279
3280
3281 /*******************************************************************
3282  Get the default server type we will announce as via nmbd.
3283 ********************************************************************/
3284 int lp_default_server_announce(void)
3285 {
3286         return default_server_announce;
3287 }
3288
3289 const char *lp_printername(int snum)
3290 {
3291         const char *ret = _lp_printername(snum);
3292         if (ret == NULL || (ret != NULL && *ret == '\0'))
3293                 ret = lp_const_servicename(snum);
3294
3295         return ret;
3296 }
3297
3298
3299 /*******************************************************************
3300  Return the max print jobs per queue.
3301 ********************************************************************/
3302
3303 int lp_maxprintjobs(int snum)
3304 {
3305         int maxjobs = LP_SNUM_OK(snum) ? ServicePtrs[snum]->iMaxPrintJobs : sDefault.iMaxPrintJobs;
3306         if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
3307                 maxjobs = PRINT_MAX_JOBID - 1;
3308
3309         return maxjobs;
3310 }