r13513: Changing defaults:
[ira/wip.git] / source3 / param / loadparm.c
index 49e63666c9953276c217326a90d5c8e9e9176890..c1cac6b966866f9c855fc7d7cdee2871ff06b488 100644 (file)
@@ -54,6 +54,7 @@
 #include "includes.h"
 
 BOOL in_client = False;                /* Not in the client by default */
+BOOL in_server = False;                /* Not in the server by default */
 BOOL bLoaded = False;
 
 extern userdom_struct current_user_info;
@@ -73,9 +74,12 @@ extern enum protocol_types Protocol;
 #endif
 
 /* some helpful bits */
-#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && ServicePtrs[(i)]->valid)
+#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && (ServicePtrs != NULL) && ServicePtrs[(i)]->valid)
 #define VALID(i) (ServicePtrs != NULL && ServicePtrs[i]->valid)
 
+#define USERSHARE_VALID 1
+#define USERSHARE_PENDING_DELETE 2
+
 int keepalive = DEFAULT_KEEPALIVE;
 BOOL use_getwd_cache = True;
 
@@ -94,8 +98,7 @@ struct _param_opt_struct {
 /* 
  * This structure describes global (ie., server-wide) parameters.
  */
-typedef struct
-{
+typedef struct {
        char *smb_ports;
        char *dos_charset;
        char *unix_charset;
@@ -109,7 +112,6 @@ typedef struct
        char *szPidDir;
        char *szRootdir;
        char *szDefaultService;
-       char *szDfree;
        char *szGetQuota;
        char *szSetQuota;
        char *szMsgCommand;
@@ -122,7 +124,7 @@ typedef struct
        char *szConfigFile;
        char *szSMBPasswdFile;
        char *szPrivateDir;
-       char **szPassdbBackend;
+       char *szPassdbBackend;
        char **szPreloadModules;
        char *szPasswordServer;
        char *szSocketOptions;
@@ -146,10 +148,10 @@ typedef struct
        char *szNetbiosName;
        char **szNetbiosAliases;
        char *szNetbiosScope;
-       char *szDomainOtherSIDs;
        char *szNameResolveOrder;
        char *szPanicAction;
        char *szAddUserScript;
+        char *szRenameUserScript;
        char *szDelUserScript;
        char *szAddGroupScript;
        char *szDelGroupScript;
@@ -159,6 +161,7 @@ typedef struct
        char *szAddMachineScript;
        char *szShutdownScript;
        char *szAbortShutdownScript;
+       char *szUsernameMapScript;
        char *szCheckPasswordScript;
        char *szWINSHook;
        char *szWINSPartners;
@@ -167,7 +170,7 @@ typedef struct
        BOOL bUtmp;
        char *szIdmapUID;
        char *szIdmapGID;
-       BOOL bEnableRidAlgorithm;
+       BOOL bPassdbExpandExplicit;
        int AlgorithmicRidBase;
        char *szTemplateHomedir;
        char *szTemplateShell;
@@ -177,20 +180,20 @@ typedef struct
        BOOL bWinbindUseDefaultDomain;
        BOOL bWinbindTrustedDomainsOnly;
        BOOL bWinbindNestedGroups;
+       BOOL bWinbindRefreshTickets;
+       BOOL bWinbindOfflineLogon;
        char **szIdmapBackend;
        char *szAddShareCommand;
        char *szChangeShareCommand;
        char *szDeleteShareCommand;
-        char *szEventLogOpenCommand;
-        char *szEventLogReadCommand;
-        char *szEventLogClearCommand;
-        char *szEventLogNumRecordsCommand;
-        char *szEventLogOldestRecordCommand;
-       char *szEventLogCloseCommand;
         char **szEventLogs;
        char *szGuestaccount;
        char *szManglingMethod;
        char **szServicesList;
+       char *szUsersharePath;
+       char *szUsershareTemplateShare;
+       char **szUsersharePrefixAllowList;
+       char **szUsersharePrefixDenyList;
        int mangle_prefix;
        int max_log_size;
        char *szLogLevel;
@@ -240,6 +243,7 @@ typedef struct
        char *szLdapAdminDn;
        char *szAclCompat;
        char *szCupsServer;
+       char *szIPrintServer;
        int ldap_passwd_sync; 
        int ldap_replication_sleep;
        int ldap_timeout; /* This is initialised in init_globals */
@@ -298,27 +302,32 @@ typedef struct
        BOOL bUnixExtensions;
        BOOL bDisableNetbios;
        BOOL bKernelChangeNotify;
+       BOOL bFamChangeNotify;
        BOOL bUseKerberosKeytab;
        BOOL bDeferSharingViolations;
        BOOL bEnablePrivileges;
        BOOL bASUSupport;
+       BOOL bUsershareOwnerOnly;
        int restrict_anonymous;
        int name_cache_timeout;
        int client_signing;
        int server_signing;
+       int iUsershareMaxShares;
+
+       BOOL bResetOnZeroVC;
        param_opt_struct *param_opt;
-}
-global;
+} global;
 
 static global Globals;
 
 /* 
  * This structure describes a single service. 
  */
-typedef struct
-{
+typedef struct {
        BOOL valid;
        BOOL autoloaded;
+       int usershare;
+       time_t usershare_last_mod;
        char *szService;
        char *szPath;
        char *szUsername;
@@ -360,6 +369,7 @@ typedef struct
        char **szVfsObjects;
        char *szMSDfsProxy;
        char *szAioWriteBehind;
+       char *szDfree;
        int iMinPrintSpace;
        int iMaxPrintJobs;
        int iMaxReportedPrintJobs;
@@ -378,6 +388,7 @@ typedef struct
        int iOplockContentionLimit;
        int iCSCPolicy;
        int iBlock_size;
+       int iDfreeCacheTime;
        BOOL bPreexecClose;
        BOOL bRootpreexecClose;
        int  iCaseSensitive;
@@ -437,20 +448,23 @@ typedef struct
        BOOL bEASupport;
        BOOL bAclCheckPermissions;
        BOOL bAclMapFullControl;
+       BOOL bAclGroupControl;
        int iallocation_roundup_size;
        int iAioReadSize;
        int iAioWriteSize;
+       int iMap_readonly;
        param_opt_struct *param_opt;
 
        char dummy[3];          /* for alignment */
-}
-service;
+} service;
 
 
 /* This is a default service used to prime a services structure */
 static service sDefault = {
        True,                   /* valid */
        False,                  /* not autoloaded */
+       0,                      /* not a usershare */
+       (time_t)0,              /* No last mod time */
        NULL,                   /* szService */
        NULL,                   /* szPath */
        NULL,                   /* szUsername */
@@ -492,6 +506,7 @@ static service sDefault = {
        NULL,                   /* vfs objects */
        NULL,                   /* szMSDfsProxy */
        NULL,                   /* szAioWriteBehind */
+       NULL,                   /* szDfree */
        0,                      /* iMinPrintSpace */
        1000,                   /* iMaxPrintJobs */
        0,                      /* iMaxReportedPrintJobs */
@@ -509,7 +524,8 @@ static service sDefault = {
        DEFAULT_PRINTING,       /* iPrinting */
        2,                      /* iOplockContentionLimit */
        0,                      /* iCSCPolicy */
-       1024,           /* iBlock_size */
+       1024,                   /* iBlock_size */
+       0,                      /* iDfreeCacheTime */
        False,                  /* bPreexecClose */
        False,                  /* bRootpreexecClose */
        Auto,                   /* case sensitive */
@@ -569,9 +585,11 @@ static service sDefault = {
        False,                  /* bEASupport */
        True,                   /* bAclCheckPermissions */
        True,                   /* bAclMapFullControl */
+       False,                  /* bAclGroupControl */
        SMB_ROUNDUP_ALLOCATION_SIZE,            /* iallocation_roundup_size */
        0,                      /* iAioReadSize */
        0,                      /* iAioWriteSize */
+       MAP_READONLY_YES,       /* iMap_readonly */
        
        NULL,                   /* Parametric options */
 
@@ -582,6 +600,9 @@ static service sDefault = {
 static service **ServicePtrs = NULL;
 static int iNumServices = 0;
 static int iServiceIndex = 0;
+static TDB_CONTEXT *ServiceHash;
+static int *invalid_services = NULL;
+static int num_invalid_services = 0;
 static BOOL bInGlobalSection = True;
 static BOOL bGlobalOnly = False;
 static int server_role;
@@ -602,7 +623,6 @@ static BOOL handle_netbios_scope( int snum, const char *pszParmValue, char **ptr
 static BOOL handle_charset( int snum, const char *pszParmValue, char **ptr );
 static BOOL handle_acl_compatibility( int snum, const char *pszParmValue, char **ptr);
 static BOOL handle_printing( int snum, const char *pszParmValue, char **ptr);
-static BOOL handle_eventlog( int snum, const char *pszParmValue, char **ptr);
 
 static void set_server_role(void);
 static void set_default_server_announce_type(void);
@@ -638,6 +658,7 @@ static const struct enum_list enum_printing[] = {
        {PRINT_PLP, "plp"},
        {PRINT_LPRNG, "lprng"},
        {PRINT_CUPS, "cups"},
+       {PRINT_IPRINT, "iprint"},
        {PRINT_LPRNT, "nt"},
        {PRINT_LPROS2, "os2"},
 #ifdef DEVELOPER
@@ -692,6 +713,18 @@ static const struct enum_list enum_announce_as[] = {
        {-1, NULL}
 };
 
+static const struct enum_list enum_map_readonly[] = {
+       {MAP_READONLY_NO, "no"},
+       {MAP_READONLY_NO, "false"},
+       {MAP_READONLY_NO, "0"},
+       {MAP_READONLY_YES, "yes"},
+       {MAP_READONLY_YES, "true"},
+       {MAP_READONLY_YES, "1"},
+       {MAP_READONLY_PERMISSIONS, "permissions"},
+       {MAP_READONLY_PERMISSIONS, "perms"},
+       {-1, NULL}
+};
+
 static const struct enum_list enum_case[] = {
        {CASE_LOWER, "lower"},
        {CASE_UPPER, "upper"},
@@ -828,7 +861,7 @@ static struct parm_struct parm_table[] = {
        {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD}, 
        {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL, NULL, FLAG_ADVANCED}, 
        {"private dir", P_STRING, P_GLOBAL, &Globals.szPrivateDir, NULL, NULL, FLAG_ADVANCED}, 
-       {"passdb backend", P_LIST, P_GLOBAL, &Globals.szPassdbBackend, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD}, 
+       {"passdb backend", P_STRING, P_GLOBAL, &Globals.szPassdbBackend, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD}, 
        {"algorithmic rid base", P_INTEGER, P_GLOBAL, &Globals.AlgorithmicRidBase, NULL, NULL, FLAG_ADVANCED}, 
        {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, FLAG_ADVANCED}, 
        {"root dir", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, FLAG_HIDE}, 
@@ -873,6 +906,7 @@ static struct parm_struct parm_table[] = {
        {"writable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL, FLAG_HIDE}, 
 
        {"acl check permissions", P_BOOL, P_LOCAL, &sDefault.bAclCheckPermissions, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
+       {"acl group control", P_BOOL, P_LOCAL, &sDefault.bAclGroupControl, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
        {"acl map full control", P_BOOL, P_LOCAL, &sDefault.bAclMapFullControl, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
        {"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, 
        {"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL, FLAG_HIDE}, 
@@ -932,6 +966,7 @@ static struct parm_struct parm_table[] = {
        {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL, NULL, FLAG_ADVANCED}, 
        {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL, NULL, FLAG_ADVANCED}, 
        {"disable netbios", P_BOOL, P_GLOBAL, &Globals.bDisableNetbios, NULL, NULL, FLAG_ADVANCED}, 
+       {"reset on zero vc", P_BOOL, P_GLOBAL, &Globals.bResetOnZeroVC, NULL, NULL, FLAG_ADVANCED}, 
 
        {"acl compatibility", P_STRING, P_GLOBAL, &Globals.szAclCompat, handle_acl_compatibility,  NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
        {"defer sharing violations", P_BOOL, P_GLOBAL, &Globals.bDeferSharingViolations, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL},
@@ -960,7 +995,7 @@ static struct parm_struct parm_table[] = {
        {"client use spnego", P_BOOL, P_GLOBAL, &Globals.bClientUseSpnego, NULL, NULL, FLAG_ADVANCED}, 
 
        {"enable asu support", P_BOOL, P_GLOBAL, &Globals.bASUSupport, NULL, NULL, FLAG_ADVANCED}, 
-       {"enable svcctl", P_LIST, P_GLOBAL, &Globals.szServicesList, NULL, NULL, FLAG_ADVANCED},
+       {"svcctl list", P_LIST, P_GLOBAL, &Globals.szServicesList, NULL, NULL, FLAG_ADVANCED},
 
        {N_("Tuning Options"), P_SEP, P_SEPARATOR}, 
 
@@ -970,6 +1005,7 @@ static struct parm_struct parm_table[] = {
        {"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL, NULL, FLAG_ADVANCED}, 
        {"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL, NULL, FLAG_ADVANCED}, 
        {"kernel change notify", P_BOOL, P_GLOBAL, &Globals.bKernelChangeNotify, NULL, NULL, FLAG_ADVANCED}, 
+       {"fam change notify", P_BOOL, P_GLOBAL, &Globals.bFamChangeNotify, NULL, NULL, FLAG_ADVANCED},
 
        {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL, NULL, FLAG_ADVANCED}, 
        {"max smbd processes", P_INTEGER, P_GLOBAL, &Globals.iMaxSmbdProcesses, NULL, NULL, FLAG_ADVANCED}, 
@@ -1003,6 +1039,7 @@ static struct parm_struct parm_table[] = {
        {"printing", P_ENUM, P_LOCAL, &sDefault.iPrinting, handle_printing, enum_printing, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, 
        {"cups options", P_STRING, P_LOCAL, &sDefault.szCupsOptions, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, 
        {"cups server", P_STRING, P_GLOBAL, &Globals.szCupsServer, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, 
+       {"iprint server", P_STRING, P_GLOBAL, &Globals.szIPrintServer, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, 
        {"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, 
        {"disable spoolss", P_BOOL, P_GLOBAL, &Globals.bDisableSpoolss, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL}, 
        {"enable spoolss", P_BOOLREV, P_GLOBAL, &Globals.bDisableSpoolss, NULL, NULL, FLAG_HIDE}, 
@@ -1043,9 +1080,10 @@ static struct parm_struct parm_table[] = {
        {"veto files", P_STRING, P_LOCAL, &sDefault.szVetoFiles, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL }, 
        {"hide files", P_STRING, P_LOCAL, &sDefault.szHideFiles, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL }, 
        {"veto oplock files", P_STRING, P_LOCAL, &sDefault.szVetoOplockFiles, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL }, 
-       {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
-       {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
        {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
+       {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
+       {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
+       {"map readonly", P_ENUM, P_LOCAL, &sDefault.iMap_readonly, NULL, enum_map_readonly, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
        {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
        {"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL | FLAG_DEPRECATED }, 
        {"max stat cache size", P_INTEGER, P_GLOBAL, &Globals.iMaxStatCacheSize, NULL, NULL, FLAG_ADVANCED}, 
@@ -1059,6 +1097,7 @@ static struct parm_struct parm_table[] = {
        {N_("Logon Options"), P_SEP, P_SEPARATOR}, 
 
        {"add user script", P_STRING, P_GLOBAL, &Globals.szAddUserScript, NULL, NULL, FLAG_ADVANCED}, 
+        {"rename user script", P_STRING, P_GLOBAL, &Globals.szRenameUserScript, NULL, NULL, FLAG_ADVANCED},
        {"delete user script", P_STRING, P_GLOBAL, &Globals.szDelUserScript, NULL, NULL, FLAG_ADVANCED}, 
        {"add group script", P_STRING, P_GLOBAL, &Globals.szAddGroupScript, NULL, NULL, FLAG_ADVANCED}, 
        {"delete group script", P_STRING, P_GLOBAL, &Globals.szDelGroupScript, NULL, NULL, FLAG_ADVANCED}, 
@@ -1068,6 +1107,7 @@ static struct parm_struct parm_table[] = {
        {"add machine script", P_STRING, P_GLOBAL, &Globals.szAddMachineScript, NULL, NULL, FLAG_ADVANCED}, 
        {"shutdown script", P_STRING, P_GLOBAL, &Globals.szShutdownScript, NULL, NULL, FLAG_ADVANCED}, 
        {"abort shutdown script", P_STRING, P_GLOBAL, &Globals.szAbortShutdownScript, NULL, NULL, FLAG_ADVANCED}, 
+       {"username map script", P_STRING, P_GLOBAL, &Globals.szUsernameMapScript, NULL, NULL, FLAG_ADVANCED}, 
 
        {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL, NULL, FLAG_ADVANCED}, 
        {"logon path", P_STRING, P_GLOBAL, &Globals.szLogonPath, NULL, NULL, FLAG_ADVANCED}, 
@@ -1143,11 +1183,6 @@ static struct parm_struct parm_table[] = {
        {"delete share command", P_STRING, P_GLOBAL, &Globals.szDeleteShareCommand, NULL, NULL, FLAG_ADVANCED}, 
 
        {N_("EventLog Options"), P_SEP, P_SEPARATOR}, 
-       {"eventlog open command", P_STRING, P_GLOBAL, &Globals.szEventLogOpenCommand, handle_eventlog, NULL, FLAG_ADVANCED},
-       {"eventlog read command", P_STRING, P_GLOBAL, &Globals.szEventLogReadCommand, handle_eventlog, NULL, FLAG_ADVANCED}, 
-       {"eventlog clear command", P_STRING, P_GLOBAL, &Globals.szEventLogClearCommand, handle_eventlog, NULL, FLAG_ADVANCED},
-       {"eventlog num records command", P_STRING, P_GLOBAL, &Globals.szEventLogNumRecordsCommand, handle_eventlog, NULL, FLAG_ADVANCED},
-       {"eventlog oldest record command", P_STRING, P_GLOBAL, &Globals.szEventLogOldestRecordCommand, handle_eventlog, NULL, FLAG_ADVANCED},
        {"eventlog list",  P_LIST, P_GLOBAL, &Globals.szEventLogs, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE}, 
        
        {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL, NULL, FLAG_HIDE}, 
@@ -1165,7 +1200,8 @@ static struct parm_struct parm_table[] = {
        {"default service", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL, FLAG_ADVANCED}, 
        {"default", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL, FLAG_ADVANCED}, 
        {"message command", P_STRING, P_GLOBAL, &Globals.szMsgCommand, NULL, NULL, FLAG_ADVANCED}, 
-       {"dfree command", P_STRING, P_GLOBAL, &Globals.szDfree, NULL, NULL, FLAG_ADVANCED}, 
+       {"dfree cache time", P_INTEGER, P_LOCAL, &sDefault.iDfreeCacheTime, NULL, NULL, FLAG_ADVANCED}, 
+       {"dfree command", P_STRING, P_LOCAL, &sDefault.szDfree, NULL, NULL, FLAG_ADVANCED}, 
        {"get quota command", P_STRING, P_GLOBAL, &Globals.szGetQuota, NULL, NULL, FLAG_ADVANCED}, 
        {"set quota command", P_STRING, P_GLOBAL, &Globals.szSetQuota, NULL, NULL, FLAG_ADVANCED}, 
        {"remote announce", P_STRING, P_GLOBAL, &Globals.szRemoteAnnounce, NULL, NULL, FLAG_ADVANCED}, 
@@ -1190,6 +1226,12 @@ static struct parm_struct parm_table[] = {
        {"root preexec close", P_BOOL, P_LOCAL, &sDefault.bRootpreexecClose, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
        {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, 
        {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, 
+       {"usershare max shares", P_INTEGER, P_GLOBAL, &Globals.iUsershareMaxShares, NULL, NULL, FLAG_ADVANCED},
+       {"usershare owner only", P_BOOL, P_GLOBAL, &Globals.bUsershareOwnerOnly, NULL, NULL, FLAG_ADVANCED}, 
+       {"usershare path", P_STRING, P_GLOBAL, &Globals.szUsersharePath, NULL, NULL, FLAG_ADVANCED},
+       {"usershare prefix allow list", P_LIST, P_GLOBAL, &Globals.szUsersharePrefixAllowList, NULL, NULL, FLAG_ADVANCED}, 
+       {"usershare prefix deny list", P_LIST, P_GLOBAL, &Globals.szUsersharePrefixDenyList, NULL, NULL, FLAG_ADVANCED}, 
+       {"usershare template share", P_STRING, P_GLOBAL, &Globals.szUsershareTemplateShare, NULL, NULL, FLAG_ADVANCED},
        {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE }, 
        {"fstype", P_STRING, P_LOCAL, &sDefault.fstype, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
        {"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, 
@@ -1218,7 +1260,7 @@ static struct parm_struct parm_table[] = {
 
        {N_("Winbind options"), P_SEP, P_SEPARATOR}, 
 
-       {"enable rid algorithm", P_BOOL, P_GLOBAL, &Globals.bEnableRidAlgorithm, NULL, NULL, FLAG_DEPRECATED}, 
+       {"passdb expand explicit", P_BOOL, P_GLOBAL, &Globals.bPassdbExpandExplicit, NULL, NULL, FLAG_ADVANCED},
        {"idmap backend", P_LIST, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED}, 
        {"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED}, 
        {"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_HIDE}, 
@@ -1235,6 +1277,8 @@ static struct parm_struct parm_table[] = {
        {"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED}, 
        {"winbind max idle children", P_INTEGER, P_GLOBAL, &Globals.winbind_max_idle_children, NULL, NULL, FLAG_ADVANCED}, 
        {"winbind nss info", P_LIST, P_GLOBAL, &Globals.szWinbindNssInfo, NULL, NULL, FLAG_ADVANCED}, 
+       {"winbind refresh tickets", P_BOOL, P_GLOBAL, &Globals.bWinbindRefreshTickets, NULL, NULL, FLAG_ADVANCED}, 
+       {"winbind offline logon", P_BOOL, P_GLOBAL, &Globals.bWinbindOfflineLogon, NULL, NULL, FLAG_ADVANCED},
 
        {NULL,  P_BOOL,  P_NONE,  NULL,  NULL,  NULL,  0}
 };
@@ -1268,6 +1312,7 @@ static void init_printer_values(service *pService)
                        break;
 
                case PRINT_CUPS:
+               case PRINT_IPRINT:
 #ifdef HAVE_CUPS
                        /* set the lpq command to contain the destination printer
                           name only.  This is used by cups_queue_get() */
@@ -1328,11 +1373,17 @@ static void init_printer_values(service *pService)
  Initialise the global parameter structure.
 ***************************************************************************/
 
-static void init_globals(void)
+static void init_globals(BOOL first_time_only)
 {
        static BOOL done_init = False;
        pstring s;
 
+        /* If requested to initialize only once and we've already done it... */
+        if (first_time_only && done_init) {
+                /* ... then we have nothing more to do */
+                return;
+        }
+
        if (!done_init) {
                int i;
 
@@ -1404,6 +1455,9 @@ static void init_globals(void)
        slprintf(s, sizeof(s) - 1, "%d.%d", DEFAULT_MAJOR_VERSION,
                 DEFAULT_MINOR_VERSION);
        string_set(&Globals.szAnnounceVersion, s);
+#ifdef DEVELOPER
+       string_set(&Globals.szPanicAction, "/bin/sleep 999999999");
+#endif
 
        pstrcpy(user_socket_options, DEFAULT_SOCKET_OPTIONS);
 
@@ -1419,6 +1473,7 @@ static void init_globals(void)
 
        Globals.bLoadPrinters = True;
        Globals.PrintcapCacheTime = 750;        /* 12.5 minutes */
+
        /* Was 65535 (0xFFFF). 0x4101 matches W2K and causes major speed improvements... */
        /* Discovered by 2 days of pain by Don McCall @ HP :-). */
        Globals.max_xmit = 0x4104;
@@ -1458,6 +1513,7 @@ static void init_globals(void)
        Globals.machine_password_timeout = 60 * 60 * 24 * 7;    /* 7 days default. */
        Globals.change_notify_timeout = 60;     /* 1 minute default. */
        Globals.bKernelChangeNotify = True;     /* On if we have it. */
+       Globals.bFamChangeNotify = True;        /* On if we have it. */
        Globals.lm_announce = 2;        /* = Auto: send only if LM clients found */
        Globals.lm_interval = 60;
        Globals.announce_as = ANNOUNCE_AS_NT_SERVER;
@@ -1498,20 +1554,19 @@ static void init_globals(void)
        Globals.bUseMmap = True;
 #endif
        Globals.bUnixExtensions = True;
+       Globals.bResetOnZeroVC = False;
 
        /* hostname lookups can be very expensive and are broken on
           a large number of sites (tridge) */
        Globals.bHostnameLookups = False;
 
-       str_list_free(&Globals.szPassdbBackend);
 #ifdef WITH_LDAP_SAMCONFIG
        string_set(&Globals.szLdapServer, "localhost");
        Globals.ldap_port = 636;
-       Globals.szPassdbBackend = str_list_make("ldapsam_compat", NULL);
+       string_set(&Globals.szPassdbBackend, "ldapsam_compat");
 #else
-       Globals.szPassdbBackend = str_list_make("smbpasswd", NULL);
+       string_set(&Globals.szPassdbBackend, "smbpasswd");
 #endif /* WITH_LDAP_SAMCONFIG */
-
        string_set(&Globals.szLdapSuffix, "");
        string_set(&Globals.szLdapMachineSuffix, "");
        string_set(&Globals.szLdapUserSuffix, "");
@@ -1565,12 +1620,7 @@ static void init_globals(void)
        string_set(&Globals.szWinbindSeparator, "\\");
        string_set(&Globals.szAclCompat, "");
        string_set(&Globals.szCupsServer, "");
-
-       string_set(&Globals.szEventLogOpenCommand, "");
-       string_set(&Globals.szEventLogReadCommand, "");
-       string_set(&Globals.szEventLogClearCommand, "");
-       string_set(&Globals.szEventLogNumRecordsCommand, "");
-       string_set(&Globals.szEventLogOldestRecordCommand, "");
+       string_set(&Globals.szIPrintServer, "");
 
        Globals.winbind_cache_time = 300;       /* 5 minutes */
        Globals.bWinbindEnumUsers = True;
@@ -1580,8 +1630,10 @@ static void init_globals(void)
        Globals.bWinbindNestedGroups = False;
        Globals.winbind_max_idle_children = 3;
        Globals.szWinbindNssInfo = str_list_make("template", NULL);
+       Globals.bWinbindRefreshTickets = False;
+       Globals.bWinbindOfflineLogon = False;
 
-       Globals.bEnableRidAlgorithm = True;
+       Globals.bPassdbExpandExplicit = True;
 
        Globals.name_cache_timeout = 660; /* In seconds */
 
@@ -1594,15 +1646,17 @@ static void init_globals(void)
        Globals.bDeferSharingViolations = True;
        string_set(&Globals.smb_ports, SMB_PORTS);
 
-       /* don't enable privileges by default since Domain 
-          Admins can then assign thr rights to perform certain 
-          operations as root */
-
-       Globals.bEnablePrivileges = False;
+       Globals.bEnablePrivileges = True;
+       Globals.bASUSupport       = False;
        
-       Globals.bASUSupport       = True;
-       
-       Globals.szServicesList = str_list_make( "Spooler NETLOGON", NULL );
+       /* User defined shares. */
+       pstrcpy(s, dyn_LOCKDIR);
+       pstrcat(s, "/usershares");
+       string_set(&Globals.szUsersharePath, s);
+       string_set(&Globals.szUsershareTemplateShare, "");
+       Globals.iUsershareMaxShares = 0;
+       /* By default disallow sharing of directories not owned by the sharer. */
+       Globals.bUsershareOwnerOnly = True;
 }
 
 static TALLOC_CTX *lp_talloc;
@@ -1619,6 +1673,19 @@ void lp_talloc_free(void)
        lp_talloc = NULL;
 }
 
+TALLOC_CTX *tmp_talloc_ctx(void)
+{
+       if (lp_talloc == NULL) {
+               lp_talloc = talloc_init(NULL);
+       }
+
+       if (lp_talloc == NULL) {
+               smb_panic("Could not create temporary talloc context\n");
+       }
+
+       return lp_talloc;
+}
+
 /*******************************************************************
  Convenience routine to grab string parameters into temporary memory
  and run standard_sub_basic on them. The buffers can be written to by
@@ -1709,7 +1776,6 @@ FN_GLOBAL_BOOL(lp_utmp, &Globals.bUtmp)
 FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir)
 FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
 FN_GLOBAL_STRING(lp_msg_command, &Globals.szMsgCommand)
-FN_GLOBAL_STRING(lp_dfree_command, &Globals.szDfree)
 FN_GLOBAL_STRING(lp_get_quota_command, &Globals.szGetQuota)
 FN_GLOBAL_STRING(lp_set_quota_command, &Globals.szSetQuota)
 FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv)
@@ -1735,10 +1801,11 @@ FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
 FN_GLOBAL_STRING(lp_nis_home_map_name, &Globals.szNISHomeMapName)
 static FN_GLOBAL_STRING(lp_announce_version, &Globals.szAnnounceVersion)
 FN_GLOBAL_LIST(lp_netbios_aliases, &Globals.szNetbiosAliases)
-FN_GLOBAL_LIST(lp_passdb_backend, &Globals.szPassdbBackend)
+FN_GLOBAL_STRING(lp_passdb_backend, &Globals.szPassdbBackend)
 FN_GLOBAL_LIST(lp_preload_modules, &Globals.szPreloadModules)
 FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction)
 FN_GLOBAL_STRING(lp_adduser_script, &Globals.szAddUserScript)
+FN_GLOBAL_STRING(lp_renameuser_script, &Globals.szRenameUserScript)
 FN_GLOBAL_STRING(lp_deluser_script, &Globals.szDelUserScript)
 
 FN_GLOBAL_CONST_STRING(lp_guestaccount, &Globals.szGuestaccount)
@@ -1752,6 +1819,7 @@ FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript)
 
 FN_GLOBAL_STRING(lp_shutdown_script, &Globals.szShutdownScript)
 FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript)
+FN_GLOBAL_STRING(lp_username_map_script, &Globals.szUsernameMapScript)
 
 FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript)
 
@@ -1766,10 +1834,11 @@ FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
 FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
 FN_GLOBAL_BOOL(lp_winbind_trusted_domains_only, &Globals.bWinbindTrustedDomainsOnly)
 FN_GLOBAL_BOOL(lp_winbind_nested_groups, &Globals.bWinbindNestedGroups)
-
+FN_GLOBAL_BOOL(lp_winbind_refresh_tickets, &Globals.bWinbindRefreshTickets)
+FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
 
 FN_GLOBAL_LIST(lp_idmap_backend, &Globals.szIdmapBackend)
-FN_GLOBAL_BOOL(lp_enable_rid_algorithm, &Globals.bEnableRidAlgorithm)
+FN_GLOBAL_BOOL(lp_passdb_expand_explicit, &Globals.bPassdbExpandExplicit)
 
 #ifdef WITH_LDAP_SAMCONFIG
 FN_GLOBAL_STRING(lp_ldap_server, &Globals.szLdapServer)
@@ -1786,16 +1855,15 @@ FN_GLOBAL_INTEGER(lp_ldap_page_size, &Globals.ldap_page_size)
 FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand)
 FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand)
 FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand)
+FN_GLOBAL_STRING(lp_usershare_path, &Globals.szUsersharePath)
+FN_GLOBAL_LIST(lp_usershare_prefix_allow_list, &Globals.szUsersharePrefixAllowList)
+FN_GLOBAL_LIST(lp_usershare_prefix_deny_list, &Globals.szUsersharePrefixDenyList)
 
-FN_GLOBAL_STRING(lp_eventlog_open_cmd, &Globals.szEventLogOpenCommand)
-FN_GLOBAL_STRING(lp_eventlog_read_cmd, &Globals.szEventLogReadCommand)
-FN_GLOBAL_STRING(lp_eventlog_clear_cmd, &Globals.szEventLogClearCommand)
-FN_GLOBAL_STRING(lp_eventlog_num_records_cmd, &Globals.szEventLogNumRecordsCommand)
-FN_GLOBAL_STRING(lp_eventlog_oldest_record_cmd, &Globals.szEventLogOldestRecordCommand)
-FN_GLOBAL_STRING(lp_eventlog_close_cmd, &Globals.szEventLogCloseCommand)
 FN_GLOBAL_LIST(lp_eventlog_list, &Globals.szEventLogs)
 
+FN_GLOBAL_BOOL(lp_usershare_owner_only, &Globals.bUsershareOwnerOnly)
 FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios)
+FN_GLOBAL_BOOL(lp_reset_on_zero_vc, &Globals.bResetOnZeroVC)
 FN_GLOBAL_BOOL(lp_ms_add_printer_wizard, &Globals.bMsAddPrinterWizard)
 FN_GLOBAL_BOOL(lp_dns_proxy, &Globals.bDNSproxy)
 FN_GLOBAL_BOOL(lp_wins_support, &Globals.bWINSsupport)
@@ -1847,6 +1915,7 @@ FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
 FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego)
 FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
 FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify)
+FN_GLOBAL_BOOL(lp_fam_change_notify, &Globals.bFamChangeNotify)
 FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab)
 FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations)
 FN_GLOBAL_BOOL(lp_enable_privileges, &Globals.bEnablePrivileges)
@@ -1881,6 +1950,8 @@ FN_GLOBAL_INTEGER(lp_map_to_guest, &Globals.map_to_guest)
 FN_GLOBAL_INTEGER(lp_oplock_break_wait_time, &Globals.oplock_break_wait_time)
 FN_GLOBAL_INTEGER(lp_lock_spin_count, &Globals.iLockSpinCount)
 FN_GLOBAL_INTEGER(lp_lock_sleep_time, &Globals.iLockSpinTime)
+FN_GLOBAL_INTEGER(lp_usershare_max_shares, &Globals.iUsershareMaxShares)
+
 FN_LOCAL_STRING(lp_preexec, szPreExec)
 FN_LOCAL_STRING(lp_postexec, szPostExec)
 FN_LOCAL_STRING(lp_rootpreexec, szRootPreExec)
@@ -1893,9 +1964,10 @@ FN_LOCAL_STRING(lp_username, szUsername)
 FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers)
 FN_LOCAL_LIST(lp_valid_users, szValidUsers)
 FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
-FN_GLOBAL_LIST(lp_enable_svcctl, &Globals.szServicesList)
+FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList)
 FN_LOCAL_STRING(lp_cups_options, szCupsOptions)
 FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer)
+FN_GLOBAL_STRING(lp_iprint_server, &Globals.szIPrintServer)
 FN_LOCAL_STRING(lp_printcommand, szPrintcommand)
 FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand)
 FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand)
@@ -1924,6 +1996,7 @@ FN_LOCAL_STRING(lp_hide_files, szHideFiles)
 FN_LOCAL_STRING(lp_veto_oplocks, szVetoOplockFiles)
 FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
 FN_LOCAL_STRING(lp_aio_write_behind, szAioWriteBehind)
+FN_LOCAL_STRING(lp_dfree_command, szDfree)
 FN_LOCAL_BOOL(lp_autoloaded, autoloaded)
 FN_LOCAL_BOOL(lp_preexec_close, bPreexecClose)
 FN_LOCAL_BOOL(lp_rootpreexec_close, bRootpreexecClose)
@@ -1979,6 +2052,7 @@ FN_LOCAL_BOOL(lp_profile_acls, bProfileAcls)
 FN_LOCAL_BOOL(lp_map_acl_inherit, bMap_acl_inherit)
 FN_LOCAL_BOOL(lp_afs_share, bAfs_Share)
 FN_LOCAL_BOOL(lp_acl_check_permissions, bAclCheckPermissions)
+FN_LOCAL_BOOL(lp_acl_group_control, bAclGroupControl)
 FN_LOCAL_BOOL(lp_acl_map_full_control, bAclMapFullControl)
 FN_LOCAL_INTEGER(lp_create_mask, iCreate_mask)
 FN_LOCAL_INTEGER(lp_force_create_mode, iCreate_force_mode)
@@ -1997,9 +2071,11 @@ FN_LOCAL_INTEGER(lp_oplock_contention_limit, iOplockContentionLimit)
 FN_LOCAL_INTEGER(lp_csc_policy, iCSCPolicy)
 FN_LOCAL_INTEGER(lp_write_cache_size, iWriteCacheSize)
 FN_LOCAL_INTEGER(lp_block_size, iBlock_size)
-FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size);
-FN_LOCAL_INTEGER(lp_aio_read_size, iAioReadSize);
-FN_LOCAL_INTEGER(lp_aio_write_size, iAioWriteSize);
+FN_LOCAL_INTEGER(lp_dfree_cache_time, iDfreeCacheTime)
+FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size)
+FN_LOCAL_INTEGER(lp_aio_read_size, iAioReadSize)
+FN_LOCAL_INTEGER(lp_aio_write_size, iAioWriteSize)
+FN_LOCAL_INTEGER(lp_map_readonly, iMap_readonly)
 FN_LOCAL_CHAR(lp_magicchar, magic_char)
 FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
 FN_GLOBAL_INTEGER(lp_winbind_max_idle_children, &Globals.winbind_max_idle_children)
@@ -2021,6 +2097,9 @@ static BOOL service_ok(int iService);
 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue);
 static BOOL do_section(const char *pszSectionName);
 static void init_copymap(service * pservice);
+static BOOL hash_a_service(const char *name, int number);
+static void free_service_byindex(int iService);
+static char * canonicalize_servicename(const char *name);
 
 /* This is a helper function for parametrical options support. */
 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
@@ -2313,6 +2392,31 @@ static void free_service(service *pservice)
        ZERO_STRUCTP(pservice);
 }
 
+
+/***************************************************************************
+ remove a service indexed in the ServicePtrs array from the ServiceHash
+ and free the dynamically allocated parts
+***************************************************************************/
+
+static void free_service_byindex(int idx)
+{
+       if ( !LP_SNUM_OK(idx) ) 
+               return;
+
+       ServicePtrs[idx]->valid = False;
+       invalid_services[num_invalid_services++] = idx;
+
+       /* we have to cleanup the hash record */
+
+       if (ServicePtrs[idx]->szService) {
+               char *canon_name = canonicalize_servicename( ServicePtrs[idx]->szService );
+               
+               tdb_delete_bystring(ServiceHash, canon_name );
+       }
+
+       free_service(ServicePtrs[idx]);
+}
+
 /***************************************************************************
  Add a new service to the services array initialising it with the given 
  service. 
@@ -2348,32 +2452,41 @@ static int add_a_service(const service *pservice, const char *name)
        }
 
        /* find an invalid one */
-       for (i = 0; i < iNumServices; i++)
-               if (!ServicePtrs[i]->valid)
-                       break;
+       i = iNumServices;
+       if (num_invalid_services > 0) {
+               i = invalid_services[--num_invalid_services];
+       }
 
        /* if not, then create one */
        if (i == iNumServices) {
                service **tsp;
+               int *tinvalid;
                
                tsp = SMB_REALLOC_ARRAY(ServicePtrs, service *, num_to_alloc);
-                                          
-               if (!tsp) {
+               if (tsp == NULL) {
                        DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
                        return (-1);
                }
-               else {
-                       ServicePtrs = tsp;
-                       ServicePtrs[iNumServices] = SMB_MALLOC_P(service);
-               }
+               ServicePtrs = tsp;
+               ServicePtrs[iNumServices] = SMB_MALLOC_P(service);
                if (!ServicePtrs[iNumServices]) {
                        DEBUG(0,("add_a_service: out of memory!\n"));
                        return (-1);
                }
-
                iNumServices++;
-       } else
-               free_service(ServicePtrs[i]);
+
+               /* enlarge invalid_services here for now... */
+               tinvalid = SMB_REALLOC_ARRAY(invalid_services, int,
+                                            num_to_alloc);
+               if (tinvalid == NULL) {
+                       DEBUG(0,("add_a_service: failed to enlarge "
+                                "invalid_services!\n"));
+                       return (-1);
+               }
+               invalid_services = tinvalid;
+       } else {
+               free_service_byindex(i);
+       }
 
        ServicePtrs[i]->valid = True;
 
@@ -2384,10 +2497,62 @@ static int add_a_service(const service *pservice, const char *name)
                
        DEBUG(8,("add_a_service: Creating snum = %d for %s\n", 
                i, ServicePtrs[i]->szService));
+
+       if (!hash_a_service(ServicePtrs[i]->szService, i)) {
+               return (-1);
+       }
                
        return (i);
 }
 
+/***************************************************************************
+  Convert a string to uppercase and remove whitespaces.
+***************************************************************************/
+
+static char *canonicalize_servicename(const char *src)
+{
+       static fstring canon; /* is fstring large enough? */
+
+       if ( !src ) {
+               DEBUG(0,("canonicalize_servicename: NULL source name!\n"));
+               return NULL;
+       }
+
+       fstrcpy( canon, src );
+       strlower_m( canon );
+
+       return canon;
+}
+
+/***************************************************************************
+  Add a name/index pair for the services array to the hash table.
+***************************************************************************/
+
+static BOOL hash_a_service(const char *name, int idx)
+{
+       char *canon_name;
+
+       if ( !ServiceHash ) {
+               DEBUG(10,("hash_a_service: creating tdb servicehash\n"));
+               ServiceHash = tdb_open("servicehash", 1031, TDB_INTERNAL, 
+                                        (O_RDWR|O_CREAT), 0600);
+               if ( !ServiceHash ) {
+                       DEBUG(0,("hash_a_service: open tdb servicehash failed!\n"));
+                       return False;
+               }
+       }
+
+       DEBUG(10,("hash_a_service: hashing index %d for service name %s\n",
+               idx, name));
+
+       if ( !(canon_name = canonicalize_servicename( name )) )
+               return False;
+
+        tdb_store_int32(ServiceHash, canon_name, idx);
+
+       return True;
+}
+
 /***************************************************************************
  Add a new home service, with the specified home directory, defaults coming 
  from service ifrom.
@@ -2417,7 +2582,7 @@ BOOL lp_add_home(const char *pszHomename, int iDefaultService,
                string_set(&ServicePtrs[i]->comment, comment);
        }
 
-       /* set the browseable flag from the gloabl default */
+       /* set the browseable flag from the global default */
 
        ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
 
@@ -2620,15 +2785,23 @@ Find a service by name. Otherwise works like get_service.
 
 static int getservicebyname(const char *pszServiceName, service * pserviceDest)
 {
-       int iService;
+       int iService = -1;
+       char *canon_name;
+
+       if (ServiceHash != NULL) {
+               if ( !(canon_name = canonicalize_servicename( pszServiceName )) )
+                       return -1;
+
+               iService = tdb_fetch_int32(ServiceHash, canon_name );
 
-       for (iService = iNumServices - 1; iService >= 0; iService--)
-               if (VALID(iService) &&
-                   strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0) {
-                       if (pserviceDest != NULL)
+               if (LP_SNUM_OK(iService)) {
+                       if (pserviceDest != NULL) {
                                copy_service(pserviceDest, ServicePtrs[iService], NULL);
-                       break;
+                       }
+               } else {
+                       iService = -1;
                }
+       }
 
        return (iService);
 }
@@ -2885,11 +3058,7 @@ static BOOL handle_charset(int snum, const char *pszParmValue, char **ptr)
        return True;
 }
 
-static BOOL handle_eventlog(int snum, const char *pszParmValue, char **ptr)
-{
-       string_set(ptr, pszParmValue);
-       return True;
-}
+
 
 static BOOL handle_workgroup(int snum, const char *pszParmValue, char **ptr)
 {
@@ -3331,7 +3500,10 @@ BOOL lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue
                        break;
 
                case P_OCTAL:
-                       sscanf(pszParmValue, "%o", (int *)parm_ptr);
+                       i = sscanf(pszParmValue, "%o", (int *)parm_ptr);
+                       if ( i != 1 ) {
+                           DEBUG ( 0, ("Invalid octal number %s\n", pszParmName ));
+                       }
                        break;
 
                case P_LIST:
@@ -3685,13 +3857,13 @@ static void dump_a_service(service * pService, FILE * f)
                }
        }
 
-       if (pService->param_opt != NULL) {
-               data = pService->param_opt;
-               while(data) {
-                       fprintf(f, "\t%s = %s\n", data->key, data->value);
-                       data = data->next;
-               }
-       }
+               if (pService->param_opt != NULL) {
+                       data = pService->param_opt;
+                       while(data) {
+                               fprintf(f, "\t%s = %s\n", data->key, data->value);
+                               data = data->next;
+                       }
+               }
 }
 
 /***************************************************************************
@@ -3896,13 +4068,14 @@ void lp_killunused(BOOL (*snumused) (int))
                if (!VALID(i))
                        continue;
 
-               /* don't kill autoloaded services */
-               if ( ServicePtrs[i]->autoloaded )
+               /* don't kill autoloaded or usershare services */
+               if ( ServicePtrs[i]->autoloaded ||
+                               ServicePtrs[i]->usershare == USERSHARE_VALID) {
                        continue;
+               }
 
                if (!snumused || !snumused(i)) {
-                       ServicePtrs[i]->valid = False;
-                       free_service(ServicePtrs[i]);
+                       free_service_byindex(i);
                }
        }
 }
@@ -3914,8 +4087,7 @@ void lp_killunused(BOOL (*snumused) (int))
 void lp_killservice(int iServiceIn)
 {
        if (VALID(iServiceIn)) {
-               ServicePtrs[iServiceIn]->valid = False;
-               free_service(ServicePtrs[iServiceIn]);
+               free_service_byindex(iServiceIn);
        }
 }
 
@@ -3978,6 +4150,28 @@ static void lp_save_defaults(void)
  Set the server type we will announce as via nmbd.
 ********************************************************************/
 
+static const struct srv_role_tab {
+       uint32 role;
+       const char *role_str;
+} srv_role_tab [] = {
+       { ROLE_STANDALONE, "ROLE_STANDALONE" },
+       { ROLE_DOMAIN_MEMBER, "ROLE_DOMAIN_MEMBER" },
+       { ROLE_DOMAIN_BDC, "ROLE_DOMAIN_BDC" },
+       { ROLE_DOMAIN_PDC, "ROLE_DOMAIN_PDC" },
+       { 0, NULL }
+};
+
+const char* server_role_str(uint32 role)
+{
+       int i = 0;
+       for (i=0; srv_role_tab[i].role_str; i++) {
+               if (role == srv_role_tab[i].role) {
+                       return srv_role_tab[i].role_str;
+               }
+       }
+       return NULL;
+}
+
 static void set_server_role(void)
 {
        server_role = ROLE_STANDALONE;
@@ -4021,27 +4215,13 @@ static void set_server_role(void)
                        break;
        }
 
-       DEBUG(10, ("set_server_role: role = "));
-
-       switch(server_role) {
-       case ROLE_STANDALONE:
-               DEBUGADD(10, ("ROLE_STANDALONE\n"));
-               break;
-       case ROLE_DOMAIN_MEMBER:
-               DEBUGADD(10, ("ROLE_DOMAIN_MEMBER\n"));
-               break;
-       case ROLE_DOMAIN_BDC:
-               DEBUGADD(10, ("ROLE_DOMAIN_BDC\n"));
-               break;
-       case ROLE_DOMAIN_PDC:
-               DEBUGADD(10, ("ROLE_DOMAIN_PDC\n"));
-               break;
-       }
+       DEBUG(10, ("set_server_role: role = %s\n", server_role_str(server_role)));
 }
 
 /***********************************************************
  If we should send plaintext/LANMAN passwords in the clinet
 ************************************************************/
+
 static void set_allowed_client_auth(void)
 {
        if (Globals.bClientNTLMv2Auth) {
@@ -4052,13 +4232,621 @@ static void set_allowed_client_auth(void)
        }
 }
 
+/***************************************************************************
+ JRA.
+ The following code allows smbd to read a user defined share file.
+ Yes, this is my intent. Yes, I'm comfortable with that...
+
+ THE FOLLOWING IS SECURITY CRITICAL CODE.
+
+ It washes your clothes, it cleans your house, it guards you while you sleep...
+ Do not f%^k with it....
+***************************************************************************/
+
+#define MAX_USERSHARE_FILE_SIZE (10*1024)
+
+/***************************************************************************
+ Check allowed stat state of a usershare file.
+ Ensure we print out who is dicking with us so the admin can
+ get their sorry ass fired.
+***************************************************************************/
+
+static BOOL check_usershare_stat(const char *fname, SMB_STRUCT_STAT *psbuf)
+{
+       if (!S_ISREG(psbuf->st_mode)) {
+               DEBUG(0,("check_usershare_stat: file %s owned by uid %u is "
+                       "not a regular file\n",
+                       fname, (unsigned int)psbuf->st_uid ));
+               return False;
+       }
+
+       /* Ensure this doesn't have the other write bit set. */
+       if (psbuf->st_mode & S_IWOTH) {
+               DEBUG(0,("check_usershare_stat: file %s owned by uid %u allows "
+                       "public write. Refusing to allow as a usershare file.\n",
+                       fname, (unsigned int)psbuf->st_uid ));
+               return False;
+       }
+
+       /* Should be 10k or less. */
+       if (psbuf->st_size > MAX_USERSHARE_FILE_SIZE) {
+               DEBUG(0,("check_usershare_stat: file %s owned by uid %u is "
+                       "too large (%u) to be a user share file.\n",
+                       fname, (unsigned int)psbuf->st_uid,
+                       (unsigned int)psbuf->st_size ));
+               return False;
+       }
+
+       return True;
+}
+
+/***************************************************************************
+ Parse the contents of a usershare file.
+***************************************************************************/
+
+enum usershare_err parse_usershare_file(TALLOC_CTX *ctx, 
+                       SMB_STRUCT_STAT *psbuf,
+                       const char *servicename,
+                       int snum,
+                       char **lines,
+                       int numlines,
+                       pstring sharepath,
+                       pstring comment,
+                       SEC_DESC **ppsd)
+{
+       const char **prefixallowlist = lp_usershare_prefix_allow_list();
+       const char **prefixdenylist = lp_usershare_prefix_deny_list();
+       SMB_STRUCT_DIR *dp;
+       SMB_STRUCT_STAT sbuf;
+
+       if (numlines < 4) {
+               return USERSHARE_MALFORMED_FILE;
+       }
+
+       if (!strequal(lines[0], "#VERSION 1")) {
+               return USERSHARE_BAD_VERSION;
+       }
+
+       if (!strnequal(lines[1], "path=", 5)) {
+               return USERSHARE_MALFORMED_PATH;
+       }
+
+       pstrcpy(sharepath, &lines[1][5]);
+       trim_string(sharepath, " ", " ");
+
+       if (!strnequal(lines[2], "comment=", 8)) {
+               return USERSHARE_MALFORMED_COMMENT_DEF;
+       }
+
+       pstrcpy(comment, &lines[2][8]);
+       trim_string(comment, " ", " ");
+       trim_char(comment, '"', '"');
+
+       if (!strnequal(lines[3], "usershare_acl=", 14)) {
+               return USERSHARE_MALFORMED_ACL_DEF;
+       }
+
+       if (!parse_usershare_acl(ctx, &lines[3][14], ppsd)) {
+               return USERSHARE_ACL_ERR;
+       }
+
+       if (snum != -1 && strequal(sharepath, ServicePtrs[snum]->szPath)) {
+               /* Path didn't change, no checks needed. */
+               return USERSHARE_OK;
+       }
+
+       /* The path *must* be absolute. */
+       if (sharepath[0] != '/') {
+               DEBUG(2,("parse_usershare_file: share %s: path %s is not an absolute path.\n",
+                       servicename, sharepath));
+               return USERSHARE_PATH_NOT_ABSOLUTE;
+       }
+
+       /* If there is a usershare prefix deny list ensure one of these paths
+          doesn't match the start of the user given path. */
+       if (prefixdenylist) {
+               int i;
+               for ( i=0; prefixdenylist[i]; i++ ) {
+                       DEBUG(10,("parse_usershare_file: share %s : checking prefixdenylist[%d]='%s' against %s\n",
+                               servicename, i, prefixdenylist[i], sharepath ));
+                       if (memcmp( sharepath, prefixdenylist[i], strlen(prefixdenylist[i])) == 0) {
+                               DEBUG(2,("parse_usershare_file: share %s path %s starts with one of the "
+                                       "usershare prefix deny list entries.\n",
+                                       servicename, sharepath));
+                               return USERSHARE_PATH_IS_DENIED;
+                       }
+               }
+       }
+
+       /* If there is a usershare prefix allow list ensure one of these paths
+          does match the start of the user given path. */
+
+       if (prefixallowlist) {
+               int i;
+               for ( i=0; prefixallowlist[i]; i++ ) {
+                       DEBUG(10,("parse_usershare_file: share %s checking prefixallowlist[%d]='%s' against %s\n",
+                               servicename, i, prefixallowlist[i], sharepath ));
+                       if (memcmp( sharepath, prefixallowlist[i], strlen(prefixallowlist[i])) == 0) {
+                               break;
+                       }
+               }
+               if (prefixallowlist[i] == NULL) {
+                       DEBUG(2,("parse_usershare_file: share %s path %s doesn't start with one of the "
+                               "usershare prefix allow list entries.\n",
+                               servicename, sharepath));
+                       return USERSHARE_PATH_NOT_ALLOWED;
+               }
+        }
+
+       /* Ensure this is pointing to a directory. */
+       dp = sys_opendir(sharepath);
+
+       if (!dp) {
+               DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n",
+                       servicename, sharepath));
+               return USERSHARE_PATH_NOT_DIRECTORY;
+       }
+
+       /* Ensure the owner of the usershare file has permission to share
+          this directory. */
+
+       if (sys_stat(sharepath, &sbuf) == -1) {
+               DEBUG(2,("parse_usershare_file: share %s : stat failed on path %s. %s\n",
+                       servicename, sharepath, strerror(errno) ));
+               sys_closedir(dp);
+               return USERSHARE_POSIX_ERR;
+       }
+
+       sys_closedir(dp);
+
+       if (!S_ISDIR(sbuf.st_mode)) {
+               DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n",
+                       servicename, sharepath ));
+               return USERSHARE_PATH_NOT_DIRECTORY;
+       }
+
+       /* Check if sharing is restricted to owner-only. */
+       /* psbuf is the stat of the usershare definition file,
+          sbuf is the stat of the target directory to be shared. */
+
+       if (lp_usershare_owner_only()) {
+               /* root can share anything. */
+               if ((psbuf->st_uid != 0) && (sbuf.st_uid != psbuf->st_uid)) {
+                       return USERSHARE_PATH_NOT_ALLOWED;
+               }
+       }
+
+       return USERSHARE_OK;
+}
+
+/***************************************************************************
+ Deal with a usershare file.
+ Returns:
+       >= 0 - snum
+       -1 - Bad name, invalid contents.
+          - service name already existed and not a usershare, problem
+           with permissions to share directory etc.
+***************************************************************************/
+
+static int process_usershare_file(const char *dir_name, const char *file_name, int snum_template)
+{
+       SMB_STRUCT_STAT sbuf;
+       SMB_STRUCT_STAT lsbuf;
+       pstring fname;
+       pstring sharepath;
+       pstring comment;
+       fstring service_name;
+       char **lines = NULL;
+       int numlines = 0;
+       int fd = -1;
+       int iService = -1;
+       TALLOC_CTX *ctx = NULL;
+       SEC_DESC *psd = NULL;
+
+       /* Ensure share name doesn't contain invalid characters. */
+       if (!validate_net_name(file_name, INVALID_SHARENAME_CHARS, strlen(file_name))) {
+               DEBUG(0,("process_usershare_file: share name %s contains "
+                       "invalid characters (any of %s)\n",
+                       file_name, INVALID_SHARENAME_CHARS ));
+               return -1;
+       }
+
+       fstrcpy(service_name, file_name);
+
+       pstrcpy(fname, dir_name);
+       pstrcat(fname, "/");
+       pstrcat(fname, file_name);
+
+       /* Minimize the race condition by doing an lstat before we
+          open and fstat. Ensure this isn't a symlink link. */
+
+       if (sys_lstat(fname, &lsbuf) != 0) {
+               DEBUG(0,("process_usershare_file: stat of %s failed. %s\n",
+                       fname, strerror(errno) ));
+               return -1;
+       }
+
+       /* This must be a regular file, not a symlink, directory or
+          other strange filetype. */
+       if (!check_usershare_stat(fname, &lsbuf)) {
+               return -1;
+       }
+
+       /* See if there is already a servicenum for this name. */
+       /* tdb_fetch_int32 returns -1 if not found. */
+       iService = (int)tdb_fetch_int32(ServiceHash, canonicalize_servicename(service_name) );
+
+       if (iService != -1 && ServicePtrs[iService]->usershare_last_mod == lsbuf.st_mtime) {
+               /* Nothing changed - Mark valid and return. */
+               DEBUG(10,("process_usershare_file: service %s not changed.\n",
+                       service_name ));
+               ServicePtrs[iService]->usershare = USERSHARE_VALID;
+               return iService;
+       }
+
+       /* Try and open the file read only - no symlinks allowed. */
+#ifdef O_NOFOLLOW
+       fd = sys_open(fname, O_RDONLY|O_NOFOLLOW, 0);
+#else
+       fd = sys_open(fname, O_RDONLY, 0);
+#endif
+
+       if (fd == -1) {
+               DEBUG(0,("process_usershare_file: unable to open %s. %s\n",
+                       fname, strerror(errno) ));
+               return -1;
+       }
+
+       /* Now fstat to be *SURE* it's a regular file. */
+       if (sys_fstat(fd, &sbuf) != 0) {
+               close(fd);
+               DEBUG(0,("process_usershare_file: fstat of %s failed. %s\n",
+                       fname, strerror(errno) ));
+               return -1;
+       }
+
+       /* Is it the same dev/inode as was lstated ? */
+       if (lsbuf.st_dev != sbuf.st_dev || lsbuf.st_ino != sbuf.st_ino) {
+               close(fd);
+               DEBUG(0,("process_usershare_file: fstat of %s is a different file from lstat. "
+                       "Symlink spoofing going on ?\n", fname ));
+               return -1;
+       }
+
+       /* This must be a regular file, not a symlink, directory or
+          other strange filetype. */
+       if (!check_usershare_stat(fname, &sbuf)) {
+               return -1;
+       }
+
+       lines = fd_lines_load(fd, &numlines, MAX_USERSHARE_FILE_SIZE);
+
+       close(fd);
+       if (lines == NULL) {
+               DEBUG(0,("process_usershare_file: loading file %s owned by %u failed.\n",
+                       fname, (unsigned int)sbuf.st_uid ));
+       }
+
+       /* Should we allow printers to be shared... ? */
+       ctx = talloc_init("usershare_sd_xctx");
+       if (!ctx) {
+               SAFE_FREE(lines);
+               return 1;
+       }
+
+       if (parse_usershare_file(ctx, &sbuf, service_name, iService, lines, numlines, sharepath, comment, &psd) != USERSHARE_OK) {
+               talloc_destroy(ctx);
+               SAFE_FREE(lines);
+               return -1;
+       }
+
+       SAFE_FREE(lines);
+
+       /* Everything ok - add the service possibly using a template. */
+       if (iService < 0) {
+               const service *sp = &sDefault;
+               if (snum_template != -1) {
+                       sp = ServicePtrs[snum_template];
+               }
+
+               if ((iService = add_a_service(sp, service_name)) < 0) {
+                       DEBUG(0, ("process_usershare_file: Failed to add "
+                               "new service %s\n", service_name));
+                       talloc_destroy(ctx);
+                       return -1;
+               }
+
+               /* Read only is controlled by usershare ACL below. */
+               ServicePtrs[iService]->bRead_only = False;
+       }
+
+       /* Write the ACL of the new/modified share. */
+       if (!set_share_security(ctx, service_name, psd)) {
+                DEBUG(0, ("process_usershare_file: Failed to set share "
+                       "security for user share %s\n",
+                       service_name ));
+               lp_remove_service(iService);
+               talloc_destroy(ctx);
+               return -1;
+       }
+
+       talloc_destroy(ctx);
+
+       /* If from a template it may be marked invalid. */
+       ServicePtrs[iService]->valid = True;
+
+       /* Set the service as a valid usershare. */
+       ServicePtrs[iService]->usershare = USERSHARE_VALID;
+
+       /* And note when it was loaded. */
+       ServicePtrs[iService]->usershare_last_mod = sbuf.st_mtime;
+       string_set(&ServicePtrs[iService]->szPath, sharepath);
+       string_set(&ServicePtrs[iService]->comment, comment);
+
+       return iService;
+}
+
+/***************************************************************************
+ Checks if a usershare entry has been modified since last load.
+***************************************************************************/
+
+static BOOL usershare_exists(int iService, time_t *last_mod)
+{
+       SMB_STRUCT_STAT lsbuf;
+       const char *usersharepath = Globals.szUsersharePath;
+       pstring fname;
+
+       pstrcpy(fname, usersharepath);
+       pstrcat(fname, "/");
+       pstrcat(fname, ServicePtrs[iService]->szService);
+
+       if (sys_lstat(fname, &lsbuf) != 0) {
+               return False;
+       }
+
+       if (!S_ISREG(lsbuf.st_mode)) {
+               return False;
+       }
+
+       *last_mod = lsbuf.st_mtime;
+       return True;
+}
+
+/***************************************************************************
+ Load a usershare service by name. Returns a valid servicenumber or -1.
+***************************************************************************/
+
+int load_usershare_service(const char *servicename)
+{
+       SMB_STRUCT_STAT sbuf;
+       const char *usersharepath = Globals.szUsersharePath;
+       int max_user_shares = Globals.iUsershareMaxShares;
+       int snum_template = -1;
+
+       if (*usersharepath == 0 ||  max_user_shares == 0) {
+               return -1;
+       }
+
+       if (sys_stat(usersharepath, &sbuf) != 0) {
+               DEBUG(0,("load_usershare_service: stat of %s failed. %s\n",
+                       usersharepath, strerror(errno) ));
+               return -1;
+       }
+
+       if (!S_ISDIR(sbuf.st_mode)) {
+               DEBUG(0,("load_usershare_service: %s is not a directory.\n",
+                       usersharepath ));
+               return -1;
+       }
+
+       /*
+        * This directory must be owned by root, and have the 't' bit set.
+        * It also must not be writable by "other".
+        */
+
+#ifdef S_ISVTX
+       if (sbuf.st_uid != 0 || !(sbuf.st_mode & S_ISVTX) || (sbuf.st_mode & S_IWOTH)) {
+#else
+       if (sbuf.st_uid != 0 || (sbuf.st_mode & S_IWOTH)) {
+#endif
+               DEBUG(0,("load_usershare_service: directory %s is not owned by root "
+                       "or does not have the sticky bit 't' set or is writable by anyone.\n",
+                       usersharepath ));
+               return -1;
+       }
+
+       /* Ensure the template share exists if it's set. */
+       if (Globals.szUsershareTemplateShare[0]) {
+               /* We can't use lp_servicenumber here as we are recommending that
+                  template shares have -valid=False set. */
+               for (snum_template = iNumServices - 1; snum_template >= 0; snum_template--) {
+                       if (ServicePtrs[snum_template]->szService &&
+                                       strequal(ServicePtrs[snum_template]->szService,
+                                               Globals.szUsershareTemplateShare)) {
+                               break;
+                       }
+               }
+
+               if (snum_template == -1) {
+                       DEBUG(0,("load_usershare_service: usershare template share %s "
+                               "does not exist.\n",
+                               Globals.szUsershareTemplateShare ));
+                       return -1;
+               }
+       }
+
+       return process_usershare_file(usersharepath, servicename, snum_template);
+}
+
+/***************************************************************************
+ Load all user defined shares from the user share directory.
+ We only do this if we're enumerating the share list.
+ This is the function that can delete usershares that have
+ been removed.
+***************************************************************************/
+
+int load_usershare_shares(void)
+{
+       SMB_STRUCT_DIR *dp;
+       SMB_STRUCT_STAT sbuf;
+       SMB_STRUCT_DIRENT *de;
+       int num_usershares = 0;
+       int max_user_shares = Globals.iUsershareMaxShares;
+       unsigned int num_dir_entries, num_bad_dir_entries, num_tmp_dir_entries;
+       unsigned int allowed_bad_entries = ((2*max_user_shares)/10);
+       unsigned int allowed_tmp_entries = ((2*max_user_shares)/10);
+       int iService;
+       int snum_template = -1;
+       const char *usersharepath = Globals.szUsersharePath;
+       int ret = lp_numservices();
+
+       if (max_user_shares == 0 || *usersharepath == '\0') {
+               return lp_numservices();
+       }
+
+       if (sys_stat(usersharepath, &sbuf) != 0) {
+               DEBUG(0,("load_usershare_shares: stat of %s failed. %s\n",
+                       usersharepath, strerror(errno) ));
+               return ret;
+       }
+
+       /*
+        * This directory must be owned by root, and have the 't' bit set.
+        * It also must not be writable by "other".
+        */
+
+#ifdef S_ISVTX
+       if (sbuf.st_uid != 0 || !(sbuf.st_mode & S_ISVTX) || (sbuf.st_mode & S_IWOTH)) {
+#else
+       if (sbuf.st_uid != 0 || (sbuf.st_mode & S_IWOTH)) {
+#endif
+               DEBUG(0,("load_usershare_shares: directory %s is not owned by root "
+                       "or does not have the sticky bit 't' set or is writable by anyone.\n",
+                       usersharepath ));
+               return ret;
+       }
+
+       /* Ensure the template share exists if it's set. */
+       if (Globals.szUsershareTemplateShare[0]) {
+               /* We can't use lp_servicenumber here as we are recommending that
+                  template shares have -valid=False set. */
+               for (snum_template = iNumServices - 1; snum_template >= 0; snum_template--) {
+                       if (ServicePtrs[snum_template]->szService &&
+                                       strequal(ServicePtrs[snum_template]->szService,
+                                               Globals.szUsershareTemplateShare)) {
+                               break;
+                       }
+               }
+
+               if (snum_template == -1) {
+                       DEBUG(0,("load_usershare_shares: usershare template share %s "
+                               "does not exist.\n",
+                               Globals.szUsershareTemplateShare ));
+                       return ret;
+               }
+       }
+
+       /* Mark all existing usershares as pending delete. */
+       for (iService = iNumServices - 1; iService >= 0; iService--) {
+               if (VALID(iService) && ServicePtrs[iService]->usershare) {
+                       ServicePtrs[iService]->usershare = USERSHARE_PENDING_DELETE;
+               }
+       }
+
+       dp = sys_opendir(usersharepath);
+       if (!dp) {
+               DEBUG(0,("load_usershare_shares:: failed to open directory %s. %s\n",
+                       usersharepath, strerror(errno) ));
+               return ret;
+       }
+
+       for (num_dir_entries = 0, num_bad_dir_entries = 0, num_tmp_dir_entries = 0;
+                       (de = sys_readdir(dp));
+                       num_dir_entries++ ) {
+               int r;
+               const char *n = de->d_name;
+
+               /* Ignore . and .. */
+               if (*n == '.') {
+                       if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
+                               continue;
+                       }
+               }
+
+               if (n[0] == ':') {
+                       /* Temporary file used when creating a share. */
+                       num_tmp_dir_entries++;
+               }
+
+               /* Allow 20% tmp entries. */
+               if (num_tmp_dir_entries > allowed_tmp_entries) {
+                       DEBUG(0,("load_usershare_shares: too many temp entries (%u) "
+                               "in directory %s\n",
+                               num_tmp_dir_entries, usersharepath));
+                       break;
+               }
+
+               r = process_usershare_file(usersharepath, n, snum_template);
+               if (r == 0) {
+                       /* Update the services count. */
+                       num_usershares++;
+                       if (num_usershares >= max_user_shares) {
+                               DEBUG(0,("load_usershare_shares: max user shares reached "
+                                       "on file %s in directory %s\n",
+                                       n, usersharepath ));
+                               break;
+                       }
+               } else if (r == -1) {
+                       num_bad_dir_entries++;
+               }
+
+               /* Allow 20% bad entries. */
+               if (num_bad_dir_entries > allowed_bad_entries) {
+                       DEBUG(0,("load_usershare_shares: too many bad entries (%u) "
+                               "in directory %s\n",
+                               num_bad_dir_entries, usersharepath));
+                       break;
+               }
+
+               /* Allow 20% bad entries. */
+               if (num_dir_entries > max_user_shares + allowed_bad_entries) {
+                       DEBUG(0,("load_usershare_shares: too many total entries (%u) "
+                       "in directory %s\n",
+                       num_dir_entries, usersharepath));
+                       break;
+               }
+       }
+
+       sys_closedir(dp);
+
+       /* Sweep through and delete any non-refreshed usershares that are
+          not currently in use. */
+       for (iService = iNumServices - 1; iService >= 0; iService--) {
+               if (VALID(iService) && (ServicePtrs[iService]->usershare == USERSHARE_PENDING_DELETE)) {
+                       if (conn_snum_used(iService)) {
+                               continue;
+                       }
+                       /* Remove from the share ACL db. */
+                       DEBUG(10,("load_usershare_shares: Removing deleted usershare %s\n",
+                               lp_servicename(iService) ));
+                       delete_share_security(iService);
+                       free_service_byindex(iService);
+               }
+       }
+
+       return lp_numservices();
+}
+
 /***************************************************************************
  Load the services array from the services file. Return True on success, 
  False on failure.
 ***************************************************************************/
 
-BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
-            BOOL add_ipc)
+BOOL lp_load(const char *pszFname,
+             BOOL global_only,
+             BOOL save_defaults,
+            BOOL add_ipc,
+             BOOL initialize_globals)
 {
        pstring n2;
        BOOL bRetval;
@@ -4077,7 +4865,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
        bInGlobalSection = True;
        bGlobalOnly = global_only;
 
-       init_globals();
+       init_globals(! initialize_globals);
        debug_init();
 
        if (save_defaults) {
@@ -4115,7 +4903,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
                   are denied */
                lp_add_ipc("IPC$", (lp_restrict_anonymous() < 2));
                if ( lp_enable_asu_support() )
-               lp_add_ipc("ADMIN$", False);
+                       lp_add_ipc("ADMIN$", False);
        }
 
        set_server_role();
@@ -4199,8 +4987,9 @@ int lp_servicenumber(const char *pszServiceName)
        int iService;
         fstring serviceName;
         
-        if (!pszServiceName)
+        if (!pszServiceName) {
                return GLOBAL_SECTION_SNUM;
+       }
         
        for (iService = iNumServices - 1; iService >= 0; iService--) {
                if (VALID(iService) && ServicePtrs[iService]->szService) {
@@ -4210,8 +4999,30 @@ int lp_servicenumber(const char *pszServiceName)
                         */
                        fstrcpy(serviceName, ServicePtrs[iService]->szService);
                        standard_sub_basic(get_current_username(), serviceName,sizeof(serviceName));
-                       if (strequal(serviceName, pszServiceName))
+                       if (strequal(serviceName, pszServiceName)) {
                                break;
+                       }
+               }
+       }
+
+       if (iService >= 0 && ServicePtrs[iService]->usershare == USERSHARE_VALID) {
+               time_t last_mod;
+
+               if (!usershare_exists(iService, &last_mod)) {
+                       /* Remove the share security tdb entry for it. */
+                       delete_share_security(iService);
+                       /* Remove it from the array. */
+                       free_service_byindex(iService);
+                       /* Doesn't exist anymore. */
+                       return GLOBAL_SECTION_SNUM;
+               }
+
+               /* Has it been modified ? If so delete and reload. */
+               if (ServicePtrs[iService]->usershare_last_mod < last_mod) {
+                       /* Remove it from the array. */
+                       free_service_byindex(iService);
+                       /* and now reload it. */
+                       iService = load_usershare_service(pszServiceName);
                }
        }
 
@@ -4331,6 +5142,7 @@ BOOL lp_preferred_master(void)
 void lp_remove_service(int snum)
 {
        ServicePtrs[snum]->valid = False;
+       invalid_services[num_invalid_services++] = snum;
 }
 
 /*******************************************************************
@@ -4424,15 +5236,6 @@ const char *lp_printername(int snum)
 }
 
 
-/****************************************************************
- Compatibility fn. for 2.2.2 code.....
-*****************************************************************/
-
-void get_private_directory(pstring privdir)
-{
-       pstrcpy (privdir, lp_private_dir());
-}
-
 /***********************************************************
  Allow daemons such as winbindd to fix their logfile name.
 ************************************************************/