Rework much of the service.c code:
authorAndrew Bartlett <abartlet@samba.org>
Sat, 15 Jun 2002 12:38:13 +0000 (12:38 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 15 Jun 2002 12:38:13 +0000 (12:38 +0000)
The aim of this execise is to give the 'security>=user' code a straight paper
path.  Security=share will sill call authorise_login(), but otherwise we avoid
that mess.

This allow *much* more accurate error code reporting, beocuse we don't start
pretending that we can use the (nonexistant) password etc.

Also in this patch is code to create the 'homes' share at session setup time
(as we have done in the past - been broken recently) and to record this on
the user's vuser struct for later reference.  The changes here should also
allow for much better use of %H (some more changes to come here).

The service.c changes move a lot of code around, but are not as drastric
as they look...

(Also included is a fix to srv_srvsvc_nt.c where 'total_entries' not
'*total_entries' was compared).

This code is needs testing, but passes my basic tests.

I expect we have lost some functionality, but the stuff I had expected
to loose was already broken before I started.  In particular, we don't 'fall
back' to guest if the user cannot access a share (for security=user).  If you
want this kind of stuff then you really want security=share anyway.

Andrew Bartlett

source/include/smb.h
source/lib/substitute.c
source/param/loadparm.c
source/passdb/pdb_get_set.c
source/rpc_server/srv_srvsvc_nt.c
source/smbd/password.c
source/smbd/service.c

index 6678a8674df1d1255f2b40233afecbc09e70dd3b..c15b15564fb63e8b1af9dab748d119f7194d2373 100644 (file)
@@ -1605,6 +1605,9 @@ typedef struct user_struct
        uint8 session_key[16];
 
        int session_id; /* used by utmp and pam session code */
+       
+       int homes_snum;
+
 } user_struct;
 
 
index 6c56cdd48084444ffbd30784675004ef66039710..eea720c01444359889e33d1f1ab6ce4aaf6505ee 100644 (file)
@@ -226,7 +226,9 @@ void standard_sub_basic(const char *smb_name, char *str)
  Do some standard substitutions in a string.
 ****************************************************************************/
 
-static void standard_sub_advanced(int snum, const char *user, const char *connectpath, gid_t gid, const char *smb_name, char *str)
+static void standard_sub_advanced(int snum, const char *user, 
+                                 const char *connectpath, gid_t gid, 
+                                 const char *smb_name, char *str)
 {
        char *p, *s, *home;
 
@@ -345,7 +347,8 @@ void standard_sub_conn(connection_struct *conn, char *str)
  share. No user specific snum created yet so servicename should be the username.
 ****************************************************************************/
 
-void standard_sub_home(int snum, const char *user, char *str)
+void standard_sub_home(int snum, const char *share, 
+                      const char *user, const char *homedir, pstring str)
 {
        char *p, *s;
 
@@ -353,8 +356,12 @@ void standard_sub_home(int snum, const char *user, char *str)
                int l = sizeof(pstring) - (int)(p-str);
                
                switch (*(p+1)) {
+               case 'H': 
+                       string_sub(p,"%H", homedir, l); 
+                       break;
+                       
                case 'S': 
-                       string_sub(p,"%S", user, l); 
+                       string_sub(p,"%S", share, l); 
                        break;
                case 'p': 
                        string_sub(p,"%p", automount_path(user), l); 
index e9ded3fb4ad4cf87103bab4013aaf85ff0a994f6..3c0820491d46ffffc09309a57cac6d2cb68a04f2 100644 (file)
@@ -1879,9 +1879,12 @@ static int add_a_service(const service * pservice, const char *name)
 add a new home service, with the specified home directory, defaults coming 
 from service ifrom.
 ***************************************************************************/
-BOOL lp_add_home(const char *pszHomename, int iDefaultService, const char *pszHomedir)
+BOOL lp_add_home(const char *pszHomename, int iDefaultService, 
+                const char *user, const char *pszHomedir)
 {
        int i;
+       pstring newHomedir;
+
        SMB_STRUCT_STAT buf;
 
        /* if the user's home directory doesn't exist, then don't
@@ -1895,8 +1898,16 @@ BOOL lp_add_home(const char *pszHomename, int iDefaultService, const char *pszHo
                return (False);
 
        if (!(*(ServicePtrs[i]->szPath))
-           || strequal(ServicePtrs[i]->szPath, lp_pathname(-1)))
-               string_set(&ServicePtrs[i]->szPath, pszHomedir);
+           || strequal(ServicePtrs[i]->szPath, lp_pathname(-1))) {
+               pstrcpy(newHomedir, pszHomedir);
+       } else {
+               pstrcpy(newHomedir, lp_pathname(iDefaultService));
+               standard_sub_home(iDefaultService, pszHomename, user, 
+                                 pszHomedir, newHomedir);
+       }
+
+       string_set(&ServicePtrs[i]->szPath, newHomedir);
+
        if (!(*(ServicePtrs[i]->comment)))
        {
                pstring comment;
@@ -1908,7 +1919,8 @@ BOOL lp_add_home(const char *pszHomename, int iDefaultService, const char *pszHo
        ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
 
        DEBUG(3,
-             ("adding home directory %s at %s\n", pszHomename, pszHomedir));
+             ("adding home's share [%s] for user %s at %s\n", pszHomename, 
+              user, newHomedir));
 
        return (True);
 }
@@ -3329,13 +3341,13 @@ static void lp_add_auto_services(char *str)
        homes = lp_servicenumber(HOMES_NAME);
 
        for (p = strtok(s, LIST_SEP); p; p = strtok(NULL, LIST_SEP)) {
-               char *home = get_user_service_home_dir(p);
+               char *home = get_user_home_dir(p);
 
                if (lp_servicenumber(p) >= 0)
                        continue;
 
                if (home && homes >= 0)
-                       lp_add_home(p, homes, home);
+                       lp_add_home(p, homes, p, home);
        }
        SAFE_FREE(s);
 }
index bbb0d87f59f23b299963df169fb5d041470c3da3..37530d0e4672a721bbe6affabf9cda49f9f290b3 100644 (file)
@@ -860,7 +860,7 @@ BOOL pdb_set_homedir (SAM_ACCOUNT *sampass, const char *home_dir, BOOL store)
        }
 
        if (store) {
-               DEBUG(10, ("pdb_set_homedir: setting home dir sam flag!"));
+               DEBUG(10, ("pdb_set_homedir: setting home dir sam flag!\n"));
                pdb_set_init_flag(sampass, FLAG_SAM_SMBHOME);
        }
 
@@ -877,7 +877,7 @@ BOOL pdb_set_unix_homedir (SAM_ACCOUNT *sampass, const char *unix_home_dir)
                return False;
 
        if (unix_home_dir) { 
-               DEBUG(10, ("pdb_set_homedir: setting home dir %s, was %s\n", unix_home_dir,
+               DEBUG(10, ("pdb_set_unix_homedir: setting home dir %s, was %s\n", unix_home_dir,
                        (sampass->private.unix_home_dir)?(sampass->private.unix_home_dir):"NULL"));
  
                sampass->private.unix_home_dir = talloc_strdup(sampass->mem_ctx, 
index f99827ea193291a98a26d98d085f1ca191c86b8b..f5b9959b2c72050ee15ad09dd730187287d23bd9 100644 (file)
@@ -308,7 +308,7 @@ void map_generic_share_sd_bits(SEC_DESC *psd)
  Can this user access with share with the required permissions ?
 ********************************************************************/
 
-BOOL share_access_check(connection_struct *conn, int snum, uint16 vuid, uint32 desired_access)
+BOOL share_access_check(connection_struct *conn, int snum, user_struct *vuser, uint32 desired_access)
 {
        uint32 granted;
        NTSTATUS status;
@@ -316,7 +316,6 @@ BOOL share_access_check(connection_struct *conn, int snum, uint16 vuid, uint32 d
        SEC_DESC *psd = NULL;
        size_t sd_size;
        NT_USER_TOKEN *token = NULL;
-       user_struct *vuser = get_valid_user_struct(vuid);
        BOOL ret = True;
 
        mem_ctx = talloc_init();
@@ -969,7 +968,7 @@ static WERROR init_srv_file_info_ctr(pipes_struct *p, SRV_FILE_INFO_CTR *ctr,
        switch (switch_value) {
        case 3: {
                int i;
-               if (total_entries > 0) {
+               if (*total_entries > 0) {
                        ctr->ptr_entries = 1;
                        ctr->file.info3 = talloc(ctx, ctr->num_entries * 
                                                 sizeof(SRV_FILE_INFO_3));
index b2cf3106cbd6864082c03b04f19460bcf0bd61c6..6eaa7b7fbbcf8e0dde78ac3271bdfdc3de5a7ef7 100644 (file)
@@ -313,7 +313,9 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name)
        /* Register a home dir service for this user */
        if ((!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)
                && (lp_servicenumber(vuser->user.unix_name) < 0)) {
-               add_home_service(vuser->user.unix_name, vuser->unix_homedir);     
+               vuser->homes_snum = add_home_service(vuser->user.unix_name, vuser->user.unix_name, vuser->unix_homedir);          
+       } else {
+               vuser->homes_snum = -1;
        }
        
        return vuser->vuid;
@@ -472,42 +474,19 @@ static char *validate_group(char *group, DATA_BLOB password,int snum)
 ****************************************************************************/
 
 BOOL authorise_login(int snum,char *user, DATA_BLOB password, 
-                    BOOL *guest,BOOL *force,uint16 vuid)
+                    BOOL *guest, BOOL *force)
 {
        BOOL ok = False;
-       user_struct *vuser = get_valid_user_struct(vuid);
-
+       
 #if DEBUG_PASSWORD
-       DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s vuid=%d\n",
-                       user,password.data, vuid));
+       DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n",
+                  user,password.data));
 #endif
 
        *guest = False;
   
        if (GUEST_ONLY(snum))
                *force = True;
-
-       if (!GUEST_ONLY(snum) && (lp_security() > SEC_SHARE)) {
-
-               /*
-                * We should just use the given vuid from a sessionsetup_and_X.
-                */
-
-               if (!vuser) {
-                       DEBUG(1,("authorise_login: refusing user '%s' with no session setup\n", user));
-                       return False;
-               }
-
-               if ((!vuser->guest && user_ok(vuser->user.unix_name,snum)) || 
-                   (vuser->guest && GUEST_OK(snum))) {
-                       fstrcpy(user,vuser->user.unix_name);
-                       *guest = vuser->guest;
-                       DEBUG(3,("authorise_login: ACCEPTED: validated based on vuid as %sguest \
-(user=%s)\n", vuser->guest ? "" : "non-", user));
-                       return True;
-               }
-       }
        /* there are several possibilities:
                1) login as the given user with given password
                2) login as a previously registered username with the given password
@@ -520,84 +499,61 @@ BOOL authorise_login(int snum,char *user, DATA_BLOB password,
                if the service is guest_only then steps 1 to 5 are skipped
        */
 
-       if (!(GUEST_ONLY(snum) && GUEST_OK(snum))) {
-               /* check for a previously registered guest username */
-               if (!ok && (vuser != 0) && vuser->guest) {        
-                       if (user_ok(vuser->user.unix_name,snum) &&
-                                       password_ok(vuser->user.unix_name, password)) {
-                               fstrcpy(user, vuser->user.unix_name);
-                               *guest = False;
-                               DEBUG(3,("authorise_login: ACCEPTED: given password with registered user %s\n", user));
+       /* now check the list of session users */
+       if (!ok) {
+               char *auser;
+               char *user_list = strdup(session_users);
+               if (!user_list)
+                       return(False);
+               
+               for (auser=strtok(user_list,LIST_SEP); !ok && auser;
+                    auser = strtok(NULL,LIST_SEP)) {
+                       fstring user2;
+                       fstrcpy(user2,auser);
+                       if (!user_ok(user2,snum))
+                               continue;
+                       
+                       if (password_ok(user2,password)) {
                                ok = True;
+                               fstrcpy(user,user2);
+                               DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \
+and given password ok\n", user));
                        }
                }
-
-               /* now check the list of session users */
-               if (!ok) {
-                       char *auser;
-                       char *user_list = strdup(session_users);
-                       if (!user_list)
-                               return(False);
-
-                       for (auser=strtok(user_list,LIST_SEP); !ok && auser;
-                                                                       auser = strtok(NULL,LIST_SEP)) {
+               
+               SAFE_FREE(user_list);
+       }
+       
+       /* check the user= fields and the given password */
+       if (!ok && lp_username(snum)) {
+               char *auser;
+               pstring user_list;
+               StrnCpy(user_list,lp_username(snum),sizeof(pstring));
+               
+               pstring_sub(user_list,"%S",lp_servicename(snum));
+               
+               for (auser=strtok(user_list,LIST_SEP); auser && !ok;
+                    auser = strtok(NULL,LIST_SEP)) {
+                       if (*auser == '@') {
+                               auser = validate_group(auser+1,password,snum);
+                               if (auser) {
+                                       ok = True;
+                                       fstrcpy(user,auser);
+                                       DEBUG(3,("authorise_login: ACCEPTED: group username \
+and given password ok (%s)\n", user));
+                               }
+                       } else {
                                fstring user2;
                                fstrcpy(user2,auser);
-                               if (!user_ok(user2,snum))
-                                       continue;
-                 
-                               if (password_ok(user2,password)) {
+                               if (user_ok(user2,snum) && password_ok(user2,password)) {
                                        ok = True;
                                        fstrcpy(user,user2);
-                                       DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \
-and given password ok\n", user));
-                               }
-                       }
-
-                       SAFE_FREE(user_list);
-               }
-
-               /* check for a previously validated username/password pair */
-               if (!ok && (lp_security() > SEC_SHARE) && (vuser != 0) && !vuser->guest &&
-                                                       user_ok(vuser->user.unix_name,snum)) {
-                       fstrcpy(user,vuser->user.unix_name);
-                       *guest = False;
-                       DEBUG(3,("authorise_login: ACCEPTED: validated uid (%s) as non-guest\n",
-                               user));
-                       ok = True;
-               }
-
-               /* check the user= fields and the given password */
-               if (!ok && lp_username(snum)) {
-                       char *auser;
-                       pstring user_list;
-                       StrnCpy(user_list,lp_username(snum),sizeof(pstring));
-
-                       pstring_sub(user_list,"%S",lp_servicename(snum));
-         
-                       for (auser=strtok(user_list,LIST_SEP); auser && !ok;
-                                                                                       auser = strtok(NULL,LIST_SEP)) {
-                               if (*auser == '@') {
-                                       auser = validate_group(auser+1,password,snum);
-                                       if (auser) {
-                                               ok = True;
-                                               fstrcpy(user,auser);
-                                               DEBUG(3,("authorise_login: ACCEPTED: group username \
-and given password ok (%s)\n", user));
-                                       }
-                               } else {
-                                       fstring user2;
-                                       fstrcpy(user2,auser);
-                                       if (user_ok(user2,snum) && password_ok(user2,password)) {
-                                               ok = True;
-                                               fstrcpy(user,user2);
-                                               DEBUG(3,("authorise_login: ACCEPTED: user list username \
+                                       DEBUG(3,("authorise_login: ACCEPTED: user list username \
 and given password ok (%s)\n", user));
-                                       }
                                }
                        }
                }
-       } /* not guest only */
+       }
 
        /* check for a normal guest connection */
        if (!ok && GUEST_OK(snum)) {
index af70e7839e0ec9c4328ac4060f9b132a0fe2f943..1bb55fbcf83827fa565f16fec6fb15afcec0e480 100644 (file)
@@ -78,7 +78,7 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
  Add a home service. Returns the new service number or -1 if fail.
 ****************************************************************************/
 
-int add_home_service(const char *service, const char *homedir)
+int add_home_service(const char *service, const char *username, const char *homedir)
 {
        int iHomeService;
 
@@ -104,7 +104,7 @@ int add_home_service(const char *service, const char *homedir)
                }
        }
 
-       lp_add_home(service, iHomeService, homedir);
+       lp_add_home(service, iHomeService, username, homedir);
        
        return lp_servicenumber(service);
 
@@ -127,7 +127,7 @@ int find_service(fstring service)
    /* now handle the special case of a home directory */
    if (iService < 0)
    {
-      char *phome_dir = get_user_service_home_dir(service);
+      char *phome_dir = get_user_home_dir(service);
 
       if(!phome_dir)
       {
@@ -136,13 +136,13 @@ int find_service(fstring service)
          * be a Windows to unix mapped user name.
          */
         if(map_username(service))
-          phome_dir = get_user_service_home_dir(service);
+          phome_dir = get_user_home_dir(service);
       }
 
       DEBUG(3,("checking for home directory %s gave %s\n",service,
             phome_dir?phome_dir:"(NULL)"));
 
-      iService = add_home_service(service,phome_dir);
+      iService = add_home_service(service,service /* 'username' */, phome_dir);
    }
 
    /* If we still don't have a service, attempt to add it as a printer. */
@@ -218,7 +218,7 @@ int find_service(fstring service)
  do some basic sainity checks on the share.  
  This function modifies dev, ecode.
 ****************************************************************************/
-static NTSTATUS share_sanity_checks(int snum, const char* service, pstring dev) 
+static NTSTATUS share_sanity_checks(int snum, pstring dev) 
 {
        
        if (!lp_snum_ok(snum) || 
@@ -228,7 +228,7 @@ static NTSTATUS share_sanity_checks(int snum, const char* service, pstring dev)
        }
 
        /* you can only connect to the IPC$ service as an ipc device */
-       if (strequal(service,"IPC$") || strequal(service,"ADMIN$"))
+       if (strequal(lp_fstype(snum), "IPC"))
                pstrcpy(dev,"IPC");
        
        if (dev[0] == '?' || !dev[0]) {
@@ -319,89 +319,26 @@ static void set_admin_user(connection_struct *conn)
 }
 
 /****************************************************************************
- Make a connection to a service.
- *
- * @param service (May be modified to canonical form???)
+  Make a connection, given the snum to connect to, and the vuser of the
+  connecting user if appropriate.
 ****************************************************************************/
 
-connection_struct *make_connection(char *service, DATA_BLOB password, 
-                                  char *dev, uint16 vuid, NTSTATUS *status)
+static connection_struct *make_connection_snum(int snum, user_struct *vuser,
+                                              DATA_BLOB password, 
+                                              char *dev, NTSTATUS *status)
 {
-       int snum;
        struct passwd *pass = NULL;
        BOOL guest = False;
        BOOL force = False;
        connection_struct *conn;
-       uid_t euid;
        struct stat st;
        fstring user;
-       ZERO_STRUCT(user);
+       *user = 0;
 
-       /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
-       if (!non_root_mode() && (euid = geteuid()) != 0) {
-               DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
-               smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
-       }
-
-       strlower(service);
-
-       snum = find_service(service);
-
-       if (snum < 0) {
-               if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
-                       DEBUG(3,("refusing IPC connection\n"));
-                       *status = NT_STATUS_ACCESS_DENIED;
-                       return NULL;
-               }
-
-               DEBUG(0,("%s (%s) couldn't find service %s\n",
-                        remote_machine, client_addr(), service));
-               *status = NT_STATUS_BAD_NETWORK_NAME;
-               return NULL;
-       }
-
-       if (strequal(service,HOMES_NAME)) {
-               if(lp_security() != SEC_SHARE) {
-                       if (validated_username(vuid)) {
-                               fstring unix_username;
-                               fstrcpy(unix_username,validated_username(vuid));
-                               return make_connection(unix_username,
-                                                      password,dev,vuid,status);
-                       }
-               } else {
-                       /* Security = share. Try with current_user_info.smb_name
-                        * as the username.  */
-                       if (* current_user_info.smb_name) {
-                               fstring unix_username;
-                               fstrcpy(unix_username,
-                                       current_user_info.smb_name);
-                               map_username(unix_username);
-                               return make_connection(unix_username,
-                                                      password,dev,vuid,status);
-                       }
-               }
-       }
-
-       if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, service, dev))) {
+       if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
                return NULL;
        }       
 
-       /* add it as a possible user name if we 
-          are in share mode security */
-       if (lp_security() == SEC_SHARE) {
-               add_session_user(service);
-       }
-
-
-       /* shall we let them in? */
-       if (!authorise_login(snum,user,password,&guest,&force,vuid)) {
-               DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
-               *status = NT_STATUS_WRONG_PASSWORD;
-               return NULL;
-       }
-
-       add_session_user(user);
-  
        conn = conn_new();
        if (!conn) {
                DEBUG(0,("Couldn't find free connection.\n"));
@@ -409,20 +346,70 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                return NULL;
        }
 
-       /* find out some info about the user */
-       pass = smb_getpwnam(user,True);
+       if (lp_guest_only(snum)) {
+               char *guestname = lp_guestaccount();
+               guest = True;
+               force = True;
+               pass = getpwnam_alloc(guestname);
+               if (!pass) {
+                       DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
+                       *status = NT_STATUS_NO_SUCH_USER;
+                       conn_free(conn);
+                       return NULL;
+               }
+               fstrcpy(user,pass->pw_name);
+               conn->force_user = True;
+               string_set(&conn->user,pass->pw_name);
+               DEBUG(3,("Guest only user %s\n",user));
+       } else if (vuser) {
+               if (vuser->guest) {
+                       if (!lp_guest_ok(snum)) {
+                               DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)", lp_servicename(snum)));
+                                     *status = NT_STATUS_ACCESS_DENIED;
+                                     conn_free(conn);
+                                     return NULL;
+                       }
+               } else {
+                       if (!user_ok(vuser->user.unix_name, snum)) {
+                               DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)", vuser->user.unix_name, lp_servicename(snum)));
+                               *status = NT_STATUS_ACCESS_DENIED;
+                               conn_free(conn);
+                               return NULL;
+                       }
+               }
+               conn->vuid = vuser->vuid;
+               conn->uid = vuser->uid;
+               conn->gid = vuser->gid;
+               string_set(&conn->user,vuser->user.unix_name);
+               fstrcpy(user,vuser->user.unix_name);
+               guest = vuser->guest; 
+       } else if (lp_security() == SEC_SHARE) {
+               /* add it as a possible user name if we 
+                  are in share mode security */
+               add_session_user(lp_servicename(snum));
+               /* shall we let them in? */
+               if (!authorise_login(snum,user,password,&guest,&force)) {
+                       DEBUG( 2, ( "Invalid username/password for %s [%s]\n", 
+                                   lp_servicename(snum), user ) );
+                       *status = NT_STATUS_WRONG_PASSWORD;
+                       return NULL;
+               }
+               pass = Get_Pwnam(user);
+               conn->force_user = force;
+               conn->uid = pass->pw_uid;
+               conn->gid = pass->pw_gid;
+               string_set(&conn->user, pass->pw_name);
+               fstrcpy(user, pass->pw_name);
 
-       if (pass == NULL) {
-               DEBUG(0,( "Couldn't find account %s\n",user));
-               *status = NT_STATUS_NO_SUCH_USER;
+       } else {
+               DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
                conn_free(conn);
+               *status = NT_STATUS_ACCESS_DENIED;
                return NULL;
        }
 
-       conn->force_user = force;
-       conn->vuid = vuid;
-       conn->uid = pass->pw_uid;
-       conn->gid = pass->pw_gid;
+       add_session_user(user);
+
        safe_strcpy(conn->client_address, client_addr(), 
                    sizeof(conn->client_address)-1);
        conn->num_files_open = 0;
@@ -455,18 +442,21 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                pstrcpy(fuser,lp_force_user(snum));
 
                /* Allow %S to be used by force user. */
-               pstring_sub(fuser,"%S",service);
+               pstring_sub(fuser,"%S",lp_servicename(snum));
 
-               pass2 = (struct passwd *)Get_Pwnam_Modify(fuser);
+               pass2 = (struct passwd *)Get_Pwnam(fuser);
                if (pass2) {
                        conn->uid = pass2->pw_uid;
                        conn->gid = pass2->pw_gid;
-                       string_set(&conn->user,fuser);
-                       fstrcpy(user,fuser);
+                       string_set(&conn->user,pass2->pw_name);
+                       fstrcpy(user,pass2->pw_name);
                        conn->force_user = True;
-                       DEBUG(3,("Forced user %s\n",fuser));      
+                       DEBUG(3,("Forced user %s\n",user));       
                } else {
+                       conn_free(conn);
                        DEBUG(1,("Couldn't find user %s\n",fuser));
+                       *status = NT_STATUS_NO_SUCH_USER;
+                       return NULL;
                }
        }
 
@@ -488,7 +478,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                BOOL user_must_be_member = False;
                
                StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
-
+               
                if (tmp_gname[0] == '+') {
                        user_must_be_member = True;
                        StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
@@ -496,7 +486,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                        StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
                }
                /* default service may be a group name          */
-               pstring_sub(gname,"%S",service);
+               pstring_sub(gname,"%S",lp_servicename(snum));
                gid = nametogid(gname);
                
                if (gid != (gid_t)-1) {
@@ -516,6 +506,8 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                                DEBUG(3,("Forced group %s\n",gname));
                        }
                } else {
+                       conn_free(conn);
+                       *status = NT_STATUS_NO_SUCH_GROUP;
                        DEBUG(1,("Couldn't find group %s\n",gname));
                }
        }
@@ -549,14 +541,14 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
         */
 
        {
-               BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA);
+               BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
 
                if (!can_write) {
-                       if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) {
+                       if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
                                /* No access, read or write. */
                                *status = NT_STATUS_ACCESS_DENIED;
                                DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
-                                       service ));
+                                         lp_servicename(snum)));
                                conn_free(conn);
                                return NULL;
                        } else {
@@ -610,9 +602,9 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                *status = NT_STATUS_LOGON_FAILURE;
                return NULL;
        }
-
+       
        /* Remember that a different vuid can connect later without these checks... */
-
+       
        /* Preexecs are done here as they might make the dir we are to ChDir to below */
        /* execute any "preexec = " line */
        if (*lp_preexec(SNUM(conn))) {
@@ -630,7 +622,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
                        return NULL;
                }
        }
-
+       
 #if CHECK_PATH_ON_TCONX
        /* win2000 does not check the permissions on the directory
           during the tree connect, instead relying on permission
@@ -695,7 +687,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
        /* Invoke VFS make connection hook */
 
        if (conn->vfs_ops.connect) {
-               if (conn->vfs_ops.connect(conn, service, user) < 0) {
+               if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) {
                        DEBUG(0,("make_connection: VFS make connection failed!\n"));
                        *status = NT_STATUS_UNSUCCESSFUL;
                        change_to_root_user();
@@ -710,6 +702,101 @@ connection_struct *make_connection(char *service, DATA_BLOB password,
        return(conn);
 }
 
+/****************************************************************************
+ Make a connection to a service.
+ *
+ * @param service 
+****************************************************************************/
+
+connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
+                                  char *dev, uint16 vuid, NTSTATUS *status)
+{
+       uid_t euid;
+       user_struct *vuser = NULL;
+       pstring service;
+       int snum = -1;
+
+       /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
+       if (!non_root_mode() && (euid = geteuid()) != 0) {
+               DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
+               smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
+       }
+
+       if(lp_security() != SEC_SHARE) {
+               vuser = get_valid_user_struct(vuid);
+               if (!vuser) {
+                       DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
+                       return NULL;
+               }
+       }
+
+       /* Logic to try and connect to the correct [homes] share, preferably without too many
+          getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
+          share name isn't the same as unix username.
+
+          The snum of the homes share is stored on the vuser at session setup time.
+       */
+
+       if (strequal(service_in,HOMES_NAME)) {
+               if(lp_security() != SEC_SHARE) {
+                       DATA_BLOB no_pw = data_blob(NULL, 0);
+                       if (vuser->homes_snum != -1) {
+                               DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
+                                       return make_connection_snum(vuser->homes_snum,
+                                                                   vuser, no_pw, 
+                                                           dev, status);
+                       }
+               } else {
+                       /* Security = share. Try with current_user_info.smb_name
+                        * as the username.  */
+                       if (*current_user_info.smb_name) {
+                               fstring unix_username;
+                               fstrcpy(unix_username,
+                                       current_user_info.smb_name);
+                               map_username(unix_username);
+                               snum = find_service(unix_username);
+                       } 
+                       if (snum != -1) {
+                               DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
+                               return make_connection_snum(snum, NULL,
+                                                           password,
+                                                           dev, status);
+                       }
+               }
+       } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
+                  && strequal(service, lp_servicename(vuser->homes_snum))) {
+               DATA_BLOB no_pw = data_blob(NULL, 0);
+               DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service));
+               return make_connection_snum(vuser->homes_snum,
+                                           vuser, no_pw, 
+                                           dev, status);
+       }
+       
+       pstrcpy(service, service_in);
+
+       strlower(service);
+
+       snum = find_service(service);
+
+       if (snum < 0) {
+               if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
+                       DEBUG(3,("refusing IPC connection to %s\n", service));
+                       *status = NT_STATUS_ACCESS_DENIED;
+                       return NULL;
+               }
+
+               DEBUG(0,("%s (%s) couldn't find service %s\n",
+                        remote_machine, client_addr(), service));
+               *status = NT_STATUS_BAD_NETWORK_NAME;
+               return NULL;
+       }
+
+       DEBUG(5, ("making a connection to 'normal' service %s\n", service));
+
+       return make_connection_snum(snum, vuser,
+                                   password,
+                                   dev, status);
+}
 
 /****************************************************************************
 close a cnum