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