035ac3422a89a7952c98c9a291c5c312b61c242b
[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] = malloc_p(service);
1580                 }
1581                 if (!ServicePtrs[iNumServices]) {
1582                         DEBUG(0,("add_a_service: out of memory!\n"));
1583                         return (-1);
1584                 }
1585
1586                 iNumServices++;
1587         } else
1588                 free_service(ServicePtrs[i]);
1589
1590         ServicePtrs[i]->valid = True;
1591
1592         init_service(ServicePtrs[i]);
1593         copy_service(ServicePtrs[i], &tservice, NULL);
1594         if (name)
1595                 string_set(&ServicePtrs[i]->szService, name);
1596         return (i);
1597 }
1598
1599 /***************************************************************************
1600  Add a new home service, with the specified home directory, defaults coming 
1601  from service ifrom.
1602 ***************************************************************************/
1603
1604 BOOL lp_add_home(const char *pszHomename, int iDefaultService, 
1605                  const char *user, const char *pszHomedir)
1606 {
1607         int i;
1608         pstring newHomedir;
1609
1610         i = add_a_service(ServicePtrs[iDefaultService], pszHomename);
1611
1612         if (i < 0)
1613                 return (False);
1614
1615         if (!(*(ServicePtrs[iDefaultService]->szPath))
1616             || strequal(ServicePtrs[iDefaultService]->szPath, lp_pathname(-1))) {
1617                 pstrcpy(newHomedir, pszHomedir);
1618         } else {
1619                 pstrcpy(newHomedir, lp_pathname(iDefaultService));
1620                 string_sub(newHomedir,"%H", pszHomedir, sizeof(newHomedir)); 
1621         }
1622
1623         string_set(&ServicePtrs[i]->szPath, newHomedir);
1624
1625         if (!(*(ServicePtrs[i]->comment))) {
1626                 pstring comment;
1627                 slprintf(comment, sizeof(comment) - 1,
1628                          "Home directory of %s", user);
1629                 string_set(&ServicePtrs[i]->comment, comment);
1630         }
1631         ServicePtrs[i]->bAvailable = sDefault.bAvailable;
1632         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1633
1634         DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename, 
1635                user, newHomedir));
1636         
1637         return (True);
1638 }
1639
1640 /***************************************************************************
1641  Add a new service, based on an old one.
1642 ***************************************************************************/
1643
1644 int lp_add_service(const char *pszService, int iDefaultService)
1645 {
1646         return (add_a_service(ServicePtrs[iDefaultService], pszService));
1647 }
1648
1649 /***************************************************************************
1650  Add the IPC service.
1651 ***************************************************************************/
1652
1653 static BOOL lp_add_ipc(const char *ipc_name, BOOL guest_ok)
1654 {
1655         pstring comment;
1656         int i = add_a_service(&sDefault, ipc_name);
1657
1658         if (i < 0)
1659                 return (False);
1660
1661         slprintf(comment, sizeof(comment) - 1,
1662                  "IPC Service (%s)", Globals.szServerString);
1663
1664         string_set(&ServicePtrs[i]->szPath, tmpdir());
1665         string_set(&ServicePtrs[i]->szUsername, "");
1666         string_set(&ServicePtrs[i]->comment, comment);
1667         string_set(&ServicePtrs[i]->fstype, "IPC");
1668         ServicePtrs[i]->iMaxConnections = 0;
1669         ServicePtrs[i]->bAvailable = True;
1670         ServicePtrs[i]->bRead_only = True;
1671         ServicePtrs[i]->bGuest_only = False;
1672         ServicePtrs[i]->bGuest_ok = guest_ok;
1673         ServicePtrs[i]->bPrint_ok = False;
1674         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1675
1676         lp_do_parameter(i, "ntvfs handler", "default");
1677
1678         DEBUG(3, ("adding IPC service\n"));
1679
1680         return (True);
1681 }
1682
1683 /***************************************************************************
1684  Add a new printer service, with defaults coming from service iFrom.
1685 ***************************************************************************/
1686
1687 BOOL lp_add_printer(const char *pszPrintername, int iDefaultService)
1688 {
1689         const char *comment = "From Printcap";
1690         int i = add_a_service(ServicePtrs[iDefaultService], pszPrintername);
1691
1692         if (i < 0)
1693                 return (False);
1694
1695         /* note that we do NOT default the availability flag to True - */
1696         /* we take it from the default service passed. This allows all */
1697         /* dynamic printers to be disabled by disabling the [printers] */
1698         /* entry (if/when the 'available' keyword is implemented!).    */
1699
1700         /* the printer name is set to the service name. */
1701         string_set(&ServicePtrs[i]->szPrintername, pszPrintername);
1702         string_set(&ServicePtrs[i]->comment, comment);
1703         ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
1704         /* Printers cannot be read_only. */
1705         ServicePtrs[i]->bRead_only = False;
1706         /* No share modes on printer services. */
1707         ServicePtrs[i]->bShareModes = False;
1708         /* No oplocks on printer services. */
1709         ServicePtrs[i]->bOpLocks = False;
1710         /* Printer services must be printable. */
1711         ServicePtrs[i]->bPrint_ok = True;
1712
1713         DEBUG(3, ("adding printer service %s\n", pszPrintername));
1714
1715         update_server_announce_as_printserver();
1716
1717         return (True);
1718 }
1719
1720 /***************************************************************************
1721  Map a parameter's string representation to something we can use. 
1722  Returns False if the parameter string is not recognised, else TRUE.
1723 ***************************************************************************/
1724
1725 static int map_parameter(const char *pszParmName)
1726 {
1727         int iIndex;
1728
1729         if (*pszParmName == '-')
1730                 return (-1);
1731
1732         for (iIndex = 0; parm_table[iIndex].label; iIndex++)
1733                 if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1734                         return (iIndex);
1735
1736         /* Warn only if it isn't parametric option */
1737         if (strchr(pszParmName, ':') == NULL)
1738                 DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
1739         /* We do return 'fail' for parametric options as well because they are
1740            stored in different storage
1741          */
1742         return (-1);
1743 }
1744
1745 /***************************************************************************
1746  Set a boolean variable from the text value stored in the passed string.
1747  Returns True in success, False if the passed string does not correctly 
1748  represent a boolean.
1749 ***************************************************************************/
1750
1751 static BOOL set_boolean(BOOL *pb, const char *pszParmValue)
1752 {
1753         BOOL bRetval;
1754
1755         bRetval = True;
1756         if (strwicmp(pszParmValue, "yes") == 0 ||
1757             strwicmp(pszParmValue, "true") == 0 ||
1758             strwicmp(pszParmValue, "1") == 0)
1759                 *pb = True;
1760         else if (strwicmp(pszParmValue, "no") == 0 ||
1761                     strwicmp(pszParmValue, "False") == 0 ||
1762                     strwicmp(pszParmValue, "0") == 0)
1763                 *pb = False;
1764         else {
1765                 DEBUG(0,
1766                       ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
1767                        pszParmValue));
1768                 bRetval = False;
1769         }
1770         return (bRetval);
1771 }
1772
1773 /***************************************************************************
1774 Find a service by name. Otherwise works like get_service.
1775 ***************************************************************************/
1776
1777 static int getservicebyname(const char *pszServiceName, service * pserviceDest)
1778 {
1779         int iService;
1780
1781         for (iService = iNumServices - 1; iService >= 0; iService--)
1782                 if (VALID(iService) &&
1783                     strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0) {
1784                         if (pserviceDest != NULL)
1785                                 copy_service(pserviceDest, ServicePtrs[iService], NULL);
1786                         break;
1787                 }
1788
1789         return (iService);
1790 }
1791
1792 /***************************************************************************
1793  Copy a service structure to another.
1794  If pcopymapDest is NULL then copy all fields
1795 ***************************************************************************/
1796
1797 static void copy_service(service * pserviceDest, service * pserviceSource, BOOL *pcopymapDest)
1798 {
1799         int i;
1800         BOOL bcopyall = (pcopymapDest == NULL);
1801         struct param_opt *data, *pdata, *paramo;
1802         BOOL not_added;
1803
1804         for (i = 0; parm_table[i].label; i++)
1805                 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL &&
1806                     (bcopyall || pcopymapDest[i])) {
1807                         void *def_ptr = parm_table[i].ptr;
1808                         void *src_ptr =
1809                                 ((char *)pserviceSource) + PTR_DIFF(def_ptr,
1810                                                                     &sDefault);
1811                         void *dest_ptr =
1812                                 ((char *)pserviceDest) + PTR_DIFF(def_ptr,
1813                                                                   &sDefault);
1814
1815                         switch (parm_table[i].type) {
1816                                 case P_BOOL:
1817                                 case P_BOOLREV:
1818                                         *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1819                                         break;
1820
1821                                 case P_INTEGER:
1822                                 case P_ENUM:
1823                                 case P_OCTAL:
1824                                         *(int *)dest_ptr = *(int *)src_ptr;
1825                                         break;
1826
1827                                 case P_CHAR:
1828                                         *(char *)dest_ptr = *(char *)src_ptr;
1829                                         break;
1830
1831                                 case P_STRING:
1832                                         string_set(dest_ptr,
1833                                                    *(char **)src_ptr);
1834                                         break;
1835
1836                                 case P_USTRING:
1837                                         string_set(dest_ptr,
1838                                                    *(char **)src_ptr);
1839                                         strupper(*(char **)dest_ptr);
1840                                         break;
1841                                 case P_LIST:
1842                                         str_list_copy((char ***)dest_ptr, *(const char ***)src_ptr);
1843                                         break;
1844                                 default:
1845                                         break;
1846                         }
1847                 }
1848
1849         if (bcopyall) {
1850                 init_copymap(pserviceDest);
1851                 if (pserviceSource->copymap)
1852                         memcpy((void *)pserviceDest->copymap,
1853                                (void *)pserviceSource->copymap,
1854                                sizeof(BOOL) * NUMPARAMETERS);
1855         }
1856         
1857         data = pserviceSource->param_opt;
1858         while (data) {
1859                 not_added = True;
1860                 pdata = pserviceDest->param_opt;
1861                 /* Traverse destination */
1862                 while (pdata) {
1863                         /* If we already have same option, override it */
1864                         if (strcmp(pdata->key, data->key) == 0) {
1865                                 string_free(&pdata->value);
1866                                 pdata->value = strdup(data->value);
1867                                 not_added = False;
1868                                 break;
1869                         }
1870                         pdata = pdata->next;
1871                 }
1872                 if (not_added) {
1873                         paramo = smb_xmalloc_p(struct param_opt);
1874                         paramo->key = strdup(data->key);
1875                         paramo->value = strdup(data->value);
1876                         DLIST_ADD(pserviceDest->param_opt, paramo);
1877                 }
1878                 data = data->next;
1879         }
1880 }
1881
1882 /***************************************************************************
1883 Check a service for consistency. Return False if the service is in any way
1884 incomplete or faulty, else True.
1885 ***************************************************************************/
1886
1887 static BOOL service_ok(int iService)
1888 {
1889         BOOL bRetval;
1890
1891         bRetval = True;
1892         if (ServicePtrs[iService]->szService[0] == '\0') {
1893                 DEBUG(0, ("The following message indicates an internal error:\n"));
1894                 DEBUG(0, ("No service name in service entry.\n"));
1895                 bRetval = False;
1896         }
1897
1898         /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1899         /* I can't see why you'd want a non-printable printer service...        */
1900         if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
1901                 if (!ServicePtrs[iService]->bPrint_ok) {
1902                         DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
1903                                ServicePtrs[iService]->szService));
1904                         ServicePtrs[iService]->bPrint_ok = True;
1905                 }
1906                 /* [printers] service must also be non-browsable. */
1907                 if (ServicePtrs[iService]->bBrowseable)
1908                         ServicePtrs[iService]->bBrowseable = False;
1909         }
1910
1911         /* If a service is flagged unavailable, log the fact at level 0. */
1912         if (!ServicePtrs[iService]->bAvailable)
1913                 DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
1914                           ServicePtrs[iService]->szService));
1915
1916         return (bRetval);
1917 }
1918
1919 static struct file_lists {
1920         struct file_lists *next;
1921         char *name;
1922         char *subfname;
1923         time_t modtime;
1924 } *file_lists = NULL;
1925
1926 /*******************************************************************
1927  Keep a linked list of all config files so we know when one has changed 
1928  it's date and needs to be reloaded.
1929 ********************************************************************/
1930
1931 static void add_to_file_list(const char *fname, const char *subfname)
1932 {
1933         struct file_lists *f = file_lists;
1934
1935         while (f) {
1936                 if (f->name && !strcmp(f->name, fname))
1937                         break;
1938                 f = f->next;
1939         }
1940
1941         if (!f) {
1942                 f = malloc_p(struct file_lists);
1943                 if (!f)
1944                         return;
1945                 f->next = file_lists;
1946                 f->name = strdup(fname);
1947                 if (!f->name) {
1948                         SAFE_FREE(f);
1949                         return;
1950                 }
1951                 f->subfname = strdup(subfname);
1952                 if (!f->subfname) {
1953                         SAFE_FREE(f);
1954                         return;
1955                 }
1956                 file_lists = f;
1957                 f->modtime = file_modtime(subfname);
1958         } else {
1959                 time_t t = file_modtime(subfname);
1960                 if (t)
1961                         f->modtime = t;
1962         }
1963 }
1964
1965 /*******************************************************************
1966  Check if a config file has changed date.
1967 ********************************************************************/
1968
1969 BOOL lp_file_list_changed(void)
1970 {
1971         struct file_lists *f = file_lists;
1972         DEBUG(6, ("lp_file_list_changed()\n"));
1973
1974         while (f) {
1975                 pstring n2;
1976                 time_t mod_time;
1977
1978                 pstrcpy(n2, f->name);
1979                 standard_sub_basic(n2,sizeof(n2));
1980
1981                 DEBUGADD(6, ("file %s -> %s  last mod_time: %s\n",
1982                              f->name, n2, ctime(&f->modtime)));
1983
1984                 mod_time = file_modtime(n2);
1985
1986                 if (mod_time && ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))) {
1987                         DEBUGADD(6,
1988                                  ("file %s modified: %s\n", n2,
1989                                   ctime(&mod_time)));
1990                         f->modtime = mod_time;
1991                         SAFE_FREE(f->subfname);
1992                         f->subfname = strdup(n2);
1993                         return (True);
1994                 }
1995                 f = f->next;
1996         }
1997         return (False);
1998 }
1999
2000 /***************************************************************************
2001  Handle the include operation.
2002 ***************************************************************************/
2003
2004 static BOOL handle_include(const char *pszParmValue, char **ptr)
2005 {
2006         pstring fname;
2007         pstrcpy(fname, pszParmValue);
2008
2009         standard_sub_basic(fname,sizeof(fname));
2010
2011         add_to_file_list(pszParmValue, fname);
2012
2013         string_set(ptr, fname);
2014
2015         if (file_exist(fname, NULL))
2016                 return (pm_process(fname, do_section, do_parameter));
2017
2018         DEBUG(2, ("Can't find include file %s\n", fname));
2019
2020         return (False);
2021 }
2022
2023 /***************************************************************************
2024  Handle the interpretation of the copy parameter.
2025 ***************************************************************************/
2026
2027 static BOOL handle_copy(const char *pszParmValue, char **ptr)
2028 {
2029         BOOL bRetval;
2030         int iTemp;
2031         service serviceTemp;
2032
2033         string_set(ptr, pszParmValue);
2034
2035         init_service(&serviceTemp);
2036
2037         bRetval = False;
2038
2039         DEBUG(3, ("Copying service from service %s\n", pszParmValue));
2040
2041         if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0) {
2042                 if (iTemp == iServiceIndex) {
2043                         DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
2044                 } else {
2045                         copy_service(ServicePtrs[iServiceIndex],
2046                                      &serviceTemp,
2047                                      ServicePtrs[iServiceIndex]->copymap);
2048                         bRetval = True;
2049                 }
2050         } else {
2051                 DEBUG(0, ("Unable to copy service - source not found: %s\n", pszParmValue));
2052                 bRetval = False;
2053         }
2054
2055         free_service(&serviceTemp);
2056         return (bRetval);
2057 }
2058
2059 /***************************************************************************
2060  Handle winbind/non unix account uid and gid allocation parameters.  The format of these
2061  parameters is:
2062
2063  [global]
2064
2065         winbind uid = 1000-1999
2066         winbind gid = 700-899
2067
2068  We only do simple parsing checks here.  The strings are parsed into useful
2069  structures in the winbind daemon code.
2070
2071 ***************************************************************************/
2072
2073 /* Some lp_ routines to return winbind [ug]id information */
2074
2075 static uid_t winbind_uid_low, winbind_uid_high;
2076 static gid_t winbind_gid_low, winbind_gid_high;
2077 static uint32_t non_unix_account_low, non_unix_account_high;
2078
2079 BOOL lp_winbind_uid(uid_t *low, uid_t *high)
2080 {
2081         if (winbind_uid_low == 0 || winbind_uid_high == 0)
2082                 return False;
2083
2084         if (low)
2085                 *low = winbind_uid_low;
2086
2087         if (high)
2088                 *high = winbind_uid_high;
2089
2090         return True;
2091 }
2092
2093 BOOL lp_winbind_gid(gid_t *low, gid_t *high)
2094 {
2095         if (winbind_gid_low == 0 || winbind_gid_high == 0)
2096                 return False;
2097
2098         if (low)
2099                 *low = winbind_gid_low;
2100
2101         if (high)
2102                 *high = winbind_gid_high;
2103
2104         return True;
2105 }
2106
2107 BOOL lp_non_unix_account_range(uint32_t *low, uint32_t *high)
2108 {
2109         if (non_unix_account_low == 0 || non_unix_account_high == 0)
2110                 return False;
2111
2112         if (low)
2113                 *low = non_unix_account_low;
2114
2115         if (high)
2116                 *high = non_unix_account_high;
2117
2118         return True;
2119 }
2120
2121 /* Do some simple checks on "winbind [ug]id" parameter values */
2122
2123 static BOOL handle_winbind_uid(const char *pszParmValue, char **ptr)
2124 {
2125         uint32_t low, high;
2126
2127         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2128                 return False;
2129
2130         /* Parse OK */
2131
2132         string_set(ptr, pszParmValue);
2133
2134         winbind_uid_low = low;
2135         winbind_uid_high = high;
2136
2137         return True;
2138 }
2139
2140 static BOOL handle_winbind_gid(const char *pszParmValue, char **ptr)
2141 {
2142         uint32_t low, high;
2143
2144         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2145                 return False;
2146
2147         /* Parse OK */
2148
2149         string_set(ptr, pszParmValue);
2150
2151         winbind_gid_low = low;
2152         winbind_gid_high = high;
2153
2154         return True;
2155 }
2156
2157 /***************************************************************************
2158  Do some simple checks on "non unix account range" parameter values.
2159 ***************************************************************************/
2160
2161 static BOOL handle_non_unix_account_range(const char *pszParmValue, char **ptr)
2162 {
2163         uint32_t low, high;
2164
2165         if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
2166                 return False;
2167
2168         /* Parse OK */
2169
2170         string_set(ptr, pszParmValue);
2171
2172         non_unix_account_low = low;
2173         non_unix_account_high = high;
2174
2175         return True;
2176 }
2177
2178
2179 /***************************************************************************
2180  Initialise a copymap.
2181 ***************************************************************************/
2182
2183 static void init_copymap(service * pservice)
2184 {
2185         int i;
2186         SAFE_FREE(pservice->copymap);
2187         pservice->copymap = malloc_array_p(BOOL, NUMPARAMETERS);
2188         if (!pservice->copymap)
2189                 DEBUG(0,
2190                       ("Couldn't allocate copymap!! (size %d)\n",
2191                        (int)NUMPARAMETERS));
2192         else
2193                 for (i = 0; i < NUMPARAMETERS; i++)
2194                         pservice->copymap[i] = True;
2195 }
2196
2197 /***************************************************************************
2198  Return the local pointer to a parameter given the service number and the 
2199  pointer into the default structure.
2200 ***************************************************************************/
2201
2202 void *lp_local_ptr(int snum, void *ptr)
2203 {
2204         return (void *)(((char *)ServicePtrs[snum]) + PTR_DIFF(ptr, &sDefault));
2205 }
2206
2207
2208 /***************************************************************************
2209  Process a parametric option
2210 ***************************************************************************/
2211 static BOOL lp_do_parameter_parametric(int snum, const char *pszParmName, const char *pszParmValue, int flags)
2212 {
2213         struct param_opt *paramo, *data;
2214         char *name;
2215
2216         while (isspace(*pszParmName)) {
2217                 pszParmName++;
2218         }
2219
2220         name = strdup(pszParmName);
2221         if (!name) return False;
2222
2223         strlower(name);
2224
2225         if (snum < 0) {
2226                 data = Globals.param_opt;
2227         } else {
2228                 data = ServicePtrs[snum]->param_opt;
2229         }
2230
2231         /* Traverse destination */
2232         for (paramo=data; paramo; paramo=paramo->next) {
2233                 /* If we already have the option set, override it unless
2234                    it was a command line option and the new one isn't */
2235                 if (strcmp(paramo->key, name) == 0) {
2236                         if ((paramo->flags & FLAG_CMDLINE) &&
2237                             !(flags & FLAG_CMDLINE)) {
2238                                 return True;
2239                         }
2240
2241                         free(paramo->value);
2242                         paramo->value = strdup(pszParmValue);
2243                         paramo->flags = flags;
2244                         free(name);
2245                         return True;
2246                 }
2247         }
2248
2249         paramo = smb_xmalloc_p(struct param_opt);
2250         paramo->key = strdup(name);
2251         paramo->value = strdup(pszParmValue);
2252         paramo->flags = flags;
2253         if (snum < 0) {
2254                 DLIST_ADD(Globals.param_opt, paramo);
2255         } else {
2256                 DLIST_ADD(ServicePtrs[snum]->param_opt, paramo);
2257         }
2258
2259         free(name);
2260         
2261         return True;
2262 }
2263
2264 /***************************************************************************
2265  Process a parameter for a particular service number. If snum < 0
2266  then assume we are in the globals.
2267 ***************************************************************************/
2268 BOOL lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue)
2269 {
2270         int parmnum, i;
2271         void *parm_ptr = NULL;  /* where we are going to store the result */
2272         void *def_ptr = NULL;
2273
2274         parmnum = map_parameter(pszParmName);
2275
2276         if (parmnum < 0) {
2277                 if (strchr(pszParmName, ':')) {
2278                         return lp_do_parameter_parametric(snum, pszParmName, pszParmValue, 0);
2279                 }
2280                 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
2281                 return (True);
2282         }
2283
2284         if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
2285                 DEBUG(1, ("WARNING: The \"%s\" option is deprecated\n",
2286                           pszParmName));
2287         }
2288
2289         /* if the flag has been set on the command line, then don't allow override,
2290            but don't report an error */
2291         if (parm_table[parmnum].flags & FLAG_CMDLINE) {
2292                 return True;
2293         }
2294
2295         def_ptr = parm_table[parmnum].ptr;
2296
2297         /* we might point at a service, the default service or a global */
2298         if (snum < 0) {
2299                 parm_ptr = def_ptr;
2300         } else {
2301                 if (parm_table[parmnum].class == P_GLOBAL) {
2302                         DEBUG(0,
2303                               ("Global parameter %s found in service section!\n",
2304                                pszParmName));
2305                         return (True);
2306                 }
2307                 parm_ptr =
2308                         ((char *)ServicePtrs[snum]) + PTR_DIFF(def_ptr,
2309                                                             &sDefault);
2310         }
2311
2312         if (snum >= 0) {
2313                 if (!ServicePtrs[snum]->copymap)
2314                         init_copymap(ServicePtrs[snum]);
2315
2316                 /* this handles the aliases - set the copymap for other entries with
2317                    the same data pointer */
2318                 for (i = 0; parm_table[i].label; i++)
2319                         if (parm_table[i].ptr == parm_table[parmnum].ptr)
2320                                 ServicePtrs[snum]->copymap[i] = False;
2321         }
2322
2323         /* if it is a special case then go ahead */
2324         if (parm_table[parmnum].special) {
2325                 parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
2326                 return (True);
2327         }
2328
2329         /* now switch on the type of variable it is */
2330         switch (parm_table[parmnum].type)
2331         {
2332                 case P_BOOL:
2333                         set_boolean(parm_ptr, pszParmValue);
2334                         break;
2335
2336                 case P_BOOLREV:
2337                         set_boolean(parm_ptr, pszParmValue);
2338                         *(BOOL *)parm_ptr = !*(BOOL *)parm_ptr;
2339                         break;
2340
2341                 case P_INTEGER:
2342                         *(int *)parm_ptr = atoi(pszParmValue);
2343                         break;
2344
2345                 case P_CHAR:
2346                         *(char *)parm_ptr = *pszParmValue;
2347                         break;
2348
2349                 case P_OCTAL:
2350                         sscanf(pszParmValue, "%o", (int *)parm_ptr);
2351                         break;
2352
2353                 case P_LIST:
2354                         *(char ***)parm_ptr = str_list_make(pszParmValue, NULL);
2355                         break;
2356
2357                 case P_STRING:
2358                         string_set(parm_ptr, pszParmValue);
2359                         break;
2360
2361                 case P_USTRING:
2362                         string_set(parm_ptr, pszParmValue);
2363                         strupper(*(char **)parm_ptr);
2364                         break;
2365
2366                 case P_ENUM:
2367                         for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
2368                                 if (strequal
2369                                     (pszParmValue,
2370                                      parm_table[parmnum].enum_list[i].name)) {
2371                                         *(int *)parm_ptr =
2372                                                 parm_table[parmnum].
2373                                                 enum_list[i].value;
2374                                         break;
2375                                 }
2376                         }
2377                         if (!parm_table[parmnum].enum_list[i].name) {
2378                                 DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
2379                                          pszParmValue, pszParmName));
2380                                 return False;
2381                         }
2382                         break;
2383                 case P_SEP:
2384                         break;
2385         }
2386
2387         return (True);
2388 }
2389
2390 /***************************************************************************
2391  Process a parameter.
2392 ***************************************************************************/
2393
2394 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue)
2395 {
2396         if (!bInGlobalSection && bGlobalOnly)
2397                 return (True);
2398
2399         return (lp_do_parameter(bInGlobalSection ? -2 : iServiceIndex,
2400                                 pszParmName, pszParmValue));
2401 }
2402
2403 /*
2404   variable argument do parameter
2405 */
2406 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
2407
2408 static BOOL do_parameter_var(const char *pszParmName, const char *fmt, ...)
2409 {
2410         char *s;
2411         BOOL ret;
2412         va_list ap;
2413
2414         va_start(ap, fmt);      
2415         s = talloc_vasprintf(NULL, fmt, ap);
2416         va_end(ap);
2417         ret = do_parameter(pszParmName, s);
2418         talloc_free(s);
2419         return ret;
2420 }
2421
2422
2423 /*
2424   set a parameter from the commandline - this is called from command line parameter
2425   parsing code. It sets the parameter then marks the parameter as unable to be modified
2426   by smb.conf processing
2427 */
2428 BOOL lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
2429 {
2430         int parmnum = map_parameter(pszParmName);
2431         int i;
2432
2433         while (isspace(*pszParmValue)) pszParmValue++;
2434
2435
2436         if (parmnum < 0 && strchr(pszParmName, ':')) {
2437                 /* set a parametric option */
2438                 return lp_do_parameter_parametric(-1, pszParmName, pszParmValue, FLAG_CMDLINE);
2439         }
2440
2441         if (parmnum < 0) {
2442                 DEBUG(0,("Unknown option '%s'\n", pszParmName));
2443                 return False;
2444         }
2445
2446         /* reset the CMDLINE flag in case this has been called before */
2447         parm_table[parmnum].flags &= ~FLAG_CMDLINE;
2448
2449         if (!lp_do_parameter(-2, pszParmName, pszParmValue)) {
2450                 return False;
2451         }
2452
2453         parm_table[parmnum].flags |= FLAG_CMDLINE;
2454
2455         /* we have to also set FLAG_CMDLINE on aliases */
2456         for (i=parmnum-1;i>=0 && parm_table[i].ptr == parm_table[parmnum].ptr;i--) {
2457                 parm_table[i].flags |= FLAG_CMDLINE;
2458         }
2459         for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].ptr == parm_table[parmnum].ptr;i++) {
2460                 parm_table[i].flags |= FLAG_CMDLINE;
2461         }
2462
2463         return True;
2464 }
2465
2466 /*
2467   set a option from the commandline in 'a=b' format. Use to support --option
2468 */
2469 BOOL lp_set_option(const char *option)
2470 {
2471         char *p, *s;
2472         BOOL ret;
2473
2474         s = strdup(option);
2475         if (!s) {
2476                 return False;
2477         }
2478
2479         p = strchr(s, '=');
2480         if (!p) {
2481                 free(s);
2482                 return False;
2483         }
2484
2485         *p = 0;
2486
2487         ret = lp_set_cmdline(s, p+1);
2488         free(s);
2489         return ret;
2490 }
2491
2492
2493 /***************************************************************************
2494  Print a parameter of the specified type.
2495 ***************************************************************************/
2496
2497 static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
2498 {
2499         int i;
2500         switch (p->type)
2501         {
2502                 case P_ENUM:
2503                         for (i = 0; p->enum_list[i].name; i++) {
2504                                 if (*(int *)ptr == p->enum_list[i].value) {
2505                                         fprintf(f, "%s",
2506                                                 p->enum_list[i].name);
2507                                         break;
2508                                 }
2509                         }
2510                         break;
2511
2512                 case P_BOOL:
2513                         fprintf(f, "%s", BOOLSTR(*(BOOL *)ptr));
2514                         break;
2515
2516                 case P_BOOLREV:
2517                         fprintf(f, "%s", BOOLSTR(!*(BOOL *)ptr));
2518                         break;
2519
2520                 case P_INTEGER:
2521                         fprintf(f, "%d", *(int *)ptr);
2522                         break;
2523
2524                 case P_CHAR:
2525                         fprintf(f, "%c", *(char *)ptr);
2526                         break;
2527
2528                 case P_OCTAL:
2529                         if (*(int *)ptr == -1) {
2530                                 fprintf(f, "-1");
2531                         } else {
2532                                 fprintf(f, "0%o", *(int *)ptr);
2533                         }
2534                         break;
2535
2536                 case P_LIST:
2537                         if ((char ***)ptr && *(char ***)ptr) {
2538                                 char **list = *(char ***)ptr;
2539                                 
2540                                 for (; *list; list++)
2541                                         fprintf(f, "%s%s", *list,
2542                                                 ((*(list+1))?", ":""));
2543                         }
2544                         break;
2545
2546                 case P_STRING:
2547                 case P_USTRING:
2548                         if (*(char **)ptr) {
2549                                 fprintf(f, "%s", *(char **)ptr);
2550                         }
2551                         break;
2552                 case P_SEP:
2553                         break;
2554         }
2555 }
2556
2557 /***************************************************************************
2558  Check if two parameters are equal.
2559 ***************************************************************************/
2560
2561 static BOOL equal_parameter(parm_type type, void *ptr1, void *ptr2)
2562 {
2563         switch (type) {
2564                 case P_BOOL:
2565                 case P_BOOLREV:
2566                         return (*((BOOL *)ptr1) == *((BOOL *)ptr2));
2567
2568                 case P_INTEGER:
2569                 case P_ENUM:
2570                 case P_OCTAL:
2571                         return (*((int *)ptr1) == *((int *)ptr2));
2572
2573                 case P_CHAR:
2574                         return (*((char *)ptr1) == *((char *)ptr2));
2575                 
2576                 case P_LIST:
2577                         return str_list_compare(*(char ***)ptr1, *(char ***)ptr2);
2578
2579                 case P_STRING:
2580                 case P_USTRING:
2581                 {
2582                         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
2583                         if (p1 && !*p1)
2584                                 p1 = NULL;
2585                         if (p2 && !*p2)
2586                                 p2 = NULL;
2587                         return (p1 == p2 || strequal(p1, p2));
2588                 }
2589                 case P_SEP:
2590                         break;
2591         }
2592         return (False);
2593 }
2594
2595 /***************************************************************************
2596  Process a new section (service). At this stage all sections are services.
2597  Later we'll have special sections that permit server parameters to be set.
2598  Returns True on success, False on failure. 
2599 ***************************************************************************/
2600
2601 static BOOL do_section(const char *pszSectionName)
2602 {
2603         BOOL bRetval;
2604         BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
2605                          (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
2606         bRetval = False;
2607
2608         /* if we've just struck a global section, note the fact. */
2609         bInGlobalSection = isglobal;
2610
2611         /* check for multiple global sections */
2612         if (bInGlobalSection) {
2613                 DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
2614                 return (True);
2615         }
2616
2617         if (!bInGlobalSection && bGlobalOnly)
2618                 return (True);
2619
2620         /* if we have a current service, tidy it up before moving on */
2621         bRetval = True;
2622
2623         if (iServiceIndex >= 0)
2624                 bRetval = service_ok(iServiceIndex);
2625
2626         /* if all is still well, move to the next record in the services array */
2627         if (bRetval) {
2628                 /* We put this here to avoid an odd message order if messages are */
2629                 /* issued by the post-processing of a previous section. */
2630                 DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
2631
2632                 if ((iServiceIndex = add_a_service(&sDefault, pszSectionName))
2633                     < 0) {
2634                         DEBUG(0, ("Failed to add a new service\n"));
2635                         return (False);
2636                 }
2637         }
2638
2639         return (bRetval);
2640 }
2641
2642
2643 /***************************************************************************
2644  Determine if a partcular base parameter is currentl set to the default value.
2645 ***************************************************************************/
2646
2647 static BOOL is_default(int i)
2648 {
2649         if (!defaults_saved)
2650                 return False;
2651         switch (parm_table[i].type) {
2652                 case P_LIST:
2653                         return str_list_compare (parm_table[i].def.lvalue, 
2654                                                 *(char ***)parm_table[i].ptr);
2655                 case P_STRING:
2656                 case P_USTRING:
2657                         return strequal(parm_table[i].def.svalue,
2658                                         *(char **)parm_table[i].ptr);
2659                 case P_BOOL:
2660                 case P_BOOLREV:
2661                         return parm_table[i].def.bvalue ==
2662                                 *(BOOL *)parm_table[i].ptr;
2663                 case P_CHAR:
2664                         return parm_table[i].def.cvalue ==
2665                                 *(char *)parm_table[i].ptr;
2666                 case P_INTEGER:
2667                 case P_OCTAL:
2668                 case P_ENUM:
2669                         return parm_table[i].def.ivalue ==
2670                                 *(int *)parm_table[i].ptr;
2671                 case P_SEP:
2672                         break;
2673         }
2674         return False;
2675 }
2676
2677 /***************************************************************************
2678 Display the contents of the global structure.
2679 ***************************************************************************/
2680
2681 static void dump_globals(FILE *f)
2682 {
2683         int i;
2684         struct param_opt *data;
2685         
2686         fprintf(f, "# Global parameters\n[global]\n");
2687
2688         for (i = 0; parm_table[i].label; i++)
2689                 if (parm_table[i].class == P_GLOBAL &&
2690                     parm_table[i].ptr &&
2691                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2692                         if (defaults_saved && is_default(i))
2693                                 continue;
2694                         fprintf(f, "\t%s = ", parm_table[i].label);
2695                         print_parameter(&parm_table[i], parm_table[i].ptr, f);
2696                         fprintf(f, "\n");
2697         }
2698         if (Globals.param_opt != NULL) {
2699                 data = Globals.param_opt;
2700                 while(data) {
2701                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2702                         data = data->next;
2703                 }
2704         }
2705
2706 }
2707
2708 /***************************************************************************
2709  Display the contents of a single services record.
2710 ***************************************************************************/
2711
2712 static void dump_a_service(service * pService, FILE * f)
2713 {
2714         int i;
2715         struct param_opt *data;
2716         
2717         if (pService != &sDefault)
2718                 fprintf(f, "\n[%s]\n", pService->szService);
2719
2720         for (i = 0; parm_table[i].label; i++)
2721                 if (parm_table[i].class == P_LOCAL &&
2722                     parm_table[i].ptr &&
2723                     (*parm_table[i].label != '-') &&
2724                     (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr))) {
2725                         int pdiff = PTR_DIFF(parm_table[i].ptr, &sDefault);
2726
2727                         if (pService == &sDefault) {
2728                                 if (defaults_saved && is_default(i))
2729                                         continue;
2730                         } else {
2731                                 if (equal_parameter(parm_table[i].type,
2732                                                     ((char *)pService) +
2733                                                     pdiff,
2734                                                     ((char *)&sDefault) +
2735                                                     pdiff))
2736                                         continue;
2737                         }
2738
2739                         fprintf(f, "\t%s = ", parm_table[i].label);
2740                         print_parameter(&parm_table[i],
2741                                         ((char *)pService) + pdiff, f);
2742                         fprintf(f, "\n");
2743         }
2744         if (pService->param_opt != NULL) {
2745                 data = pService->param_opt;
2746                 while(data) {
2747                         fprintf(f, "\t%s = %s\n", data->key, data->value);
2748                         data = data->next;
2749                 }
2750         }
2751 }
2752
2753
2754 /***************************************************************************
2755  Return info about the next service  in a service. snum==-1 gives the globals.
2756  Return NULL when out of parameters.
2757 ***************************************************************************/
2758
2759 struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
2760 {
2761         if (snum == -1) {
2762                 /* do the globals */
2763                 for (; parm_table[*i].label; (*i)++) {
2764                         if (parm_table[*i].class == P_SEPARATOR)
2765                                 return &parm_table[(*i)++];
2766
2767                         if (!parm_table[*i].ptr
2768                             || (*parm_table[*i].label == '-'))
2769                                 continue;
2770
2771                         if ((*i) > 0
2772                             && (parm_table[*i].ptr ==
2773                                 parm_table[(*i) - 1].ptr))
2774                                 continue;
2775
2776                         return &parm_table[(*i)++];
2777                 }
2778         } else {
2779                 service *pService = ServicePtrs[snum];
2780
2781                 for (; parm_table[*i].label; (*i)++) {
2782                         if (parm_table[*i].class == P_SEPARATOR)
2783                                 return &parm_table[(*i)++];
2784
2785                         if (parm_table[*i].class == P_LOCAL &&
2786                             parm_table[*i].ptr &&
2787                             (*parm_table[*i].label != '-') &&
2788                             ((*i) == 0 ||
2789                              (parm_table[*i].ptr !=
2790                               parm_table[(*i) - 1].ptr)))
2791                         {
2792                                 int pdiff =
2793                                         PTR_DIFF(parm_table[*i].ptr,
2794                                                  &sDefault);
2795
2796                                 if (allparameters ||
2797                                     !equal_parameter(parm_table[*i].type,
2798                                                      ((char *)pService) +
2799                                                      pdiff,
2800                                                      ((char *)&sDefault) +
2801                                                      pdiff))
2802                                 {
2803                                         return &parm_table[(*i)++];
2804                                 }
2805                         }
2806                 }
2807         }
2808
2809         return NULL;
2810 }
2811
2812
2813 /***************************************************************************
2814  Return TRUE if the passed service number is within range.
2815 ***************************************************************************/
2816
2817 BOOL lp_snum_ok(int iService)
2818 {
2819         return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
2820 }
2821
2822 /***************************************************************************
2823  Auto-load some home services.
2824 ***************************************************************************/
2825
2826 static void lp_add_auto_services(const char *str)
2827 {
2828         return;
2829 }
2830
2831 /***************************************************************************
2832  Auto-load one printer.
2833 ***************************************************************************/
2834
2835 void lp_add_one_printer(char *name, char *comment)
2836 {
2837         int printers = lp_servicenumber(PRINTERS_NAME);
2838         int i;
2839
2840         if (lp_servicenumber(name) < 0) {
2841                 lp_add_printer(name, printers);
2842                 if ((i = lp_servicenumber(name)) >= 0) {
2843                         string_set(&ServicePtrs[i]->comment, comment);
2844                         ServicePtrs[i]->autoloaded = True;
2845                 }
2846         }
2847 }
2848
2849 /***************************************************************************
2850  Announce ourselves as a print server.
2851 ***************************************************************************/
2852
2853 void update_server_announce_as_printserver(void)
2854 {
2855         default_server_announce |= SV_TYPE_PRINTQ_SERVER;       
2856 }
2857
2858 /***************************************************************************
2859  Have we loaded a services file yet?
2860 ***************************************************************************/
2861
2862 BOOL lp_loaded(void)
2863 {
2864         return (bLoaded);
2865 }
2866
2867 /***************************************************************************
2868  Unload unused services.
2869 ***************************************************************************/
2870
2871 void lp_killunused(struct smbsrv_connection *smb, BOOL (*snumused) (struct smbsrv_connection *, int))
2872 {
2873         int i;
2874         for (i = 0; i < iNumServices; i++) {
2875                 if (!VALID(i))
2876                         continue;
2877
2878                 if (!snumused || !snumused(smb, i)) {
2879                         ServicePtrs[i]->valid = False;
2880                         free_service(ServicePtrs[i]);
2881                 }
2882         }
2883 }
2884
2885 /***************************************************************************
2886  Unload a service.
2887 ***************************************************************************/
2888
2889 void lp_killservice(int iServiceIn)
2890 {
2891         if (VALID(iServiceIn)) {
2892                 ServicePtrs[iServiceIn]->valid = False;
2893                 free_service(ServicePtrs[iServiceIn]);
2894         }
2895 }
2896
2897 /***************************************************************************
2898  Save the curent values of all global and sDefault parameters into the 
2899  defaults union. This allows swat and testparm to show only the
2900  changed (ie. non-default) parameters.
2901 ***************************************************************************/
2902
2903 static void lp_save_defaults(void)
2904 {
2905         int i;
2906         for (i = 0; parm_table[i].label; i++) {
2907                 if (i > 0 && parm_table[i].ptr == parm_table[i - 1].ptr)
2908                         continue;
2909                 switch (parm_table[i].type) {
2910                         case P_LIST:
2911                                 str_list_copy(&(parm_table[i].def.lvalue),
2912                                             *(const char ***)parm_table[i].ptr);
2913                                 break;
2914                         case P_STRING:
2915                         case P_USTRING:
2916                                 if (parm_table[i].ptr) {
2917                                         parm_table[i].def.svalue = strdup(*(char **)parm_table[i].ptr);
2918                                 } else {
2919                                         parm_table[i].def.svalue = NULL;
2920                                 }
2921                                 break;
2922                         case P_BOOL:
2923                         case P_BOOLREV:
2924                                 parm_table[i].def.bvalue =
2925                                         *(BOOL *)parm_table[i].ptr;
2926                                 break;
2927                         case P_CHAR:
2928                                 parm_table[i].def.cvalue =
2929                                         *(char *)parm_table[i].ptr;
2930                                 break;
2931                         case P_INTEGER:
2932                         case P_OCTAL:
2933                         case P_ENUM:
2934                                 parm_table[i].def.ivalue =
2935                                         *(int *)parm_table[i].ptr;
2936                                 break;
2937                         case P_SEP:
2938                                 break;
2939                 }
2940         }
2941         defaults_saved = True;
2942 }
2943
2944 /*******************************************************************
2945  Set the server type we will announce as via nmbd.
2946 ********************************************************************/
2947
2948 static void set_server_role(void)
2949 {
2950         server_role = ROLE_STANDALONE;
2951
2952         switch (lp_security()) {
2953                 case SEC_SHARE:
2954                         if (lp_domain_logons())
2955                                 DEBUG(0, ("Server's Role (logon server) conflicts with share-level security\n"));
2956                         break;
2957                 case SEC_SERVER:
2958                 case SEC_DOMAIN:
2959                 case SEC_ADS:
2960                         if (lp_domain_logons()) {
2961                                 server_role = ROLE_DOMAIN_PDC;
2962                                 break;
2963                         }
2964                         server_role = ROLE_DOMAIN_MEMBER;
2965                         break;
2966                 case SEC_USER:
2967                         if (lp_domain_logons()) {
2968
2969                                 if (Globals.bDomainMaster) /* auto or yes */ 
2970                                         server_role = ROLE_DOMAIN_PDC;
2971                                 else
2972                                         server_role = ROLE_DOMAIN_BDC;
2973                         }
2974                         break;
2975                 default:
2976                         DEBUG(0, ("Server's Role undefined due to unknown security mode\n"));
2977                         break;
2978         }
2979
2980         DEBUG(10, ("set_server_role: role = "));
2981
2982         switch(server_role) {
2983         case ROLE_STANDALONE:
2984                 DEBUGADD(10, ("ROLE_STANDALONE\n"));
2985                 break;
2986         case ROLE_DOMAIN_MEMBER:
2987                 DEBUGADD(10, ("ROLE_DOMAIN_MEMBER\n"));
2988                 break;
2989         case ROLE_DOMAIN_BDC:
2990                 DEBUGADD(10, ("ROLE_DOMAIN_BDC\n"));
2991                 break;
2992         case ROLE_DOMAIN_PDC:
2993                 DEBUGADD(10, ("ROLE_DOMAIN_PDC\n"));
2994                 break;
2995         }
2996 }
2997
2998 /***************************************************************************
2999  Load the services array from the services file. Return True on success, 
3000  False on failure.
3001 ***************************************************************************/
3002
3003 BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
3004              BOOL add_ipc)
3005 {
3006         pstring n2;
3007         BOOL bRetval;
3008         struct param_opt *data;
3009
3010         pstrcpy(n2, pszFname);
3011         standard_sub_basic(n2,sizeof(n2));
3012
3013         add_to_file_list(pszFname, n2);
3014
3015         bRetval = False;
3016
3017         DEBUG(2, ("lp_load: refreshing parameters from %s\n", pszFname));
3018         
3019         bInGlobalSection = True;
3020         bGlobalOnly = global_only;
3021
3022         init_globals();
3023
3024         if (save_defaults)
3025         {
3026                 lp_save_defaults();
3027         }
3028
3029         if (Globals.param_opt != NULL) {
3030                 struct param_opt *next;
3031                 for (data=Globals.param_opt; data; data=next) {
3032                         next = data->next;
3033                         if (data->flags & FLAG_CMDLINE) continue;
3034                         free(data->key);
3035                         free(data->value);
3036                         DLIST_REMOVE(Globals.param_opt, data);
3037                         free(data);
3038                 }
3039         }
3040         
3041         /* We get sections first, so have to start 'behind' to make up */
3042         iServiceIndex = -1;
3043         bRetval = pm_process(n2, do_section, do_parameter);
3044
3045         /* finish up the last section */
3046         DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
3047         if (bRetval)
3048                 if (iServiceIndex >= 0)
3049                         bRetval = service_ok(iServiceIndex);
3050
3051         lp_add_auto_services(lp_auto_services());
3052
3053         if (add_ipc) {
3054                 /* When 'restrict anonymous = 2' guest connections to ipc$
3055                    are denied */
3056                 lp_add_ipc("IPC$", (lp_restrict_anonymous() < 2));
3057                 lp_add_ipc("ADMIN$", False);
3058         }
3059
3060         set_server_role();
3061         set_default_server_announce_type();
3062
3063         bLoaded = True;
3064
3065         /* Now we check bWINSsupport and set szWINSserver to 127.0.0.1 */
3066         /* if bWINSsupport is true and we are in the client            */
3067         if (in_client && Globals.bWINSsupport) {
3068                 lp_do_parameter(-1, "wins server", "127.0.0.1");
3069         }
3070
3071         lp_do_parameter(-1, "gensec:krb5", "False");
3072         lp_do_parameter(-1, "gensec:ms_krb5", "False");
3073
3074         init_iconv();
3075
3076         return (bRetval);
3077 }
3078
3079 /***************************************************************************
3080  Reset the max number of services.
3081 ***************************************************************************/
3082
3083 void lp_resetnumservices(void)
3084 {
3085         iNumServices = 0;
3086 }
3087
3088 /***************************************************************************
3089  Return the max number of services.
3090 ***************************************************************************/
3091
3092 int lp_numservices(void)
3093 {
3094         return (iNumServices);
3095 }
3096
3097 /***************************************************************************
3098 Display the contents of the services array in human-readable form.
3099 ***************************************************************************/
3100
3101 void lp_dump(FILE *f, BOOL show_defaults, int maxtoprint)
3102 {
3103         int iService;
3104
3105         if (show_defaults)
3106                 defaults_saved = False;
3107
3108         dump_globals(f);
3109
3110         dump_a_service(&sDefault, f);
3111
3112         for (iService = 0; iService < maxtoprint; iService++)
3113                 lp_dump_one(f, show_defaults, iService);
3114 }
3115
3116 /***************************************************************************
3117 Display the contents of one service in human-readable form.
3118 ***************************************************************************/
3119
3120 void lp_dump_one(FILE * f, BOOL show_defaults, int snum)
3121 {
3122         if (VALID(snum)) {
3123                 if (ServicePtrs[snum]->szService[0] == '\0')
3124                         return;
3125                 dump_a_service(ServicePtrs[snum], f);
3126         }
3127 }
3128
3129 /***************************************************************************
3130 Return the number of the service with the given name, or -1 if it doesn't
3131 exist. Note that this is a DIFFERENT ANIMAL from the internal function
3132 getservicebyname()! This works ONLY if all services have been loaded, and
3133 does not copy the found service.
3134 ***************************************************************************/
3135
3136 int lp_servicenumber(const char *pszServiceName)
3137 {
3138         int iService;
3139         fstring serviceName;
3140  
3141  
3142         for (iService = iNumServices - 1; iService >= 0; iService--) {
3143                 if (VALID(iService) && ServicePtrs[iService]->szService) {
3144                         /*
3145                          * The substitution here is used to support %U is
3146                          * service names
3147                          */
3148                         fstrcpy(serviceName, ServicePtrs[iService]->szService);
3149                         standard_sub_basic(serviceName,sizeof(serviceName));
3150                         if (strequal(serviceName, pszServiceName))
3151                                 break;
3152                 }
3153         }
3154
3155         if (iService < 0)
3156                 DEBUG(7,("lp_servicenumber: couldn't find %s\n", pszServiceName));
3157
3158         return (iService);
3159 }
3160
3161 /*******************************************************************
3162  A useful volume label function. 
3163 ********************************************************************/
3164 const char *volume_label(int snum)
3165 {
3166         const char *ret = lp_volume(snum);
3167         if (!*ret)
3168                 return lp_servicename(snum);
3169         return (ret);
3170 }
3171
3172
3173 /*******************************************************************
3174  Set the server type we will announce as via nmbd.
3175 ********************************************************************/
3176
3177 static void set_default_server_announce_type(void)
3178 {
3179         default_server_announce = 0;
3180         default_server_announce |= SV_TYPE_WORKSTATION;
3181         default_server_announce |= SV_TYPE_SERVER;
3182         default_server_announce |= SV_TYPE_SERVER_UNIX;
3183
3184         switch (lp_announce_as()) {
3185                 case ANNOUNCE_AS_NT_SERVER:
3186                         default_server_announce |= SV_TYPE_SERVER_NT;
3187                         /* fall through... */
3188                 case ANNOUNCE_AS_NT_WORKSTATION:
3189                         default_server_announce |= SV_TYPE_NT;
3190                         break;
3191                 case ANNOUNCE_AS_WIN95:
3192                         default_server_announce |= SV_TYPE_WIN95_PLUS;
3193                         break;
3194                 case ANNOUNCE_AS_WFW:
3195                         default_server_announce |= SV_TYPE_WFW;
3196                         break;
3197                 default:
3198                         break;
3199         }
3200
3201         switch (lp_server_role()) {
3202                 case ROLE_DOMAIN_MEMBER:
3203                         default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
3204                         break;
3205                 case ROLE_DOMAIN_PDC:
3206                         default_server_announce |= SV_TYPE_DOMAIN_CTRL;
3207                         break;
3208                 case ROLE_DOMAIN_BDC:
3209                         default_server_announce |= SV_TYPE_DOMAIN_BAKCTRL;
3210                         break;
3211                 case ROLE_STANDALONE:
3212                 default:
3213                         break;
3214         }
3215         if (lp_time_server())
3216                 default_server_announce |= SV_TYPE_TIME_SOURCE;
3217
3218         if (lp_host_msdfs())
3219                 default_server_announce |= SV_TYPE_DFS_SERVER;
3220 }
3221
3222 /***********************************************************
3223  returns role of Samba server
3224 ************************************************************/
3225
3226 int lp_server_role(void)
3227 {
3228         return server_role;
3229 }
3230
3231 /***********************************************************
3232  If we are PDC then prefer us as DMB
3233 ************************************************************/
3234
3235 BOOL lp_domain_master(void)
3236 {
3237         if (Globals.bDomainMaster == Auto)
3238                 return (lp_server_role() == ROLE_DOMAIN_PDC);
3239
3240         return Globals.bDomainMaster;
3241 }
3242
3243 /***********************************************************
3244  If we are DMB then prefer us as LMB
3245 ************************************************************/
3246
3247 BOOL lp_preferred_master(void)
3248 {
3249         if (Globals.bPreferredMaster == Auto)
3250                 return (lp_local_master() && lp_domain_master());
3251
3252         return Globals.bPreferredMaster;
3253 }
3254
3255 /*******************************************************************
3256  Remove a service.
3257 ********************************************************************/
3258
3259 void lp_remove_service(int snum)
3260 {
3261         ServicePtrs[snum]->valid = False;
3262 }
3263
3264 /*******************************************************************
3265  Copy a service.
3266 ********************************************************************/
3267
3268 void lp_copy_service(int snum, const char *new_name)
3269 {
3270         const char *oldname = lp_servicename(snum);
3271         do_section(new_name);
3272         if (snum >= 0) {
3273                 snum = lp_servicenumber(new_name);
3274                 if (snum >= 0)
3275                         lp_do_parameter(snum, "copy", oldname);
3276         }
3277 }
3278
3279
3280 /*******************************************************************
3281  Get the default server type we will announce as via nmbd.
3282 ********************************************************************/
3283 int lp_default_server_announce(void)
3284 {
3285         return default_server_announce;
3286 }
3287
3288 const char *lp_printername(int snum)
3289 {
3290         const char *ret = _lp_printername(snum);
3291         if (ret == NULL || (ret != NULL && *ret == '\0'))
3292                 ret = lp_const_servicename(snum);
3293
3294         return ret;
3295 }
3296
3297
3298 /*******************************************************************
3299  Return the max print jobs per queue.
3300 ********************************************************************/
3301
3302 int lp_maxprintjobs(int snum)
3303 {
3304         int maxjobs = LP_SNUM_OK(snum) ? ServicePtrs[snum]->iMaxPrintJobs : sDefault.iMaxPrintJobs;
3305         if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
3306                 maxjobs = PRINT_MAX_JOBID - 1;
3307
3308         return maxjobs;
3309 }