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