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