Exemplo n.º 1
0
static bool add_delete_on_close_token(struct share_mode_data *d,
			uint32_t name_hash,
			const struct security_token *nt_tok,
			const struct security_unix_token *tok)
{
	struct delete_token *tmp, *dtl;

	tmp = talloc_realloc(d, d->delete_tokens, struct delete_token,
			     d->num_delete_tokens+1);
	if (tmp == NULL) {
		return false;
	}
	d->delete_tokens = tmp;
	dtl = &d->delete_tokens[d->num_delete_tokens];

	dtl->name_hash = name_hash;
	dtl->delete_nt_token = dup_nt_token(d->delete_tokens, nt_tok);
	if (dtl->delete_nt_token == NULL) {
		return false;
	}
	dtl->delete_token = copy_unix_token(d->delete_tokens, tok);
	if (dtl->delete_token == NULL) {
		return false;
	}
	d->num_delete_tokens += 1;
	d->modified = true;
	return true;
}
Exemplo n.º 2
0
bool copy_current_user(struct current_user *dst, struct current_user *src)
{
	gid_t *groups;
	struct security_token *nt_token;

	groups = (gid_t *)memdup(src->ut.groups,
				 sizeof(gid_t) * src->ut.ngroups);
	if ((src->ut.ngroups != 0) && (groups == NULL)) {
		return False;
	}

	nt_token = dup_nt_token(NULL, src->nt_user_token);
	if (nt_token == NULL) {
		SAFE_FREE(groups);
		return False;
	}

	dst->conn = src->conn;
	dst->vuid = src->vuid;
	dst->ut.uid = src->ut.uid;
	dst->ut.gid = src->ut.gid;
	dst->ut.ngroups = src->ut.ngroups;
	dst->ut.groups = groups;
	dst->nt_user_token = nt_token;
	return True;
}
Exemplo n.º 3
0
void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
{
	struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
	
	/* Set the security context */

	DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
		(unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));

	debug_nt_user_token(DBGC_CLASS, 5, token);
	debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);

	gain_root();

#ifdef HAVE_SETGROUPS
	sys_setgroups(ngroups, groups);
#endif

	ctx_p->ut.ngroups = ngroups;

	SAFE_FREE(ctx_p->ut.groups);
	if (token && (token == ctx_p->token)) {
		smb_panic("DUPLICATE_TOKEN");
	}

	TALLOC_FREE(ctx_p->token);
	
	if (ngroups) {
		ctx_p->ut.groups = (gid_t *)memdup(groups,
						   sizeof(gid_t) * ngroups);
		if (!ctx_p->ut.groups) {
			smb_panic("memdup failed");
		}
	} else {
		ctx_p->ut.groups = NULL;
	}

	if (token) {
		ctx_p->token = dup_nt_token(NULL, token);
		if (!ctx_p->token) {
			smb_panic("dup_nt_token failed");
		}
	} else {
		ctx_p->token = NULL;
	}

	become_id(uid, gid);

	ctx_p->ut.uid = uid;
	ctx_p->ut.gid = gid;

	/* Update current_user stuff */

	current_user.ut.uid = uid;
	current_user.ut.gid = gid;
	current_user.ut.ngroups = ngroups;
	current_user.ut.groups = groups;
	current_user.nt_user_token = ctx_p->token;
}
Exemplo n.º 4
0
struct auth_serversupplied_info *copy_serverinfo(TALLOC_CTX *mem_ctx,
						 const struct auth_serversupplied_info *src)
{
	struct auth_serversupplied_info *dst;

	dst = make_server_info(mem_ctx);
	if (dst == NULL) {
		return NULL;
	}

	dst->guest = src->guest;
	dst->system = src->system;
	dst->utok.uid = src->utok.uid;
	dst->utok.gid = src->utok.gid;
	dst->utok.ngroups = src->utok.ngroups;
	if (src->utok.ngroups != 0) {
		dst->utok.groups = (gid_t *)TALLOC_MEMDUP(
			dst, src->utok.groups,
			sizeof(gid_t)*dst->utok.ngroups);
	} else {
		dst->utok.groups = NULL;
	}

	if (src->security_token) {
		dst->security_token = dup_nt_token(dst, src->security_token);
		if (!dst->security_token) {
			TALLOC_FREE(dst);
			return NULL;
		}
	}

	dst->user_session_key = data_blob_talloc( dst, src->user_session_key.data,
						src->user_session_key.length);

	dst->lm_session_key = data_blob_talloc(dst, src->lm_session_key.data,
						src->lm_session_key.length);

	dst->info3 = copy_netr_SamInfo3(dst, src->info3);
	if (!dst->info3) {
		TALLOC_FREE(dst);
		return NULL;
	}
	dst->extra = src->extra;

	dst->unix_name = talloc_strdup(dst, src->unix_name);
	if (!dst->unix_name) {
		TALLOC_FREE(dst);
		return NULL;
	}

	dst->sanitized_username = talloc_strdup(dst, src->sanitized_username);
	if (!dst->sanitized_username) {
		TALLOC_FREE(dst);
		return NULL;
	}

	return dst;
}
Exemplo n.º 5
0
void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, const struct security_token *token)
{
	struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];

	/* Set the security context */

	DEBUG(4, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
		(unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));

	security_token_debug(DBGC_CLASS, 5, token);
	debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);

	/* Change uid, gid and supplementary group list. */
	set_unix_security_ctx(uid, gid, ngroups, groups);

	ctx_p->ut.ngroups = ngroups;

	SAFE_FREE(ctx_p->ut.groups);
	if (token && (token == ctx_p->token)) {
		smb_panic("DUPLICATE_TOKEN");
	}

	TALLOC_FREE(ctx_p->token);

	if (ngroups) {
		ctx_p->ut.groups = (gid_t *)memdup(groups,
						   sizeof(gid_t) * ngroups);
		if (!ctx_p->ut.groups) {
			smb_panic("memdup failed");
		}
	} else {
		ctx_p->ut.groups = NULL;
	}

	if (token) {
		ctx_p->token = dup_nt_token(NULL, token);
		if (!ctx_p->token) {
			smb_panic("dup_nt_token failed");
		}
	} else {
		ctx_p->token = NULL;
	}

	ctx_p->ut.uid = uid;
	ctx_p->ut.gid = gid;

	/* Update current_user stuff */

	current_user.ut.uid = uid;
	current_user.ut.gid = gid;
	current_user.ut.ngroups = ngroups;
	current_user.ut.groups = groups;
	current_user.nt_user_token = ctx_p->token;
}
Exemplo n.º 6
0
void set_delete_on_close_lck(files_struct *fsp,
			struct share_mode_lock *lck,
			bool delete_on_close,
			const struct security_token *nt_tok,
			const struct security_unix_token *tok)
{
	struct share_mode_data *d = lck->data;
	int i;
	bool ret;

	if (delete_on_close) {
		SMB_ASSERT(nt_tok != NULL);
		SMB_ASSERT(tok != NULL);
	} else {
		SMB_ASSERT(nt_tok == NULL);
		SMB_ASSERT(tok == NULL);
	}

	for (i=0; i<d->num_delete_tokens; i++) {
		struct delete_token *dt = &d->delete_tokens[i];
		if (dt->name_hash == fsp->name_hash) {
			d->modified = true;
			if (delete_on_close == false) {
				/* Delete this entry. */
				TALLOC_FREE(dt->delete_nt_token);
				TALLOC_FREE(dt->delete_token);
				*dt = d->delete_tokens[
					d->num_delete_tokens-1];
				d->num_delete_tokens -= 1;
			} else {
				/* Replace this token with the
				   given tok. */
				TALLOC_FREE(dt->delete_nt_token);
				dt->delete_nt_token = dup_nt_token(dt, nt_tok);
				SMB_ASSERT(dt->delete_nt_token != NULL);
				TALLOC_FREE(dt->delete_token);
				dt->delete_token = copy_unix_token(dt, tok);
				SMB_ASSERT(dt->delete_token != NULL);
			}
			return;
		}
	}

	if (!delete_on_close) {
		/* Nothing to delete - not found. */
		return;
	}

	ret = add_delete_on_close_token(lck->data, fsp->name_hash, nt_tok, tok);
	SMB_ASSERT(ret);
}
Exemplo n.º 7
0
void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
{
	struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
	
	/* Set the security context */

	DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
		(unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));

	if (ngroups) {
		int i;

		DEBUG(3, ("%d user groups: \n", ngroups));
		for (i = 0; i < ngroups; i++) {
			DEBUGADD(3, ("%u ", (unsigned int)groups[i]));
		}

		DEBUG(3, ("\n"));
	}
	

	gain_root();

#ifdef HAVE_SETGROUPS
	sys_setgroups(ngroups, groups);
#endif

	ctx_p->ngroups = ngroups;

	SAFE_FREE(ctx_p->groups);
	if (token && (token == ctx_p->token))
		smb_panic("DUPLICATE_TOKEN");

	delete_nt_token(&ctx_p->token);
	
	ctx_p->groups = memdup(groups, sizeof(gid_t) * ngroups);
	ctx_p->token = dup_nt_token(token);

	become_id(uid, gid);

	ctx_p->uid = uid;
	ctx_p->gid = gid;

	/* Update current_user stuff */

	current_user.uid = uid;
	current_user.gid = gid;
	current_user.ngroups = ngroups;
	current_user.groups = groups;
	current_user.nt_user_token = ctx_p->token;
}
bool push_sec_ctx(void)
{
	struct sec_ctx *ctx_p;

	/* Check we don't overflow our stack */

	if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
		DEBUG(0, ("Security context stack overflow!\n"));
		smb_panic("Security context stack overflow!");
	}

	/* Store previous user context */

	sec_ctx_stack_ndx++;

	ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];

	ctx_p->ut.uid = geteuid();
	ctx_p->ut.gid = getegid();

 	DEBUG(4, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n", 
 		  (unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx ));

	ctx_p->token = dup_nt_token(NULL,
				    sec_ctx_stack[sec_ctx_stack_ndx-1].token);

	ctx_p->ut.ngroups = sys_getgroups(0, NULL);

	if (ctx_p->ut.ngroups != 0) {
		if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) {
			DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
			TALLOC_FREE(ctx_p->token);
			return False;
		}

		sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups);
	} else {
		ctx_p->ut.groups = NULL;
	}

	return True;
}
Exemplo n.º 9
0
BOOL push_sec_ctx(void)
{
	struct sec_ctx *ctx_p;

	/* Check we don't overflow our stack */

	if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
		DEBUG(0, ("Security context stack overflow!\n"));
		smb_panic("Security context stack overflow!\n");
	}

	/* Store previous user context */

	sec_ctx_stack_ndx++;

	ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];

	ctx_p->uid = geteuid();
	ctx_p->gid = getegid();

 	DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n", 
 		  (unsigned int)ctx_p->uid, (unsigned int)ctx_p->gid, sec_ctx_stack_ndx ));

	ctx_p->token = dup_nt_token(sec_ctx_stack[sec_ctx_stack_ndx-1].token);

	ctx_p->ngroups = sys_getgroups(0, NULL);

	if (ctx_p->ngroups != 0) {
		if (!(ctx_p->groups = malloc(ctx_p->ngroups * sizeof(gid_t)))) {
			DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
			delete_nt_token(&ctx_p->token);
			return False;
		}

		sys_getgroups(ctx_p->ngroups, ctx_p->groups);
	} else {
		ctx_p->groups = NULL;
	}

	return True;
}
Exemplo n.º 10
0
int register_vuid(auth_serversupplied_info *server_info,
		  DATA_BLOB session_key, DATA_BLOB response_blob,
		  const char *smb_name)
{
	user_struct *vuser = NULL;

	/* Paranoia check. */
	if(lp_security() == SEC_SHARE) {
		smb_panic("Tried to register uid in security=share\n");
	}

	/* Limit allowed vuids to 16bits - VUID_OFFSET. */
	if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) {
		data_blob_free(&session_key);
		return UID_FIELD_INVALID;
	}

	if((vuser = SMB_MALLOC_P(user_struct)) == NULL) {
		DEBUG(0,("Failed to malloc users struct!\n"));
		data_blob_free(&session_key);
		return UID_FIELD_INVALID;
	}

	ZERO_STRUCTP(vuser);

	/* Allocate a free vuid. Yes this is a linear search... :-) */
	while( get_valid_user_struct(next_vuid) != NULL ) {
		next_vuid++;
		/* Check for vuid wrap. */
		if (next_vuid == UID_FIELD_INVALID)
			next_vuid = VUID_OFFSET;
	}

	DEBUG(10,("register_vuid: allocated vuid = %u\n",
		  (unsigned int)next_vuid ));

	vuser->vuid = next_vuid;

	if (!server_info) {
		/*
		 * This happens in an unfinished NTLMSSP session setup. We
		 * need to allocate a vuid between the first and second calls
		 * to NTLMSSP.
		 */
		next_vuid++;
		num_validated_vuids++;
		
		vuser->server_info = NULL;
		
		DLIST_ADD(validated_users, vuser);
		
		return vuser->vuid;
	}

	/* the next functions should be done by a SID mapping system (SMS) as
	 * the new real sam db won't have reference to unix uids or gids
	 */
	
	vuser->uid = server_info->uid;
	vuser->gid = server_info->gid;
	
	vuser->n_groups = server_info->n_groups;
	if (vuser->n_groups) {
		if (!(vuser->groups = (gid_t *)memdup(server_info->groups,
						      sizeof(gid_t) *
						      vuser->n_groups))) {
			DEBUG(0,("register_vuid: failed to memdup "
				 "vuser->groups\n"));
			data_blob_free(&session_key);
			free(vuser);
			TALLOC_FREE(server_info);
			return UID_FIELD_INVALID;
		}
	}

	vuser->guest = server_info->guest;
	fstrcpy(vuser->user.unix_name, server_info->unix_name); 

	/* This is a potentially untrusted username */
	alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$",
		     sizeof(vuser->user.smb_name));

	fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account));
	fstrcpy(vuser->user.full_name,
		pdb_get_fullname(server_info->sam_account));

	{
		/* Keep the homedir handy */
		const char *homedir =
			pdb_get_homedir(server_info->sam_account);
		const char *logon_script =
			pdb_get_logon_script(server_info->sam_account);

		if (!IS_SAM_DEFAULT(server_info->sam_account,
				    PDB_UNIXHOMEDIR)) {
			const char *unix_homedir =
				pdb_get_unix_homedir(server_info->sam_account);
			if (unix_homedir) {
				vuser->unix_homedir =
					smb_xstrdup(unix_homedir);
			}
		} else {
			struct passwd *passwd =
				getpwnam_alloc(NULL, vuser->user.unix_name);
			if (passwd) {
				vuser->unix_homedir =
					smb_xstrdup(passwd->pw_dir);
				TALLOC_FREE(passwd);
			}
		}
		
		if (homedir) {
			vuser->homedir = smb_xstrdup(homedir);
		}
		if (logon_script) {
			vuser->logon_script = smb_xstrdup(logon_script);
		}
	}

	vuser->session_key = session_key;

	DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", 
		  (unsigned int)vuser->uid, 
		  (unsigned int)vuser->gid,
		  vuser->user.unix_name, vuser->user.smb_name,
		  vuser->user.domain, vuser->guest ));

	DEBUG(3, ("User name: %s\tReal name: %s\n", vuser->user.unix_name,
		  vuser->user.full_name));	

 	if (server_info->ptok) {
		vuser->nt_user_token = dup_nt_token(NULL, server_info->ptok);
	} else {
		DEBUG(1, ("server_info does not contain a user_token - "
			  "cannot continue\n"));
		TALLOC_FREE(server_info);
		data_blob_free(&session_key);
		SAFE_FREE(vuser->homedir);
		SAFE_FREE(vuser->unix_homedir);
		SAFE_FREE(vuser->logon_script);

		SAFE_FREE(vuser);
		return UID_FIELD_INVALID;
	}

	/* use this to keep tabs on all our info from the authentication */
	vuser->server_info = server_info;

	DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",
		 (int)vuser->uid,vuser->user.unix_name, vuser->vuid));

	next_vuid++;
	num_validated_vuids++;

	DLIST_ADD(validated_users, vuser);

	if (!session_claim(vuser)) {
		DEBUG(1, ("Failed to claim session for vuid=%d\n",
			  vuser->vuid));
		invalidate_vuid(vuser->vuid);
		return UID_FIELD_INVALID;
	}

	/* Register a home dir service for this user iff
	
	   (a) This is not a guest connection,
	   (b) we have a home directory defined 
	   (c) there s not an existing static share by that name
	   
	   If a share exists by this name (autoloaded or not) reuse it . */

	vuser->homes_snum = -1;

	if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) 
	{
		int servicenumber = lp_servicenumber(vuser->user.unix_name);

		if ( servicenumber == -1 ) {
			DEBUG(3, ("Adding homes service for user '%s' using "
				  "home directory: '%s'\n", 
				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 {
			DEBUG(3, ("Using static (or previously created) "
				  "service for user '%s'; path = '%s'\n", 
				  vuser->user.unix_name,
				  lp_pathname(servicenumber) ));
			vuser->homes_snum = servicenumber;
		}
	} 
	
	if (srv_is_signing_negotiated() && !vuser->guest &&
	    !srv_signing_started()) {
		/* Try and turn on server signing on the first non-guest
		 * sessionsetup. */
		srv_set_signing(vuser->session_key, response_blob);
	}
	
	/* fill in the current_user_info struct */
	set_current_user_info( &vuser->user );


	return vuser->vuid;
}
Exemplo n.º 11
0
static void *make_internal_rpc_pipe_p(char *pipe_name, 
			      connection_struct *conn, uint16 vuid)
{
	pipes_struct *p;
	user_struct *vuser = get_valid_user_struct(vuid);

	DEBUG(4,("Create pipe requested %s\n", pipe_name));

	if (!vuser && vuid != UID_FIELD_INVALID) {
		DEBUG(0,("ERROR! vuid %d did not map to a valid vuser struct!\n", vuid));
		return NULL;
	}

	p = (pipes_struct *)malloc(sizeof(*p));

	if (!p)
	{
		DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
		return NULL;
	}

	ZERO_STRUCTP(p);

	if ((p->mem_ctx = talloc_init("pipe %s %p", pipe_name, p)) == NULL) {
		DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
		SAFE_FREE(p);
		return NULL;
	}

	if (!init_pipe_handle_list(p, pipe_name)) {
		DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
		talloc_destroy(p->mem_ctx);
		SAFE_FREE(p);
		return NULL;
	}

	/*
	 * Initialize the incoming RPC data buffer with one PDU worth of memory.
	 * We cheat here and say we're marshalling, as we intend to add incoming
	 * data directly into the prs_struct and we want it to auto grow. We will
	 * change the type to UNMARSALLING before processing the stream.
	 */

	if(!prs_init(&p->in_data.data, MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
		DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n"));
		return NULL;
	}

	DLIST_ADD(InternalPipes, p);

	p->conn = conn;

	/* Ensure the connection isn't idled whilst this pipe is open. */
	p->conn->num_files_open++;

	p->vuid  = vuid;

	p->ntlmssp_chal_flags = 0;
	p->ntlmssp_auth_validated = False;
	p->ntlmssp_auth_requested = False;

	p->pipe_bound = False;
	p->fault_state = False;
	p->endian = RPC_LITTLE_ENDIAN;

	ZERO_STRUCT(p->pipe_user);

	p->pipe_user.uid = (uid_t)-1;
	p->pipe_user.gid = (gid_t)-1;
	
	/* Store the session key and NT_TOKEN */
	if (vuser) {
		p->session_key = data_blob(vuser->session_key.data, vuser->session_key.length);
		p->pipe_user.nt_user_token = dup_nt_token(vuser->nt_user_token);
	}

	/*
	 * Initialize the incoming RPC struct.
	 */

	p->in_data.pdu_needed_len = 0;
	p->in_data.pdu_received_len = 0;

	/*
	 * Initialize the outgoing RPC struct.
	 */

	p->out_data.current_pdu_len = 0;
	p->out_data.current_pdu_sent = 0;
	p->out_data.data_sent_length = 0;

	/*
	 * Initialize the outgoing RPC data buffer with no memory.
	 */	
	prs_init(&p->out_data.rdata, 0, p->mem_ctx, MARSHALL);
	
	fstrcpy(p->name, pipe_name);
	
	DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
		 pipe_name, pipes_open));

	return (void*)p;
}
Exemplo n.º 12
0
/* This function MUST only used to create the cached server_info for
 * guest.
 *
 * This is a lossy conversion.  Variables known to be lost so far
 * include:
 *
 * - nss_token (not needed because the only read doesn't happen
 * for the GUEST user, as this routine populates ->security_token
 *
 * - extra (not needed because the guest account must have valid RIDs per the output of get_guest_info3())
 *
 * - The 'server_info' parameter allows the missing 'info3' to be copied across.
 */
static struct auth_serversupplied_info *copy_session_info_serverinfo_guest(TALLOC_CTX *mem_ctx,
									   const struct auth_session_info *src,
									   struct auth_serversupplied_info *server_info)
{
	struct auth_serversupplied_info *dst;

	dst = make_server_info(mem_ctx);
	if (dst == NULL) {
		return NULL;
	}

	/* This element must be provided to convert back to an auth_serversupplied_info */
	SMB_ASSERT(src->unix_info);

	dst->guest = true;
	dst->system = false;

	/* This element must be provided to convert back to an
	 * auth_serversupplied_info.  This needs to be from the
	 * auth_session_info because the group values in particular
	 * may change during create_local_token() processing */
	SMB_ASSERT(src->unix_token);
	dst->utok.uid = src->unix_token->uid;
	dst->utok.gid = src->unix_token->gid;
	dst->utok.ngroups = src->unix_token->ngroups;
	if (src->unix_token->ngroups != 0) {
		dst->utok.groups = (gid_t *)talloc_memdup(
			dst, src->unix_token->groups,
			sizeof(gid_t)*dst->utok.ngroups);
	} else {
		dst->utok.groups = NULL;
	}

	/* We must have a security_token as otherwise the lossy
	 * conversion without nss_token would cause create_local_token
	 * to take the wrong path */
	SMB_ASSERT(src->security_token);

	dst->security_token = dup_nt_token(dst, src->security_token);
	if (!dst->security_token) {
		TALLOC_FREE(dst);
		return NULL;
	}

	dst->session_key = data_blob_talloc( dst, src->session_key.data,
						src->session_key.length);

	/* This is OK because this functions is only used for the
	 * GUEST account, which has all-zero keys for both values */
	dst->lm_session_key = data_blob_talloc(dst, src->session_key.data,
						src->session_key.length);

	dst->info3 = copy_netr_SamInfo3(dst, server_info->info3);
	if (!dst->info3) {
		TALLOC_FREE(dst);
		return NULL;
	}

	dst->unix_name = talloc_strdup(dst, src->unix_info->unix_name);
	if (!dst->unix_name) {
		TALLOC_FREE(dst);
		return NULL;
	}

	return dst;
}
Exemplo n.º 13
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.º 14
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.º 15
0
NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
			    const struct auth_serversupplied_info *server_info,
			    DATA_BLOB *session_key,
			    const char *smb_username, /* for ->sanitized_username, for %U subs */
			    struct auth_session_info **session_info_out)
{
	struct security_token *t;
	NTSTATUS status;
	size_t i;
	struct dom_sid tmp_sid;
	struct auth_session_info *session_info;
	struct unixid *ids;
	fstring tmp;

	/* Ensure we can't possible take a code path leading to a
	 * null defref. */
	if (!server_info) {
		return NT_STATUS_LOGON_FAILURE;
	}

	session_info = talloc_zero(mem_ctx, struct auth_session_info);
	if (!session_info) {
		return NT_STATUS_NO_MEMORY;
	}

	session_info->unix_token = talloc_zero(session_info, struct security_unix_token);
	if (!session_info->unix_token) {
		TALLOC_FREE(session_info);
		return NT_STATUS_NO_MEMORY;
	}

	session_info->unix_token->uid = server_info->utok.uid;
	session_info->unix_token->gid = server_info->utok.gid;

	session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
	if (!session_info->unix_info) {
		TALLOC_FREE(session_info);
		return NT_STATUS_NO_MEMORY;
	}

	session_info->unix_info->unix_name = talloc_strdup(session_info, server_info->unix_name);
	if (!session_info->unix_info->unix_name) {
		TALLOC_FREE(session_info);
		return NT_STATUS_NO_MEMORY;
	}

	/* This is a potentially untrusted username for use in %U */
	alpha_strcpy(tmp, smb_username, ". _-$", sizeof(tmp));
	session_info->unix_info->sanitized_username =
				talloc_strdup(session_info->unix_info, tmp);

	if (session_key) {
		data_blob_free(&session_info->session_key);
		session_info->session_key = data_blob_talloc(session_info,
								  session_key->data,
								  session_key->length);
		if (!session_info->session_key.data && session_key->length) {
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		session_info->session_key = data_blob_talloc( session_info, server_info->session_key.data,
							      server_info->session_key.length);
	}

	/* We need to populate session_info->info with the information found in server_info->info3 */
	status = make_user_info_SamBaseInfo(session_info, "", &server_info->info3->base,
					    server_info->guest == false,
					    &session_info->info);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("conversion of info3 into auth_user_info failed!\n"));
		TALLOC_FREE(session_info);
		return status;
	}

	if (server_info->security_token) {
		/* Just copy the token, it has already been finalised
		 * (nasty hack to support a cached guest/system session_info
		 */

		session_info->security_token = dup_nt_token(session_info, server_info->security_token);
		if (!session_info->security_token) {
			TALLOC_FREE(session_info);
			return NT_STATUS_NO_MEMORY;
		}

		session_info->unix_token->ngroups = server_info->utok.ngroups;
		if (server_info->utok.ngroups != 0) {
			session_info->unix_token->groups = (gid_t *)talloc_memdup(
				session_info->unix_token, server_info->utok.groups,
				sizeof(gid_t)*session_info->unix_token->ngroups);
		} else {
			session_info->unix_token->groups = NULL;
		}

		*session_info_out = session_info;
		return NT_STATUS_OK;
	}

	/*
	 * If winbind is not around, we can not make much use of the SIDs the
	 * domain controller provided us with. Likewise if the user name was
	 * mapped to some local unix user.
	 */

	if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) ||
	    (server_info->nss_token)) {
		char *found_username = NULL;
		status = create_token_from_username(session_info,
						    server_info->unix_name,
						    server_info->guest,
						    &session_info->unix_token->uid,
						    &session_info->unix_token->gid,
						    &found_username,
						    &session_info->security_token);
		if (NT_STATUS_IS_OK(status)) {
			session_info->unix_info->unix_name = found_username;
		}
	} else {
		status = create_local_nt_token_from_info3(session_info,
							  server_info->guest,
							  server_info->info3,
							  &server_info->extra,
							  &session_info->security_token);
	}

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

	/* Convert the SIDs to gids. */

	session_info->unix_token->ngroups = 0;
	session_info->unix_token->groups = NULL;

	t = session_info->security_token;

	ids = talloc_array(talloc_tos(), struct unixid,
			   t->num_sids);
	if (ids == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!sids_to_unixids(t->sids, t->num_sids, ids)) {
		TALLOC_FREE(ids);
		return NT_STATUS_NO_MEMORY;
	}

	for (i=0; i<t->num_sids; i++) {

		if (i == 0 && ids[i].type != ID_TYPE_BOTH) {
			continue;
		}

		if (ids[i].type != ID_TYPE_GID &&
		    ids[i].type != ID_TYPE_BOTH) {
			DEBUG(10, ("Could not convert SID %s to gid, "
				   "ignoring it\n",
				   sid_string_dbg(&t->sids[i])));
			continue;
		}
		if (!add_gid_to_array_unique(session_info, ids[i].id,
					     &session_info->unix_token->groups,
					     &session_info->unix_token->ngroups)) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	/*
	 * Add the "Unix Group" SID for each gid to catch mapped groups
	 * and their Unix equivalent.  This is to solve the backwards
	 * compatibility problem of 'valid users = +ntadmin' where
	 * ntadmin has been paired with "Domain Admins" in the group
	 * mapping table.  Otherwise smb.conf would need to be changed
	 * to 'valid user = "******"'.  --jerry
	 *
	 * For consistency we also add the "Unix User" SID,
	 * so that the complete unix token is represented within
	 * the nt token.
	 */

	uid_to_unix_users_sid(session_info->unix_token->uid, &tmp_sid);

	add_sid_to_array_unique(session_info->security_token, &tmp_sid,
				&session_info->security_token->sids,
				&session_info->security_token->num_sids);

	for ( i=0; i<session_info->unix_token->ngroups; i++ ) {
		gid_to_unix_groups_sid(session_info->unix_token->groups[i], &tmp_sid);
		add_sid_to_array_unique(session_info->security_token, &tmp_sid,
					&session_info->security_token->sids,
					&session_info->security_token->num_sids);
	}

	security_token_debug(DBGC_AUTH, 10, session_info->security_token);
	debug_unix_user_token(DBGC_AUTH, 10,
			      session_info->unix_token->uid,
			      session_info->unix_token->gid,
			      session_info->unix_token->ngroups,
			      session_info->unix_token->groups);

	status = log_nt_token(session_info->security_token);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	*session_info_out = session_info;
	return NT_STATUS_OK;
}
Exemplo n.º 16
0
BOOL change_to_user(connection_struct *conn, uint16 vuid)
{
	user_struct *vuser = get_valid_user_struct(vuid);
	int snum;
	gid_t gid;
	uid_t uid;
	char group_c;
	BOOL must_free_token = False;
	NT_USER_TOKEN *token = NULL;

	if (!conn) {
		DEBUG(2,("change_to_user: Connection not open\n"));
		return(False);
	}

	/*
	 * We need a separate check in security=share mode due to vuid
	 * always being UID_FIELD_INVALID. If we don't do this then
	 * in share mode security we are *always* changing uid's between
	 * SMB's - this hurts performance - Badly.
	 */

	if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
	   (current_user.ut.uid == conn->uid)) {
		DEBUG(4,("change_to_user: Skipping user change - already "
			 "user\n"));
		return(True);
	} else if ((current_user.conn == conn) && 
		   (vuser != 0) && (current_user.vuid == vuid) && 
		   (current_user.ut.uid == vuser->uid)) {
		DEBUG(4,("change_to_user: Skipping user change - already "
			 "user\n"));
		return(True);
	}

	snum = SNUM(conn);

	if ((vuser) && !check_user_ok(conn, vuser, snum)) {
		DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
			 "not permitted access to share %s.\n",
			 vuser->user.smb_name, vuser->user.unix_name, vuid,
			 lp_servicename(snum)));
		return False;
	}

	if (conn->force_user) /* security = share sets this too */ {
		uid = conn->uid;
		gid = conn->gid;
		current_user.ut.groups = conn->groups;
		current_user.ut.ngroups = conn->ngroups;
		token = conn->nt_user_token;
	} else if (vuser) {
		uid = conn->admin_user ? 0 : vuser->uid;
		gid = vuser->gid;
		current_user.ut.ngroups = vuser->n_groups;
		current_user.ut.groups  = vuser->groups;
		token = vuser->nt_user_token;
	} else {
		DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
			 "share %s.\n",vuid, lp_servicename(snum) ));
		return False;
	}

	/*
	 * See if we should force group for this service.
	 * If so this overrides any group set in the force
	 * user code.
	 */

	if((group_c = *lp_force_group(snum))) {

		token = dup_nt_token(NULL, token);
		if (token == NULL) {
			DEBUG(0, ("dup_nt_token failed\n"));
			return False;
		}
		must_free_token = True;

		if(group_c == '+') {

			/*
			 * Only force group if the user is a member of
			 * the service group. Check the group memberships for
			 * this user (we already have this) to
			 * see if we should force the group.
			 */

			int i;
			for (i = 0; i < current_user.ut.ngroups; i++) {
				if (current_user.ut.groups[i] == conn->gid) {
					gid = conn->gid;
					gid_to_sid(&token->user_sids[1], gid);
					break;
				}
			}
		} else {
			gid = conn->gid;
			gid_to_sid(&token->user_sids[1], gid);
		}
	}
	
	set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
		    token);

	/*
	 * Free the new token (as set_sec_ctx copies it).
	 */

	if (must_free_token)
		TALLOC_FREE(token);

	current_user.conn = conn;
	current_user.vuid = vuid;

	DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
		 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
  
	return(True);
}
Exemplo n.º 17
0
static void *make_internal_rpc_pipe_p(char *pipe_name, 
			      connection_struct *conn, uint16 vuid)
{
	pipes_struct *p;
	user_struct *vuser = get_valid_user_struct(vuid);

	DEBUG(4,("Create pipe requested %s\n", pipe_name));

	if (!vuser && vuid != UID_FIELD_INVALID) {
		DEBUG(0,("ERROR! vuid %d did not map to a valid vuser struct!\n", vuid));
		return NULL;
	}

	p = SMB_MALLOC_P(pipes_struct);

	if (!p) {
		DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
		return NULL;
	}

	ZERO_STRUCTP(p);

	if ((p->mem_ctx = talloc_init("pipe %s %p", pipe_name, p)) == NULL) {
		DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
		SAFE_FREE(p);
		return NULL;
	}

	if ((p->pipe_state_mem_ctx = talloc_init("pipe_state %s %p", pipe_name, p)) == NULL) {
		DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
		talloc_destroy(p->mem_ctx);
		SAFE_FREE(p);
		return NULL;
	}

	if (!init_pipe_handle_list(p, pipe_name)) {
		DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
		talloc_destroy(p->mem_ctx);
		talloc_destroy(p->pipe_state_mem_ctx);
		SAFE_FREE(p);
		return NULL;
	}

	/*
	 * Initialize the incoming RPC data buffer with one PDU worth of memory.
	 * We cheat here and say we're marshalling, as we intend to add incoming
	 * data directly into the prs_struct and we want it to auto grow. We will
	 * change the type to UNMARSALLING before processing the stream.
	 */

	if(!prs_init(&p->in_data.data, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
		DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n"));
		talloc_destroy(p->mem_ctx);
		talloc_destroy(p->pipe_state_mem_ctx);
		close_policy_by_pipe(p);
		SAFE_FREE(p);
		return NULL;
	}

	DLIST_ADD(InternalPipes, p);

	p->conn = conn;

	p->vuid  = vuid;

	p->endian = RPC_LITTLE_ENDIAN;

	ZERO_STRUCT(p->pipe_user);

	p->pipe_user.ut.uid = (uid_t)-1;
	p->pipe_user.ut.gid = (gid_t)-1;
	
	/* Store the session key and NT_TOKEN */
	if (vuser) {
		p->session_key = data_blob(vuser->session_key.data, vuser->session_key.length);
		p->pipe_user.nt_user_token = dup_nt_token(
			NULL, vuser->nt_user_token);
	}

	/*
	 * Initialize the outgoing RPC data buffer with no memory.
	 */	
	prs_init(&p->out_data.rdata, 0, p->mem_ctx, MARSHALL);
	
	fstrcpy(p->name, pipe_name);
	
	DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
		 pipe_name, pipes_open));

	return (void*)p;
}