Example #1
0
/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
				  TALLOC_CTX *mem_ctx,
				  const DOM_SID *user_sid,
				  uint32 *num_groups, DOM_SID ***user_grpsids)
{
	CLI_POLICY_HND *hnd;
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	POLICY_HND dom_pol, user_pol;
	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
	BOOL got_dom_pol = False, got_user_pol = False;
	DOM_GID *user_groups;
	unsigned int i;
	unsigned int retry;
	fstring sid_string;
	uint32 user_rid;
	NET_USER_INFO_3 *user;

	DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid)));

	*num_groups = 0;
	*user_grpsids = NULL;

	/* so lets see if we have a cached user_info_3 */
	
	if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			sid_string_static(user_sid)));
			
		*num_groups = user->num_groups;
				
		(*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID*, *num_groups);
		for (i=0;i<(*num_groups);i++) {
			(*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user->gids[i].g_rid);
		}
				
		SAFE_FREE(user);
				
		return NT_STATUS_OK;
	}
Example #2
0
/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
				  TALLOC_CTX *mem_ctx,
				  const DOM_SID *user_sid,
				  uint32 *num_groups, DOM_SID ***user_grpsids)
{
	CLI_POLICY_HND *hnd;
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	POLICY_HND dom_pol, user_pol;
	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
	BOOL got_dom_pol = False, got_user_pol = False;
	DOM_GID *user_groups;
	unsigned int i;
	unsigned int retry;
	fstring sid_string;
	uint32 user_rid;
	NET_USER_INFO_3 *user;

	DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid)));

	*num_groups = 0;
	*user_grpsids = NULL;

	/* so lets see if we have a cached user_info_3 */
	
	if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			sid_string_static(user_sid)));
			
		*num_groups = user->num_groups;
				
		(*user_grpsids) = talloc(mem_ctx, sizeof(DOM_SID*) * (*num_groups));
		for (i=0;i<(*num_groups);i++) {
			(*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user->gids[i].g_rid);
		}
				
		SAFE_FREE(user);
				
		return NT_STATUS_OK;
	}

	/* no cache; hit the wire */
	
	retry = 0;
	do {
		/* Get sam handle; if we fail here there is no hope */
		
		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd))) 		
			goto done;

		/* Get domain handle */
		
		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
					      des_access, &domain->sid, &dom_pol);
	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && 
			hnd && hnd->cli && hnd->cli->fd == -1);

	if (!NT_STATUS_IS_OK(result))
		goto done;

	got_dom_pol = True;


	if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
		goto done;
	}

	/* Get user handle */
	result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
					des_access, user_rid, &user_pol);

	if (!NT_STATUS_IS_OK(result))
		goto done;

	got_user_pol = True;

	/* Query user rids */
	result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, 
					   num_groups, &user_groups);

	if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
		goto done;

	(*user_grpsids) = talloc(mem_ctx, sizeof(DOM_SID*) * (*num_groups));
	if (!(*user_grpsids)) {
		result = NT_STATUS_NO_MEMORY;
		goto done;
	}

	for (i=0;i<(*num_groups);i++) {
		(*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user_groups[i].g_rid);
	}
	
 done:
	/* Clean up policy handles */
	if (got_user_pol)
		cli_samr_close(hnd->cli, mem_ctx, &user_pol);

	if (got_dom_pol)
		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);

	return result;
}
Example #3
0
/* Lookup user information from a rid or username. */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const DOM_SID *user_sid, 
			   WINBIND_USERINFO *user_info)
{
	CLI_POLICY_HND *hnd = NULL;
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	POLICY_HND dom_pol, user_pol;
	BOOL got_dom_pol = False, got_user_pol = False;
	SAM_USERINFO_CTR *ctr;
	int retry;
	fstring sid_string;
	uint32 user_rid;
	NET_USER_INFO_3 *user;

	DEBUG(3,("rpc: query_user rid=%s\n", sid_to_string(sid_string, user_sid)));
	if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
		goto done;
	}
	
	/* try netsamlogon cache first */
			
	if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL ) 
	{
				
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			sid_string_static(user_sid)));
			
		user_info->user_sid  = rid_to_talloced_sid( domain, mem_ctx, user_rid );
		user_info->group_sid = rid_to_talloced_sid( domain, mem_ctx, user->group_rid );
				
		user_info->acct_name = unistr2_tdup(mem_ctx, &user->uni_user_name);
		user_info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name);
								
		SAFE_FREE(user);
				
		return NT_STATUS_OK;
	}
	
	/* no cache; hit the wire */
		
	retry = 0;
	do {
		/* Get sam handle; if we fail here there is no hope */
		
		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd))) 
			goto done;
			
		/* Get domain handle */

		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
					      SEC_RIGHTS_MAXIMUM_ALLOWED, 
					      &domain->sid, &dom_pol);
	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
			hnd && hnd->cli && hnd->cli->fd == -1);

	if (!NT_STATUS_IS_OK(result))
		goto done;

	got_dom_pol = True;

	/* Get user handle */
	result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
				    SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);

	if (!NT_STATUS_IS_OK(result))
		goto done;

	got_user_pol = True;

	/* Get user info */
	result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, 
					 0x15, &ctr);

	if (!NT_STATUS_IS_OK(result))
		goto done;

	cli_samr_close(hnd->cli, mem_ctx, &user_pol);
	got_user_pol = False;

	user_info->user_sid = rid_to_talloced_sid(domain, mem_ctx, user_rid);
	user_info->group_sid = rid_to_talloced_sid(domain, mem_ctx, ctr->info.id21->group_rid);
	user_info->acct_name = unistr2_tdup(mem_ctx, 
					    &ctr->info.id21->uni_user_name);
	user_info->full_name = unistr2_tdup(mem_ctx, 
					    &ctr->info.id21->uni_full_name);

 done:
	/* Clean up policy handles */
	if (got_user_pol)
		cli_samr_close(hnd->cli, mem_ctx, &user_pol);

	if (got_dom_pol)
		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);

	return result;
}                                   
Example #4
0
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const struct dom_sid *sid,
			   struct wbint_userinfo *info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	char *sidstr;
	uint32 group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	struct netr_SamInfo3 *user = NULL;
	gid_t gid = -1;
	int ret;
	char *ads_name;

	DEBUG(3,("ads: query_user\n"));

	info->homedir = NULL;
	info->shell = NULL;

	/* try netsamlogon cache first */

	if (winbindd_use_cache() && (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			 sid_string_dbg(sid)));

		sid_compose(&info->user_sid, &domain->sid, user->base.rid);
		sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);

		info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
		info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);

		nss_get_info_cached( domain, sid, mem_ctx,
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid );
		info->primary_gid = gid;

		TALLOC_FREE(user);

		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain(domain)) {
		DEBUG(8,("query_user: No incoming trust from domain %s\n",
			 domain->name));

		/* We still need to generate some basic information
		   about the user even if we cannot contact the 
		   domain.  Most of this stuff we can deduce. */

		sid_copy( &info->user_sid, sid );

		/* Assume "Domain Users" for the primary group */

		sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );

		/* Try to fill in what the nss_info backend can do */

		nss_get_info_cached( domain, sid, mem_ctx,
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid);
		info->primary_gid = gid;

		return NT_STATUS_OK;
	}

	/* no cache...do the query */

	if ( (ads = ads_cached_connection(domain)) == NULL ) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		return NT_STATUS_SERVER_DISABLED;
	}

	sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);

	ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
	TALLOC_FREE(sidstr);
	if (ret == -1) {
		return NT_STATUS_NO_MEMORY;
	}
	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	SAFE_FREE(ldap_exp);
	if (!ADS_ERR_OK(rc) || !msg) {
		DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
			 sid_string_dbg(sid), ads_errstr(rc)));
		return ads_ntstatus(rc);
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		DEBUG(1,("query_user(sid=%s): Not found\n",
			 sid_string_dbg(sid)));
		ads_msgfree(ads, msg);
		return NT_STATUS_NO_SUCH_USER;
	}

	info->acct_name = ads_pull_username(ads, mem_ctx, msg);

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
		DEBUG(1,("No primary group for %s !?\n",
			 sid_string_dbg(sid)));
		ads_msgfree(ads, msg);
		return NT_STATUS_NO_SUCH_USER;
	}
	sid_copy(&info->user_sid, sid);
	sid_compose(&info->group_sid, &domain->sid, group_rid);

	/*
	 * We have to fetch the "name" attribute before doing the
	 * nss_get_info_cached call. nss_get_info_cached might destroy
	 * the ads struct, potentially invalidating the ldap message.
	 */
	ads_name = ads_pull_string(ads, mem_ctx, msg, "name");

	ads_msgfree(ads, msg);
	msg = NULL;

	status = nss_get_info_cached( domain, sid, mem_ctx,
		      &info->homedir, &info->shell, &info->full_name, 
		      &gid);
	info->primary_gid = gid;
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("nss_get_info_cached failed: %s\n",
			  nt_errstr(status)));
		return status;
	}

	if (info->full_name == NULL) {
		info->full_name = ads_name;
	} else {
		TALLOC_FREE(ads_name);
	}

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user gave %s\n", info->acct_name));
	return NT_STATUS_OK;
}
Example #5
0
bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
{
    uint8_t dummy = 0;
    TDB_DATA data = { .dptr = &dummy, .dsize = sizeof(dummy) };
    char keystr[DOM_SID_STR_BUFLEN];
    bool result = false;
    struct dom_sid	user_sid;
    TALLOC_CTX *tmp_ctx = talloc_stackframe();
    DATA_BLOB blob;
    enum ndr_err_code ndr_err;
    struct netsamlogoncache_entry r;
    int ret;

    if (!info3) {
        return false;
    }

    if (!netsamlogon_cache_init()) {
        DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
                 NETSAMLOGON_TDB));
        return false;
    }

    /*
     * First write a record with just the domain sid for
     * netsamlogon_cache_domain_known. Use TDB_INSERT to avoid
     * overwriting potentially other data. We're just interested
     * in the existence of that record.
     */
    dom_sid_string_buf(info3->base.domain_sid, keystr, sizeof(keystr));

    ret = tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_INSERT);

    if ((ret == -1) && (tdb_error(netsamlogon_tdb) != TDB_ERR_EXISTS)) {
        DBG_WARNING("Could not store domain marker for %s: %s\n",
                    keystr, tdb_errorstr(netsamlogon_tdb));
        TALLOC_FREE(tmp_ctx);
        return false;
    }

    sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);

    /* Prepare key as DOMAIN-SID/USER-RID string */
    dom_sid_string_buf(&user_sid, keystr, sizeof(keystr));

    DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr));

    /* Prepare data */

    if (info3->base.full_name.string == NULL) {
        struct netr_SamInfo3 *cached_info3;
        const char *full_name = NULL;

        cached_info3 = netsamlogon_cache_get(tmp_ctx, &user_sid);
        if (cached_info3 != NULL) {
            full_name = cached_info3->base.full_name.string;
        }

        if (full_name != NULL) {
            info3->base.full_name.string = talloc_strdup(info3, full_name);
        }
    }

    /* only Samba fills in the username, not sure why NT doesn't */
    /* so we fill it in since winbindd_getpwnam() makes use of it */

    if (!info3->base.account_name.string) {
        info3->base.account_name.string = talloc_strdup(info3, username);
    }

    r.timestamp = time(NULL);
    r.info3 = *info3;

    if (DEBUGLEVEL >= 10) {
        NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
    }

    ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, &r,
                                   (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry);
    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
        DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n"));
        TALLOC_FREE(tmp_ctx);
        return false;
    }

    data.dsize = blob.length;
    data.dptr = blob.data;

    if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) == 0) {
        result = true;
    }

    TALLOC_FREE(tmp_ctx);

    return result;
}

/***********************************************************************
 Retrieves a netr_SamInfo3 structure from a tdb.  Caller must
 free the user_info struct (talloced memory)
***********************************************************************/

struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
{
    struct netr_SamInfo3 *info3 = NULL;
    TDB_DATA data;
    char keystr[DOM_SID_STR_BUFLEN];
    enum ndr_err_code ndr_err;
    DATA_BLOB blob;
    struct netsamlogoncache_entry r;

    if (!netsamlogon_cache_init()) {
        DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
                 NETSAMLOGON_TDB));
        return NULL;
    }

    /* Prepare key as DOMAIN-SID/USER-RID string */
    dom_sid_string_buf(user_sid, keystr, sizeof(keystr));
    DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr));
    data = tdb_fetch_bystring( netsamlogon_tdb, keystr );

    if (!data.dptr) {
        return NULL;
    }

    info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
    if (!info3) {
        goto done;
    }

    blob = data_blob_const(data.dptr, data.dsize);

    ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
                                   (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);

    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
        DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
        tdb_delete_bystring(netsamlogon_tdb, keystr);
        TALLOC_FREE(info3);
        goto done;
    }

    if (DEBUGLEVEL >= 10) {
        NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
    }

    info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
            sizeof(r.info3));

done:
    SAFE_FREE(data.dptr);

    return info3;
}

bool netsamlogon_cache_have(const struct dom_sid *sid)
{
    char keystr[DOM_SID_STR_BUFLEN];
    bool ok;

    if (!netsamlogon_cache_init()) {
        DBG_WARNING("Cannot open %s\n", NETSAMLOGON_TDB);
        return false;
    }

    dom_sid_string_buf(sid, keystr, sizeof(keystr));

    ok = tdb_exists(netsamlogon_tdb, string_term_tdb_data(keystr));
    return ok;
}
Example #6
0
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const DOM_SID *sid, 
			   struct wbint_userinfo *info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	char *sidstr;
	uint32 group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	struct netr_SamInfo3 *user = NULL;
	gid_t gid;

	DEBUG(3,("ads: query_user\n"));

	info->homedir = NULL;
	info->shell = NULL;
	info->primary_gid = (gid_t)-1;

	/* try netsamlogon cache first */

	if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) 
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			 sid_string_dbg(sid)));

		sid_compose(&info->user_sid, &domain->sid, user->base.rid);
		sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);

		info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
		info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);

		nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid );
		info->primary_gid = gid;

		TALLOC_FREE(user);

		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain(domain)) {
		DEBUG(8,("query_user: No incoming trust from domain %s\n",
			 domain->name));

		/* We still need to generate some basic information
		   about the user even if we cannot contact the 
		   domain.  Most of this stuff we can deduce. */

		sid_copy( &info->user_sid, sid );

		/* Assume "Domain Users" for the primary group */

		sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );

		/* Try to fill in what the nss_info backend can do */

		nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid);
		info->primary_gid = gid;

		status = NT_STATUS_OK;
		goto done;
	}

	/* no cache...do the query */

	if ( (ads = ads_cached_connection(domain)) == NULL ) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	sidstr = sid_binstring(talloc_tos(), sid);
	if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	free(ldap_exp);
	TALLOC_FREE(sidstr);
	if (!ADS_ERR_OK(rc) || !msg) {
		DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
			 sid_string_dbg(sid), ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		DEBUG(1,("query_user(sid=%s): Not found\n",
			 sid_string_dbg(sid)));
		goto done;
	}

	info->acct_name = ads_pull_username(ads, mem_ctx, msg);

	nss_get_info_cached( domain, sid, mem_ctx, ads, msg, 
		      &info->homedir, &info->shell, &info->full_name, 
		      &gid);
	info->primary_gid = gid;

	if (info->full_name == NULL) {
		info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
	}

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
		DEBUG(1,("No primary group for %s !?\n",
			 sid_string_dbg(sid)));
		goto done;
	}

	sid_copy(&info->user_sid, sid);
	sid_compose(&info->group_sid, &domain->sid, group_rid);

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user gave %s\n", info->acct_name));
done:
	if (msg) 
		ads_msgfree(ads, msg);

	return status;
}