c0f54860c1b78ad60084ca85744cb49c928f66b5
[samba.git] / source / param / loadparm.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Parameter loading functions
5    Copyright (C) Karl Auer 1993-1998
6
7    Largely re-written by Andrew Tridgell, September 1994
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /*
25  *  Load parameters.
26  *
27  *  This module provides suitable callback functions for the params
28  *  module. It builds the internal table of service details which is
29  *  then used by the rest of the server.
30  *
31  * To add a parameter:
32  *
33  * 1) add it to the global or service structure definition
34  * 2) add it to the parm_table
35  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
36  * 4) If it's a global then initialise it in init_globals. If a local
37  *    (ie. service) parameter then initialise it in the sDefault structure
38  *  
39  *
40  * Notes:
41  *   The configuration file is processed sequentially for speed. It is NOT
42  *   accessed randomly as happens in 'real' Windows. For this reason, there
43  *   is a fair bit of sequence-dependent code here - ie., code which assumes
44  *   that certain things happen before others. In particular, the code which
45  *   happens at the boundary between sections is delicately poised, so be
46  *   careful!
47  *
48  */
49
50 #include "includes.h"
51
52 /* Set default coding system for KANJI if none specified in Makefile. */
53 /* 
54  * We treat KANJI specially due to historical precedent (it was the
55  * first non-english codepage added to Samba). With the new dynamic
56  * codepage support this is not needed anymore.
57  *
58  * The define 'KANJI' is being overloaded to mean 'use kanji codepage
59  * by default' and also 'this is the filename-to-disk conversion 
60  * method to use'. This really should be removed and all control
61  * over this left in the smb.conf parameters 'client codepage'
62  * and 'coding system'.
63  */
64 #ifndef KANJI
65 #define KANJI "sjis"
66 #endif /* KANJI */
67
68 BOOL bLoaded = False;
69
70 extern int DEBUGLEVEL;
71 extern pstring user_socket_options;
72 extern pstring myname;
73
74 #ifndef GLOBAL_NAME
75 #define GLOBAL_NAME "global"
76 #endif
77
78 #ifndef PRINTERS_NAME
79 #define PRINTERS_NAME "printers"
80 #endif
81
82 #ifndef HOMES_NAME
83 #define HOMES_NAME "homes"
84 #endif
85
86 /* some helpful bits */
87 #define pSERVICE(i) ServicePtrs[i]
88 #define iSERVICE(i) (*pSERVICE(i))
89 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices) && iSERVICE(iService).valid)
90 #define VALID(i) iSERVICE(i).valid
91
92 /* these are the types of parameter we have */
93 typedef enum
94 {
95   P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
96   P_STRING,P_USTRING,P_GSTRING,P_UGSTRING,P_ENUM
97 } parm_type;
98
99 typedef enum
100 {
101   P_LOCAL,P_GLOBAL,P_NONE
102 } parm_class;
103
104 int keepalive=0;
105 extern BOOL use_getwd_cache;
106
107 extern int extra_time_offset;
108
109 /* 
110  * This structure describes global (ie., server-wide) parameters.
111  */
112 typedef struct
113 {
114   char *szPrintcapname;
115   char *szLockDir;
116   char *szRootdir;
117   char *szDefaultService;
118   char *szDfree;
119   char *szMsgCommand;
120   char *szHostsEquiv;
121   char *szServerString;
122   char *szAutoServices;
123   char *szPasswdProgram;
124   char *szPasswdChat;
125   char *szLogFile;
126   char *szConfigFile;
127   char *szSMBPasswdFile;
128   char *szPasswordServer;
129   char *szSocketOptions;
130   char *szValidChars;
131   char *szWorkGroup;
132   char *szDomainAdminUsers;
133   char *szDomainGuestUsers;
134   char *szDomainHostsallow; 
135   char *szDomainHostsdeny;
136   char *szUsernameMap;
137   char *szCharacterSet;
138   char *szLogonScript;
139   char *szLogonPath;
140   char *szLogonDrive;
141   char *szLogonHome;
142   char *szSmbrun;
143   char *szWINSserver;
144   char *szCodingSystem;
145   char *szInterfaces;
146   char *szRemoteAnnounce;
147   char *szRemoteBrowseSync;
148   char *szSocketAddress;
149   char *szNISHomeMapName;
150   char *szAnnounceVersion; /* This is initialised in init_globals */
151   char *szNetbiosAliases;
152   char *szDomainSID;
153   char *szDomainOtherSIDs;
154   char *szDomainGroups;
155   char *szDriverFile;
156   int max_log_size;
157   int mangled_stack;
158   int max_xmit;
159   int max_mux;
160   int max_packet;
161   int pwordlevel;
162   int unamelevel;
163   int deadtime;
164   int maxprotocol;
165   int security;
166   int maxdisksize;
167   int lpqcachetime;
168   int syslog;
169   int os_level;
170   int max_ttl;
171   int max_wins_ttl;
172   int min_wins_ttl;
173   int ReadSize;
174   int lm_announce;
175   int lm_interval;
176   int shmem_size;
177   int client_code_page;
178   int announce_as;   /* This is initialised in init_globals */
179   BOOL bDNSproxy;
180   BOOL bWINSsupport;
181   BOOL bWINSproxy;
182   BOOL bLocalMaster;
183   BOOL bPreferredMaster;
184   BOOL bDomainController;
185   BOOL bDomainMaster;
186   BOOL bDomainLogons;
187   BOOL bEncryptPasswords;
188   BOOL bStripDot;
189   BOOL bNullPasswords;
190   BOOL bLoadPrinters;
191   BOOL bUseRhosts;
192   BOOL bReadRaw;
193   BOOL bWriteRaw;
194   BOOL bReadPrediction;
195   BOOL bReadbmpx;
196   BOOL bSyslogOnly;
197   BOOL bBrowseList;
198   BOOL bUnixRealname;
199   BOOL bNISHomeMap;
200   BOOL bTimeServer;
201   BOOL bBindInterfacesOnly;
202   BOOL bNetWkstaUserLogon;
203 } global;
204
205 static global Globals;
206
207
208
209 /* 
210  * This structure describes a single service. 
211  */
212 typedef struct
213 {
214   BOOL valid;
215   char *szService;
216   char *szPath;
217   char *szUsername;
218   char *szGuestaccount;
219   char *szInvalidUsers;
220   char *szValidUsers;
221   char *szAdminUsers;
222   char *szCopy;
223   char *szInclude;
224   char *szPreExec;
225   char *szPostExec;
226   char *szRootPreExec;
227   char *szRootPostExec;
228   char *szPrintcommand;
229   char *szLpqcommand;
230   char *szLprmcommand;
231   char *szLppausecommand;
232   char *szLpresumecommand;
233   char *szPrintername;
234   char *szPrinterDriver;
235   char *szPrinterDriverLocation;
236   char *szDontdescend;
237   char *szHostsallow;
238   char *szHostsdeny;
239   char *szMagicScript;
240   char *szMagicOutput;
241   char *szMangledMap;
242   char *szVetoFiles;
243   char *szHideFiles;
244   char *szVetoOplockFiles;
245   char *comment;
246   char *force_user;
247   char *force_group;
248   char *readlist;
249   char *writelist;
250   char *volume;
251   int  iMinPrintSpace;
252   int  iCreate_mask;
253   int  iCreate_force_mode;
254   int  iDir_mask;
255   int  iDir_force_mode;
256   int  iMaxConnections;
257   int  iDefaultCase;
258   int  iPrinting;
259   BOOL bAlternatePerm;
260   BOOL bRevalidate;
261   BOOL bCaseSensitive;
262   BOOL bCasePreserve;
263   BOOL bShortCasePreserve;
264   BOOL bCaseMangle;
265   BOOL status;
266   BOOL bHideDotFiles;
267   BOOL bBrowseable;
268   BOOL bAvailable;
269   BOOL bRead_only;
270   BOOL bNo_set_dir;
271   BOOL bGuest_only;
272   BOOL bGuest_ok;
273   BOOL bPrint_ok;
274   BOOL bPostscript;
275   BOOL bMap_system;
276   BOOL bMap_hidden;
277   BOOL bMap_archive;
278   BOOL bLocking;
279   BOOL bStrictLocking;
280   BOOL bShareModes;
281   BOOL bOpLocks;
282   BOOL bOnlyUser;
283   BOOL bMangledNames;
284   BOOL bWidelinks;
285   BOOL bSymlinks;
286   BOOL bSyncAlways;
287   char magic_char;
288   BOOL *copymap;
289   BOOL bDeleteReadonly;
290   BOOL bFakeOplocks;
291   BOOL bDeleteVetoFiles;
292   BOOL bDosFiletimes;
293   BOOL bDosFiletimeResolution;
294   char dummy[3]; /* for alignment */
295 } service;
296
297
298 /* This is a default service used to prime a services structure */
299 static service sDefault = 
300 {
301   True,   /* valid */
302   NULL,    /* szService */
303   NULL,    /* szPath */
304   NULL,    /* szUsername */
305   NULL,    /* szGuestAccount  - this is set in init_globals() */
306   NULL,    /* szInvalidUsers */
307   NULL,    /* szValidUsers */
308   NULL,    /* szAdminUsers */
309   NULL,    /* szCopy */
310   NULL,    /* szInclude */
311   NULL,    /* szPreExec */
312   NULL,    /* szPostExec */
313   NULL,    /* szRootPreExec */
314   NULL,    /* szRootPostExec */
315   NULL,    /* szPrintcommand */
316   NULL,    /* szLpqcommand */
317   NULL,    /* szLprmcommand */
318   NULL,    /* szLppausecommand */
319   NULL,    /* szLpresumecommand */
320   NULL,    /* szPrintername */
321   NULL,    /* szPrinterDriver - this is set in init_globals() */
322   NULL,    /* szPrinterDriverLocation */
323   NULL,    /* szDontdescend */
324   NULL,    /* szHostsallow */
325   NULL,    /* szHostsdeny */
326   NULL,    /* szMagicScript */
327   NULL,    /* szMagicOutput */
328   NULL,    /* szMangledMap */
329   NULL,    /* szVetoFiles */
330   NULL,    /* szHideFiles */
331   NULL,    /* szVetoOplockFiles */
332   NULL,    /* comment */
333   NULL,    /* force user */
334   NULL,    /* force group */
335   NULL,    /* readlist */
336   NULL,    /* writelist */
337   NULL,    /* volume */
338   0,       /* iMinPrintSpace */
339   0744,    /* iCreate_mask */
340   0000,    /* iCreate_force_mode */
341   0755,    /* iDir_mask */
342   0000,    /* iDir_force_mode */
343   0,       /* iMaxConnections */
344   CASE_LOWER, /* iDefaultCase */
345   DEFAULT_PRINTING, /* iPrinting */
346   False,   /* bAlternatePerm */
347   False,   /* revalidate */
348   False,   /* case sensitive */
349   False,   /* case preserve */
350   False,   /* short case preserve */
351   False,  /* case mangle */
352   True,  /* status */
353   True,  /* bHideDotFiles */
354   True,  /* bBrowseable */
355   True,  /* bAvailable */
356   True,  /* bRead_only */
357   True,  /* bNo_set_dir */
358   False, /* bGuest_only */
359   False, /* bGuest_ok */
360   False, /* bPrint_ok */
361   False, /* bPostscript */
362   False, /* bMap_system */
363   False, /* bMap_hidden */
364   True,  /* bMap_archive */
365   True,  /* bLocking */
366   False,  /* bStrictLocking */
367   True,  /* bShareModes */
368   True,  /* bOpLocks */
369   False, /* bOnlyUser */
370   True,  /* bMangledNames */
371   True,  /* bWidelinks */
372   True,  /* bSymlinks */
373   False, /* bSyncAlways */
374   '~',   /* magic char */
375   NULL,  /* copymap */
376   False, /* bDeleteReadonly */
377   False, /* bFakeOplocks */
378   False, /* bDeleteVetoFiles */
379   False, /* bDosFiletimes */
380   False, /* bDosFiletimeResolution */
381   ""     /* dummy */
382 };
383
384
385
386 /* local variables */
387 static service **ServicePtrs = NULL;
388 static int iNumServices = 0;
389 static int iServiceIndex = 0;
390 static BOOL bInGlobalSection = True;
391 static BOOL bGlobalOnly = False;
392 static int default_server_announce;
393
394 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
395
396 /* prototypes for the special type handlers */
397 static BOOL handle_valid_chars(char *pszParmValue, char **ptr);
398 static BOOL handle_include(char *pszParmValue, char **ptr);
399 static BOOL handle_copy(char *pszParmValue, char **ptr);
400 static BOOL handle_character_set(char *pszParmValue,char **ptr);
401 static BOOL handle_coding_system(char *pszParmValue,char **ptr);
402
403 static void set_default_server_announce_type(void);
404
405 struct enum_list {
406         int value;
407         char *name;
408 };
409
410 static struct enum_list enum_protocol[] = {{PROTOCOL_NT1, "NT1"}, {PROTOCOL_LANMAN2, "LANMAN2"}, 
411                                            {PROTOCOL_LANMAN1, "LANMAN1"}, {PROTOCOL_CORE,"CORE"}, 
412                                            {PROTOCOL_COREPLUS, "COREPLUS"}, 
413                                            {PROTOCOL_COREPLUS, "CORE+"}, {-1, NULL}};
414
415 static struct enum_list enum_security[] = {{SEC_SHARE, "SHARE"},  {SEC_USER, "USER"}, 
416                                            {SEC_SERVER, "SERVER"}, {-1, NULL}};
417
418 static struct enum_list enum_printing[] = {{PRINT_SYSV, "sysv"}, {PRINT_AIX, "aix"}, 
419                                            {PRINT_HPUX, "hpux"}, {PRINT_BSD, "bsd"},
420                                            {PRINT_QNX, "qnx"},   {PRINT_PLP, "plp"},
421                                            {PRINT_LPRNG, "lprng"}, {-1, NULL}};
422
423 static struct enum_list enum_announce_as[] = {{ANNOUNCE_AS_NT, "NT"}, {ANNOUNCE_AS_WIN95, "win95"},
424                                               {ANNOUNCE_AS_WFW, "WfW"}, {-1, NULL}};
425
426 static struct enum_list enum_case[] = {{CASE_LOWER, "lower"}, {CASE_UPPER, "upper"}, {-1, NULL}};
427
428 static struct enum_list enum_lm_announce[] = {{0, "False"}, {1, "True"}, {2, "Auto"}, {-1, NULL}};
429
430 static struct parm_struct
431 {
432         char *label;
433         parm_type type;
434         parm_class class;
435         void *ptr;
436         BOOL (*special)();
437         struct enum_list *enum_list;
438 } parm_table[] =
439 {
440   {"debuglevel",       P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL,   NULL},
441   {"log level",        P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL,   NULL},
442   {"syslog",           P_INTEGER, P_GLOBAL, &Globals.syslog,            NULL,   NULL},
443   {"syslog only",      P_BOOL,    P_GLOBAL, &Globals.bSyslogOnly,       NULL,   NULL},
444   {"protocol",         P_ENUM,    P_GLOBAL, &Globals.maxprotocol,       NULL,   enum_protocol},
445   {"security",         P_ENUM,    P_GLOBAL, &Globals.security,          NULL,   enum_security},
446   {"max disk size",    P_INTEGER, P_GLOBAL, &Globals.maxdisksize,       NULL,   NULL},
447   {"lpq cache time",   P_INTEGER, P_GLOBAL, &Globals.lpqcachetime,      NULL,   NULL},
448   {"announce as",      P_ENUM,    P_GLOBAL, &Globals.announce_as,       NULL,   enum_announce_as},
449   {"encrypt passwords",P_BOOL,    P_GLOBAL, &Globals.bEncryptPasswords, NULL,   NULL},
450   {"getwd cache",      P_BOOL,    P_GLOBAL, &use_getwd_cache,           NULL,   NULL},
451   {"read prediction",  P_BOOL,    P_GLOBAL, &Globals.bReadPrediction,   NULL,   NULL},
452   {"read bmpx",        P_BOOL,    P_GLOBAL, &Globals.bReadbmpx,         NULL,   NULL},
453   {"read raw",         P_BOOL,    P_GLOBAL, &Globals.bReadRaw,          NULL,   NULL},
454   {"write raw",        P_BOOL,    P_GLOBAL, &Globals.bWriteRaw,         NULL,   NULL},
455   {"use rhosts",       P_BOOL,    P_GLOBAL, &Globals.bUseRhosts,        NULL,   NULL},
456   {"load printers",    P_BOOL,    P_GLOBAL, &Globals.bLoadPrinters,     NULL,   NULL},
457   {"null passwords",   P_BOOL,    P_GLOBAL, &Globals.bNullPasswords,    NULL,   NULL},
458   {"strip dot",        P_BOOL,    P_GLOBAL, &Globals.bStripDot,         NULL,   NULL},
459   {"interfaces",       P_STRING,  P_GLOBAL, &Globals.szInterfaces,      NULL,   NULL},
460   {"bind interfaces only", P_BOOL,P_GLOBAL, &Globals.bBindInterfacesOnly,NULL,   NULL},
461   {"networkstation user login", P_BOOL,P_GLOBAL, &Globals.bNetWkstaUserLogon,NULL,   NULL},
462   {"password server",  P_STRING,  P_GLOBAL, &Globals.szPasswordServer,  NULL,   NULL},
463   {"socket options",   P_GSTRING, P_GLOBAL, user_socket_options,        NULL,   NULL},
464   {"netbios name",     P_UGSTRING,P_GLOBAL, myname,                     NULL,   NULL},
465   {"netbios aliases",  P_STRING,  P_GLOBAL, &Globals.szNetbiosAliases,  NULL,   NULL},
466   {"smbrun",           P_STRING,  P_GLOBAL, &Globals.szSmbrun,          NULL,   NULL},
467   {"log file",         P_STRING,  P_GLOBAL, &Globals.szLogFile,         NULL,   NULL},
468   {"config file",      P_STRING,  P_GLOBAL, &Globals.szConfigFile,      NULL,   NULL},
469   {"smb passwd file",  P_STRING,  P_GLOBAL, &Globals.szSMBPasswdFile,   NULL,   NULL},
470   {"hosts equiv",      P_STRING,  P_GLOBAL, &Globals.szHostsEquiv,      NULL,   NULL},
471   {"preload",          P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL,   NULL},
472   {"auto services",    P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL,   NULL},
473   {"server string",    P_STRING,  P_GLOBAL, &Globals.szServerString,    NULL,   NULL},
474   {"printcap name",    P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL,   NULL},
475   {"printcap",         P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL,   NULL},
476   {"lock dir",         P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL,   NULL},
477   {"lock directory",   P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL,   NULL},
478   {"root directory",   P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL,   NULL},
479   {"root dir",         P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL,   NULL},
480   {"root",             P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL,   NULL},
481   {"default service",  P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL,   NULL},
482   {"default",          P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL,   NULL},
483   {"message command",  P_STRING,  P_GLOBAL, &Globals.szMsgCommand,      NULL,   NULL},
484   {"dfree command",    P_STRING,  P_GLOBAL, &Globals.szDfree,           NULL,   NULL},
485   {"passwd program",   P_STRING,  P_GLOBAL, &Globals.szPasswdProgram,   NULL,   NULL},
486   {"passwd chat",      P_STRING,  P_GLOBAL, &Globals.szPasswdChat,      NULL,   NULL},
487   {"valid chars",      P_STRING,  P_GLOBAL, &Globals.szValidChars,      handle_valid_chars, NULL},
488   {"workgroup",        P_USTRING, P_GLOBAL, &Globals.szWorkGroup,       NULL,   NULL},
489 #ifdef NTDOMAIN
490   {"domain sid",       P_USTRING, P_GLOBAL, &Globals.szDomainSID,       NULL,   NULL},
491   {"domain other sids",P_STRING,  P_GLOBAL, &Globals.szDomainOtherSIDs, NULL,   NULL},
492   {"domain groups",    P_STRING,  P_GLOBAL, &Globals.szDomainGroups,    NULL,   NULL},
493   {"domain controller",P_BOOL  ,  P_GLOBAL, &Globals.bDomainController,NULL,   NULL},
494   {"domain admin users",P_STRING, P_GLOBAL, &Globals.szDomainAdminUsers, NULL,   NULL},
495   {"domain guest users",P_STRING, P_GLOBAL, &Globals.szDomainGuestUsers, NULL,   NULL},
496   {"domain hosts allow",P_STRING, P_GLOBAL, &Globals.szDomainHostsallow, NULL,   NULL},
497   {"domain allow hosts",P_STRING, P_GLOBAL, &Globals.szDomainHostsallow, NULL,   NULL},
498   {"domain hosts deny", P_STRING, P_GLOBAL, &Globals.szDomainHostsdeny,  NULL,   NULL},
499   {"domain deny hosts", P_STRING, P_GLOBAL, &Globals.szDomainHostsdeny,  NULL,   NULL},
500 #endif /* NTDOMAIN */
501   {"username map",     P_STRING,  P_GLOBAL, &Globals.szUsernameMap,     NULL,   NULL},
502   {"character set",    P_STRING,  P_GLOBAL, &Globals.szCharacterSet,    handle_character_set, NULL},
503   {"logon script",     P_STRING,  P_GLOBAL, &Globals.szLogonScript,     NULL,   NULL},
504   {"logon path",       P_STRING,  P_GLOBAL, &Globals.szLogonPath,       NULL,   NULL},
505   {"logon drive",      P_STRING,  P_GLOBAL, &Globals.szLogonDrive,      NULL,   NULL},
506   {"logon home",       P_STRING,  P_GLOBAL, &Globals.szLogonHome,       NULL,   NULL},
507   {"remote announce",  P_STRING,  P_GLOBAL, &Globals.szRemoteAnnounce,  NULL,   NULL},
508   {"remote browse sync",P_STRING, P_GLOBAL, &Globals.szRemoteBrowseSync,NULL,   NULL},
509   {"socket address",   P_STRING,  P_GLOBAL, &Globals.szSocketAddress,   NULL,   NULL},
510   {"homedir map",      P_STRING,  P_GLOBAL, &Globals.szNISHomeMapName,  NULL,   NULL},
511   {"announce version", P_STRING,  P_GLOBAL, &Globals.szAnnounceVersion, NULL,   NULL},
512   {"max log size",     P_INTEGER, P_GLOBAL, &Globals.max_log_size,      NULL,   NULL},
513   {"mangled stack",    P_INTEGER, P_GLOBAL, &Globals.mangled_stack,     NULL,   NULL},
514   {"max mux",          P_INTEGER, P_GLOBAL, &Globals.max_mux,           NULL,   NULL},
515   {"max xmit",         P_INTEGER, P_GLOBAL, &Globals.max_xmit,          NULL,   NULL},
516   {"max packet",       P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL,   NULL},
517   {"packet size",      P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL,   NULL},
518   {"password level",   P_INTEGER, P_GLOBAL, &Globals.pwordlevel,        NULL,   NULL},
519   {"username level",   P_INTEGER, P_GLOBAL, &Globals.unamelevel,        NULL,   NULL},
520   {"keepalive",        P_INTEGER, P_GLOBAL, &keepalive,                 NULL,   NULL},
521   {"deadtime",         P_INTEGER, P_GLOBAL, &Globals.deadtime,          NULL,   NULL},
522   {"time offset",      P_INTEGER, P_GLOBAL, &extra_time_offset,         NULL,   NULL},
523   {"read size",        P_INTEGER, P_GLOBAL, &Globals.ReadSize,          NULL,   NULL},
524   {"shared mem size",  P_INTEGER, P_GLOBAL, &Globals.shmem_size,        NULL,   NULL},
525   {"coding system",    P_STRING,  P_GLOBAL, &Globals.szCodingSystem,    handle_coding_system, NULL},
526   {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page,  NULL,   NULL},
527   {"os level",         P_INTEGER, P_GLOBAL, &Globals.os_level,          NULL,   NULL},
528   {"max ttl",          P_INTEGER, P_GLOBAL, &Globals.max_ttl,           NULL,   NULL},
529   {"max wins ttl",     P_INTEGER, P_GLOBAL, &Globals.max_wins_ttl,      NULL,   NULL},
530   {"min wins ttl",     P_INTEGER, P_GLOBAL, &Globals.min_wins_ttl,      NULL,   NULL},
531   {"lm announce",      P_ENUM,    P_GLOBAL, &Globals.lm_announce,       NULL,   enum_lm_announce},
532   {"lm interval",      P_INTEGER, P_GLOBAL, &Globals.lm_interval,       NULL,   NULL},
533   {"dns proxy",        P_BOOL,    P_GLOBAL, &Globals.bDNSproxy,         NULL,   NULL},
534   {"wins support",     P_BOOL,    P_GLOBAL, &Globals.bWINSsupport,      NULL,   NULL},
535   {"wins proxy",       P_BOOL,    P_GLOBAL, &Globals.bWINSproxy,        NULL,   NULL},
536   {"wins server",      P_STRING,  P_GLOBAL, &Globals.szWINSserver,      NULL,   NULL},
537   {"preferred master", P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL,   NULL},
538   {"prefered master",  P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL,   NULL},
539   {"local master",     P_BOOL,    P_GLOBAL, &Globals.bLocalMaster,      NULL,   NULL},
540   {"domain master",    P_BOOL,    P_GLOBAL, &Globals.bDomainMaster,     NULL,   NULL},
541   {"domain logons",    P_BOOL,    P_GLOBAL, &Globals.bDomainLogons,     NULL,   NULL},
542   {"browse list",      P_BOOL,    P_GLOBAL, &Globals.bBrowseList,       NULL,   NULL},
543   {"unix realname",    P_BOOL,    P_GLOBAL, &Globals.bUnixRealname,     NULL,   NULL},
544   {"NIS homedir",      P_BOOL,    P_GLOBAL, &Globals.bNISHomeMap,       NULL,   NULL},
545   {"time server",      P_BOOL,    P_GLOBAL, &Globals.bTimeServer,       NULL,   NULL},
546   {"printer driver file", P_STRING,  P_GLOBAL, &Globals.szDriverFile,   NULL,   NULL},
547   {"-valid",           P_BOOL,    P_LOCAL,  &sDefault.valid,            NULL,   NULL},
548   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,          NULL,   NULL},
549   {"copy",             P_STRING,  P_LOCAL,  &sDefault.szCopy,           handle_copy, NULL},
550   {"include",          P_STRING,  P_LOCAL,  &sDefault.szInclude,        handle_include, NULL},
551   {"exec",             P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL,   NULL},
552   {"preexec",          P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL,   NULL},
553   {"postexec",         P_STRING,  P_LOCAL,  &sDefault.szPostExec,       NULL,   NULL},
554   {"root preexec",     P_STRING,  P_LOCAL,  &sDefault.szRootPreExec,    NULL,   NULL},
555   {"root postexec",    P_STRING,  P_LOCAL,  &sDefault.szRootPostExec,   NULL,   NULL},
556   {"alternate permissions",P_BOOL,P_LOCAL,  &sDefault.bAlternatePerm,   NULL,   NULL},
557   {"revalidate",       P_BOOL,    P_LOCAL,  &sDefault.bRevalidate,      NULL,   NULL},
558   {"default case",     P_ENUM, P_LOCAL,  &sDefault.iDefaultCase,        NULL,   enum_case},
559   {"case sensitive",   P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL,   NULL},
560   {"casesignames",     P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL,   NULL},
561   {"preserve case",    P_BOOL,    P_LOCAL,  &sDefault.bCasePreserve,    NULL,   NULL},
562   {"short preserve case",P_BOOL,  P_LOCAL,  &sDefault.bShortCasePreserve,NULL,   NULL},
563   {"mangle case",      P_BOOL,    P_LOCAL,  &sDefault.bCaseMangle,      NULL,   NULL},
564   {"mangling char",    P_CHAR,    P_LOCAL,  &sDefault.magic_char,       NULL,   NULL},
565   {"browseable",       P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL,   NULL},
566   {"browsable",        P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL,   NULL},
567   {"available",        P_BOOL,    P_LOCAL,  &sDefault.bAvailable,       NULL,   NULL},
568   {"path",             P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL,   NULL},
569   {"directory",        P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL,   NULL},
570   {"username",         P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL,   NULL},
571   {"user",             P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL,   NULL},
572   {"users",            P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL,   NULL},
573   {"guest account",    P_STRING,  P_LOCAL,  &sDefault.szGuestaccount,   NULL,   NULL},
574   {"invalid users",    P_STRING,  P_LOCAL,  &sDefault.szInvalidUsers,   NULL,   NULL},
575   {"valid users",      P_STRING,  P_LOCAL,  &sDefault.szValidUsers,     NULL,   NULL},
576   {"admin users",      P_STRING,  P_LOCAL,  &sDefault.szAdminUsers,     NULL,   NULL},
577   {"read list",        P_STRING,  P_LOCAL,  &sDefault.readlist,         NULL,   NULL},
578   {"write list",       P_STRING,  P_LOCAL,  &sDefault.writelist,        NULL,   NULL},
579   {"volume",           P_STRING,  P_LOCAL,  &sDefault.volume,           NULL,   NULL},
580   {"force user",       P_STRING,  P_LOCAL,  &sDefault.force_user,       NULL,   NULL},
581   {"force group",      P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL,   NULL},
582   {"group",            P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL,   NULL},
583   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL},
584   {"write ok",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL},
585   {"writeable",        P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL},
586   {"writable",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL,   NULL},
587   {"max connections",  P_INTEGER, P_LOCAL,  &sDefault.iMaxConnections,  NULL,   NULL},
588   {"min print space",  P_INTEGER, P_LOCAL,  &sDefault.iMinPrintSpace,   NULL,   NULL},
589   {"create mask",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mask,     NULL,   NULL},
590   {"create mode",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mask,     NULL,   NULL},
591   {"force create mode",P_OCTAL,   P_LOCAL,  &sDefault.iCreate_force_mode,     NULL,   NULL},
592   {"directory mask",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_mask,        NULL,   NULL},
593   {"directory mode",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_mask,        NULL,   NULL},
594   {"force directory mode",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_force_mode,        NULL,   NULL},
595   {"set directory",    P_BOOLREV, P_LOCAL,  &sDefault.bNo_set_dir,      NULL,   NULL},
596   {"status",           P_BOOL,    P_LOCAL,  &sDefault.status,           NULL,   NULL},
597   {"hide dot files",   P_BOOL,    P_LOCAL,  &sDefault.bHideDotFiles,    NULL,   NULL},
598   {"delete veto files",P_BOOL,    P_LOCAL,  &sDefault.bDeleteVetoFiles, NULL,   NULL},
599   {"veto files",       P_STRING,  P_LOCAL,  &sDefault.szVetoFiles,      NULL,   NULL},
600   {"hide files",       P_STRING,  P_LOCAL,  &sDefault.szHideFiles,      NULL,   NULL},
601   {"veto oplock files",P_STRING,  P_LOCAL,  &sDefault.szVetoOplockFiles,NULL,   NULL},
602   {"guest only",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL,   NULL},
603   {"only guest",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL,   NULL},
604   {"guest ok",         P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL,   NULL},
605   {"public",           P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL,   NULL},
606   {"print ok",         P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL,   NULL},
607   {"printable",        P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL,   NULL},
608   {"postscript",       P_BOOL,    P_LOCAL,  &sDefault.bPostscript,      NULL,   NULL},
609   {"map system",       P_BOOL,    P_LOCAL,  &sDefault.bMap_system,      NULL,   NULL},
610   {"map hidden",       P_BOOL,    P_LOCAL,  &sDefault.bMap_hidden,      NULL,   NULL},
611   {"map archive",      P_BOOL,    P_LOCAL,  &sDefault.bMap_archive,     NULL,   NULL},
612   {"locking",          P_BOOL,    P_LOCAL,  &sDefault.bLocking,         NULL,   NULL},
613   {"strict locking",   P_BOOL,    P_LOCAL,  &sDefault.bStrictLocking,   NULL,   NULL},
614   {"share modes",      P_BOOL,    P_LOCAL,  &sDefault.bShareModes,      NULL,   NULL},
615   {"oplocks",          P_BOOL,    P_LOCAL,  &sDefault.bOpLocks,         NULL,   NULL},
616   {"only user",        P_BOOL,    P_LOCAL,  &sDefault.bOnlyUser,        NULL,   NULL},
617   {"wide links",       P_BOOL,    P_LOCAL,  &sDefault.bWidelinks,       NULL,   NULL},
618   {"follow symlinks",  P_BOOL,    P_LOCAL,  &sDefault.bSymlinks,        NULL,   NULL},
619   {"sync always",      P_BOOL,    P_LOCAL,  &sDefault.bSyncAlways,      NULL,   NULL},
620   {"mangled names",    P_BOOL,    P_LOCAL,  &sDefault.bMangledNames,    NULL,   NULL},
621   {"fake oplocks",     P_BOOL,    P_LOCAL,  &sDefault.bFakeOplocks,     NULL,   NULL},
622   {"printing",         P_ENUM,    P_LOCAL,  &sDefault.iPrinting,        NULL,   enum_printing},
623   {"print command",    P_STRING,  P_LOCAL,  &sDefault.szPrintcommand,   NULL,   NULL},
624   {"lpq command",      P_STRING,  P_LOCAL,  &sDefault.szLpqcommand,     NULL,   NULL},
625   {"lprm command",     P_STRING,  P_LOCAL,  &sDefault.szLprmcommand,    NULL,   NULL},
626   {"lppause command",  P_STRING,  P_LOCAL,  &sDefault.szLppausecommand, NULL,   NULL},
627   {"lpresume command", P_STRING,  P_LOCAL,  &sDefault.szLpresumecommand,NULL,   NULL},
628   {"printer",          P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL,   NULL},
629   {"printer name",     P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL,   NULL},
630   {"printer driver",   P_STRING,  P_LOCAL,  &sDefault.szPrinterDriver,  NULL,   NULL},
631   {"printer driver location",   P_STRING,  P_LOCAL,  &sDefault.szPrinterDriverLocation,  NULL,   NULL},
632   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL,   NULL},
633   {"allow hosts",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL,   NULL},
634   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL,   NULL},
635   {"deny hosts",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL,   NULL},
636   {"dont descend",     P_STRING,  P_LOCAL,  &sDefault.szDontdescend,    NULL,   NULL},
637   {"magic script",     P_STRING,  P_LOCAL,  &sDefault.szMagicScript,    NULL,   NULL},
638   {"magic output",     P_STRING,  P_LOCAL,  &sDefault.szMagicOutput,    NULL,   NULL},
639   {"mangled map",      P_STRING,  P_LOCAL,  &sDefault.szMangledMap,     NULL,   NULL},
640   {"delete readonly",  P_BOOL,    P_LOCAL,  &sDefault.bDeleteReadonly,  NULL,   NULL},
641   {"dos filetimes",    P_BOOL,    P_LOCAL,  &sDefault.bDosFiletimes,    NULL,   NULL},
642   {"dos filetime resolution",   P_BOOL,    P_LOCAL,  &sDefault.bDosFiletimeResolution,    NULL,   NULL},
643
644   {NULL,               P_BOOL,    P_NONE,   NULL,                       NULL,   NULL}
645 };
646
647
648
649 /***************************************************************************
650 Initialise the global parameter structure.
651 ***************************************************************************/
652 static void init_globals(void)
653 {
654   static BOOL done_init = False;
655   pstring s;
656
657   if (!done_init)
658     {
659       int i;
660       bzero((void *)&Globals,sizeof(Globals));
661
662       for (i = 0; parm_table[i].label; i++) 
663         if ((parm_table[i].type == P_STRING ||
664              parm_table[i].type == P_USTRING) && 
665             parm_table[i].ptr)
666           string_init(parm_table[i].ptr,"");
667
668       string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
669       string_set(&sDefault.szPrinterDriver, "NULL");
670
671       done_init = True;
672     }
673
674
675   DEBUG(3,("Initialising global parameters\n"));
676
677 #ifdef SMB_PASSWD_FILE
678   string_set(&Globals.szSMBPasswdFile, SMB_PASSWD_FILE);
679 #endif
680   string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
681   string_set(&Globals.szWorkGroup, WORKGROUP);
682   string_set(&Globals.szPasswdProgram, SMB_PASSWD);
683   string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
684   string_set(&Globals.szDriverFile, DRIVERFILE);
685   string_set(&Globals.szLockDir, LOCKDIR);
686   string_set(&Globals.szRootdir, "/");
687   string_set(&Globals.szSmbrun, SMBRUN);
688   string_set(&Globals.szSocketAddress, "0.0.0.0");
689   sprintf(s,"Samba %s",VERSION);
690   string_set(&Globals.szServerString,s);
691   sprintf(s,"%d.%d", DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION);
692   string_set(&Globals.szAnnounceVersion,s);
693
694   string_set(&Globals.szLogonDrive, "");
695   /* %N is the NIS auto.home server if -DAUTOHOME is used, else same as %L */
696   string_set(&Globals.szLogonHome, "\\\\%N\\%U");
697   string_set(&Globals.szLogonPath, "\\\\%N\\%U\\profile");
698
699   Globals.bLoadPrinters = True;
700   Globals.bUseRhosts = False;
701   Globals.max_packet = 65535;
702   Globals.mangled_stack = 50;
703   Globals.max_xmit = 65535;
704   Globals.max_mux = 50; /* This is *needed* for profile support. */
705   Globals.lpqcachetime = 10;
706   Globals.pwordlevel = 0;
707   Globals.unamelevel = 0;
708   Globals.deadtime = 0;
709   Globals.max_log_size = 5000;
710   Globals.maxprotocol = PROTOCOL_NT1;
711   Globals.security = SEC_SHARE;
712   Globals.bEncryptPasswords = False;
713   Globals.bReadRaw = True;
714   Globals.bWriteRaw = True;
715   Globals.bReadPrediction = False;
716   Globals.bReadbmpx = True;
717   Globals.bNullPasswords = False;
718   Globals.bStripDot = False;
719   Globals.syslog = 1;
720   Globals.bSyslogOnly = False;
721   Globals.os_level = 0;
722   Globals.max_ttl = 60*60*4; /* 4 hours default */
723   Globals.max_wins_ttl = 60*60*24*3; /* 3 days default */
724   Globals.min_wins_ttl = 60*60*6; /* 6 hours default */
725   Globals.ReadSize = 16*1024;
726   Globals.lm_announce = 2;   /* = Auto: send only if LM clients found */
727   Globals.lm_interval = 60;
728   Globals.shmem_size = SHMEM_SIZE;
729   Globals.announce_as = ANNOUNCE_AS_NT;
730   Globals.bUnixRealname = False;
731 #if (defined(NETGROUP) && defined(AUTOMOUNT))
732   Globals.bNISHomeMap = False;
733   string_set(&Globals.szNISHomeMapName, "auto.home");
734 #endif
735   Globals.client_code_page = DEFAULT_CLIENT_CODE_PAGE;
736   Globals.bTimeServer = False;
737   Globals.bBindInterfacesOnly = False;
738   Globals.bNetWkstaUserLogon = True;
739
740 /* these parameters are set to defaults that are more appropriate
741    for the increasing samba install base:
742
743    as a member of the workgroup, that will possibly become a
744    _local_ master browser (lm = True).  this is opposed to a forced
745    local master browser startup (pm = True).
746
747    doesn't provide WINS server service by default (wsupp = False),
748    and doesn't provide domain master browser services by default, either.
749
750 */
751
752   Globals.bPreferredMaster = False;
753   Globals.bLocalMaster = True;
754   Globals.bDomainMaster = False;
755   Globals.bDomainLogons = False;
756   Globals.bBrowseList = True;
757   Globals.bWINSsupport = False;
758   Globals.bWINSproxy = False;
759
760   Globals.bDNSproxy = True;
761
762   /*
763    * This must be done last as it checks the value in 
764    * client_code_page.
765    */
766
767   interpret_coding_system(KANJI);
768 }
769
770 /***************************************************************************
771 check if a string is initialised and if not then initialise it
772 ***************************************************************************/
773 static void string_initial(char **s,char *v)
774 {
775   if (!*s || !**s)
776     string_init(s,v);
777 }
778
779
780 /***************************************************************************
781 Initialise the sDefault parameter structure.
782 ***************************************************************************/
783 static void init_locals(void)
784 {
785   /* choose defaults depending on the type of printing */
786   switch (sDefault.iPrinting)
787     {
788     case PRINT_BSD:
789     case PRINT_AIX:
790     case PRINT_LPRNG:
791     case PRINT_PLP:
792       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
793       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
794       string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
795       break;
796
797     case PRINT_SYSV:
798     case PRINT_HPUX:
799       string_initial(&sDefault.szLpqcommand,"lpstat -o%p");
800       string_initial(&sDefault.szLprmcommand,"cancel %p-%j");
801       string_initial(&sDefault.szPrintcommand,"lp -c -d%p %s; rm %s");
802 #ifdef SVR4
803       string_initial(&sDefault.szLppausecommand,"lp -i %p-%j -H hold");
804       string_initial(&sDefault.szLpresumecommand,"lp -i %p-%j -H resume");
805 #endif
806       break;
807
808     case PRINT_QNX:
809       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
810       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
811       string_initial(&sDefault.szPrintcommand,"lp -r -P%p %s");
812       break;
813
814       
815     }
816 }
817
818
819 /******************************************************************* a
820 convenience routine to grab string parameters into a rotating buffer,
821 and run standard_sub_basic on them. The buffers can be written to by
822 callers without affecting the source string.
823 ********************************************************************/
824 char *lp_string(char *s)
825 {
826   static char *bufs[10];
827   static int buflen[10];
828   static int next = -1;  
829   char *ret;
830   int i;
831   int len = s?strlen(s):0;
832
833   if (next == -1) {
834     /* initialisation */
835     for (i=0;i<10;i++) {
836       bufs[i] = NULL;
837       buflen[i] = 0;
838     }
839     next = 0;
840   }
841
842   len = MAX(len+100,sizeof(pstring)); /* the +100 is for some
843                                          substitution room */
844
845   if (buflen[next] != len) {
846     buflen[next] = len;
847     if (bufs[next]) free(bufs[next]);
848     bufs[next] = (char *)malloc(len);
849     if (!bufs[next]) {
850       DEBUG(0,("out of memory in lp_string()"));
851       exit(1);
852     }
853   } 
854
855   ret = &bufs[next][0];
856   next = (next+1)%10;
857
858   if (!s) 
859     *ret = 0;
860   else
861     StrCpy(ret,s);
862
863   trim_string(ret, "\"", "\"");
864
865   standard_sub_basic(ret);
866   return(ret);
867 }
868
869
870 /*
871    In this section all the functions that are used to access the 
872    parameters from the rest of the program are defined 
873 */
874
875 #define FN_GLOBAL_STRING(fn_name,ptr) \
876  char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
877 #define FN_GLOBAL_BOOL(fn_name,ptr) \
878  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
879 #define FN_GLOBAL_CHAR(fn_name,ptr) \
880  char fn_name(void) {return(*(char *)(ptr));}
881 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
882  int fn_name(void) {return(*(int *)(ptr));}
883
884 #define FN_LOCAL_STRING(fn_name,val) \
885  char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : sDefault.val));}
886 #define FN_LOCAL_BOOL(fn_name,val) \
887  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
888 #define FN_LOCAL_CHAR(fn_name,val) \
889  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
890 #define FN_LOCAL_INTEGER(fn_name,val) \
891  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
892
893 FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile)
894 FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun)
895 FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
896 FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
897 FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
898 FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname)
899 FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir)
900 FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir)
901 FN_GLOBAL_STRING(lp_defaultservice,&Globals.szDefaultService)
902 FN_GLOBAL_STRING(lp_msg_command,&Globals.szMsgCommand)
903 FN_GLOBAL_STRING(lp_dfree_command,&Globals.szDfree)
904 FN_GLOBAL_STRING(lp_hosts_equiv,&Globals.szHostsEquiv)
905 FN_GLOBAL_STRING(lp_auto_services,&Globals.szAutoServices)
906 FN_GLOBAL_STRING(lp_passwd_program,&Globals.szPasswdProgram)
907 FN_GLOBAL_STRING(lp_passwd_chat,&Globals.szPasswdChat)
908 FN_GLOBAL_STRING(lp_passwordserver,&Globals.szPasswordServer)
909 FN_GLOBAL_STRING(lp_workgroup,&Globals.szWorkGroup)
910 FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
911 FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) 
912 FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) 
913 FN_GLOBAL_STRING(lp_logon_path,&Globals.szLogonPath) 
914 FN_GLOBAL_STRING(lp_logon_drive,&Globals.szLogonDrive) 
915 FN_GLOBAL_STRING(lp_logon_home,&Globals.szLogonHome) 
916 FN_GLOBAL_STRING(lp_remote_announce,&Globals.szRemoteAnnounce) 
917 FN_GLOBAL_STRING(lp_remote_browse_sync,&Globals.szRemoteBrowseSync) 
918 FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
919 FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
920 FN_GLOBAL_STRING(lp_socket_address,&Globals.szSocketAddress)
921 FN_GLOBAL_STRING(lp_nis_home_map_name,&Globals.szNISHomeMapName)
922 FN_GLOBAL_STRING(lp_announce_version,&Globals.szAnnounceVersion)
923 FN_GLOBAL_STRING(lp_netbios_aliases,&Globals.szNetbiosAliases)
924 FN_GLOBAL_STRING(lp_driverfile,&Globals.szDriverFile)
925
926 #ifdef NTDOMAIN
927 FN_GLOBAL_STRING(lp_domain_sid,&Globals.szDomainSID)
928 FN_GLOBAL_STRING(lp_domain_other_sids,&Globals.szDomainOtherSIDs)
929 FN_GLOBAL_STRING(lp_domain_groups,&Globals.szDomainGroups)
930 FN_GLOBAL_STRING(lp_domain_admin_users,&Globals.szDomainAdminUsers)
931 FN_GLOBAL_STRING(lp_domain_guest_users,&Globals.szDomainGuestUsers)
932 FN_GLOBAL_STRING(lp_domain_hostsallow,&Globals.szDomainHostsallow)
933 FN_GLOBAL_STRING(lp_domain_hostsdeny,&Globals.szDomainHostsdeny)
934 #endif /* NTDOMAIN */
935
936 FN_GLOBAL_BOOL(lp_dns_proxy,&Globals.bDNSproxy)
937 FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
938 FN_GLOBAL_BOOL(lp_we_are_a_wins_server,&Globals.bWINSsupport)
939 FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
940 FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster)
941 FN_GLOBAL_BOOL(lp_domain_controller,&Globals.bDomainController)
942 FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
943 FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
944 FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
945 FN_GLOBAL_BOOL(lp_load_printers,&Globals.bLoadPrinters)
946 FN_GLOBAL_BOOL(lp_use_rhosts,&Globals.bUseRhosts)
947 FN_GLOBAL_BOOL(lp_getwdcache,&use_getwd_cache)
948 FN_GLOBAL_BOOL(lp_readprediction,&Globals.bReadPrediction)
949 FN_GLOBAL_BOOL(lp_readbmpx,&Globals.bReadbmpx)
950 FN_GLOBAL_BOOL(lp_readraw,&Globals.bReadRaw)
951 FN_GLOBAL_BOOL(lp_writeraw,&Globals.bWriteRaw)
952 FN_GLOBAL_BOOL(lp_null_passwords,&Globals.bNullPasswords)
953 FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
954 FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
955 FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
956 FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
957 FN_GLOBAL_BOOL(lp_unix_realname,&Globals.bUnixRealname)
958 FN_GLOBAL_BOOL(lp_nis_home_map,&Globals.bNISHomeMap)
959 FN_GLOBAL_BOOL(lp_time_server,&Globals.bTimeServer)
960 FN_GLOBAL_BOOL(lp_bind_interfaces_only,&Globals.bBindInterfacesOnly)
961 FN_GLOBAL_BOOL(lp_net_wksta_user_logon,&Globals.bNetWkstaUserLogon)
962
963 FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
964 FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
965 FN_GLOBAL_INTEGER(lp_max_wins_ttl,&Globals.max_wins_ttl)
966 FN_GLOBAL_INTEGER(lp_min_wins_ttl,&Globals.max_wins_ttl)
967 FN_GLOBAL_INTEGER(lp_max_log_size,&Globals.max_log_size)
968 FN_GLOBAL_INTEGER(lp_mangledstack,&Globals.mangled_stack)
969 FN_GLOBAL_INTEGER(lp_maxxmit,&Globals.max_xmit)
970 FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
971 FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
972 FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
973 FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
974 FN_GLOBAL_INTEGER(lp_usernamelevel,&Globals.unamelevel)
975 FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
976 FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size)
977 FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
978 FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
979 FN_GLOBAL_INTEGER(lp_security,&Globals.security)
980 FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
981 FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
982 FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
983 FN_GLOBAL_INTEGER(lp_client_code_page,&Globals.client_code_page)
984 FN_GLOBAL_INTEGER(lp_announce_as,&Globals.announce_as)
985 FN_GLOBAL_INTEGER(lp_lm_announce,&Globals.lm_announce)
986 FN_GLOBAL_INTEGER(lp_lm_interval,&Globals.lm_interval)
987
988 FN_LOCAL_STRING(lp_preexec,szPreExec)
989 FN_LOCAL_STRING(lp_postexec,szPostExec)
990 FN_LOCAL_STRING(lp_rootpreexec,szRootPreExec)
991 FN_LOCAL_STRING(lp_rootpostexec,szRootPostExec)
992 FN_LOCAL_STRING(lp_servicename,szService)
993 FN_LOCAL_STRING(lp_pathname,szPath)
994 FN_LOCAL_STRING(lp_dontdescend,szDontdescend)
995 FN_LOCAL_STRING(lp_username,szUsername)
996 FN_LOCAL_STRING(lp_guestaccount,szGuestaccount)
997 FN_LOCAL_STRING(lp_invalid_users,szInvalidUsers)
998 FN_LOCAL_STRING(lp_valid_users,szValidUsers)
999 FN_LOCAL_STRING(lp_admin_users,szAdminUsers)
1000 FN_LOCAL_STRING(lp_printcommand,szPrintcommand)
1001 FN_LOCAL_STRING(lp_lpqcommand,szLpqcommand)
1002 FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
1003 FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
1004 FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
1005 FN_LOCAL_STRING(lp_printername,szPrintername)
1006 FN_LOCAL_STRING(lp_printerdriver,szPrinterDriver)
1007 FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
1008 FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
1009 FN_LOCAL_STRING(lp_magicscript,szMagicScript)
1010 FN_LOCAL_STRING(lp_magicoutput,szMagicOutput)
1011 FN_LOCAL_STRING(lp_comment,comment)
1012 FN_LOCAL_STRING(lp_force_user,force_user)
1013 FN_LOCAL_STRING(lp_force_group,force_group)
1014 FN_LOCAL_STRING(lp_readlist,readlist)
1015 FN_LOCAL_STRING(lp_writelist,writelist)
1016 FN_LOCAL_STRING(lp_volume,volume)
1017 FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
1018 FN_LOCAL_STRING(lp_veto_files,szVetoFiles)
1019 FN_LOCAL_STRING(lp_hide_files,szHideFiles)
1020 FN_LOCAL_STRING(lp_veto_oplocks,szVetoOplockFiles)
1021 FN_LOCAL_STRING(lp_driverlocation,szPrinterDriverLocation)
1022
1023 FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
1024 FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
1025 FN_LOCAL_BOOL(lp_casesensitive,bCaseSensitive)
1026 FN_LOCAL_BOOL(lp_preservecase,bCasePreserve)
1027 FN_LOCAL_BOOL(lp_shortpreservecase,bShortCasePreserve)
1028 FN_LOCAL_BOOL(lp_casemangle,bCaseMangle)
1029 FN_LOCAL_BOOL(lp_status,status)
1030 FN_LOCAL_BOOL(lp_hide_dot_files,bHideDotFiles)
1031 FN_LOCAL_BOOL(lp_browseable,bBrowseable)
1032 FN_LOCAL_BOOL(lp_readonly,bRead_only)
1033 FN_LOCAL_BOOL(lp_no_set_dir,bNo_set_dir)
1034 FN_LOCAL_BOOL(lp_guest_ok,bGuest_ok)
1035 FN_LOCAL_BOOL(lp_guest_only,bGuest_only)
1036 FN_LOCAL_BOOL(lp_print_ok,bPrint_ok)
1037 FN_LOCAL_BOOL(lp_postscript,bPostscript)
1038 FN_LOCAL_BOOL(lp_map_hidden,bMap_hidden)
1039 FN_LOCAL_BOOL(lp_map_archive,bMap_archive)
1040 FN_LOCAL_BOOL(lp_locking,bLocking)
1041 FN_LOCAL_BOOL(lp_strict_locking,bStrictLocking)
1042 FN_LOCAL_BOOL(lp_share_modes,bShareModes)
1043 FN_LOCAL_BOOL(lp_oplocks,bOpLocks)
1044 FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
1045 FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
1046 FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
1047 FN_LOCAL_BOOL(lp_symlinks,bSymlinks)
1048 FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
1049 FN_LOCAL_BOOL(lp_map_system,bMap_system)
1050 FN_LOCAL_BOOL(lp_delete_readonly,bDeleteReadonly)
1051 FN_LOCAL_BOOL(lp_fake_oplocks,bFakeOplocks)
1052 FN_LOCAL_BOOL(lp_recursive_veto_delete,bDeleteVetoFiles)
1053 FN_LOCAL_BOOL(lp_dos_filetimes,bDosFiletimes)
1054 FN_LOCAL_BOOL(lp_dos_filetime_resolution,bDosFiletimeResolution)
1055
1056 FN_LOCAL_INTEGER(lp_create_mode,iCreate_mask)
1057 FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
1058 FN_LOCAL_INTEGER(lp_dir_mode,iDir_mask)
1059 FN_LOCAL_INTEGER(lp_force_dir_mode,iDir_force_mode)
1060 FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
1061 FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
1062 FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
1063 FN_LOCAL_INTEGER(lp_printing,iPrinting)
1064
1065 FN_LOCAL_CHAR(lp_magicchar,magic_char)
1066
1067
1068
1069 /* local prototypes */
1070 static int    strwicmp( char *psz1, char *psz2 );
1071 static int    map_parameter( char *pszParmName);
1072 static BOOL   set_boolean( BOOL *pb, char *pszParmValue );
1073 static int    getservicebyname(char *pszServiceName, service *pserviceDest);
1074 static void   copy_service( service *pserviceDest, 
1075                             service *pserviceSource,
1076                             BOOL *pcopymapDest );
1077 static BOOL   service_ok(int iService);
1078 static BOOL   do_parameter(char *pszParmName, char *pszParmValue);
1079 static BOOL   do_section(char *pszSectionName);
1080 static void init_copymap(service *pservice);
1081
1082
1083 /***************************************************************************
1084 initialise a service to the defaults
1085 ***************************************************************************/
1086 static void init_service(service *pservice)
1087 {
1088   bzero((char *)pservice,sizeof(service));
1089   copy_service(pservice,&sDefault,NULL);
1090 }
1091
1092
1093 /***************************************************************************
1094 free the dynamically allocated parts of a service struct
1095 ***************************************************************************/
1096 static void free_service(service *pservice)
1097 {
1098   int i;
1099   if (!pservice)
1100      return;
1101
1102   if(pservice->szService)
1103     DEBUG(5,("free_service: Freeing service %s\n", pservice->szService));
1104
1105   string_free(&pservice->szService);
1106   if (pservice->copymap)
1107   {
1108     free(pservice->copymap);
1109     pservice->copymap = NULL;
1110   }
1111  
1112   for (i=0;parm_table[i].label;i++)
1113     if ((parm_table[i].type == P_STRING ||
1114          parm_table[i].type == P_USTRING) &&
1115         parm_table[i].class == P_LOCAL)
1116       string_free((char **)(((char *)pservice) + PTR_DIFF(parm_table[i].ptr,&sDefault)));
1117 }
1118
1119 /***************************************************************************
1120 add a new service to the services array initialising it with the given 
1121 service
1122 ***************************************************************************/
1123 static int add_a_service(service *pservice, char *name)
1124 {
1125   int i;
1126   service tservice;
1127   int num_to_alloc = iNumServices+1;
1128
1129   tservice = *pservice;
1130
1131   /* it might already exist */
1132   if (name) 
1133     {
1134       i = getservicebyname(name,NULL);
1135       if (i >= 0)
1136         return(i);
1137     }
1138
1139   /* find an invalid one */
1140   for (i=0;i<iNumServices;i++)
1141     if (!pSERVICE(i)->valid)
1142       break;
1143
1144   /* if not, then create one */
1145   if (i == iNumServices)
1146     {
1147       ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
1148       if (ServicePtrs)
1149         pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
1150
1151       if (!ServicePtrs || !pSERVICE(iNumServices))
1152         return(-1);
1153
1154       iNumServices++;
1155     }
1156   else
1157     free_service(pSERVICE(i));
1158
1159   pSERVICE(i)->valid = True;
1160
1161   init_service(pSERVICE(i));
1162   copy_service(pSERVICE(i),&tservice,NULL);
1163   if (name)
1164     string_set(&iSERVICE(i).szService,name);  
1165
1166   return(i);
1167 }
1168
1169 /***************************************************************************
1170 add a new home service, with the specified home directory, defaults coming 
1171 from service ifrom
1172 ***************************************************************************/
1173 BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir)
1174 {
1175   int i = add_a_service(pSERVICE(iDefaultService),pszHomename);
1176
1177   if (i < 0)
1178     return(False);
1179
1180   if (!(*(iSERVICE(i).szPath)) || strequal(iSERVICE(i).szPath,lp_pathname(-1)))
1181     string_set(&iSERVICE(i).szPath,pszHomedir);
1182   if (!(*(iSERVICE(i).comment)))
1183     {
1184       pstring comment;
1185       sprintf(comment,"Home directory of %s",pszHomename);
1186       string_set(&iSERVICE(i).comment,comment);
1187     }
1188   iSERVICE(i).bAvailable = sDefault.bAvailable;
1189   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
1190
1191   DEBUG(3,("adding home directory %s at %s\n", pszHomename, pszHomedir));
1192
1193   return(True);
1194 }
1195
1196 /***************************************************************************
1197 add a new service, based on an old one
1198 ***************************************************************************/
1199 int lp_add_service(char *pszService, int iDefaultService)
1200 {
1201   return(add_a_service(pSERVICE(iDefaultService),pszService));
1202 }
1203
1204
1205 /***************************************************************************
1206 add the IPC service
1207 ***************************************************************************/
1208 static BOOL lp_add_ipc(void)
1209 {
1210   pstring comment;
1211   int i = add_a_service(&sDefault,"IPC$");
1212
1213   if (i < 0)
1214     return(False);
1215
1216   sprintf(comment,"IPC Service (%s)",lp_serverstring());
1217
1218   string_set(&iSERVICE(i).szPath,tmpdir());
1219   string_set(&iSERVICE(i).szUsername,"");
1220   string_set(&iSERVICE(i).comment,comment);
1221   iSERVICE(i).status = False;
1222   iSERVICE(i).iMaxConnections = 0;
1223   iSERVICE(i).bAvailable = True;
1224   iSERVICE(i).bRead_only = True;
1225   iSERVICE(i).bGuest_only = False;
1226   iSERVICE(i).bGuest_ok = True;
1227   iSERVICE(i).bPrint_ok = False;
1228   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
1229
1230   DEBUG(3,("adding IPC service\n"));
1231
1232   return(True);
1233 }
1234
1235
1236 /***************************************************************************
1237 add a new printer service, with defaults coming from service iFrom
1238 ***************************************************************************/
1239 BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
1240 {
1241   char *comment = "From Printcap";
1242   int i = add_a_service(pSERVICE(iDefaultService),pszPrintername);
1243   
1244   if (i < 0)
1245     return(False);
1246   
1247   /* note that we do NOT default the availability flag to True - */
1248   /* we take it from the default service passed. This allows all */
1249   /* dynamic printers to be disabled by disabling the [printers] */
1250   /* entry (if/when the 'available' keyword is implemented!).    */
1251   
1252   /* the printer name is set to the service name. */
1253   string_set(&iSERVICE(i).szPrintername,pszPrintername);
1254   string_set(&iSERVICE(i).comment,comment);
1255   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
1256   /* Printers cannot be read_only. */
1257   iSERVICE(i).bRead_only = False;
1258   /* No share modes on printer services. */
1259   iSERVICE(i).bShareModes = False;
1260   /* No oplocks on printer services. */
1261   iSERVICE(i).bOpLocks = False;
1262   /* Printer services must be printable. */
1263   iSERVICE(i).bPrint_ok = True;
1264   
1265   DEBUG(3,("adding printer service %s\n",pszPrintername));
1266   
1267   return(True);
1268 }
1269
1270
1271 /***************************************************************************
1272 Do a case-insensitive, whitespace-ignoring string compare.
1273 ***************************************************************************/
1274 static int strwicmp(char *psz1, char *psz2)
1275 {
1276    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
1277    /* appropriate value. */
1278    if (psz1 == psz2)
1279       return (0);
1280    else
1281       if (psz1 == NULL)
1282          return (-1);
1283       else
1284           if (psz2 == NULL)
1285               return (1);
1286
1287    /* sync the strings on first non-whitespace */
1288    while (1)
1289    {
1290       while (isspace(*psz1))
1291          psz1++;
1292       while (isspace(*psz2))
1293          psz2++;
1294       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
1295          break;
1296       psz1++;
1297       psz2++;
1298    }
1299    return (*psz1 - *psz2);
1300 }
1301
1302 /***************************************************************************
1303 Map a parameter's string representation to something we can use. 
1304 Returns False if the parameter string is not recognised, else TRUE.
1305 ***************************************************************************/
1306 static int map_parameter(char *pszParmName)
1307 {
1308    int iIndex;
1309
1310    if (*pszParmName == '-')
1311      return(-1);
1312
1313    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
1314       if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1315          return(iIndex);
1316
1317    DEBUG(0,( "Unknown parameter encountered: \"%s\"\n", pszParmName));
1318    return(-1);
1319 }
1320
1321
1322 /***************************************************************************
1323 Set a boolean variable from the text value stored in the passed string.
1324 Returns True in success, False if the passed string does not correctly 
1325 represent a boolean.
1326 ***************************************************************************/
1327 static BOOL set_boolean(BOOL *pb, char *pszParmValue)
1328 {
1329    BOOL bRetval;
1330
1331    bRetval = True;
1332    if (strwicmp(pszParmValue, "yes") == 0 ||
1333        strwicmp(pszParmValue, "true") == 0 ||
1334        strwicmp(pszParmValue, "1") == 0)
1335       *pb = True;
1336    else
1337       if (strwicmp(pszParmValue, "no") == 0 ||
1338           strwicmp(pszParmValue, "False") == 0 ||
1339           strwicmp(pszParmValue, "0") == 0)
1340          *pb = False;
1341       else
1342       {
1343          DEBUG(0,( "Badly formed boolean in configuration file: \"%s\".\n",
1344                pszParmValue));
1345          bRetval = False;
1346       }
1347    return (bRetval);
1348 }
1349
1350 /***************************************************************************
1351 Find a service by name. Otherwise works like get_service.
1352 ***************************************************************************/
1353 static int getservicebyname(char *pszServiceName, service *pserviceDest)
1354 {
1355    int iService;
1356
1357    for (iService = iNumServices - 1; iService >= 0; iService--)
1358       if (VALID(iService) &&
1359           strwicmp(iSERVICE(iService).szService, pszServiceName) == 0) 
1360       {
1361          if (pserviceDest != NULL)
1362            copy_service(pserviceDest, pSERVICE(iService), NULL);
1363          break;
1364       }
1365
1366    return (iService);
1367 }
1368
1369
1370
1371 /***************************************************************************
1372 Copy a service structure to another
1373
1374 If pcopymapDest is NULL then copy all fields
1375 ***************************************************************************/
1376 static void copy_service(service *pserviceDest, 
1377                          service *pserviceSource,
1378                          BOOL *pcopymapDest)
1379 {
1380   int i;
1381   BOOL bcopyall = (pcopymapDest == NULL);
1382
1383   for (i=0;parm_table[i].label;i++)
1384     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL && 
1385         (bcopyall || pcopymapDest[i]))
1386       {
1387         void *def_ptr = parm_table[i].ptr;
1388         void *src_ptr = 
1389           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
1390         void *dest_ptr = 
1391           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
1392
1393         switch (parm_table[i].type)
1394           {
1395           case P_BOOL:
1396           case P_BOOLREV:
1397             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1398             break;
1399
1400           case P_INTEGER:
1401           case P_ENUM:
1402           case P_OCTAL:
1403             *(int *)dest_ptr = *(int *)src_ptr;
1404             break;
1405
1406           case P_CHAR:
1407             *(char *)dest_ptr = *(char *)src_ptr;
1408             break;
1409
1410           case P_STRING:
1411             string_set(dest_ptr,*(char **)src_ptr);
1412             break;
1413
1414           case P_USTRING:
1415             string_set(dest_ptr,*(char **)src_ptr);
1416             strupper(*(char **)dest_ptr);
1417             break;
1418           default:
1419             break;
1420           }
1421       }
1422
1423   if (bcopyall)
1424     {
1425       init_copymap(pserviceDest);
1426       if (pserviceSource->copymap)
1427         memcpy((void *)pserviceDest->copymap,
1428                (void *)pserviceSource->copymap,sizeof(BOOL)*NUMPARAMETERS);
1429     }
1430 }
1431
1432 /***************************************************************************
1433 Check a service for consistency. Return False if the service is in any way
1434 incomplete or faulty, else True.
1435 ***************************************************************************/
1436 static BOOL service_ok(int iService)
1437 {
1438    BOOL bRetval;
1439
1440    bRetval = True;
1441    if (iSERVICE(iService).szService[0] == '\0')
1442    {
1443       DEBUG(0,( "The following message indicates an internal error:\n"));
1444       DEBUG(0,( "No service name in service entry.\n"));
1445       bRetval = False;
1446    }
1447
1448    /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1449    /* I can't see why you'd want a non-printable printer service...        */
1450    if (strwicmp(iSERVICE(iService).szService,PRINTERS_NAME) == 0)
1451       if (!iSERVICE(iService).bPrint_ok)
1452       {
1453          DEBUG(0,( "WARNING: [%s] service MUST be printable!\n",
1454                iSERVICE(iService).szService));
1455          iSERVICE(iService).bPrint_ok = True;
1456       }
1457
1458    if (iSERVICE(iService).szPath[0] == '\0' &&
1459        strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
1460    {
1461       DEBUG(0,("No path in service %s - using %s\n",iSERVICE(iService).szService,tmpdir()));
1462       string_set(&iSERVICE(iService).szPath,tmpdir());      
1463    }
1464
1465    /* If a service is flagged unavailable, log the fact at level 0. */
1466    if (!iSERVICE(iService).bAvailable) 
1467       DEBUG(1,( "NOTE: Service %s is flagged unavailable.\n",
1468             iSERVICE(iService).szService));
1469
1470    return (bRetval);
1471 }
1472
1473 static struct file_lists {
1474   struct file_lists *next;
1475   char *name;
1476   time_t modtime;
1477 } *file_lists = NULL;
1478
1479 /*******************************************************************
1480 keep a linked list of all config files so we know when one has changed 
1481 it's date and needs to be reloaded
1482 ********************************************************************/
1483 static void add_to_file_list(char *fname)
1484 {
1485   struct file_lists *f=file_lists;
1486
1487   while (f) {
1488     if (f->name && !strcmp(f->name,fname)) break;
1489     f = f->next;
1490   }
1491
1492   if (!f) {
1493     f = (struct file_lists *)malloc(sizeof(file_lists[0]));
1494     if (!f) return;
1495     f->next = file_lists;
1496     f->name = strdup(fname);
1497     if (!f->name) {
1498       free(f);
1499       return;
1500     }
1501     file_lists = f;
1502   }
1503
1504   {
1505     pstring n2;
1506     pstrcpy(n2,fname);
1507     standard_sub_basic(n2);
1508     f->modtime = file_modtime(n2);
1509   }
1510
1511 }
1512
1513 /*******************************************************************
1514 check if a config file has changed date
1515 ********************************************************************/
1516 BOOL lp_file_list_changed(void)
1517 {
1518   struct file_lists *f = file_lists;
1519   DEBUG(6,("lp_file_list_changed()\n"));
1520
1521   while (f)
1522   {
1523     pstring n2;
1524     time_t mod_time;
1525
1526     pstrcpy(n2,f->name);
1527     standard_sub_basic(n2);
1528
1529     DEBUG(6,("file %s -> %s  last mod_time: %s\n",
1530              f->name, n2, ctime(&f->modtime)));
1531
1532     mod_time = file_modtime(n2);
1533
1534     if (f->modtime != mod_time) {
1535             DEBUG(6,("file %s modified: %s\n", n2, ctime(&mod_time)));
1536             f->modtime = mod_time;
1537             return(True);
1538     }
1539     f = f->next;   
1540   }
1541   return(False);
1542 }
1543
1544 /***************************************************************************
1545   handle the interpretation of the coding system parameter
1546   *************************************************************************/
1547 static BOOL handle_coding_system(char *pszParmValue,char **ptr)
1548 {
1549         string_set(ptr,pszParmValue);
1550         interpret_coding_system(pszParmValue);
1551         return(True);
1552 }
1553
1554 /***************************************************************************
1555 handle the interpretation of the character set system parameter
1556 ***************************************************************************/
1557 static BOOL handle_character_set(char *pszParmValue,char **ptr)
1558 {
1559         string_set(ptr,pszParmValue);
1560         interpret_character_set(pszParmValue);
1561         return(True);
1562 }
1563
1564
1565 /***************************************************************************
1566 handle the valid chars lines
1567 ***************************************************************************/
1568 static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
1569
1570   string_set(ptr,pszParmValue);
1571
1572   /* A dependency here is that the parameter client code page must be
1573      set before this is called - as calling codepage_initialise()
1574      would overwrite the valid char lines.
1575    */
1576   codepage_initialise(lp_client_code_page());
1577
1578   add_char_string(pszParmValue);
1579   return(True);
1580 }
1581
1582
1583 /***************************************************************************
1584 handle the include operation
1585 ***************************************************************************/
1586 static BOOL handle_include(char *pszParmValue,char **ptr)
1587
1588   pstring fname;
1589   pstrcpy(fname,pszParmValue);
1590
1591   add_to_file_list(fname);
1592
1593   standard_sub_basic(fname);
1594
1595   string_set(ptr,fname);
1596
1597   if (file_exist(fname,NULL))
1598     return(pm_process(fname, do_section, do_parameter));      
1599
1600   DEBUG(2,("Can't find include file %s\n",fname));
1601
1602   return(False);
1603 }
1604
1605
1606 /***************************************************************************
1607 handle the interpretation of the copy parameter
1608 ***************************************************************************/
1609 static BOOL handle_copy(char *pszParmValue,char **ptr)
1610 {
1611    BOOL bRetval;
1612    int iTemp;
1613    service serviceTemp;
1614
1615    string_set(ptr,pszParmValue);
1616
1617    init_service(&serviceTemp);
1618
1619    bRetval = False;
1620    
1621    DEBUG(3,("Copying service from service %s\n",pszParmValue));
1622
1623    if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0)
1624      {
1625        if (iTemp == iServiceIndex)
1626          {
1627            DEBUG(0,("Can't copy service %s - unable to copy self!\n",
1628                     pszParmValue));
1629          }
1630        else
1631          {
1632            copy_service(pSERVICE(iServiceIndex), 
1633                         &serviceTemp,
1634                         iSERVICE(iServiceIndex).copymap);
1635            bRetval = True;
1636          }
1637      }
1638    else
1639      {
1640        DEBUG(0,( "Unable to copy service - source not found: %s\n",
1641                 pszParmValue));
1642        bRetval = False;
1643      }
1644
1645    free_service(&serviceTemp);
1646    return (bRetval);
1647 }
1648
1649
1650 /***************************************************************************
1651 initialise a copymap
1652 ***************************************************************************/
1653 static void init_copymap(service *pservice)
1654 {
1655   int i;
1656   if (pservice->copymap) free(pservice->copymap);
1657   pservice->copymap = (BOOL *)malloc(sizeof(BOOL)*NUMPARAMETERS);
1658   if (!pservice->copymap)
1659     DEBUG(0,("Couldn't allocate copymap!! (size %d)\n",NUMPARAMETERS));
1660
1661   for (i=0;i<NUMPARAMETERS;i++)
1662     pservice->copymap[i] = True;
1663 }
1664
1665
1666 /***************************************************************************
1667 Process a parameter for a particular service number. If snum < 0
1668 then assume we are in the globals
1669 ***************************************************************************/
1670 BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue)
1671 {
1672    int parmnum, i;
1673    void *parm_ptr=NULL; /* where we are going to store the result */
1674    void *def_ptr=NULL;
1675
1676    parmnum = map_parameter(pszParmName);
1677
1678    if (parmnum < 0)
1679      {
1680        DEBUG(0,( "Ignoring unknown parameter \"%s\"\n", pszParmName));
1681        return(True);
1682      }
1683
1684    def_ptr = parm_table[parmnum].ptr;
1685
1686    /* we might point at a service, the default service or a global */
1687    if (snum < 0) {
1688      parm_ptr = def_ptr;
1689    } else {
1690        if (parm_table[parmnum].class == P_GLOBAL) {
1691            DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
1692            return(True);
1693          }
1694        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
1695    }
1696
1697    if (snum >= 0) {
1698            if (!iSERVICE(snum).copymap)
1699                    init_copymap(pSERVICE(snum));
1700            
1701            /* this handles the aliases - set the copymap for other entries with
1702               the same data pointer */
1703            for (i=0;parm_table[i].label;i++)
1704                    if (parm_table[i].ptr == parm_table[parmnum].ptr)
1705                            iSERVICE(snum).copymap[i] = False;
1706    }
1707
1708    /* if it is a special case then go ahead */
1709    if (parm_table[parmnum].special) {
1710            parm_table[parmnum].special(pszParmValue,parm_ptr);
1711            return(True);
1712    }
1713
1714    /* now switch on the type of variable it is */
1715    switch (parm_table[parmnum].type)
1716      {
1717      case P_BOOL:
1718        set_boolean(parm_ptr,pszParmValue);
1719        break;
1720
1721      case P_BOOLREV:
1722        set_boolean(parm_ptr,pszParmValue);
1723        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
1724        break;
1725
1726      case P_INTEGER:
1727        *(int *)parm_ptr = atoi(pszParmValue);
1728        break;
1729
1730      case P_CHAR:
1731        *(char *)parm_ptr = *pszParmValue;
1732        break;
1733
1734      case P_OCTAL:
1735        sscanf(pszParmValue,"%o",(int *)parm_ptr);
1736        break;
1737
1738      case P_STRING:
1739        string_set(parm_ptr,pszParmValue);
1740        break;
1741
1742      case P_USTRING:
1743        string_set(parm_ptr,pszParmValue);
1744        strupper(*(char **)parm_ptr);
1745        break;
1746
1747      case P_GSTRING:
1748        strcpy((char *)parm_ptr,pszParmValue);
1749        break;
1750
1751      case P_UGSTRING:
1752        strcpy((char *)parm_ptr,pszParmValue);
1753        strupper((char *)parm_ptr);
1754        break;
1755
1756      case P_ENUM:
1757              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
1758                      if (strequal(pszParmValue, parm_table[parmnum].enum_list[i].name)) {
1759                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
1760                              break;
1761                      }
1762              }
1763              break;
1764      }
1765
1766    return(True);
1767 }
1768
1769 /***************************************************************************
1770 Process a parameter.
1771 ***************************************************************************/
1772 static BOOL do_parameter(char *pszParmName, char *pszParmValue)
1773 {
1774    if (!bInGlobalSection && bGlobalOnly) return(True);
1775
1776    DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
1777
1778    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, pszParmName, pszParmValue);
1779 }
1780
1781
1782 /***************************************************************************
1783 print a parameter of the specified type
1784 ***************************************************************************/
1785 static void print_parameter(struct parm_struct *p,void *ptr, FILE *f)
1786 {
1787         int i;
1788         switch (p->type) {
1789         case P_ENUM:
1790                 for (i=0;p->enum_list[i].name;i++) {
1791                         if (*(int *)ptr == p->enum_list[i].value) {
1792                                 fprintf(f,"%s",p->enum_list[i].name);
1793                                 break;
1794                         }
1795                 }
1796                 break;
1797
1798         case P_BOOL:
1799                 fprintf(f,"%s",BOOLSTR(*(BOOL *)ptr));
1800                 break;
1801       
1802         case P_BOOLREV:
1803                 fprintf(f,"%s",BOOLSTR(! *(BOOL *)ptr));
1804                 break;
1805       
1806         case P_INTEGER:
1807                 fprintf(f,"%d",*(int *)ptr);
1808                 break;
1809       
1810         case P_CHAR:
1811                 fprintf(f,"%c",*(char *)ptr);
1812                 break;
1813       
1814         case P_OCTAL:
1815                 fprintf(f,"0%o",*(int *)ptr);
1816                 break;
1817       
1818         case P_GSTRING:
1819         case P_UGSTRING:
1820                 if ((char *)ptr)
1821                         fprintf(f,"%s",(char *)ptr);
1822                 break;
1823                 
1824         case P_STRING:
1825         case P_USTRING:
1826                 if (*(char **)ptr)
1827                         fprintf(f,"%s",*(char **)ptr);
1828                 break;
1829         }
1830 }
1831
1832
1833 /***************************************************************************
1834 print a parameter of the specified type
1835 ***************************************************************************/
1836 static void parameter_string(struct parm_struct *p,void *ptr,char *s)
1837 {
1838         int i;
1839         s[0] = 0;
1840         
1841         switch (p->type) {
1842         case P_ENUM:
1843                 for (i=0;p->enum_list[i].name;i++) {
1844                         if (*(int *)ptr == p->enum_list[i].value) {
1845                                 sprintf(s,"%s",p->enum_list[i].name);
1846                                 break;
1847                         }
1848                 }
1849                 break;
1850
1851         case P_BOOL:
1852                 sprintf(s, "%s",BOOLSTR(*(BOOL *)ptr));
1853                 break;
1854                 
1855         case P_BOOLREV:
1856                 sprintf(s, "%s",BOOLSTR(! *(BOOL *)ptr));
1857                 break;
1858                 
1859         case P_INTEGER:
1860                 sprintf(s, "%d",*(int *)ptr);
1861                 break;
1862                 
1863         case P_CHAR:
1864                 sprintf(s, "%c",*(char *)ptr);
1865                 break;
1866                 
1867         case P_OCTAL:
1868                 sprintf(s, "0%o",*(int *)ptr);
1869                 break;
1870                 
1871         case P_GSTRING:
1872         case P_UGSTRING:
1873                 if ((char *)ptr)
1874                         sprintf(s, "%s",(char *)ptr);
1875                 break;
1876                 
1877         case P_STRING:
1878         case P_USTRING:
1879                 if (*(char **)ptr)
1880                         sprintf(s, "%s",*(char **)ptr);
1881                 break;
1882         }
1883 }
1884
1885
1886 /***************************************************************************
1887 check if two parameters are equal
1888 ***************************************************************************/
1889 static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
1890 {
1891   switch (type)
1892     {
1893     case P_BOOL:
1894     case P_BOOLREV:
1895       return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
1896
1897     case P_INTEGER:
1898     case P_ENUM:
1899     case P_OCTAL:
1900       return(*((int *)ptr1) == *((int *)ptr2));
1901       
1902     case P_CHAR:
1903       return(*((char *)ptr1) == *((char *)ptr2));
1904
1905     case P_GSTRING:
1906     case P_UGSTRING:
1907       {
1908         char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
1909         if (p1 && !*p1) p1 = NULL;
1910         if (p2 && !*p2) p2 = NULL;
1911         return(p1==p2 || strequal(p1,p2));
1912       }
1913     case P_STRING:
1914     case P_USTRING:
1915       {
1916         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
1917         if (p1 && !*p1) p1 = NULL;
1918         if (p2 && !*p2) p2 = NULL;
1919         return(p1==p2 || strequal(p1,p2));
1920       }
1921     }
1922   return(False);
1923 }
1924
1925 /***************************************************************************
1926 Process a new section (service). At this stage all sections are services.
1927 Later we'll have special sections that permit server parameters to be set.
1928 Returns True on success, False on failure.
1929 ***************************************************************************/
1930 static BOOL do_section(char *pszSectionName)
1931 {
1932    BOOL bRetval;
1933    BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) || 
1934                     (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
1935    bRetval = False;
1936
1937    /* if we were in a global section then do the local inits */
1938    if (bInGlobalSection && !isglobal)
1939      init_locals();
1940
1941    /* if we've just struck a global section, note the fact. */
1942    bInGlobalSection = isglobal;   
1943
1944    /* check for multiple global sections */
1945    if (bInGlobalSection)
1946    {
1947      DEBUG(3,( "Processing section \"[%s]\"\n", pszSectionName));
1948      return(True);
1949    }
1950
1951    if (!bInGlobalSection && bGlobalOnly) return(True);
1952
1953    /* if we have a current service, tidy it up before moving on */
1954    bRetval = True;
1955
1956    if (iServiceIndex >= 0)
1957      bRetval = service_ok(iServiceIndex);
1958
1959    /* if all is still well, move to the next record in the services array */
1960    if (bRetval)
1961      {
1962        /* We put this here to avoid an odd message order if messages are */
1963        /* issued by the post-processing of a previous section. */
1964        DEBUG(2,( "Processing section \"[%s]\"\n", pszSectionName));
1965
1966        if ((iServiceIndex=add_a_service(&sDefault,pszSectionName)) < 0)
1967          {
1968            DEBUG(0,("Failed to add a new service\n"));
1969            return(False);
1970          }
1971      }
1972
1973    return (bRetval);
1974 }
1975
1976 /***************************************************************************
1977 Display the contents of the global structure.
1978 ***************************************************************************/
1979 static void dump_globals(FILE *f)
1980 {
1981   int i;
1982   fprintf(f, "# Global parameters\n");
1983
1984   for (i=0;parm_table[i].label;i++)
1985     if (parm_table[i].class == P_GLOBAL &&
1986         parm_table[i].ptr &&
1987         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1988       {
1989         fprintf(f,"\t%s = ",parm_table[i].label);
1990         print_parameter(&parm_table[i],parm_table[i].ptr, f);
1991         fprintf(f,"\n");
1992       }
1993 }
1994
1995 /***************************************************************************
1996 Display the contents of a single services record.
1997 ***************************************************************************/
1998 static void dump_a_service(service *pService, FILE *f)
1999 {
2000   int i;
2001   if (pService == &sDefault)
2002     fprintf(f,"\n\n# Default service parameters\n");
2003   else
2004     fprintf(f,"\n[%s]\n",pService->szService);
2005
2006   for (i=0;parm_table[i].label;i++)
2007     if (parm_table[i].class == P_LOCAL &&
2008         parm_table[i].ptr && 
2009         (*parm_table[i].label != '-') &&
2010         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
2011       {
2012         int pdiff = PTR_DIFF(parm_table[i].ptr,&sDefault);
2013
2014         if (pService == &sDefault || !equal_parameter(parm_table[i].type,
2015                                                       ((char *)pService) + pdiff,
2016                                                       ((char *)&sDefault) + pdiff))
2017           {
2018             fprintf(f,"\t%s = ",parm_table[i].label);
2019             print_parameter(&parm_table[i],
2020                             ((char *)pService) + pdiff, f);
2021             fprintf(f,"\n");
2022           }
2023       }
2024 }
2025
2026
2027 /***************************************************************************
2028 return info about the next service  in a service. snum==-1 gives the default
2029 serice and snum==-2 gives the globals
2030
2031 return 0 when out of parameters
2032 ***************************************************************************/
2033 int lp_next_parameter(int snum, int *i, char *label, 
2034                            char *value, int allparameters)
2035 {
2036         if (snum == -2) {
2037                 /* do the globals */
2038                 for (;parm_table[*i].label;(*i)++)
2039                         if (parm_table[*i].class == P_GLOBAL &&
2040                             parm_table[*i].ptr && 
2041                             (*parm_table[*i].label != '-') &&
2042                             ((*i) == 0 || 
2043                              (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
2044                                 strcpy(label, parm_table[*i].label);
2045                                 parameter_string(&parm_table[*i],
2046                                                  parm_table[*i].ptr,
2047                                                  value);
2048                                 (*i)++;
2049                                 return 1;
2050                         }
2051                 return 0;
2052         } else {
2053                 service *pService = (snum==-1?&sDefault:pSERVICE(snum));
2054
2055                 for (;parm_table[*i].label;(*i)++)
2056                         if (parm_table[*i].class == P_LOCAL &&
2057                             parm_table[*i].ptr && 
2058                             (*parm_table[*i].label != '-') &&
2059                             ((*i) == 0 || 
2060                              (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
2061                                 int pdiff = PTR_DIFF(parm_table[*i].ptr,&sDefault);
2062                                 
2063                                 if (snum == -1 || allparameters ||
2064                                     !equal_parameter(parm_table[*i].type,
2065                                                      ((char *)pService) + pdiff,
2066                                                      ((char *)&sDefault) + pdiff)) {
2067                                         strcpy(label, parm_table[*i].label);
2068                                         parameter_string(&parm_table[*i],
2069                                                          ((char *)pService) + pdiff,
2070                                                          value);
2071                                         (*i)++;
2072                                         return 1;
2073                                 }
2074                         }
2075         }
2076
2077   return 0;
2078 }
2079
2080
2081 #if 0
2082 /***************************************************************************
2083 Display the contents of a single copy structure.
2084 ***************************************************************************/
2085 static void dump_copy_map(BOOL *pcopymap)
2086 {
2087   int i;
2088   if (!pcopymap) return;
2089
2090   printf("\n\tNon-Copied parameters:\n");
2091
2092   for (i=0;parm_table[i].label;i++)
2093     if (parm_table[i].class == P_LOCAL &&
2094         parm_table[i].ptr && !pcopymap[i] &&
2095         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
2096       {
2097         printf("\t\t%s\n",parm_table[i].label);
2098       }
2099 }
2100 #endif
2101
2102 /***************************************************************************
2103 Return TRUE if the passed service number is within range.
2104 ***************************************************************************/
2105 BOOL lp_snum_ok(int iService)
2106 {
2107    return (LP_SNUM_OK(iService) && iSERVICE(iService).bAvailable);
2108 }
2109
2110
2111 /***************************************************************************
2112 auto-load some homes and printer services
2113 ***************************************************************************/
2114 static void lp_add_auto_services(char *str)
2115 {
2116   char *s;
2117   char *p;
2118   int homes = lp_servicenumber(HOMES_NAME);
2119   int printers = lp_servicenumber(PRINTERS_NAME);
2120
2121   if (!str)
2122     return;
2123
2124   s = strdup(str);
2125   if (!s) return;
2126
2127   for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP))
2128     {
2129       char *home = get_home_dir(p);
2130
2131       if (lp_servicenumber(p) >= 0) continue;
2132
2133       if (home && homes >= 0)
2134         {
2135           lp_add_home(p,homes,home);
2136           continue;
2137         }
2138
2139       if (printers >= 0 && pcap_printername_ok(p,NULL))
2140         lp_add_printer(p,printers);
2141     }
2142   free(s);
2143 }
2144
2145 /***************************************************************************
2146 auto-load one printer
2147 ***************************************************************************/
2148 static void lp_add_one_printer(char *name,char *comment)
2149 {
2150   int printers = lp_servicenumber(PRINTERS_NAME);
2151   int i;
2152
2153   if (lp_servicenumber(name) < 0)
2154     {
2155       lp_add_printer(name,printers);
2156       if ((i=lp_servicenumber(name)) >= 0)
2157         string_set(&iSERVICE(i).comment,comment);
2158     }      
2159 }
2160
2161
2162 /***************************************************************************
2163 auto-load printer services
2164 ***************************************************************************/
2165 static void lp_add_all_printers(void)
2166 {
2167   int printers = lp_servicenumber(PRINTERS_NAME);
2168
2169   if (printers < 0) return;
2170
2171   pcap_printer_fn(lp_add_one_printer);
2172 }
2173
2174 /***************************************************************************
2175 have we loaded a services file yet?
2176 ***************************************************************************/
2177 BOOL lp_loaded(void)
2178 {
2179   return(bLoaded);
2180 }
2181
2182 /***************************************************************************
2183 unload unused services
2184 ***************************************************************************/
2185 void lp_killunused(BOOL (*snumused)(int ))
2186 {
2187   int i;
2188   for (i=0;i<iNumServices;i++)
2189     if (VALID(i) && (!snumused || !snumused(i)))
2190       {
2191         iSERVICE(i).valid = False;
2192         free_service(pSERVICE(i));
2193       }
2194 }
2195
2196 /***************************************************************************
2197 Load the services array from the services file. Return True on success, 
2198 False on failure.
2199 ***************************************************************************/
2200 BOOL lp_load(char *pszFname,BOOL global_only)
2201 {
2202   pstring n2;
2203   BOOL bRetval;
2204  
2205   add_to_file_list(pszFname);
2206
2207   bRetval = False;
2208
2209   bInGlobalSection = True;
2210   bGlobalOnly = global_only;
2211   
2212   init_globals();
2213   
2214   pstrcpy(n2,pszFname);
2215   standard_sub_basic(n2);
2216
2217   /* We get sections first, so have to start 'behind' to make up */
2218   iServiceIndex = -1;
2219   bRetval = pm_process(n2, do_section, do_parameter);
2220   
2221   /* finish up the last section */
2222   DEBUG(3,("pm_process() returned %s\n", BOOLSTR(bRetval)));
2223   if (bRetval)
2224     if (iServiceIndex >= 0)
2225       bRetval = service_ok(iServiceIndex);         
2226
2227   lp_add_auto_services(lp_auto_services());
2228   if (lp_load_printers())
2229     lp_add_all_printers();
2230
2231   lp_add_ipc();
2232
2233   set_default_server_announce_type();
2234
2235   bLoaded = True;
2236
2237   return (bRetval);
2238 }
2239
2240
2241 /***************************************************************************
2242 return the max number of services
2243 ***************************************************************************/
2244 int lp_numservices(void)
2245 {
2246   return(iNumServices);
2247 }
2248
2249 /***************************************************************************
2250 Display the contents of the services array in human-readable form.
2251 ***************************************************************************/
2252 void lp_dump(FILE *f)
2253 {
2254    int iService;
2255
2256    dump_globals(f);
2257    
2258    dump_a_service(&sDefault, f);
2259
2260    for (iService = 0; iService < iNumServices; iService++)
2261    {
2262      if (VALID(iService))
2263        {
2264          if (iSERVICE(iService).szService[0] == '\0')
2265            break;
2266          dump_a_service(pSERVICE(iService), f);
2267        }
2268    }
2269 }
2270
2271
2272 /***************************************************************************
2273 Return the number of the service with the given name, or -1 if it doesn't
2274 exist. Note that this is a DIFFERENT ANIMAL from the internal function
2275 getservicebyname()! This works ONLY if all services have been loaded, and
2276 does not copy the found service.
2277 ***************************************************************************/
2278 int lp_servicenumber(char *pszServiceName)
2279 {
2280    int iService;
2281
2282    for (iService = iNumServices - 1; iService >= 0; iService--)
2283       if (VALID(iService) &&
2284           strequal(lp_servicename(iService), pszServiceName)) 
2285          break;
2286
2287    if (iService < 0)
2288      DEBUG(7,("lp_servicenumber: couldn't find %s\n",pszServiceName));
2289    
2290    return (iService);
2291 }
2292
2293 /*******************************************************************
2294   a useful volume label function
2295   ******************************************************************/
2296 char *volume_label(int snum)
2297 {
2298   char *ret = lp_volume(snum);
2299   if (!*ret) return(lp_servicename(snum));
2300   return(ret);
2301 }
2302
2303 #if 0
2304 /*
2305  * nmbd only loads the global section. There seems to be no way to
2306  * determine exactly is a service is printable by only looking at the
2307  * [global] section so for now always announce as a print server. This
2308  * will need looking at in the future. Jeremy (jallison@whistle.com).
2309  */
2310 /*******************************************************************
2311  Return true if any printer services are defined.
2312   ******************************************************************/
2313 static BOOL lp_printer_services(void)
2314 {
2315   int iService;
2316
2317   for (iService = iNumServices - 1; iService >= 0; iService--)
2318       if (VALID(iService) && iSERVICE(iService).bPrint_ok)
2319           return True;
2320   return False;
2321 }
2322 #endif
2323
2324 /*******************************************************************
2325  Set the server type we will announce as via nmbd.
2326 ********************************************************************/
2327 static void set_default_server_announce_type()
2328 {
2329   default_server_announce = (SV_TYPE_WORKSTATION | SV_TYPE_SERVER |
2330                               SV_TYPE_SERVER_UNIX | SV_TYPE_PRINTQ_SERVER);
2331   if(lp_announce_as() == ANNOUNCE_AS_NT)
2332     default_server_announce |= (SV_TYPE_SERVER_NT | SV_TYPE_NT);
2333   else if(lp_announce_as() == ANNOUNCE_AS_WIN95)
2334     default_server_announce |= SV_TYPE_WIN95_PLUS;
2335   else if(lp_announce_as() == ANNOUNCE_AS_WFW)
2336     default_server_announce |= SV_TYPE_WFW;
2337   default_server_announce |= (lp_time_server() ? SV_TYPE_TIME_SOURCE : 0);
2338 /*
2339  * nmbd only loads the [global] section. There seems to be no way to
2340  * determine exactly if any service is printable by only looking at the
2341  * [global] section so for now always announce as a print server. This
2342  * will need looking at in the future. Jeremy (jallison@whistle.com).
2343  */
2344 #if 0
2345   default_server_announce |= (lp_printer_services() ? SV_TYPE_PRINTQ_SERVER : 0);
2346 #endif
2347 }
2348
2349
2350 /*******************************************************************
2351 rename a service
2352 ********************************************************************/
2353 void lp_rename_service(int snum, char *new_name)
2354 {
2355         string_set(&pSERVICE(snum)->szService, new_name);
2356 }
2357
2358 /*******************************************************************
2359 remove a service
2360 ********************************************************************/
2361 void lp_remove_service(int snum)
2362 {
2363         pSERVICE(snum)->valid = False;
2364 }
2365
2366 /*******************************************************************
2367 copy a service
2368 ********************************************************************/
2369 void lp_copy_service(int snum, char *new_name)
2370 {
2371         char *oldname = lp_servicename(snum);
2372         do_section(new_name);
2373         if (snum >= 0) {
2374                 snum = lp_servicenumber(new_name);
2375                 if (snum >= 0)
2376                         lp_do_parameter(snum, "copy", oldname);
2377         }
2378 }
2379
2380
2381 /*******************************************************************
2382  Get the default server type we will announce as via nmbd.
2383 ********************************************************************/
2384 int lp_default_server_announce(void)
2385 {
2386   return default_server_announce;
2387 }
2388
2389 /*******************************************************************
2390  Split the announce version into major and minor numbers.
2391 ********************************************************************/
2392 int lp_major_announce_version(void)
2393 {
2394   static BOOL got_major = False;
2395   static int major_version = DEFAULT_MAJOR_VERSION;
2396   char *vers;
2397   char *p;
2398
2399   if(got_major)
2400     return major_version;
2401
2402   got_major = True;
2403   if((vers = lp_announce_version()) == NULL)
2404     return major_version;
2405   
2406   if((p = strchr(vers, '.')) == 0)
2407     return major_version;
2408
2409   *p = '\0';
2410   major_version = atoi(vers);
2411   return major_version;
2412 }
2413
2414 int lp_minor_announce_version(void)
2415 {
2416   static BOOL got_minor = False;
2417   static int minor_version = DEFAULT_MINOR_VERSION;
2418   char *vers;
2419   char *p;
2420
2421   if(got_minor)
2422     return minor_version;
2423
2424   got_minor = True;
2425   if((vers = lp_announce_version()) == NULL)
2426     return minor_version;
2427   
2428   if((p = strchr(vers, '.')) == 0)              
2429     return minor_version;
2430     
2431   p++;
2432   minor_version = atoi(p);
2433   return minor_version;
2434 }  
2435