Exemplo n.º 1
0
bool pdb_set_group_sid(struct samu *sampass, const DOM_SID *g_sid, enum pdb_value_state flag)
{
	gid_t gid;

	if (!g_sid)
		return False;

	if ( !(sampass->group_sid = TALLOC_P( sampass, DOM_SID )) ) {
		return False;
	}

	/* if we cannot resolve the SID to gid, then just ignore it and 
	   store DOMAIN_USERS as the primary groupSID */

	if ( sid_to_gid( g_sid, &gid ) ) {
		sid_copy(sampass->group_sid, g_sid);
	} else {
		sid_compose(sampass->group_sid, get_global_sam_sid(),
			    DOMAIN_GROUP_RID_USERS);
	}

	DEBUG(10, ("pdb_set_group_sid: setting group sid %s\n", 
		   sid_string_dbg(sampass->group_sid)));

	return pdb_set_init_flags(sampass, PDB_GROUPSID, flag);
}
Exemplo n.º 2
0
/**
 * Turn SID into UID/GID and setup a struct ifs_identity
 */
static bool
onefs_sid_to_identity(const struct dom_sid *sid, struct ifs_identity *id,
    bool is_group)
{
	enum ifs_identity_type type = IFS_ID_TYPE_LAST+1;
	uid_t uid = 0;
	gid_t gid = 0;

	if (!sid || sid_equal(sid, &global_sid_NULL))
		type = IFS_ID_TYPE_NULL;
	else if (sid_equal(sid, &global_sid_World))
		type = IFS_ID_TYPE_EVERYONE;
	else if (sid_equal(sid, &global_sid_Creator_Owner))
		type = IFS_ID_TYPE_CREATOR_OWNER;
	else if (sid_equal(sid, &global_sid_Creator_Group))
		type = IFS_ID_TYPE_CREATOR_GROUP;
	else if (is_group) {
		if (!sid_to_gid(sid, &gid))
			return false;
		type = IFS_ID_TYPE_GID;
	} else {
		if (sid_to_uid(sid, &uid))
			type = IFS_ID_TYPE_UID;
		else if (sid_to_gid(sid, &gid))
			type = IFS_ID_TYPE_GID;
		else
			return false;
	}

	if (aclu_initialize_identity(id, type, uid, gid, is_group)) {
		DEBUG(3, ("Call to aclu_initialize_identity failed! id=%x, "
		    "type=%d, uid=%u, gid=%u, is_group=%d\n",
		    (unsigned int)id, type, uid, gid, is_group));
		return false;
	}

	return true;
}
Exemplo n.º 3
0
/**
 * Create the requested BUILTIN if it doesn't already exist.  This requires
 * winbindd to be running.
 *
 * @param[in] rid BUILTIN rid to create
 * @return Normal NTSTATUS return.
 */
static NTSTATUS create_builtin(uint32 rid)
{
	NTSTATUS status = NT_STATUS_OK;
	struct dom_sid sid;
	gid_t gid;

	if (!sid_compose(&sid, &global_sid_Builtin, rid)) {
		return NT_STATUS_NO_SUCH_ALIAS;
	}

	if (!sid_to_gid(&sid, &gid)) {
		if (!lp_winbind_nested_groups() || !winbind_ping()) {
			return NT_STATUS_PROTOCOL_UNREACHABLE;
		}
		status = pdb_create_builtin_alias(rid);
	}
	return status;
}
Exemplo n.º 4
0
static NTSTATUS find_forced_group(bool force_user,
				  int snum, const char *username,
				  DOM_SID *pgroup_sid,
				  gid_t *pgid)
{
	NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
	TALLOC_CTX *frame = talloc_stackframe();
	DOM_SID group_sid;
	enum lsa_SidType type;
	char *groupname;
	bool user_must_be_member = False;
	gid_t gid;

	groupname = talloc_strdup(talloc_tos(), lp_force_group(snum));
	if (groupname == NULL) {
		DEBUG(1, ("talloc_strdup failed\n"));
		result = NT_STATUS_NO_MEMORY;
		goto done;
	}

	if (groupname[0] == '+') {
		user_must_be_member = True;
		groupname += 1;
	}

	groupname = talloc_string_sub(talloc_tos(), groupname,
				      "%S", lp_servicename(snum));
	if (groupname == NULL) {
		DEBUG(1, ("talloc_string_sub failed\n"));
		result = NT_STATUS_NO_MEMORY;
		goto done;
	}

	if (!lookup_name_smbconf(talloc_tos(), groupname,
			 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
			 NULL, NULL, &group_sid, &type)) {
		DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
			   groupname));
		goto done;
	}

	if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
	    (type != SID_NAME_WKN_GRP)) {
		DEBUG(10, ("%s is a %s, not a group\n", groupname,
			   sid_type_lookup(type)));
		goto done;
	}

	if (!sid_to_gid(&group_sid, &gid)) {
		DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
			   sid_string_dbg(&group_sid), groupname));
		goto done;
	}

	/*
	 * 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 (force_user && user_must_be_member) {
		if (user_in_group_sid(username, &group_sid)) {
			sid_copy(pgroup_sid, &group_sid);
			*pgid = gid;
			DEBUG(3,("Forced group %s for member %s\n",
				 groupname, username));
		} else {
			DEBUG(0,("find_forced_group: forced user %s is not a member "
				"of forced group %s. Disallowing access.\n",
				username, groupname ));
			result = NT_STATUS_MEMBER_NOT_IN_GROUP;
			goto done;
		}
	} else {
		sid_copy(pgroup_sid, &group_sid);
		*pgid = gid;
		DEBUG(3,("Forced group %s\n", groupname));
	}

	result = NT_STATUS_OK;
 done:
	TALLOC_FREE(frame);
	return result;
}
Exemplo n.º 5
0
void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok)
{
	int total_groups;
	int current_n_groups = *n_groups;
	gid_t *final_groups = NULL;
	size_t i;
	NT_USER_TOKEN *ptok = *pptok;
	NT_USER_TOKEN *new_tok = NULL;
 
	if (!ptok || (ptok->num_sids == 0))
		return;

	new_tok = dup_nt_token(ptok);
	if (!new_tok) {
		DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n"));
		return;
	}
	/* Leave the allocated space but empty the number of SIDs. */
	new_tok->num_sids = 0;

	total_groups = current_n_groups + ptok->num_sids;
 
	final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t));
	if (!final_groups) {
		DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n"));
		delete_nt_token(&new_tok);
		return;
	}
 
	memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t));
	for (i = 0; i < ptok->num_sids; i++) {
		enum SID_NAME_USE sid_type;
		gid_t new_grp;
 
		if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) {
			/*
			 * Don't add the gid_t if it is already in the current group
			 * list. Some UNIXen don't like the same group more than once.
			 */
			int j;

			for (j = 0; j < current_n_groups; j++)
				if (final_groups[j] == new_grp)
					break;
		
			if ( j == current_n_groups) {
				/* Group not already present. */
				final_groups[current_n_groups++] = new_grp;
			}
		} else {
			/* SID didn't map. Copy to the new token to be saved. */
			sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
		}
	}
 
	SAFE_FREE(*pp_groups);
	*pp_groups = final_groups;
	*n_groups = current_n_groups;

	/* Replace the old token with the truncated one. */
	delete_nt_token(&ptok);
	*pptok = new_tok;
}
Exemplo n.º 6
0
/*******************************************************************
 gets a domain user's groups
 ********************************************************************/
NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, uint32 **prids, DOM_SID *q_sid)
{
	SAM_ACCOUNT *sam_pass=NULL;
	int i, cur_rid=0;
	gid_t gid;
	gid_t *groups = NULL;
	int num_groups;
	GROUP_MAP map;
	DOM_SID tmp_sid;
	fstring user_name;
	fstring str_domsid, str_qsid;
	uint32 rid,grid;
	uint32 *rids=NULL, *new_rids=NULL;
	gid_t winbind_gid_low, winbind_gid_high;
	BOOL ret;
	BOOL winbind_groups_exist;

	/*
	 * this code is far from perfect.
	 * first it enumerates the full /etc/group and that can be slow.
	 * second, it works only with users' SIDs
	 * whereas the day we support nested groups, it will have to
	 * support both users's SIDs and domain groups' SIDs
	 *
	 * having our own ldap backend would be so much faster !
	 * we're far from that, but hope one day ;-) JFM.
	 */

	*prids=NULL;
	*numgroups=0;

	winbind_groups_exist = lp_idmap_gid(&winbind_gid_low, &winbind_gid_high);


	DEBUG(10,("get_alias_user_groups: looking if SID %s is a member of groups in the SID domain %s\n", 
	          sid_to_string(str_qsid, q_sid), sid_to_string(str_domsid, sid)));

	pdb_init_sam(&sam_pass);
	become_root();
	ret = pdb_getsampwsid(sam_pass, q_sid);
	unbecome_root();
	if (ret == False) {
		pdb_free_sam(&sam_pass);
		return NT_STATUS_NO_SUCH_USER;
	}

	fstrcpy(user_name, pdb_get_username(sam_pass));
	grid=pdb_get_group_rid(sam_pass);
	if (!NT_STATUS_IS_OK(sid_to_gid(pdb_get_group_sid(sam_pass), &gid))) {
		/* this should never happen */
		DEBUG(2,("get_alias_user_groups: sid_to_gid failed!\n"));
		pdb_free_sam(&sam_pass);
		return NT_STATUS_UNSUCCESSFUL;
	}

	become_root();
	/* on some systems this must run as root */
	num_groups = getgroups_user(user_name, &groups);	
	unbecome_root();
	if (num_groups == -1) {
		/* this should never happen */
		DEBUG(2,("get_alias_user_groups: getgroups_user failed\n"));
		pdb_free_sam(&sam_pass);
		return NT_STATUS_UNSUCCESSFUL;
	}

	for (i=0;i<num_groups;i++) {

		if (!get_group_from_gid(groups[i], &map)) {
			DEBUG(10,("get_alias_user_groups: gid %d. not found\n", (int)groups[i]));
			continue;
		}
		
		/* if it's not an alias, continue */
		if (map.sid_name_use != SID_NAME_ALIAS) {
			DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
			continue;
		}

		sid_copy(&tmp_sid, &map.sid);
		sid_split_rid(&tmp_sid, &rid);
		
		/* if the sid is not in the correct domain, continue */
		if (!sid_equal(&tmp_sid, sid)) {
			DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
			continue;
		}

		/* Don't return winbind groups as they are not local! */
		if (winbind_groups_exist && (groups[i] >= winbind_gid_low) && (groups[i] <= winbind_gid_high)) {
			DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name));
			continue;
		}

		/* Don't return user private groups... */
		if (Get_Pwnam(map.nt_name) != 0) {
			DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name));
			continue;			
		}
		
		new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
		if (new_rids==NULL) {
			DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
			pdb_free_sam(&sam_pass);
			free(groups);
			return NT_STATUS_NO_MEMORY;
		}
		rids=new_rids;
		
		sid_peek_rid(&map.sid, &(rids[cur_rid]));
		cur_rid++;
		break;
	}

	if(num_groups) 
		free(groups);

	/* now check for the user's gid (the primary group rid) */
	for (i=0; i<cur_rid && grid!=rids[i]; i++)
		;

	/* the user's gid is already there */
	if (i!=cur_rid) {
		DEBUG(10,("get_alias_user_groups: user is already in the list. good.\n"));
		goto done;
	}

	DEBUG(10,("get_alias_user_groups: looking for gid %d of user %s\n", (int)gid, user_name));

	if(!get_group_from_gid(gid, &map)) {
		DEBUG(0,("get_alias_user_groups: gid of user %s doesn't exist. Check your "
		"/etc/passwd and /etc/group files\n", user_name));
		goto done;
	}	

	/* the primary group isn't an alias */
	if (map.sid_name_use!=SID_NAME_ALIAS) {
		DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
		goto done;
	}

	sid_copy(&tmp_sid, &map.sid);
	sid_split_rid(&tmp_sid, &rid);

	/* if the sid is not in the correct domain, continue */
	if (!sid_equal(&tmp_sid, sid)) {
		DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
		goto done;
	}

	/* Don't return winbind groups as they are not local! */
	if (winbind_groups_exist && (gid >= winbind_gid_low) && (gid <= winbind_gid_high)) {
		DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name ));
		goto done;
	}

	/* Don't return user private groups... */
	if (Get_Pwnam(map.nt_name) != 0) {
		DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name ));
		goto done;			
	}

	new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
	if (new_rids==NULL) {
		DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
		pdb_free_sam(&sam_pass);
		return NT_STATUS_NO_MEMORY;
	}
	rids=new_rids;

 	sid_peek_rid(&map.sid, &(rids[cur_rid]));
	cur_rid++;

done:
 	*prids=rids;
	*numgroups=cur_rid;
	pdb_free_sam(&sam_pass);

	return NT_STATUS_OK;
}
Exemplo n.º 7
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);
}
Exemplo n.º 8
0
static bool smbacl4_fill_ace4(
    const struct smb_filename *filename,
    smbacl4_vfs_params *params,
    uid_t ownerUID,
    gid_t ownerGID,
    const struct security_ace *ace_nt, /* input */
    SMB_ACE4PROP_T *ace_v4 /* output */
)
{
    DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));

    memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));

    /* only ACCESS|DENY supported right now */
    ace_v4->aceType = ace_nt->type;

    ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
                           ace_nt->flags);

    /* remove inheritance flags on files */
    if (VALID_STAT(filename->st) &&
            !S_ISDIR(filename->st.st_ex_mode)) {
        DEBUG(10, ("Removing inheritance flags from a file\n"));
        ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
                              SMB_ACE4_DIRECTORY_INHERIT_ACE|
                              SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
                              SMB_ACE4_INHERIT_ONLY_ACE);
    }

    ace_v4->aceMask = ace_nt->access_mask &
                      (SEC_STD_ALL | SEC_FILE_ALL);

    se_map_generic(&ace_v4->aceMask, &file_generic_mapping);

    if (ace_v4->aceFlags!=ace_nt->flags)
        DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
                  ace_v4->aceFlags, ace_nt->flags));

    if (ace_v4->aceMask!=ace_nt->access_mask)
        DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
                  ace_v4->aceMask, ace_nt->access_mask));

    if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
        ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
        ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
    } else if (params->mode!=e_special &&
               dom_sid_equal(&ace_nt->trustee,
                             &global_sid_Creator_Owner)) {
        DEBUG(10, ("Map creator owner\n"));
        ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
        ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
        /* A non inheriting creator owner entry has no effect. */
        ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
        if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
                && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
            return false;
        }
    } else if (params->mode!=e_special &&
               dom_sid_equal(&ace_nt->trustee,
                             &global_sid_Creator_Group)) {
        DEBUG(10, ("Map creator owner group\n"));
        ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
        ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
        /* A non inheriting creator group entry has no effect. */
        ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
        if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
                && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
            return false;
        }
    } else {
        uid_t uid;
        gid_t gid;

        if (sid_to_gid(&ace_nt->trustee, &gid)) {
            ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
            ace_v4->who.gid = gid;
        } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
            ace_v4->who.uid = uid;
        } else {
            DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
                      "convert %s to uid or gid\n",
                      filename->base_name,
                      sid_string_dbg(&ace_nt->trustee)));
            return false;
        }
    }

    return true; /* OK */
}