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