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