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