Example #1
0
/****************************************************************************
  make a connection to a service
****************************************************************************/
connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
{
	int snum;
	struct passwd *pass = NULL;
	BOOL guest = False;
	BOOL force = False;
	extern int Client;
	connection_struct *conn;
	int ret;

	strlower(service);

	snum = find_service(service);
	if (snum < 0) {
		extern int Client;
		if (strequal(service,"IPC$")) {
			DEBUG(3,("refusing IPC connection\n"));
			*ecode = ERRnoipc;
			return NULL;
		}

		DEBUG(0,("%s (%s) couldn't find service %s\n",
			 remote_machine, client_addr(Client), service));
		*ecode = ERRinvnetname;
		return NULL;
	}

	if (strequal(service,HOMES_NAME)) {
		if (*user && Get_Pwnam(user,True)) {
			fstring dos_username;
			fstrcpy(dos_username, user);
			unix_to_dos(dos_username, True);
			return(make_connection(dos_username,user,password,
					       pwlen,dev,vuid,ecode));
		}

		if(lp_security() != SEC_SHARE) {
			if (validated_username(vuid)) {
				fstring dos_username;
				fstrcpy(user,validated_username(vuid));
				fstrcpy(dos_username, user);
				unix_to_dos(dos_username, True);
				return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
			}
		} else {
			/* Security = share. Try with sesssetup_user
			 * as the username.  */
			if(*sesssetup_user) {
				fstring dos_username;
				fstrcpy(user,sesssetup_user);
				fstrcpy(dos_username, user);
				unix_to_dos(dos_username, True);
				return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
			}
		}
	}

	if (!lp_snum_ok(snum) || 
	    !check_access(Client, 
			  lp_hostsallow(snum), lp_hostsdeny(snum))) {    
		*ecode = ERRaccess;
		return NULL;
	}

	/* you can only connect to the IPC$ service as an ipc device */
	if (strequal(service,"IPC$"))
		pstrcpy(dev,"IPC");
	
	if (*dev == '?' || !*dev) {
		if (lp_print_ok(snum)) {
			pstrcpy(dev,"LPT1:");
		} else {
			pstrcpy(dev,"A:");
		}
	}

	/* if the request is as a printer and you can't print then refuse */
	strupper(dev);
	if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
		DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
		*ecode = ERRinvdevice;
		return NULL;
	}

	/* lowercase the user name */
	strlower(user);

	/* add it as a possible user name */
	add_session_user(service);

	/* shall we let them in? */
	if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
		DEBUG( 2, ( "Invalid username/password for %s\n", service ) );
		*ecode = ERRbadpw;
		return NULL;
	}
  
	conn = conn_new();
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*ecode = ERRnoresource;
		conn_free(conn);
		return NULL;
	}

	/* find out some info about the user */
	pass = Get_Pwnam(user,True);

	if (pass == NULL) {
		DEBUG(0,( "Couldn't find account %s\n",user));
		*ecode = ERRbaduid;
		conn_free(conn);
		return NULL;
	}

	conn->read_only = lp_readonly(snum);

	{
		pstring list;
		StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
		pstring_sub(list,"%S",service);

		if (user_in_list(user,list))
			conn->read_only = True;
		
		StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
		pstring_sub(list,"%S",service);
		
		if (user_in_list(user,list))
			conn->read_only = False;    
	}

	/* admin user check */
	
	/* JRA - original code denied admin user if the share was
	   marked read_only. Changed as I don't think this is needed,
	   but old code left in case there is a problem here.
	*/
	if (user_in_list(user,lp_admin_users(snum)) 
#if 0
	    && !conn->read_only
#endif
	    ) {
		conn->admin_user = True;
		DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
	} else {
		conn->admin_user = False;
	}
    
	conn->force_user = force;
	conn->vuid = vuid;
	conn->uid = pass->pw_uid;
	conn->gid = pass->pw_gid;
	safe_strcpy(conn->client_address, client_addr(Client), sizeof(conn->client_address)-1);
	conn->num_files_open = 0;
	conn->lastused = time(NULL);
	conn->service = snum;
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = (strncmp(dev,"IPC",3) == 0);
	conn->dirptr = NULL;
	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	string_set(&conn->dirpath,"");
	string_set(&conn->user,user);
	
	/*
	 * If force user is true, then store the
	 * given userid and also the primary groupid
	 * of the user we're forcing.
	 */
	
	if (*lp_force_user(snum)) {
		struct passwd *pass2;
		pstring fuser;
		pstrcpy(fuser,lp_force_user(snum));

		/* Allow %S to be used by force user. */
		pstring_sub(fuser,"%S",service);

		pass2 = (struct passwd *)Get_Pwnam(fuser,True);
		if (pass2) {
			conn->uid = pass2->pw_uid;
			conn->gid = pass2->pw_gid;
			string_set(&conn->user,fuser);
			fstrcpy(user,fuser);
			conn->force_user = True;
			DEBUG(3,("Forced user %s\n",fuser));	  
		} else {
			DEBUG(1,("Couldn't find user %s\n",fuser));
		}
	}

#ifdef HAVE_GETGRNAM 
	/*
	 * If force group is true, then override
	 * any groupid stored for the connecting user.
	 */
	
	if (*lp_force_group(snum)) {
		struct group *gptr;
		pstring gname;
		pstring tmp_gname;
		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);
		} else {
			StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
		}
		/* default service may be a group name 		*/
		pstring_sub(gname,"%S",service);
		gptr = (struct group *)getgrnam(gname);
		
		if (gptr) {
			/*
			 * If the user has been forced and the forced group starts
			 * with a '+', then we only set the group to be the forced
			 * group if the forced user is a member of that group.
			 * Otherwise, the meaning of the '+' would be ignored.
			 */
			if (conn->force_user && user_must_be_member) {
				int i;
				for (i = 0; gptr->gr_mem[i] != NULL; i++) {
					if (strcmp(user,gptr->gr_mem[i]) == 0) {
						conn->gid = gptr->gr_gid;
						DEBUG(3,("Forced group %s for member %s\n",gname,user));
						break;
					}
				}
			} else {
				conn->gid = gptr->gr_gid;
				DEBUG(3,("Forced group %s\n",gname));
			}
		} else {
			DEBUG(1,("Couldn't find group %s\n",gname));
		}
	}
#endif /* HAVE_GETGRNAM */

	{
		pstring s;
		pstrcpy(s,lp_pathname(snum));
		standard_sub(conn,s);
		string_set(&conn->connectpath,s);
		DEBUG(3,("Connect path is %s\n",s));
	}

	/* groups stuff added by ih */
	conn->ngroups = 0;
	conn->groups = NULL;
	
	if (!IS_IPC(conn)) {
		/* Find all the groups this uid is in and
		   store them. Used by become_user() */
		setup_groups(conn->user,conn->uid,conn->gid,
			     &conn->ngroups,&conn->groups);
		
		/* check number of connections */
		if (!claim_connection(conn,
				      lp_servicename(SNUM(conn)),
				      lp_max_connections(SNUM(conn)),
				      False)) {
			DEBUG(1,("too many connections - rejected\n"));
			*ecode = ERRnoresource;
			conn_free(conn);
			return NULL;
		}  
		
		if (lp_status(SNUM(conn)))
			claim_connection(conn,"STATUS.",
					 MAXSTATUS,False);
	} /* IS_IPC */
	
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(SNUM(conn))) {
		pstring cmd;
		pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
		standard_sub(conn,cmd);
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL,False);
		if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
			DEBUG(1,("preexec gave %d - failing connection\n", ret));
			conn_free(conn);
			*ecode = ERRsrverror;
			return NULL;
		}
	}
	
	if (!become_user(conn, conn->vuid)) {
		DEBUG(0,("Can't become connected user!\n"));
		if (!IS_IPC(conn)) {
			yield_connection(conn,
					 lp_servicename(SNUM(conn)),
					 lp_max_connections(SNUM(conn)));
			if (lp_status(SNUM(conn))) {
				yield_connection(conn,"STATUS.",MAXSTATUS);
			}
		}
		conn_free(conn);
		*ecode = ERRbadpw;
		return NULL;
	}
	
	if (dos_ChDir(conn->connectpath) != 0) {
		DEBUG(0,("Can't change directory to %s (%s)\n",
			 conn->connectpath,strerror(errno)));
		unbecome_user();
		if (!IS_IPC(conn)) {
			yield_connection(conn,
					 lp_servicename(SNUM(conn)),
					 lp_max_connections(SNUM(conn)));
			if (lp_status(SNUM(conn))) 
				yield_connection(conn,"STATUS.",MAXSTATUS);
		}
		conn_free(conn);
		*ecode = ERRinvnetname;
		return NULL;
	}
	
	string_set(&conn->origpath,conn->connectpath);
	
#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early */
	{
		pstring s;
		pstrcpy(s,conn->connectpath);
		dos_GetWd(s);
		string_set(&conn->connectpath,s);
		dos_ChDir(conn->connectpath);
	}
#endif
	
	add_session_user(user);
		
	/* execute any "preexec = " line */
	if (*lp_preexec(SNUM(conn))) {
		pstring cmd;
		pstrcpy(cmd,lp_preexec(SNUM(conn)));
		standard_sub(conn,cmd);
		ret = smbrun(cmd,NULL,False);
		if (ret != 0 && lp_preexec_close(SNUM(conn))) {
			DEBUG(1,("preexec gave %d - failing connection\n", ret));
			conn_free(conn);
			*ecode = ERRsrverror;
			return NULL;
		}
	}

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using.
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", remote_machine, conn->client_address );
		dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
		dbgtext( "as user %s ", user );
		dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
		dbgtext( "(pid %d)\n", (int)getpid() );
	}
	
	/* we've finished with the sensitive stuff */
	unbecome_user();
	
	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
		set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
	}
	
	return(conn);
}
Example #2
0
static NTSTATUS create_connection_server_info(struct smbd_server_connection *sconn,
					      TALLOC_CTX *mem_ctx, int snum,
                                              struct auth_serversupplied_info *vuid_serverinfo,
					      DATA_BLOB password,
                                              struct auth_serversupplied_info **presult)
{
        if (lp_guest_only(snum)) {
                return make_server_info_guest(mem_ctx, presult);
        }

        if (vuid_serverinfo != NULL) {

		struct auth_serversupplied_info *result;

                /*
                 * This is the normal security != share case where we have a
                 * valid vuid from the session setup.                 */

                if (vuid_serverinfo->guest) {
                        if (!lp_guest_ok(snum)) {
                                DEBUG(2, ("guest user (from session setup) "
                                          "not permitted to access this share "
                                          "(%s)\n", lp_servicename(snum)));
                                return NT_STATUS_ACCESS_DENIED;
                        }
                } else {
                        if (!user_ok_token(vuid_serverinfo->unix_name,
					   pdb_get_domain(vuid_serverinfo->sam_account),
                                           vuid_serverinfo->ptok, snum)) {
                                DEBUG(2, ("user '%s' (from session setup) not "
                                          "permitted to access this share "
                                          "(%s)\n",
                                          vuid_serverinfo->unix_name,
                                          lp_servicename(snum)));
                                return NT_STATUS_ACCESS_DENIED;
                        }
                }

                result = copy_serverinfo(mem_ctx, vuid_serverinfo);
		if (result == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		*presult = result;
		return NT_STATUS_OK;
        }

        if (lp_security() == SEC_SHARE) {

                fstring user;
		bool guest;

                /* add the sharename as a possible user name if we
                   are in share mode security */

                add_session_user(sconn, lp_servicename(snum));

                /* shall we let them in? */

                if (!authorise_login(sconn, snum,user,password,&guest)) {
                        DEBUG( 2, ( "Invalid username/password for [%s]\n",
                                    lp_servicename(snum)) );
			return NT_STATUS_WRONG_PASSWORD;
                }

		return make_serverinfo_from_username(mem_ctx, user, guest,
						     presult);
        }

	DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
	return NT_STATUS_ACCESS_DENIED;
}
Example #3
0
static connection_struct *make_connection_snum(int snum, user_struct *vuser,
					       DATA_BLOB password, 
					       const char *pdev,
					       NTSTATUS *status)
{
	struct passwd *pass = NULL;
	BOOL guest = False;
	connection_struct *conn;
	SMB_STRUCT_STAT st;
	fstring user;
	fstring dev;
	int ret;
	struct timespec atime_ts, mtime_ts, ctime_ts;

	*user = 0;
	fstrcpy(dev, pdev);
	SET_STAT_INVALID(st);

	if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
		return NULL;
	}	

	conn = conn_new();
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*status = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}

	conn->params->service = snum;
	conn->nt_user_token = NULL;

	if (lp_guest_only(snum)) {
		const char *guestname = lp_guestaccount();
		NTSTATUS status2;
		char *found_username = NULL;

		guest = True;
		pass = getpwnam_alloc(NULL, guestname);
		if (!pass) {
			DEBUG(0,("make_connection_snum: Invalid guest "
				 "account %s??\n",guestname));
			conn_free(conn);
			*status = NT_STATUS_NO_SUCH_USER;
			return NULL;
		}
		status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True,
						     &conn->uid, &conn->gid,
						     &found_username,
						     &conn->nt_user_token);
		if (!NT_STATUS_IS_OK(status2)) {
			TALLOC_FREE(pass);
			conn_free(conn);
			*status = status2;
			return NULL;
		}
		fstrcpy(user, found_username);
		string_set(&conn->user,user);
		conn->force_user = True;
		TALLOC_FREE(found_username);
		TALLOC_FREE(pass);
		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)\n", lp_servicename(snum)));
				      conn_free(conn);
				      *status = NT_STATUS_ACCESS_DENIED;
				      return NULL;
			}
		} else {
			if (!user_ok_token(vuser->user.unix_name,
					   vuser->nt_user_token, snum)) {
				DEBUG(2, ("user '%s' (from session setup) not "
					  "permitted to access this share "
					  "(%s)\n", vuser->user.unix_name,
					  lp_servicename(snum)));
				conn_free(conn);
				*status = NT_STATUS_ACCESS_DENIED;
				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) {
		NTSTATUS status2;
		char *found_username = NULL;

		/* 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)) {
			DEBUG( 2, ( "Invalid username/password for [%s]\n", 
				    lp_servicename(snum)) );
			conn_free(conn);
			*status = NT_STATUS_WRONG_PASSWORD;
			return NULL;
		}
		pass = Get_Pwnam(user);
		status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True,
						     &conn->uid, &conn->gid,
						     &found_username,
						     &conn->nt_user_token);
		if (!NT_STATUS_IS_OK(status2)) {
			conn_free(conn);
			*status = status2;
			return NULL;
		}
		fstrcpy(user, found_username);
		string_set(&conn->user,user);
		TALLOC_FREE(found_username);
		conn->force_user = True;
	} else {
		DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
		conn_free(conn);
		*status = NT_STATUS_ACCESS_DENIED;
		return NULL;
	}

	add_session_user(user);

	safe_strcpy(conn->client_address, client_addr(), 
		    sizeof(conn->client_address)-1);
	conn->num_files_open = 0;
	conn->lastused = conn->lastused_count = time(NULL);
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
		      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
	conn->dirptr = NULL;

	/* Case options for the share. */
	if (lp_casesensitive(snum) == Auto) {
		/* We will be setting this per packet. Set to be case
		 * insensitive for now. */
		conn->case_sensitive = False;
	} else {
		conn->case_sensitive = (BOOL)lp_casesensitive(snum);
	}

	conn->case_preserve = lp_preservecase(snum);
	conn->short_case_preserve = lp_shortpreservecase(snum);

	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	conn->aio_write_behind_list = NULL;
	string_set(&conn->dirpath,"");
	string_set(&conn->user,user);

	conn->read_only = lp_readonly(SNUM(conn));
	conn->admin_user = False;

	/*
	 * If force user is true, then store the given userid and the gid of
	 * the user we're forcing.
	 * For auxiliary groups see below.
	 */
	
	if (*lp_force_user(snum)) {
		NTSTATUS status2;

		status2 = find_forced_user(conn,
				(vuser != NULL) && vuser->guest,
				user);
		if (!NT_STATUS_IS_OK(status2)) {
			conn_free(conn);
			*status = status2;
			return NULL;
		}
		string_set(&conn->user,user);
		conn->force_user = True;
		DEBUG(3,("Forced user %s\n",user));	  
	}

	/*
	 * If force group is true, then override
	 * any groupid stored for the connecting user.
	 */
	
	if (*lp_force_group(snum)) {
		NTSTATUS status2;
		DOM_SID group_sid;

		status2 = find_forced_group(conn->force_user,
					    snum, user,
					    &group_sid, &conn->gid);
		if (!NT_STATUS_IS_OK(status2)) {
			conn_free(conn);
			*status = status2;
			return NULL;
		}

		if ((conn->nt_user_token == NULL) && (vuser != NULL)) {

			/* Not force user and not security=share, but force
			 * group. vuser has a token to copy */
			
			conn->nt_user_token = dup_nt_token(
				NULL, vuser->nt_user_token);
			if (conn->nt_user_token == NULL) {
				DEBUG(0, ("dup_nt_token failed\n"));
				conn_free(conn);
				*status = NT_STATUS_NO_MEMORY;
				return NULL;
			}
		}

		/* If conn->nt_user_token is still NULL, we have
		 * security=share. This means ignore the SID, as we had no
		 * vuser to copy from */

		if (conn->nt_user_token != NULL) {
			/* Overwrite the primary group sid */
			sid_copy(&conn->nt_user_token->user_sids[1],
				 &group_sid);

		}
		conn->force_group = True;
	}

	if (conn->nt_user_token != NULL) {
		size_t i;

		/* We have a share-specific token from force [user|group].
		 * This means we have to create the list of unix groups from
		 * the list of sids. */

		conn->ngroups = 0;
		conn->groups = NULL;

		for (i=0; i<conn->nt_user_token->num_sids; i++) {
			gid_t gid;
			DOM_SID *sid = &conn->nt_user_token->user_sids[i];

			if (!sid_to_gid(sid, &gid)) {
				DEBUG(10, ("Could not convert SID %s to gid, "
					   "ignoring it\n",
					   sid_string_static(sid)));
				continue;
			}
			if (!add_gid_to_array_unique(conn->mem_ctx, gid, &conn->groups,
						&conn->ngroups)) {
				DEBUG(0, ("add_gid_to_array_unique failed\n"));
				conn_free(conn);
				*status = NT_STATUS_NO_MEMORY;
				return NULL;
			}
		}
	}

	{
		pstring s;
		pstrcpy(s,lp_pathname(snum));
		standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
				      conn->connectpath, conn->gid,
				      get_current_username(),
				      current_user_info.domain,
				      s, sizeof(s));

		if (s[0] == '\0') {
			DEBUG(6, ("service [%s] did not resolve to a path\n",
				lp_servicename(snum)));
			conn_free(conn);
			*status = NT_STATUS_BAD_NETWORK_NAME;
			return NULL;
		}

		set_conn_connectpath(conn,s);
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(snum)));
	}

	/*
	 * New code to check if there's a share security descripter
	 * added from NT server manager. This is done after the
	 * smb.conf checks are done as we need a uid and token. JRA.
	 *
	 */

	{
		BOOL can_write = False;
		NT_USER_TOKEN *token = conn->nt_user_token ?
			conn->nt_user_token :
			(vuser ? vuser->nt_user_token : NULL);

		/*
		 * I don't believe this can happen. But the
		 * logic above is convoluted enough to confuse
		 * automated checkers, so be sure. JRA.
		 */

		if (token == NULL) {
			DEBUG(0,("make_connection: connection to %s "
				 "denied due to missing "
				 "NT token.\n",
				  lp_servicename(snum)));
			conn_free(conn);
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}

		can_write = share_access_check(token,
						    lp_servicename(snum),
						    FILE_WRITE_DATA);

		if (!can_write) {
			if (!share_access_check(token,
						lp_servicename(snum),
						FILE_READ_DATA)) {
				/* No access, read or write. */
				DEBUG(0,("make_connection: connection to %s "
					 "denied due to security "
					 "descriptor.\n",
					  lp_servicename(snum)));
				conn_free(conn);
				*status = NT_STATUS_ACCESS_DENIED;
				return NULL;
			} else {
				conn->read_only = True;
			}
		}
	}
	/* Initialise VFS function pointers */

	if (!smbd_vfs_init(conn)) {
		DEBUG(0, ("vfs_init failed for service %s\n",
			  lp_servicename(snum)));
		conn_free(conn);
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/*
	 * If widelinks are disallowed we need to canonicalise the connect
	 * path here to ensure we don't have any symlinks in the
	 * connectpath. We will be checking all paths on this connection are
	 * below this directory. We must do this after the VFS init as we
	 * depend on the realpath() pointer in the vfs table. JRA.
	 */
	if (!lp_widelinks(snum)) {
		pstring s;
		pstrcpy(s,conn->connectpath);
		canonicalize_path(conn, s);
		set_conn_connectpath(conn,s);
	}

	if ((!conn->printer) && (!conn->ipc)) {
		conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(),
					       smbd_messaging_context(),
					       smbd_event_context(),
					       conn);
	}

/* ROOT Activities: */	
	/* check number of connections */
	if (!claim_connection(conn,
			      lp_servicename(snum),
			      lp_max_connections(snum),
			      False,0)) {
		DEBUG(1,("too many connections - rejected\n"));
		conn_free(conn);
		*status = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}  

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(snum)) {
		pstring cmd;
		pstrcpy(cmd,lp_rootpreexec(snum));
		standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
				      conn->connectpath, conn->gid,
				      get_current_username(),
				      current_user_info.domain,
				      cmd, sizeof(cmd));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		if (ret != 0 && lp_rootpreexec_close(snum)) {
			DEBUG(1,("root preexec gave %d - failing "
				 "connection\n", ret));
			yield_connection(conn, lp_servicename(snum));
			conn_free(conn);
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

/* USER Activites: */
	if (!change_to_user(conn, conn->vuid)) {
		/* No point continuing if they fail the basic checks */
		DEBUG(0,("Can't become connected user!\n"));
		yield_connection(conn, lp_servicename(snum));
		conn_free(conn);
		*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)) {
		pstring cmd;
		pstrcpy(cmd,lp_preexec(snum));
		standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
				      conn->connectpath, conn->gid,
				      get_current_username(),
				      current_user_info.domain,
				      cmd, sizeof(cmd));
		ret = smbrun(cmd,NULL);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			change_to_root_user();
			yield_connection(conn, lp_servicename(snum));
			conn_free(conn);
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

#ifdef WITH_FAKE_KASERVER
	if (lp_afs_share(snum)) {
		afs_login(conn);
	}
#endif
	
	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(snum));
		set_namearray( &conn->hide_list, lp_hide_files(snum));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
	}
	
	/* Invoke VFS make connection hook - do this before the VFS_STAT call
	   to allow any filesystems needing user credentials to initialize
	   themselves. */

	if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
		DEBUG(0,("make_connection: VFS make connection failed!\n"));
		change_to_root_user();
		yield_connection(conn, lp_servicename(snum));
		conn_free(conn);
		*status = NT_STATUS_UNSUCCESSFUL;
		return NULL;
	}

	/* win2000 does not check the permissions on the directory
	   during the tree connect, instead relying on permission
	   check during individual operations. To match this behaviour
	   I have disabled this chdir check (tridge) */
	/* the alternative is just to check the directory exists */
	if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
	    !S_ISDIR(st.st_mode)) {
		if (ret == 0 && !S_ISDIR(st.st_mode)) {
			DEBUG(0,("'%s' is not a directory, when connecting to "
				 "[%s]\n", conn->connectpath,
				 lp_servicename(snum)));
		} else {
			DEBUG(0,("'%s' does not exist or permission denied "
				 "when connecting to [%s] Error was %s\n",
				 conn->connectpath, lp_servicename(snum),
				 strerror(errno) ));
		}
		change_to_root_user();
		/* Call VFS disconnect hook */    
		SMB_VFS_DISCONNECT(conn);
		yield_connection(conn, lp_servicename(snum));
		conn_free(conn);
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	string_set(&conn->origpath,conn->connectpath);

	mtime_ts = get_mtimespec(&st);
	ctime_ts = get_ctimespec(&st);
	atime_ts = get_atimespec(&st);

	conn->ts_res = TIMESTAMP_SET_SECONDS;

	if (mtime_ts.tv_nsec ||
			atime_ts.tv_nsec ||
			ctime_ts.tv_nsec) {
		/* If any of the normal UNIX directory timestamps
		 * have a non-zero tv_nsec component assume
		 * we might be able to set sub-second timestamps.
		 * See what filetime set primitives we have.
		 */
#if defined(HAVE_UTIMES)
		/* utimes allows msec timestamps to be set. */
		conn->ts_res = TIMESTAMP_SET_MSEC;
#elif defined(HAVE_UTIME)
		/* utime only allows sec timestamps to be set. */
		conn->ts_res = TIMESTAMP_SET_SECONDS;
#endif

		/* TODO. Add a configure test for the Linux
		 * nsec timestamp set system call, and use it
		 * if available....
		 */
		DEBUG(10,("make_connection_snum: timestamp "
			"resolution of %s "
			"available on share %s, directory %s\n",
			conn->ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
			lp_servicename(conn->cnum),
			conn->connectpath ));
	}

#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early if possible */
	if (vfs_ChDir(conn,conn->connectpath) == 0) {
		pstring s;
		pstrcpy(s,conn->connectpath);
		vfs_GetWd(conn,s);
		set_conn_connectpath(conn,s);
		vfs_ChDir(conn,conn->connectpath);
	}
#endif
	
	if (lp_unix_extensions() && lp_widelinks(snum)) {
		DEBUG(0,("Share '%s' has wide links and unix extensions enabled. "
			"These parameters are incompatible. "
			"Disabling wide links for this share.\n",
			lp_servicename(snum) ));
		lp_do_parameter(snum, "wide links", "False");
	}

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using
	 * (at least initially).
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", get_remote_machine_name(),
			 conn->client_address );
		dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
		dbgtext( "connect to service %s ", lp_servicename(snum) );
		dbgtext( "initially as user %s ", user );
		dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
		dbgtext( "(pid %d)\n", (int)sys_getpid() );
	}
	
	/* we've finished with the user stuff - go back to root */
	change_to_root_user();
	return(conn);
}