Example #1
0
NTSTATUS make_session_info_from_username(TALLOC_CTX *mem_ctx,
					 const char *username,
					 bool is_guest,
					 struct auth_session_info **session_info)
{
	struct passwd *pwd;
	NTSTATUS status;
	struct auth_serversupplied_info *result;

	pwd = Get_Pwnam_alloc(talloc_tos(), username);
	if (pwd == NULL) {
		return NT_STATUS_NO_SUCH_USER;
	}

	status = make_server_info_pw(&result, pwd->pw_name, pwd);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	result->nss_token = true;
	result->guest = is_guest;

	/* Now turn the server_info into a session_info with the full token etc */
	status = create_local_token(mem_ctx, result, NULL, pwd->pw_name, session_info);
	TALLOC_FREE(result);
	TALLOC_FREE(pwd);

	return status;
}
Example #2
0
NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
				       const char *username,
				       bool is_guest,
				       struct auth_serversupplied_info **presult)
{
	struct auth_serversupplied_info *result;
	struct passwd *pwd;
	NTSTATUS status;

	pwd = Get_Pwnam_alloc(talloc_tos(), username);
	if (pwd == NULL) {
		return NT_STATUS_NO_SUCH_USER;
	}

	status = make_server_info_pw(&result, pwd->pw_name, pwd);

	TALLOC_FREE(pwd);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	result->nss_token = true;
	result->guest = is_guest;

	status = create_local_token(result);

	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(result);
		return status;
	}

	*presult = talloc_steal(mem_ctx, result);
	return NT_STATUS_OK;
}
Example #3
0
NTSTATUS make_server_info_sam(struct auth_serversupplied_info **server_info,
			      struct samu *sampass)
{
	struct passwd *pwd;
	struct auth_serversupplied_info *result;
	const char *username = pdb_get_username(sampass);
	NTSTATUS status;

	if ( !(result = make_server_info(NULL)) ) {
		return NT_STATUS_NO_MEMORY;
	}

	if ( !(pwd = Get_Pwnam_alloc(result, username)) ) {
		DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n",
			  pdb_get_username(sampass)));
		TALLOC_FREE(result);
		return NT_STATUS_NO_SUCH_USER;
	}

	status = samu_to_SamInfo3(result, sampass, lp_netbios_name(),
				  &result->info3, &result->extra);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(result);
		return status;
	}

	result->unix_name = pwd->pw_name;
	/* Ensure that we keep pwd->pw_name, because we will free pwd below */
	talloc_steal(result, pwd->pw_name);
	result->utok.gid = pwd->pw_gid;
	result->utok.uid = pwd->pw_uid;

	TALLOC_FREE(pwd);

	if (IS_DC && is_our_machine_account(username)) {
		/*
		 * This is a hack of monstrous proportions.
		 * If we know it's winbindd talking to us,
		 * we know we must never recurse into it,
		 * so turn off contacting winbindd for this
		 * entire process. This will get fixed when
		 * winbindd doesn't need to talk to smbd on
		 * a PDC. JRA.
		 */

		(void)winbind_off();

		DEBUG(10, ("make_server_info_sam: our machine account %s "
			   "turning off winbindd requests.\n", username));
	}

	DEBUG(5,("make_server_info_sam: made server info for user %s -> %s\n",
		 pdb_get_username(sampass), result->unix_name));

	*server_info = result;

	return NT_STATUS_OK;
}
Example #4
0
static NTSTATUS get_guest_info3(TALLOC_CTX *mem_ctx,
				struct netr_SamInfo3 *info3)
{
	const char *guest_account = lp_guestaccount();
	struct dom_sid domain_sid;
	struct passwd *pwd;
	const char *tmp;

	pwd = Get_Pwnam_alloc(mem_ctx, guest_account);
	if (pwd == NULL) {
		DEBUG(0,("SamInfo3_for_guest: Unable to locate guest "
			 "account [%s]!\n", guest_account));
		return NT_STATUS_NO_SUCH_USER;
	}

	/* Set account name */
	tmp = talloc_strdup(mem_ctx, pwd->pw_name);
	if (tmp == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	init_lsa_String(&info3->base.account_name, tmp);

	/* Set domain name */
	tmp = talloc_strdup(mem_ctx, get_global_sam_name());
	if (tmp == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	init_lsa_StringLarge(&info3->base.logon_domain, tmp);

	/* Domain sid */
	sid_copy(&domain_sid, get_global_sam_sid());

	info3->base.domain_sid = dom_sid_dup(mem_ctx, &domain_sid);
	if (info3->base.domain_sid == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	/* Guest rid */
	info3->base.rid = DOMAIN_RID_GUEST;

	/* Primary gid */
	info3->base.primary_gid = DOMAIN_RID_GUESTS;

	/* Set as guest */
	info3->base.user_flags = NETLOGON_GUEST;

	TALLOC_FREE(pwd);
	return NT_STATUS_OK;
}
Example #5
0
bool lookup_unix_user_name(const char *name, DOM_SID *sid)
{
	struct passwd *pwd;

	pwd = Get_Pwnam_alloc(talloc_autofree_context(), name);
	if (pwd == NULL) {
		return False;
	}

	sid_copy(sid, &global_sid_Unix_Users);
	sid_append_rid(sid, (uint32_t)pwd->pw_uid); /* For 64-bit uid's we have enough
					  * space ... */
	TALLOC_FREE(pwd);
	return True;
}
Example #6
0
char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user)
{
	struct passwd *pass;
	char *result;

	/* Ensure the user exists. */

	pass = Get_Pwnam_alloc(mem_ctx, user);

	if (!pass)
		return(NULL);

	/* Return home directory from struct passwd. */

	result = talloc_move(mem_ctx, &pass->pw_dir);

	TALLOC_FREE(pass);
	return result;
}
Example #7
0
NTSTATUS make_session_info_from_username(TALLOC_CTX *mem_ctx,
					 const char *username,
					 bool is_guest,
					 struct auth_session_info **session_info)
{
	struct passwd *pwd;
	NTSTATUS status;
	struct auth_serversupplied_info *result;
	TALLOC_CTX *tmp_ctx;

	tmp_ctx = talloc_stackframe();
	if (tmp_ctx == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	pwd = Get_Pwnam_alloc(tmp_ctx, username);
	if (pwd == NULL) {
		status = NT_STATUS_NO_SUCH_USER;
		goto done;
	}

	status = make_server_info_pw(tmp_ctx, pwd->pw_name, pwd, &result);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	result->nss_token = true;
	result->guest = is_guest;

	/* Now turn the server_info into a session_info with the full token etc */
	status = create_local_token(mem_ctx,
				    result,
				    NULL,
				    pwd->pw_name,
				    session_info);

done:
	talloc_free(tmp_ctx);

	return status;
}
Example #8
0
void add_session_user(const char *user)
{
	struct passwd *pw;
	char *tmp;

	pw = Get_Pwnam_alloc(talloc_tos(), user);

	if (pw == NULL) {
		return;
	}

	if (session_userlist == NULL) {
		session_userlist = SMB_STRDUP(pw->pw_name);
		goto done;
	}

	if (in_list(pw->pw_name,session_userlist,False) ) {
		goto done;
	}

	if (strlen(session_userlist) > 128 * 1024) {
		DEBUG(3,("add_session_user: session userlist already "
			 "too large.\n"));
		goto done;
	}

	if (asprintf(&tmp, "%s %s", session_userlist, pw->pw_name) == -1) {
		DEBUG(3, ("asprintf failed\n"));
		goto done;
	}

	SAFE_FREE(session_userlist);
	session_userlist = tmp;
 done:
	TALLOC_FREE(pw);
}
Example #9
0
File: uid.c Project: Arkhont/samba
bool change_to_guest(void)
{
	struct passwd *pass;

	pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
	if (!pass) {
		return false;
	}

#ifdef AIX
	/* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
	   setting IDs */
	initgroups(pass->pw_name, pass->pw_gid);
#endif

	set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);

	current_user.conn = NULL;
	current_user.vuid = UID_FIELD_INVALID;

	TALLOC_FREE(pass);

	return true;
}
Example #10
0
struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser,
			     char **p_save_username, bool create )
{
	struct passwd *pw = NULL;
	char *p = NULL;
	char *username = NULL;

	/* we only save a copy of the username it has been mangled 
	   by winbindd use default domain */
	*p_save_username = NULL;

	/* don't call map_username() here since it has to be done higher 
	   up the stack so we don't call it multiple times */

	username = talloc_strdup(mem_ctx, domuser);
	if (!username) {
		return NULL;
	}

	p = strchr_m( username, *lp_winbind_separator() );

	/* code for a DOMAIN\user string */

	if ( p ) {
		pw = Get_Pwnam_alloc( mem_ctx, domuser );
		if ( pw ) {
			/* make sure we get the case of the username correct */
			/* work around 'winbind use default domain = yes' */

			if ( lp_winbind_use_default_domain() &&
			     !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) {
				char *domain;

				/* split the domain and username into 2 strings */
				*p = '\0';
				domain = username;

				*p_save_username = talloc_asprintf(mem_ctx,
								"%s%c%s",
								domain,
								*lp_winbind_separator(),
								pw->pw_name);
				if (!*p_save_username) {
					TALLOC_FREE(pw);
					return NULL;
				}
			} else {
				*p_save_username = talloc_strdup(mem_ctx, pw->pw_name);
			}

			/* whew -- done! */
			return pw;
		}

		/* setup for lookup of just the username */
		/* remember that p and username are overlapping memory */

		p++;
		username = talloc_strdup(mem_ctx, p);
		if (!username) {
			return NULL;
		}
	}

	/* just lookup a plain username */

	pw = Get_Pwnam_alloc(mem_ctx, username);

	/* Create local user if requested but only if winbindd
	   is not running.  We need to protect against cases
	   where winbindd is failing and then prematurely
	   creating users in /etc/passwd */

	if ( !pw && create && !winbind_ping() ) {
		/* Don't add a machine account. */
		if (username[strlen(username)-1] == '$')
			return NULL;

		_smb_create_user(NULL, username, NULL);
		pw = Get_Pwnam_alloc(mem_ctx, username);
	}

	/* one last check for a valid passwd struct */

	if (pw) {
		*p_save_username = talloc_strdup(mem_ctx, pw->pw_name);
	}
	return pw;
}
Example #11
0
static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
{
	int i;

	/* initialize the status to avoid suprise */
	for (i = 0; ids[i]; i++) {
		ids[i]->status = ID_UNKNOWN;
	}

	for (i = 0; ids[i]; i++) {
		struct group *gr;
		enum lsa_SidType type;
		char *name = NULL;
		bool ret;

		/* by default calls to winbindd are disabled
		   the following call will not recurse so this is safe */
		(void)winbind_on();
		ret = winbind_lookup_sid(talloc_tos(), ids[i]->sid, NULL,
					 (const char **)&name, &type);
		(void)winbind_off();

		if (!ret) {
			/* TODO: how do we know if the name is really not mapped,
			 * or something just failed ? */
			ids[i]->status = ID_UNMAPPED;
			continue;
		}

		switch (type) {
		case SID_NAME_USER: {
			struct passwd *pw;

			/* this will find also all lower case name and use username level */

			pw = Get_Pwnam_alloc(talloc_tos(), name);
			if (pw) {
				ids[i]->xid.id = pw->pw_uid;
				ids[i]->xid.type = ID_TYPE_UID;
				ids[i]->status = ID_MAPPED;
			}
			TALLOC_FREE(pw);
			break;
		}

		case SID_NAME_DOM_GRP:
		case SID_NAME_ALIAS:
		case SID_NAME_WKN_GRP:

			gr = getgrnam(name);
			if (gr) {
				ids[i]->xid.id = gr->gr_gid;
				ids[i]->xid.type = ID_TYPE_GID;
				ids[i]->status = ID_MAPPED;
			}
			break;

		default:
			ids[i]->status = ID_UNKNOWN;
			break;
		}
		TALLOC_FREE(name);
	}
	return NT_STATUS_OK;
}
Example #12
0
bool authorise_login(int snum, fstring user, DATA_BLOB password,
		     bool *guest)
{
	bool ok = False;

#ifdef DEBUG_PASSWORD
	DEBUG(100,("authorise_login: checking authorisation on "
		   "user=%s pass=%s\n", user,password.data));
#endif

	*guest = False;

	/* there are several possibilities:
		1) login as the given user with given password
		2) login as a previously registered username with the given
		   password
		3) login as a session list username with the given password
		4) login as a previously validated user/password pair
		5) login as the "user ="******"user ="******"");

		if (!user_list)
			return(False);

		for (auser = strtok_r(user_list, LIST_SEP, &saveptr);
		     !ok && auser;
		     auser = strtok_r(NULL, LIST_SEP, &saveptr)) {
			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));
			}
		}

		SAFE_FREE(user_list);
	}

	/* check the user= fields and the given password */
	if (!ok && lp_username(snum)) {
		TALLOC_CTX *ctx = talloc_tos();
		char *auser;
		char *user_list = talloc_strdup(ctx, lp_username(snum));
		char *saveptr;

		if (!user_list) {
			goto check_guest;
		}

		user_list = talloc_string_sub(ctx,
				user_list,
				"%S",
				lp_servicename(snum));

		if (!user_list) {
			goto check_guest;
		}

		for (auser = strtok_r(user_list, LIST_SEP, &saveptr);
		     auser && !ok;
		     auser = strtok_r(NULL, LIST_SEP, &saveptr)) {
			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 and "
						 "given password ok (%s)\n",
						 user));
				}
			}
		}
	}

  check_guest:

	/* check for a normal guest connection */
	if (!ok && GUEST_OK(snum)) {
		struct passwd *guest_pw;
		fstring guestname;
		fstrcpy(guestname,lp_guestaccount());
		guest_pw = Get_Pwnam_alloc(talloc_tos(), guestname);
		if (guest_pw != NULL) {
			fstrcpy(user,guestname);
			ok = True;
			DEBUG(3,("authorise_login: ACCEPTED: guest account "
				 "and guest ok (%s)\n",	user));
		} else {
			DEBUG(0,("authorise_login: Invalid guest account "
				 "%s??\n",guestname));
		}
		TALLOC_FREE(guest_pw);
		*guest = True;
	}

	if (ok && !user_ok(user, snum)) {
		DEBUG(0,("authorise_login: rejected invalid user %s\n",user));
		ok = False;
	}

	return(ok);
}
Example #13
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;
	char addr[INET6_ADDRSTRLEN];
	bool on_err_call_dis_hook = false;

	*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(talloc_tos(), 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_alloc(talloc_tos(), user);
		status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True,
						     &conn->uid, &conn->gid,
						     &found_username,
						     &conn->nt_user_token);
		TALLOC_FREE(pass);
		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(get_client_fd(),addr,sizeof(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->encrypt_level = lp_smb_encrypt(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_dbg(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;
			}
		}
	}

	{
		char *s = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)), conn->user,
					conn->connectpath, conn->gid,
					get_current_username(),
					current_user_info.domain,
					lp_pathname(snum));
		if (!s) {
			conn_free(conn);
			*status = NT_STATUS_NO_MEMORY;
			return NULL;
		}

		if (!set_conn_connectpath(conn,s)) {
			TALLOC_FREE(s);
			conn_free(conn);
			*status = NT_STATUS_NO_MEMORY;
			return NULL;
		}
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(snum)));
		TALLOC_FREE(s);
	}

	/*
	 * 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)) {
		if (!canonicalize_connect_path(conn)) {
			DEBUG(0, ("canonicalize_connect_path failed "
			"for service %s, path %s\n",
				lp_servicename(snum),
				conn->connectpath));
			conn_free(conn);
			*status = NT_STATUS_BAD_NETWORK_NAME;
			return NULL;
		}
	}

	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: */	
	/*
	 * Enforce the max connections parameter.
	 */

	if ((lp_max_connections(snum) > 0)
	    && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
		lp_max_connections(snum))) {

		DEBUG(1, ("Max connections (%d) exceeded for %s\n",
			  lp_max_connections(snum), lp_servicename(snum)));
		conn_free(conn);
		*status = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}  

	/*
	 * Get us an entry in the connections db
	 */
	if (!claim_connection(conn, lp_servicename(snum), 0)) {
		DEBUG(1, ("Could not store connections entry\n"));
		conn_free(conn);
		*status = NT_STATUS_INTERNAL_DB_ERROR;
		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)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)), conn->user,
					conn->connectpath, conn->gid,
					get_current_username(),
					current_user_info.domain,
					lp_rootpreexec(snum));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		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)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)), conn->user,
					conn->connectpath, conn->gid,
					get_current_username(),
					current_user_info.domain,
					lp_preexec(snum));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			*status = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

#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));
		set_namearray( &conn->aio_write_behind_list,
				lp_aio_write_behind(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"));
		*status = NT_STATUS_UNSUCCESSFUL;
		goto err_root_exit;
	}

	/* Any error exit after here needs to call the disconnect hook. */
	on_err_call_dis_hook = true;

	/* 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) ));
		}
		*status = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}

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

#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early if possible */
	if (vfs_ChDir(conn,conn->connectpath) == 0) {
		TALLOC_CTX *ctx = talloc_tos();
		char *s = vfs_GetWd(ctx,s);
		if (!s) {
			*status = map_nt_error_from_unix(errno);
			goto err_root_exit;
		}
		if (!set_conn_connectpath(conn,s)) {
			*status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}
		vfs_ChDir(conn,conn->connectpath);
	}
#endif

	/* Figure out the characteristics of the underlying filesystem. This
	 * assumes that all the filesystem mounted withing a share path have
	 * the same characteristics, which is likely but not guaranteed.
	 */

	conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);

	/*
	 * 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);

  err_root_exit:

	change_to_root_user();
	if (on_err_call_dis_hook) {
		/* Call VFS disconnect hook */
		SMB_VFS_DISCONNECT(conn);
	}
	yield_connection(conn, lp_servicename(snum));
	conn_free(conn);
	return NULL;
}
Example #14
0
const DOM_SID *pdb_get_group_sid(struct samu *sampass)
{
	DOM_SID *gsid;
	struct passwd *pwd;

	/* Return the cached group SID if we have that */
	if ( sampass->group_sid ) {
		return sampass->group_sid;
	}

	/* generate the group SID from the user's primary Unix group */

	if ( !(gsid  = TALLOC_P( sampass, DOM_SID )) ) {
		return NULL;
	}

	/* No algorithmic mapping, meaning that we have to figure out the
	   primary group SID according to group mapping and the user SID must
	   be a newly allocated one.  We rely on the user's Unix primary gid.
	   We have no choice but to fail if we can't find it. */

	if ( sampass->unix_pw ) {
		pwd = sampass->unix_pw;
	} else {
		pwd = Get_Pwnam_alloc( sampass, pdb_get_username(sampass) );
	}

	if ( !pwd ) {
		DEBUG(0,("pdb_get_group_sid: Failed to find Unix account for %s\n", pdb_get_username(sampass) ));
		return NULL;
	}

	if ( pdb_gid_to_sid(pwd->pw_gid, gsid) ) {
		enum lsa_SidType type = SID_NAME_UNKNOWN;
		TALLOC_CTX *mem_ctx = talloc_init("pdb_get_group_sid");
		bool lookup_ret;

		if (!mem_ctx) {
			return NULL;
		}

		/* Now check that it's actually a domain group and not something else */

		lookup_ret = lookup_sid(mem_ctx, gsid, NULL, NULL, &type);

		TALLOC_FREE( mem_ctx );

		if ( lookup_ret && (type == SID_NAME_DOM_GRP) ) {
			sampass->group_sid = gsid;
			return sampass->group_sid;
		}

		DEBUG(3, ("Primary group for user %s is a %s and not a domain group\n", 
			pwd->pw_name, sid_type_lookup(type)));
	}

	/* Just set it to the 'Domain Users' RID of 512 which will 
	   always resolve to a name */

	sid_compose(gsid, get_global_sam_sid(), DOMAIN_GROUP_RID_USERS);

	sampass->group_sid = gsid;

	return sampass->group_sid;
}