This commit does 3 main things:
[kai/samba.git] / source3 / param / loadparm.c
index 2a76ce70f773e60168602bcd5c4e1ebbb9158df6..b6eabcd72732a459616649ab938696449728e681 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Parameter loading functions
-   Copyright (C) Karl Auer 1993,1994
+   Copyright (C) Karl Auer 1993,1997
 
    Largely re-written by Andrew Tridgell, September 1994
    
 
 #include "includes.h"
 
+/* Set default coding system for KANJI if none specified in Makefile. */
+#ifndef KANJI
+#define KANJI "sjis"
+#endif /* KANJI */
+
 BOOL bLoaded = False;
 
 extern int DEBUGLEVEL;
@@ -97,43 +102,44 @@ int keepalive=0;
 extern BOOL use_getwd_cache;
 
 extern int extra_time_offset;
-#ifdef KANJI
 extern int coding_system;
-#endif
 
 /* 
  * This structure describes global (ie., server-wide) parameters.
  */
 typedef struct
 {
-  char *szAutoServices;
-  char *szCharacterSet;
-  char *szConfigFile;
+  char *szPrintcapname;
+  char *szLockDir;
+  char *szRootdir;
   char *szDefaultService;
   char *szDfree;
-  char *szDomainController;
-  char *szHostsEquiv;
-  char *szInterfaces;
-  char *szLockDir;
-  char *szLogFile;
-  char *szLogonScript;
   char *szMsgCommand;
-  char *szPasswdChat;
-  char *szPasswdProgram;
-  char *szPasswordServer;
-  char *szPrintcapname;
-  char *szRemoteAnnounce;
-  char *szRootdir;
-  char *szServerComment;
+  char *szHostsEquiv;
   char *szServerString;
-  char *szSmbrun;
+  char *szAutoServices;
+  char *szPasswdProgram;
+  char *szPasswdChat;
+  char *szLogFile;
+  char *szConfigFile;
   char *szSMBPasswdFile;
-  char *szSocketAddress;
+  char *szPasswordServer;
   char *szSocketOptions;
-  char *szUsernameMap;
   char *szValidChars;
-  char *szWINSserver;
   char *szWorkGroup;
+  char *szDomainController;
+  char *szUsernameMap;
+  char *szCharacterSet;
+  char *szLogonScript;
+  char *szLogonPath;
+  char *szSmbrun;
+  char *szWINSserver;
+  char *szInterfaces;
+  char *szRemoteAnnounce;
+  char *szSocketAddress;
+  char *szNISHomeMapName;
+  char *szAnnounceVersion; /* This is initialised in init_globals */
+  char *szNetbiosAliases;
   int max_log_size;
   int mangled_stack;
   int max_xmit;
@@ -150,10 +156,15 @@ typedef struct
   int os_level;
   int max_ttl;
   int ReadSize;
+  int shmem_size;
+  int shmem_hash_size;
+  int client_code_page;
+  int announce_as;   /* This is initialised in init_globals */
+  BOOL bDNSproxy;
   BOOL bWINSsupport;
   BOOL bWINSproxy;
-  BOOL bPreferredMaster;
   BOOL bLocalMaster;
+  BOOL bPreferredMaster;
   BOOL bDomainMaster;
   BOOL bDomainLogons;
   BOOL bEncryptPasswords;
@@ -167,6 +178,9 @@ typedef struct
   BOOL bReadbmpx;
   BOOL bSyslogOnly;
   BOOL bBrowseList;
+  BOOL bUnixRealname;
+  BOOL bNISHomeMap;
+  BOOL bTimeServer;
 } global;
 
 static global Globals;
@@ -205,6 +219,8 @@ typedef struct
   char *szMagicScript;
   char *szMagicOutput;
   char *szMangledMap;
+  char *szVetoFiles;
+  char *szHideFiles;
   char *comment;
   char *force_user;
   char *force_group;
@@ -212,7 +228,10 @@ typedef struct
   char *writelist;
   char *volume;
   int  iMinPrintSpace;
-  int  iCreate_mode;
+  int  iCreate_mask;
+  int  iCreate_force_mode;
+  int  iDir_mask;
+  int  iDir_force_mode;
   int  iMaxConnections;
   int  iDefaultCase;
   BOOL bAlternatePerm;
@@ -240,10 +259,12 @@ typedef struct
   BOOL bOnlyUser;
   BOOL bMangledNames;
   BOOL bWidelinks;
+  BOOL bSymlinks;
   BOOL bSyncAlways;
   char magic_char;
   BOOL *copymap;
   BOOL bDeleteReadonly;
+  BOOL bFakeOplocks;
   char dummy[3]; /* for alignment */
 } service;
 
@@ -255,7 +276,7 @@ static service sDefault =
   NULL,    /* szService */
   NULL,    /* szPath */
   NULL,    /* szUsername */
-  NULL,    /* szGuestAccount */
+  NULL,    /* szGuestAccount  - this is set in init_globals() */
   NULL,    /* szInvalidUsers */
   NULL,    /* szValidUsers */
   NULL,    /* szAdminUsers */
@@ -271,13 +292,15 @@ static service sDefault =
   NULL,    /* szLppausecommand */
   NULL,    /* szLpresumecommand */
   NULL,    /* szPrintername */
-  NULL,    /* szPrinterDriver */
+  NULL,    /* szPrinterDriver - this is set in init_globals() */
   NULL,    /* szDontdescend */
   NULL,    /* szHostsallow */
   NULL,    /* szHostsdeny */
   NULL,    /* szMagicScript */
   NULL,    /* szMagicOutput */
   NULL,    /* szMangledMap */
+  NULL,    /* szVetoFiles */
+  NULL,    /* szHideFiles */
   NULL,    /* comment */
   NULL,    /* force user */
   NULL,    /* force group */
@@ -285,7 +308,10 @@ static service sDefault =
   NULL,    /* writelist */
   NULL,    /* volume */
   0,       /* iMinPrintSpace */
-  0755,    /* iCreate_mode */
+  0744,    /* iCreate_mask */
+  0000,    /* iCreate_force_mode */
+  0755,    /* iDir_mask */
+  0000,    /* iDir_force_mode */
   0,       /* iMaxConnections */
   CASE_LOWER, /* iDefaultCase */
   False,   /* bAlternatePerm */
@@ -313,10 +339,12 @@ static service sDefault =
   False, /* bOnlyUser */
   True,  /* bMangledNames */
   True,  /* bWidelinks */
+  True,  /* bSymlinks */
   False, /* bSyncAlways */
   '~',   /* magic char */
   NULL,  /* copymap */
   False, /* bDeleteReadonly */
+  False, /* bFakeOplocks */
   ""     /* dummy */
 };
 
@@ -328,7 +356,7 @@ static int iNumServices = 0;
 static int iServiceIndex = 0;
 static BOOL bInGlobalSection = True;
 static BOOL bGlobalOnly = False;
-
+static int default_server_announce;
 
 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
 
@@ -341,9 +369,10 @@ static BOOL handle_security(char *pszParmValue,int *val);
 static BOOL handle_case(char *pszParmValue,int *val);
 static BOOL handle_printing(char *pszParmValue,int *val);
 static BOOL handle_character_set(char *pszParmValue,int *val);
-#ifdef KANJI
+static BOOL handle_announce_as(char *pszParmValue, int *val);
 static BOOL handle_coding_system(char *pszParmValue,int *val);
-#endif /* KANJI */
+
+static void set_default_server_announce_type(void);
 
 struct parm_struct
 {
@@ -363,6 +392,7 @@ struct parm_struct
   {"printing",         P_INTEGER, P_GLOBAL, &Globals.printing,handle_printing},
   {"max disk size",    P_INTEGER, P_GLOBAL, &Globals.maxdisksize,       NULL},
   {"lpq cache time",   P_INTEGER, P_GLOBAL, &Globals.lpqcachetime,      NULL},
+  {"announce as",      P_INTEGER, P_GLOBAL, &Globals.announce_as,      handle_announce_as},
   {"encrypt passwords",P_BOOL,    P_GLOBAL, &Globals.bEncryptPasswords, NULL},
   {"getwd cache",      P_BOOL,    P_GLOBAL, &use_getwd_cache,           NULL},
   {"read prediction",  P_BOOL,    P_GLOBAL, &Globals.bReadPrediction,   NULL},
@@ -377,6 +407,7 @@ struct parm_struct
   {"password server",  P_STRING,  P_GLOBAL, &Globals.szPasswordServer,  NULL},
   {"socket options",   P_GSTRING, P_GLOBAL, user_socket_options,        NULL},
   {"netbios name",     P_UGSTRING,P_GLOBAL, myname,                     NULL},
+  {"netbios aliases",  P_STRING,  P_GLOBAL, &Globals.szNetbiosAliases,  NULL},
   {"smbrun",           P_STRING,  P_GLOBAL, &Globals.szSmbrun,          NULL},
   {"log file",         P_STRING,  P_GLOBAL, &Globals.szLogFile,         NULL},
   {"config file",      P_STRING,  P_GLOBAL, &Globals.szConfigFile,      NULL},
@@ -384,7 +415,6 @@ struct parm_struct
   {"hosts equiv",      P_STRING,  P_GLOBAL, &Globals.szHostsEquiv,      NULL},
   {"preload",          P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL},
   {"auto services",    P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL},
-  {"server comment",   P_STRING,  P_GLOBAL, &Globals.szServerComment,   NULL},
   {"server string",    P_STRING,  P_GLOBAL, &Globals.szServerString,    NULL},
   {"printcap name",    P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL},
   {"printcap",         P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL},
@@ -405,8 +435,11 @@ struct parm_struct
   {"username map",     P_STRING,  P_GLOBAL, &Globals.szUsernameMap,     NULL},
   {"character set",    P_STRING,  P_GLOBAL, &Globals.szCharacterSet,    handle_character_set},
   {"logon script",     P_STRING,  P_GLOBAL, &Globals.szLogonScript,     NULL},
+  {"logon path",       P_STRING,  P_GLOBAL, &Globals.szLogonPath,       NULL},
   {"remote announce",  P_STRING,  P_GLOBAL, &Globals.szRemoteAnnounce,  NULL},
   {"socket address",   P_STRING,  P_GLOBAL, &Globals.szSocketAddress,   NULL},
+  {"homedir map",      P_STRING,  P_GLOBAL, &Globals.szNISHomeMapName,  NULL},
+  {"announce version", P_STRING,  P_GLOBAL, &Globals.szAnnounceVersion, NULL},
   {"max log size",     P_INTEGER, P_GLOBAL, &Globals.max_log_size,      NULL},
   {"mangled stack",    P_INTEGER, P_GLOBAL, &Globals.mangled_stack,     NULL},
   {"max mux",          P_INTEGER, P_GLOBAL, &Globals.max_mux,           NULL},
@@ -418,11 +451,13 @@ struct parm_struct
   {"deadtime",         P_INTEGER, P_GLOBAL, &Globals.deadtime,          NULL},
   {"time offset",      P_INTEGER, P_GLOBAL, &extra_time_offset,         NULL},
   {"read size",        P_INTEGER, P_GLOBAL, &Globals.ReadSize,          NULL},
-#ifdef KANJI
+  {"shared mem size",  P_INTEGER, P_GLOBAL, &Globals.shmem_size,        NULL},
+  {"shared file entries",  P_INTEGER, P_GLOBAL, &Globals.shmem_hash_size, NULL},
   {"coding system",    P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
-#endif /* KANJI */
+  {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page, NULL},
   {"os level",         P_INTEGER, P_GLOBAL, &Globals.os_level,          NULL},
   {"max ttl",          P_INTEGER, P_GLOBAL, &Globals.max_ttl,           NULL},
+  {"dns proxy",        P_BOOL,    P_GLOBAL, &Globals.bDNSproxy,         NULL},
   {"wins support",     P_BOOL,    P_GLOBAL, &Globals.bWINSsupport,      NULL},
   {"wins proxy",       P_BOOL,    P_GLOBAL, &Globals.bWINSproxy,        NULL},
   {"wins server",      P_STRING,  P_GLOBAL, &Globals.szWINSserver,      NULL},
@@ -432,7 +467,9 @@ struct parm_struct
   {"domain master",    P_BOOL,    P_GLOBAL, &Globals.bDomainMaster,     NULL},
   {"domain logons",    P_BOOL,    P_GLOBAL, &Globals.bDomainLogons,     NULL},
   {"browse list",      P_BOOL,    P_GLOBAL, &Globals.bBrowseList,       NULL},
-
+  {"unix realname",    P_BOOL,    P_GLOBAL, &Globals.bUnixRealname,     NULL},
+  {"NIS homedir",      P_BOOL,    P_GLOBAL, &Globals.bNISHomeMap,       NULL},
+  {"time server",      P_BOOL,    P_GLOBAL, &Globals.bTimeServer,      NULL},
   {"-valid",           P_BOOL,    P_LOCAL,  &sDefault.valid,            NULL},
   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,          NULL},
   {"copy",             P_STRING,  P_LOCAL,  &sDefault.szCopy,    handle_copy},
@@ -475,11 +512,17 @@ struct parm_struct
   {"writable",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
   {"max connections",  P_INTEGER, P_LOCAL,  &sDefault.iMaxConnections,  NULL},
   {"min print space",  P_INTEGER, P_LOCAL,  &sDefault.iMinPrintSpace,   NULL},
-  {"create mask",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mode,     NULL},
-  {"create mode",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mode,     NULL},
+  {"create mask",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mask,     NULL},
+  {"create mode",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mask,     NULL},
+  {"force create mode",P_OCTAL,   P_LOCAL,  &sDefault.iCreate_force_mode,     NULL},
+  {"directory mask",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_mask,        NULL},
+  {"directory mode",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_mask,        NULL},
+  {"force directory mode",   P_OCTAL,   P_LOCAL,  &sDefault.iDir_force_mode,        NULL},
   {"set directory",    P_BOOLREV, P_LOCAL,  &sDefault.bNo_set_dir,      NULL},
   {"status",           P_BOOL,    P_LOCAL,  &sDefault.status,           NULL},
   {"hide dot files",   P_BOOL,    P_LOCAL,  &sDefault.bHideDotFiles,    NULL},
+  {"veto files",       P_STRING,  P_LOCAL,  &sDefault.szVetoFiles,      NULL},
+  {"hide files",       P_STRING,  P_LOCAL,  &sDefault.szHideFiles,      NULL},
   {"guest only",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL},
   {"only guest",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL},
   {"guest ok",         P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL},
@@ -495,8 +538,10 @@ struct parm_struct
   {"share modes",      P_BOOL,    P_LOCAL,  &sDefault.bShareModes,      NULL},
   {"only user",        P_BOOL,    P_LOCAL,  &sDefault.bOnlyUser,        NULL},
   {"wide links",       P_BOOL,    P_LOCAL,  &sDefault.bWidelinks,       NULL},
+  {"follow symlinks",  P_BOOL,    P_LOCAL,  &sDefault.bSymlinks,        NULL},
   {"sync always",      P_BOOL,    P_LOCAL,  &sDefault.bSyncAlways,      NULL},
   {"mangled names",    P_BOOL,    P_LOCAL,  &sDefault.bMangledNames,    NULL},
+  {"fake oplocks",     P_BOOL,    P_LOCAL,  &sDefault.bFakeOplocks,     NULL},
   {"print command",    P_STRING,  P_LOCAL,  &sDefault.szPrintcommand,   NULL},
   {"lpq command",      P_STRING,  P_LOCAL,  &sDefault.szLpqcommand,     NULL},
   {"lprm command",     P_STRING,  P_LOCAL,  &sDefault.szLprmcommand,    NULL},
@@ -540,6 +585,7 @@ static void init_globals(void)
          string_init(parm_table[i].ptr,"");
 
       string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
+      string_set(&sDefault.szPrinterDriver, "NULL");
 
       done_init = True;
     }
@@ -552,11 +598,7 @@ static void init_globals(void)
 #endif
   string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
   string_set(&Globals.szWorkGroup, WORKGROUP);
-#ifdef SMB_PASSWD
   string_set(&Globals.szPasswdProgram, SMB_PASSWD);
-#else
-  string_set(&Globals.szPasswdProgram, "/bin/passwd");
-#endif
   string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
   string_set(&Globals.szLockDir, LOCKDIR);
   string_set(&Globals.szRootdir, "/");
@@ -564,15 +606,14 @@ static void init_globals(void)
   string_set(&Globals.szSocketAddress, "0.0.0.0");
   sprintf(s,"Samba %s",VERSION);
   string_set(&Globals.szServerString,s);
-  strcpy(s,"Samba %v"); /* samba comment */
-  string_sub(s,"%v",VERSION);
-  string_set(&Globals.szServerComment,s);
+  sprintf(s,"%d.%d", DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION);
+  string_set(&Globals.szAnnounceVersion,s);
   Globals.bLoadPrinters = True;
   Globals.bUseRhosts = False;
   Globals.max_packet = 65535;
   Globals.mangled_stack = 50;
-  Globals.max_xmit = Globals.max_packet;
-  Globals.max_mux = 2;
+  Globals.max_xmit = 65535;
+  Globals.max_mux = 50; /* This is *needed* for profile support. */
   Globals.lpqcachetime = 10;
   Globals.pwordlevel = 0;
   Globals.deadtime = 0;
@@ -591,19 +632,51 @@ static void init_globals(void)
   Globals.bSyslogOnly = False;
   Globals.os_level = 0;
   Globals.max_ttl = 60*60*4; /* 2 hours default */
-  Globals.bPreferredMaster = True; /* force election on startup */
-  Globals.bLocalMaster  = True; /* master browser on local subnet */
-  Globals.bDomainMaster = False; /* maintain wide area network browse list */
+  Globals.ReadSize = 16*1024;
+  Globals.shmem_size = SHMEM_SIZE;
+  Globals.shmem_hash_size = SHMEM_HASH_SIZE;
+  Globals.announce_as = ANNOUNCE_AS_NT;
+  Globals.bUnixRealname = False;
+#if (defined(NETGROUP) && defined(AUTOMOUNT))
+  Globals.bNISHomeMap = False;
+  string_set(&Globals.szNISHomeMapName, "auto.home");
+#endif
+  coding_system = interpret_coding_system (KANJI, SJIS_CODE);
+  Globals.client_code_page = DEFAULT_CLIENT_CODE_PAGE;
+  Globals.bTimeServer = False;
+
+/* these parameters are set to defaults that are more appropriate
+   for the increasing samba install base:
+
+   as a member of the workgroup, that will possibly become a
+   _local_ master browser (lm = True).  this is opposed to a forced
+   local master browser startup (pm = True).
+
+   doesn't provide WINS server service by default (wsupp = False),
+   and doesn't provide domain master browser services by default, either.
+
+*/
+
+  Globals.bPreferredMaster = False;
+  Globals.bLocalMaster = True;
+  Globals.bDomainMaster = False;
   Globals.bDomainLogons = False;
   Globals.bBrowseList = True;
-  Globals.bWINSsupport = True;
+  Globals.bWINSsupport = False;
   Globals.bWINSproxy = False;
-  Globals.ReadSize = 16*1024;
 
-#ifdef KANJI
-  coding_system = interpret_coding_system (KANJI, SJIS_CODE);
-#endif /* KANJI */
+/* this parameter is currently set to the default functionality
+   in samba.  given that w95 and NT is starting to use DNS for
+   server resolution, i expect that at some point it would be
+   sensible to default this to False.
+
+   this parameter is added because nmbd is a single process, and
+   gethostbyname is a blocking call, which can take out nmbd for
+   several seconds while a dns lookup is performed.
 
+ */
+
+  Globals.bDNSproxy = True;
 }
 
 /***************************************************************************
@@ -732,7 +805,6 @@ FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun)
 FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
 FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
 FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
-FN_GLOBAL_STRING(lp_server_comment,&Globals.szServerComment)
 FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname)
 FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir)
 FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir)
@@ -749,11 +821,16 @@ FN_GLOBAL_STRING(lp_domain_controller,&Globals.szDomainController)
 FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
 FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) 
 FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) 
+FN_GLOBAL_STRING(lp_logon_path,&Globals.szLogonPath) 
 FN_GLOBAL_STRING(lp_remote_announce,&Globals.szRemoteAnnounce) 
 FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
 FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
 FN_GLOBAL_STRING(lp_socket_address,&Globals.szSocketAddress)
+FN_GLOBAL_STRING(lp_nis_home_map_name,&Globals.szNISHomeMapName)
+FN_GLOBAL_STRING(lp_announce_version,&Globals.szAnnounceVersion)
+FN_GLOBAL_STRING(lp_netbios_aliases,&Globals.szNetbiosAliases)
 
+FN_GLOBAL_BOOL(lp_dns_proxy,&Globals.bDNSproxy)
 FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
 FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
 FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster)
@@ -772,6 +849,9 @@ FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
 FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
 FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
 FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
+FN_GLOBAL_BOOL(lp_unix_realname,&Globals.bUnixRealname)
+FN_GLOBAL_BOOL(lp_nis_home_map,&Globals.bNISHomeMap)
+FN_GLOBAL_BOOL(lp_time_server,&Globals.bTimeServer)
 
 FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
 FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
@@ -783,6 +863,8 @@ FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
 FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
 FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
 FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
+FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size)
+FN_GLOBAL_INTEGER(lp_shmem_hash_size,&Globals.shmem_hash_size)
 FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
 FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
 FN_GLOBAL_INTEGER(lp_security,&Globals.security)
@@ -790,6 +872,8 @@ FN_GLOBAL_INTEGER(lp_printing,&Globals.printing)
 FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
 FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
 FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
+FN_GLOBAL_INTEGER(lp_client_code_page,&Globals.client_code_page)
+FN_GLOBAL_INTEGER(lp_announce_as,&Globals.announce_as)
 
 FN_LOCAL_STRING(lp_preexec,szPreExec)
 FN_LOCAL_STRING(lp_postexec,szPostExec)
@@ -821,6 +905,8 @@ FN_LOCAL_STRING(lp_readlist,readlist)
 FN_LOCAL_STRING(lp_writelist,writelist)
 FN_LOCAL_STRING(lp_volume,volume)
 FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
+FN_LOCAL_STRING(lp_veto_files,szVetoFiles)
+FN_LOCAL_STRING(lp_hide_files,szHideFiles)
 
 FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
 FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
@@ -845,11 +931,16 @@ FN_LOCAL_BOOL(lp_share_modes,bShareModes)
 FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
 FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
 FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
+FN_LOCAL_BOOL(lp_symlinks,bSymlinks)
 FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
 FN_LOCAL_BOOL(lp_map_system,bMap_system)
 FN_LOCAL_BOOL(lp_delete_readonly,bDeleteReadonly)
+FN_LOCAL_BOOL(lp_fake_oplocks,bFakeOplocks)
 
-FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
+FN_LOCAL_INTEGER(lp_create_mode,iCreate_mask)
+FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
+FN_LOCAL_INTEGER(lp_dir_mode,iDir_mask)
+FN_LOCAL_INTEGER(lp_force_dir_mode,iDir_force_mode)
 FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
 FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
 FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
@@ -869,8 +960,6 @@ static void   copy_service( service *pserviceDest,
 static BOOL   service_ok(int iService);
 static BOOL   do_parameter(char *pszParmName, char *pszParmValue);
 static BOOL   do_section(char *pszSectionName);
-static void   dump_globals(void);
-static void   dump_a_service(service *pService);
 static void init_copymap(service *pservice);
 
 
@@ -999,7 +1088,7 @@ static BOOL lp_add_ipc(void)
 
   sprintf(comment,"IPC Service (%s)",lp_serverstring());
 
-  string_set(&iSERVICE(i).szPath,"/tmp");
+  string_set(&iSERVICE(i).szPath,tmpdir());
   string_set(&iSERVICE(i).szUsername,"");
   string_set(&iSERVICE(i).comment,comment);
   iSERVICE(i).status = False;
@@ -1037,6 +1126,12 @@ BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
   string_set(&iSERVICE(i).szPrintername,pszPrintername);
   string_set(&iSERVICE(i).comment,comment);
   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
+  /* Printers cannot be read_only. */
+  iSERVICE(i).bRead_only = False;
+  /* No share modes on printer services. */
+  iSERVICE(i).bShareModes = False;
+  /* Printer services must be printable. */
+  iSERVICE(i).bPrint_ok = True;
   
   DEBUG(3,("adding printer service %s\n",pszPrintername));
   
@@ -1233,8 +1328,8 @@ static BOOL service_ok(int iService)
    if (iSERVICE(iService).szPath[0] == '\0' &&
        strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
    {
-      DEBUG(0,("No path in service %s - using /tmp\n",iSERVICE(iService).szService));
-      string_set(&iSERVICE(iService).szPath,"/tmp");      
+      DEBUG(0,("No path in service %s - using %s\n",iSERVICE(iService).szService,tmpdir()));
+      string_set(&iSERVICE(iService).szPath,tmpdir());      
    }
 
    /* If a service is flagged unavailable, log the fact at level 0. */
@@ -1291,17 +1386,31 @@ check if a config file has changed date
 BOOL lp_file_list_changed(void)
 {
   struct file_lists *f = file_lists;
-  while (f) {
+  DEBUG(6,("lp_file_list_changed()\n"));
+
+  while (f)
+  {
     pstring n2;
+    time_t mod_time;
+
     strcpy(n2,f->name);
     standard_sub_basic(n2);
-    if (f->modtime != file_modtime(n2)) return(True);
+
+    DEBUG(6,("file %s -> %s  last mod_time: %s\n",
+             f->name, n2, ctime(&f->modtime)));
+
+    mod_time = file_modtime(n2);
+
+    if (f->modtime != mod_time)
+    {
+      DEBUG(6,("file %s modified: %s\n", n2, ctime(&mod_time)));
+      return(True);
+    }
     f = f->next;   
   }
   return(False);
 }
 
-#ifdef KANJI
 /***************************************************************************
   handle the interpretation of the coding system parameter
   *************************************************************************/
@@ -1310,7 +1419,6 @@ static BOOL handle_coding_system(char *pszParmValue,int *val)
   *val = interpret_coding_system(pszParmValue,*val);
   return(True);
 }
-#endif /* KANJI */
 
 /***************************************************************************
 handle the interpretation of the character set system parameter
@@ -1346,9 +1454,9 @@ handle the interpretation of the default case
 ***************************************************************************/
 static BOOL handle_case(char *pszParmValue,int *val)
 {
-  if (strequal(pszParmValue,"LOWER"))
+  if (strnequal(pszParmValue,"LOWER", 5))
     *val = CASE_LOWER;
-  else if (strequal(pszParmValue,"UPPER"))
+  else if (strnequal(pszParmValue,"UPPER", 5))
     *val = CASE_UPPER;
   return(True);
 }
@@ -1358,23 +1466,37 @@ handle the interpretation of the printing system
 ***************************************************************************/
 static BOOL handle_printing(char *pszParmValue,int *val)
 {
-  if (strequal(pszParmValue,"sysv"))
+  if (strnequal(pszParmValue,"sysv", 4))
     *val = PRINT_SYSV;
-  else if (strequal(pszParmValue,"aix"))
+  else if (strnequal(pszParmValue,"aix", 3))
     *val = PRINT_AIX;
-  else if (strequal(pszParmValue,"hpux"))
+  else if (strnequal(pszParmValue,"hpux", 4))
     *val = PRINT_HPUX;
-  else if (strequal(pszParmValue,"bsd"))
+  else if (strnequal(pszParmValue,"bsd", 3))
     *val = PRINT_BSD;
-  else if (strequal(pszParmValue,"qnx"))
+  else if (strnequal(pszParmValue,"qnx",3))
     *val = PRINT_QNX;
-  else if (strequal(pszParmValue,"plp"))
+  else if (strnequal(pszParmValue,"plp", 3))
     *val = PRINT_PLP;
-  else if (strequal(pszParmValue,"lprng"))
+  else if (strnequal(pszParmValue,"lprng", 5))
     *val = PRINT_LPRNG;
   return(True);
 }
 
+/***************************************************************************
+handle the announce as parameter
+***************************************************************************/
+static BOOL handle_announce_as(char *pszParmValue,int *val)
+{
+  if (strnequal(pszParmValue,"NT", 2))
+    *val = ANNOUNCE_AS_NT;
+  else if (strnequal(pszParmValue,"win95", 5))
+    *val = ANNOUNCE_AS_WIN95;
+  else if (strnequal(pszParmValue,"WfW", 3))
+    *val = ANNOUNCE_AS_WFW;
+  return True;
+} 
+
 /***************************************************************************
 handle the valid chars lines
 ***************************************************************************/
@@ -1382,6 +1504,12 @@ static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
 { 
   string_set(ptr,pszParmValue);
 
+  /* A dependency here is that the parameter client code page must be
+     set before this is called - as calling codepage_initialise()
+     would overwrite the valid char lines.
+   */
+  codepage_initialise(lp_client_code_page());
+
   add_char_string(pszParmValue);
   return(True);
 }
@@ -1471,18 +1599,15 @@ static void init_copymap(service *pservice)
 
 
 /***************************************************************************
-Process a parameter.
+Process a parameter for a particular service number. If snum < 0
+then assume we are in the globals
 ***************************************************************************/
-static BOOL do_parameter(char *pszParmName, char *pszParmValue)
+BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue)
 {
    int parmnum;
    void *parm_ptr=NULL; /* where we are going to store the result */
    void *def_ptr=NULL;
 
-   if (!bInGlobalSection && bGlobalOnly) return(True);
-
-   DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
-   
    parmnum = map_parameter(pszParmName);
 
    if (parmnum < 0)
@@ -1494,37 +1619,33 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)
    def_ptr = parm_table[parmnum].ptr;
 
    /* we might point at a service, the default service or a global */
-   if (bInGlobalSection)
+   if (snum < 0) {
      parm_ptr = def_ptr;
-   else
-     {
-       if (parm_table[parmnum].class == P_GLOBAL)
-        {
+   } else {
+       if (parm_table[parmnum].class == P_GLOBAL) {
           DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
           return(True);
         }
-       parm_ptr = ((char *)pSERVICE(iServiceIndex)) + PTR_DIFF(def_ptr,&sDefault);
-     }
+       parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
+   }
 
-   if (!bInGlobalSection)
-     {
-       int i;
-       if (!iSERVICE(iServiceIndex).copymap)
-        init_copymap(pSERVICE(iServiceIndex));
-       
-       /* this handles the aliases - set the copymap for other entries with
-         the same data pointer */
-       for (i=0;parm_table[i].label;i++)
-        if (parm_table[i].ptr == parm_table[parmnum].ptr)
-          iSERVICE(iServiceIndex).copymap[i] = False;
-     }
+   if (snum >= 0) {
+          int i;
+          if (!iSERVICE(snum).copymap)
+                  init_copymap(pSERVICE(snum));
+          
+          /* this handles the aliases - set the copymap for other entries with
+             the same data pointer */
+          for (i=0;parm_table[i].label;i++)
+                  if (parm_table[i].ptr == parm_table[parmnum].ptr)
+                          iSERVICE(snum).copymap[i] = False;
+   }
 
    /* if it is a special case then go ahead */
-   if (parm_table[parmnum].special)
-     {
-       parm_table[parmnum].special(pszParmValue,parm_ptr);
-       return(True);
-     }
+   if (parm_table[parmnum].special) {
+          parm_table[parmnum].special(pszParmValue,parm_ptr);
+          return(True);
+   }
 
    /* now switch on the type of variable it is */
    switch (parm_table[parmnum].type)
@@ -1572,48 +1693,105 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)
    return(True);
 }
 
+/***************************************************************************
+Process a parameter.
+***************************************************************************/
+static BOOL do_parameter(char *pszParmName, char *pszParmValue)
+{
+   if (!bInGlobalSection && bGlobalOnly) return(True);
+
+   DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
+
+   return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, pszParmName, pszParmValue);
+}
+
+
 /***************************************************************************
 print a parameter of the specified type
 ***************************************************************************/
-static void print_parameter(parm_type type,void *ptr)
+static void print_parameter(parm_type type,void *ptr, FILE *f)
 {
   switch (type)
     {
     case P_BOOL:
-      printf("%s",BOOLSTR(*(BOOL *)ptr));
+      fprintf(f,"%s",BOOLSTR(*(BOOL *)ptr));
       break;
       
     case P_BOOLREV:
-      printf("%s",BOOLSTR(! *(BOOL *)ptr));
+      fprintf(f,"%s",BOOLSTR(! *(BOOL *)ptr));
       break;
       
     case P_INTEGER:
-      printf("%d",*(int *)ptr);
+      fprintf(f,"%d",*(int *)ptr);
       break;
       
     case P_CHAR:
-      printf("%c",*(char *)ptr);
+      fprintf(f,"%c",*(char *)ptr);
       break;
       
     case P_OCTAL:
-      printf("0%o",*(int *)ptr);
+      fprintf(f,"0%o",*(int *)ptr);
       break;
       
     case P_GSTRING:
     case P_UGSTRING:
       if ((char *)ptr)
-       printf("%s",(char *)ptr);
+       fprintf(f,"%s",(char *)ptr);
       break;
 
     case P_STRING:
     case P_USTRING:
       if (*(char **)ptr)
-       printf("%s",*(char **)ptr);
+       fprintf(f,"%s",*(char **)ptr);
       break;
     }
 }
 
 
+/***************************************************************************
+print a parameter of the specified type
+***************************************************************************/
+static void parameter_string(parm_type type,void *ptr,char *s)
+{
+       s[0] = 0;
+       
+       switch (type)
+               {
+               case P_BOOL:
+                       sprintf(s, "%s",BOOLSTR(*(BOOL *)ptr));
+                       break;
+                       
+               case P_BOOLREV:
+                       sprintf(s, "%s",BOOLSTR(! *(BOOL *)ptr));
+                       break;
+                       
+               case P_INTEGER:
+                       sprintf(s, "%d",*(int *)ptr);
+                       break;
+                       
+               case P_CHAR:
+                       sprintf(s, "%c",*(char *)ptr);
+                       break;
+                       
+               case P_OCTAL:
+                       sprintf(s, "0%o",*(int *)ptr);
+                       break;
+                       
+               case P_GSTRING:
+               case P_UGSTRING:
+                       if ((char *)ptr)
+                               sprintf(s, "%s",(char *)ptr);
+                       break;
+                       
+               case P_STRING:
+               case P_USTRING:
+                       if (*(char **)ptr)
+                               sprintf(s, "%s",*(char **)ptr);
+                       break;
+               }
+}
+
+
 /***************************************************************************
 check if two parameters are equal
 ***************************************************************************/
@@ -1706,32 +1884,32 @@ static BOOL do_section(char *pszSectionName)
 /***************************************************************************
 Display the contents of the global structure.
 ***************************************************************************/
-static void dump_globals(void)
+static void dump_globals(FILE *f)
 {
   int i;
-  printf("Global parameters:\n");
+  fprintf(f, "# Global parameters\n");
 
   for (i=0;parm_table[i].label;i++)
     if (parm_table[i].class == P_GLOBAL &&
        parm_table[i].ptr &&
        (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
       {
-       printf("\t%s: ",parm_table[i].label);
-       print_parameter(parm_table[i].type,parm_table[i].ptr);
-       printf("\n");
+       fprintf(f,"\t%s = ",parm_table[i].label);
+       print_parameter(parm_table[i].type,parm_table[i].ptr, f);
+       fprintf(f,"\n");
       }
 }
 
 /***************************************************************************
 Display the contents of a single services record.
 ***************************************************************************/
-static void dump_a_service(service *pService)
+static void dump_a_service(service *pService, FILE *f)
 {
   int i;
   if (pService == &sDefault)
-    printf("\nDefault service parameters:\n");
+    fprintf(f,"\n\n# Default service parameters\n");
   else
-    printf("\nService parameters [%s]:\n",pService->szService);
+    fprintf(f,"\n[%s]\n",pService->szService);
 
   for (i=0;parm_table[i].label;i++)
     if (parm_table[i].class == P_LOCAL &&
@@ -1745,14 +1923,69 @@ static void dump_a_service(service *pService)
                                                      ((char *)pService) + pdiff,
                                                      ((char *)&sDefault) + pdiff))
          {
-           printf("\t%s: ",parm_table[i].label);
+           fprintf(f,"\t%s = ",parm_table[i].label);
            print_parameter(parm_table[i].type,
-                           ((char *)pService) + pdiff);
-           printf("\n");
+                           ((char *)pService) + pdiff, f);
+           fprintf(f,"\n");
          }
       }
 }
 
+
+/***************************************************************************
+return info about the next service  in a service. snum==-1 gives the default
+serice and snum==-2 gives the globals
+
+return 0 when out of parameters
+***************************************************************************/
+int lp_next_parameter(int snum, int *i, char *label, 
+                          char *value, int allparameters)
+{
+       if (snum == -2) {
+               /* do the globals */
+               for (;parm_table[*i].label;(*i)++)
+                       if (parm_table[*i].class == P_GLOBAL &&
+                           parm_table[*i].ptr && 
+                           (*parm_table[*i].label != '-') &&
+                           ((*i) == 0 || 
+                            (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
+                               strcpy(label, parm_table[*i].label);
+                               parameter_string(parm_table[*i].type,
+                                                parm_table[*i].ptr,
+                                                value);
+                               (*i)++;
+                               return 1;
+                       }
+               return 0;
+       } else {
+               service *pService = (snum==-1?&sDefault:pSERVICE(snum));
+
+               for (;parm_table[*i].label;(*i)++)
+                       if (parm_table[*i].class == P_LOCAL &&
+                           parm_table[*i].ptr && 
+                           (*parm_table[*i].label != '-') &&
+                           ((*i) == 0 || 
+                            (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
+                               int pdiff = PTR_DIFF(parm_table[*i].ptr,&sDefault);
+                               
+                               if (snum == -1 || allparameters ||
+                                   !equal_parameter(parm_table[*i].type,
+                                                    ((char *)pService) + pdiff,
+                                                    ((char *)&sDefault) + pdiff)) {
+                                       strcpy(label, parm_table[*i].label);
+                                       parameter_string(parm_table[*i].type,
+                                                        ((char *)pService) + pdiff,
+                                                        value);
+                                       (*i)++;
+                                       return 1;
+                               }
+                       }
+       }
+
+  return 0;
+}
+
+
 #if 0
 /***************************************************************************
 Display the contents of a single copy structure.
@@ -1861,7 +2094,7 @@ void lp_killunused(BOOL (*snumused)(int ))
 {
   int i;
   for (i=0;i<iNumServices;i++)
-    if (VALID(i) && !snumused(i))
+    if (VALID(i) && (!snumused || !snumused(i)))
       {
        iSERVICE(i).valid = False;
        free_service(pSERVICE(i));
@@ -1876,7 +2109,7 @@ BOOL lp_load(char *pszFname,BOOL global_only)
 {
   pstring n2;
   BOOL bRetval;
-  
   add_to_file_list(pszFname);
 
   bRetval = False;
@@ -1905,6 +2138,8 @@ BOOL lp_load(char *pszFname,BOOL global_only)
 
   lp_add_ipc();
 
+  set_default_server_announce_type();
+
   bLoaded = True;
 
   return (bRetval);
@@ -1922,13 +2157,13 @@ int lp_numservices(void)
 /***************************************************************************
 Display the contents of the services array in human-readable form.
 ***************************************************************************/
-void lp_dump(void)
+void lp_dump(FILE *f)
 {
    int iService;
 
-   dump_globals();
+   dump_globals(f);
    
-   dump_a_service(&sDefault);
+   dump_a_service(&sDefault, f);
 
    for (iService = 0; iService < iNumServices; iService++)
    {
@@ -1936,11 +2171,12 @@ void lp_dump(void)
        {
         if (iSERVICE(iService).szService[0] == '\0')
           break;
-        dump_a_service(pSERVICE(iService));
+        dump_a_service(pSERVICE(iService), f);
        }
    }
 }
 
+
 /***************************************************************************
 Return the number of the service with the given name, or -1 if it doesn't
 exist. Note that this is a DIFFERENT ANIMAL from the internal function
@@ -1971,3 +2207,137 @@ char *volume_label(int snum)
   if (!*ret) return(lp_servicename(snum));
   return(ret);
 }
+
+#if 0
+/*
+ * nmbd only loads the global section. There seems to be no way to
+ * determine exactly is a service is printable by only looking at the
+ * [global] section so for now always announce as a print server. This
+ * will need looking at in the future. Jeremy (jallison@whistle.com).
+ */
+/*******************************************************************
+ Return true if any printer services are defined.
+  ******************************************************************/
+static BOOL lp_printer_services(void)
+{
+  int iService;
+
+  for (iService = iNumServices - 1; iService >= 0; iService--)
+      if (VALID(iService) && iSERVICE(iService).bPrint_ok)
+          return True;
+  return False;
+}
+#endif
+
+/*******************************************************************
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+static void set_default_server_announce_type()
+{
+  default_server_announce = (SV_TYPE_WORKSTATION | SV_TYPE_SERVER |
+                              SV_TYPE_SERVER_UNIX | SV_TYPE_PRINTQ_SERVER);
+  if(lp_announce_as() == ANNOUNCE_AS_NT)
+    default_server_announce |= (SV_TYPE_SERVER_NT | SV_TYPE_NT);
+  else if(lp_announce_as() == ANNOUNCE_AS_WIN95)
+    default_server_announce |= SV_TYPE_WIN95_PLUS;
+  else if(lp_announce_as() == ANNOUNCE_AS_WFW)
+    default_server_announce |= SV_TYPE_WFW;
+  default_server_announce |= (lp_time_server() ? SV_TYPE_TIME_SOURCE : 0);
+/*
+ * nmbd only loads the [global] section. There seems to be no way to
+ * determine exactly if any service is printable by only looking at the
+ * [global] section so for now always announce as a print server. This
+ * will need looking at in the future. Jeremy (jallison@whistle.com).
+ */
+#if 0
+  default_server_announce |= (lp_printer_services() ? SV_TYPE_PRINTQ_SERVER : 0);
+#endif
+}
+
+
+/*******************************************************************
+rename a service
+********************************************************************/
+void lp_rename_service(int snum, char *new_name)
+{
+       string_set(&pSERVICE(snum)->szService, new_name);
+}
+
+/*******************************************************************
+remove a service
+********************************************************************/
+void lp_remove_service(int snum)
+{
+       pSERVICE(snum)->valid = False;
+}
+
+/*******************************************************************
+copy a service
+********************************************************************/
+void lp_copy_service(int snum, char *new_name)
+{
+       char *oldname = lp_servicename(snum);
+       do_section(new_name);
+       if (snum >= 0) {
+               snum = lp_servicenumber(new_name);
+               if (snum >= 0)
+                       lp_do_parameter(snum, "copy", oldname);
+       }
+}
+
+
+/*******************************************************************
+ Get the default server type we will announce as via nmbd.
+********************************************************************/
+int lp_default_server_announce(void)
+{
+  return default_server_announce;
+}
+
+/*******************************************************************
+ Split the announce version into major and minor numbers.
+********************************************************************/
+int lp_major_announce_version(void)
+{
+  static BOOL got_major = False;
+  static int major_version = DEFAULT_MAJOR_VERSION;
+  char *vers;
+  char *p;
+
+  if(got_major)
+    return major_version;
+
+  got_major = True;
+  if((vers = lp_announce_version()) == NULL)
+    return major_version;
+  
+  if((p = strchr(vers, '.')) == 0)
+    return major_version;
+
+  *p = '\0';
+  major_version = atoi(vers);
+  return major_version;
+}
+
+int lp_minor_announce_version(void)
+{
+  static BOOL got_minor = False;
+  static int minor_version = DEFAULT_MINOR_VERSION;
+  char *vers;
+  char *p;
+
+  if(got_minor)
+    return minor_version;
+
+  got_minor = True;
+  if((vers = lp_announce_version()) == NULL)
+    return minor_version;
+  
+  if((p = strchr(vers, '.')) == 0)              
+    return minor_version;
+    
+  p++;
+  minor_version = atoi(p);
+  return minor_version;
+}  
+