winbindd_cache.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 1,621 行 · 第 1/3 页

C
1,621
字号
		/* null strings are marked as len 0xFFFF */		centry_put_uint8(centry, 0xFF);		return;	}	len = strlen(s);	/* can't handle more than 254 char strings. Truncating is probably best */	if (len > 254) {		DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));		len = 254;	}	centry_put_uint8(centry, len);	centry_expand(centry, len);	memcpy(centry->data + centry->ofs, s, len);	centry->ofs += len;}static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid) {	fstring sid_string;	centry_put_string(centry, sid_to_string(sid_string, sid));}/*  start a centry for output. When finished, call centry_end()*/struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status){	struct cache_entry *centry;	if (!wcache->tdb)		return NULL;	centry = SMB_XMALLOC_P(struct cache_entry);	centry->len = 8192; /* reasonable default */	centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);	centry->ofs = 0;	centry->sequence_number = domain->sequence_number;	centry_put_uint32(centry, NT_STATUS_V(status));	centry_put_uint32(centry, centry->sequence_number);	return centry;}/*  finish a centry and write it to the tdb*/static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);static void centry_end(struct cache_entry *centry, const char *format, ...){	va_list ap;	char *kstr;	TDB_DATA key, data;	va_start(ap, format);	smb_xvasprintf(&kstr, format, ap);	va_end(ap);	key.dptr = kstr;	key.dsize = strlen(kstr);	data.dptr = (char *)centry->data;	data.dsize = centry->ofs;	tdb_store(wcache->tdb, key, data, TDB_REPLACE);	free(kstr);}static void wcache_save_name_to_sid(struct winbindd_domain *domain, 				    NTSTATUS status, const char *domain_name,				    const char *name, const DOM_SID *sid, 				    enum SID_NAME_USE type){	struct cache_entry *centry;	fstring uname;	centry = centry_start(domain, status);	if (!centry)		return;	centry_put_uint32(centry, type);	centry_put_sid(centry, sid);	fstrcpy(uname, name);	strupper_m(uname);	centry_end(centry, "NS/%s/%s", domain_name, uname);	DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname,		  sid_string_static(sid)));	centry_free(centry);}static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 				    const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type){	struct cache_entry *centry;	fstring sid_string;	centry = centry_start(domain, status);	if (!centry)		return;	if (NT_STATUS_IS_OK(status)) {		centry_put_uint32(centry, type);		centry_put_string(centry, domain_name);		centry_put_string(centry, name);	}	centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));	DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));	centry_free(centry);}static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info){	struct cache_entry *centry;	fstring sid_string;	centry = centry_start(domain, status);	if (!centry)		return;	centry_put_string(centry, info->acct_name);	centry_put_string(centry, info->full_name);	centry_put_string(centry, info->homedir);	centry_put_string(centry, info->shell);	centry_put_sid(centry, &info->user_sid);	centry_put_sid(centry, &info->group_sid);	centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));	DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));	centry_free(centry);}/* Query display info. This is the basic user list fn */static NTSTATUS query_user_list(struct winbindd_domain *domain,				TALLOC_CTX *mem_ctx,				uint32 *num_entries, 				WINBIND_USERINFO **info){	struct winbind_cache *cache = get_cache(domain);	struct cache_entry *centry = NULL;	NTSTATUS status;	unsigned int i, retry;	if (!cache->tdb)		goto do_query;	centry = wcache_fetch(cache, domain, "UL/%s", domain->name);	if (!centry)		goto do_query;	*num_entries = centry_uint32(centry);		if (*num_entries == 0)		goto do_cached;	(*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);	if (! (*info))		smb_panic("query_user_list out of memory");	for (i=0; i<(*num_entries); i++) {		(*info)[i].acct_name = centry_string(centry, mem_ctx);		(*info)[i].full_name = centry_string(centry, mem_ctx);		(*info)[i].homedir = centry_string(centry, mem_ctx);		(*info)[i].shell = centry_string(centry, mem_ctx);		centry_sid(centry, &(*info)[i].user_sid);		centry_sid(centry, &(*info)[i].group_sid);	}do_cached:		status = centry->status;	DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status %s\n",		domain->name, get_friendly_nt_error_msg(status) ));	centry_free(centry);	return status;do_query:	*num_entries = 0;	*info = NULL;	/* Return status value returned by seq number check */	if (!NT_STATUS_IS_OK(domain->last_status))		return domain->last_status;	/* Put the query_user_list() in a retry loop.  There appears to be	 * some bug either with Windows 2000 or Samba's handling of large	 * rpc replies.  This manifests itself as sudden disconnection	 * at a random point in the enumeration of a large (60k) user list.	 * The retry loop simply tries the operation again. )-:  It's not	 * pretty but an acceptable workaround until we work out what the	 * real problem is. */	retry = 0;	do {		DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",			domain->name ));		status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);		if (!NT_STATUS_IS_OK(status))			DEBUG(3, ("query_user_list: returned 0x%08x, "				  "retrying\n", NT_STATUS_V(status)));			if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {				DEBUG(3, ("query_user_list: flushing "					  "connection cache\n"));				invalidate_cm_connection(&domain->conn);			}	} while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && 		 (retry++ < 5));	/* and save it */	refresh_sequence_number(domain, False);	centry = centry_start(domain, status);	if (!centry)		goto skip_save;	centry_put_uint32(centry, *num_entries);	for (i=0; i<(*num_entries); i++) {		centry_put_string(centry, (*info)[i].acct_name);		centry_put_string(centry, (*info)[i].full_name);		centry_put_string(centry, (*info)[i].homedir);		centry_put_string(centry, (*info)[i].shell);		centry_put_sid(centry, &(*info)[i].user_sid);		centry_put_sid(centry, &(*info)[i].group_sid);		if (domain->backend->consistent) {			/* when the backend is consistent we can pre-prime some mappings */			wcache_save_name_to_sid(domain, NT_STATUS_OK, 						domain->name,						(*info)[i].acct_name, 						&(*info)[i].user_sid,						SID_NAME_USER);			wcache_save_sid_to_name(domain, NT_STATUS_OK, 						&(*info)[i].user_sid,						domain->name,						(*info)[i].acct_name, 						SID_NAME_USER);			wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);		}	}		centry_end(centry, "UL/%s", domain->name);	centry_free(centry);skip_save:	return status;}/* list all domain groups */static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,				TALLOC_CTX *mem_ctx,				uint32 *num_entries, 				struct acct_info **info){	struct winbind_cache *cache = get_cache(domain);	struct cache_entry *centry = NULL;	NTSTATUS status;	unsigned int i;	if (!cache->tdb)		goto do_query;	centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);	if (!centry)		goto do_query;	*num_entries = centry_uint32(centry);		if (*num_entries == 0)		goto do_cached;	(*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);	if (! (*info))		smb_panic("enum_dom_groups out of memory");	for (i=0; i<(*num_entries); i++) {		fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));		fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));		(*info)[i].rid = centry_uint32(centry);	}do_cached:		status = centry->status;	DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status %s\n",		domain->name, get_friendly_nt_error_msg(status) ));	centry_free(centry);	return status;do_query:	*num_entries = 0;	*info = NULL;	/* Return status value returned by seq number check */	if (!NT_STATUS_IS_OK(domain->last_status))		return domain->last_status;	DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",		domain->name ));	status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);	/* and save it */	refresh_sequence_number(domain, False);	centry = centry_start(domain, status);	if (!centry)		goto skip_save;	centry_put_uint32(centry, *num_entries);	for (i=0; i<(*num_entries); i++) {		centry_put_string(centry, (*info)[i].acct_name);		centry_put_string(centry, (*info)[i].acct_desc);		centry_put_uint32(centry, (*info)[i].rid);	}		centry_end(centry, "GL/%s/domain", domain->name);	centry_free(centry);skip_save:	return status;}/* list all domain groups */static NTSTATUS enum_local_groups(struct winbindd_domain *domain,				TALLOC_CTX *mem_ctx,				uint32 *num_entries, 				struct acct_info **info){	struct winbind_cache *cache = get_cache(domain);	struct cache_entry *centry = NULL;	NTSTATUS status;	unsigned int i;	if (!cache->tdb)		goto do_query;	centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);	if (!centry)		goto do_query;	*num_entries = centry_uint32(centry);		if (*num_entries == 0)		goto do_cached;	(*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);	if (! (*info))		smb_panic("enum_dom_groups out of memory");	for (i=0; i<(*num_entries); i++) {		fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));		fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));		(*info)[i].rid = centry_uint32(centry);	}do_cached:		/* If we are returning cached data and the domain controller	   is down then we don't know whether the data is up to date	   or not.  Return NT_STATUS_MORE_PROCESSING_REQUIRED to	   indicate this. */	if (wcache_server_down(domain)) {		DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));		status = NT_STATUS_MORE_PROCESSING_REQUIRED;	} else		status = centry->status;	DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status %s\n",		domain->name, get_friendly_nt_error_msg(status) ));	centry_free(centry);	return status;do_query:	*num_entries = 0;	*info = NULL;	/* Return status value returned by seq number check */	if (!NT_STATUS_IS_OK(domain->last_status))		return domain->last_status;	DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",		domain->name ));	status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);	/* and save it */	refresh_sequence_number(domain, False);	centry = centry_start(domain, status);	if (!centry)		goto skip_save;	centry_put_uint32(centry, *num_entries);	for (i=0; i<(*num_entries); i++) {		centry_put_string(centry, (*info)[i].acct_name);		centry_put_string(centry, (*info)[i].acct_desc);		centry_put_uint32(centry, (*info)[i].rid);	}	centry_end(centry, "GL/%s/local", domain->name);	centry_free(centry);skip_save:	return status;}/* convert a single name to a sid in a domain */static NTSTATUS name_to_sid(struct winbindd_domain *domain,			    TALLOC_CTX *mem_ctx,			    const char *domain_name,			    const char *name,			    DOM_SID *sid,			    enum SID_NAME_USE *type){	struct winbind_cache *cache = get_cache(domain);	struct cache_entry *centry = NULL;	NTSTATUS status;	fstring uname;	if (!cache->tdb)		goto do_query;	fstrcpy(uname, name);	strupper_m(uname);	centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);	if (!centry)		goto do_query;	*type = (enum SID_NAME_USE)centry_uint32(centry);	centry_sid(centry, sid);	status = centry->status;	DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",		domain->name, get_friendly_nt_error_msg(status) ));	centry_free(centry);	return status;do_query:	ZERO_STRUCTP(sid);	/* If the seq number check indicated that there is a problem	 * with this DC, then return that status... except for	 * access_denied.  This is special because the dc may be in	 * "restrict anonymous = 1" mode, in which case it will deny	 * most unauthenticated operations, but *will* allow the LSA	 * name-to-sid that we try as a fallback. */	if (!(NT_STATUS_IS_OK(domain->last_status)	      || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))		return domain->last_status;	DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",		domain->name ));	status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);	/* and save it */	wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);	if (NT_STATUS_IS_OK(status)) {		strupper_m(CONST_DISCARD(char *,domain_name));		strlower_m(CONST_DISCARD(char *,name));		wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);	}	return status;}/* convert a sid to a user or group name. The sid is guaranteed to be in the domain   given */static NTSTATUS sid_to_name(struct winbindd_domain *domain,			    TALLOC_CTX *mem_ctx,			    const DOM_SID *sid,			    char **domain_name,			    char **name,			    enum SID_NAME_USE *type){	struct winbind_cache *cache = get_cache(domain);	struct cache_entry *centry = NULL;	NTSTATUS status;	fstring sid_string;	if (!cache->tdb)		goto do_query;	centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));	if (!centry)		goto do_query;	if (NT_STATUS_IS_OK(centry->status)) {		*type = (enum SID_NAME_USE)centry_uint32(centry);		*domain_name = centry_string(centry, mem_ctx);		*name = centry_string(centry, mem_ctx);	}	status = centry->status;	DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status %s\n",		domain->name, get_friendly_nt_error_msg(status) ));	centry_free(centry);	return status;do_query:	*name = NULL;	*domain_name = NULL;	/* If the seq number check indicated that there is a problem	 * with this DC, then return that status... except for	 * access_denied.  This is special because the dc may be in	 * "restrict anonymous = 1" mode, in which case it will deny	 * most unauthenticated operations, but *will* allow the LSA	 * sid-to-name that we try as a fallback. */	if (!(NT_STATUS_IS_OK(domain->last_status)	      || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))		return domain->last_status;	DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",		domain->name ));	status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);	/* and save it */	refresh_sequence_number(domain, False);	wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);	/* We can't save the name to sid mapping here, as with sid history a	 * later name2sid would give the wrong sid. */	return status;}/* Lookup user information from a rid */static NTSTATUS query_user(struct winbindd_domain *domain, 			   TALLOC_CTX *mem_ctx, 			   const DOM_SID *user_sid, 			   WINBIND_USERINFO *info){	struct winbind_cache *cache = get_cache(domain);	struct cache_entry *centry = NULL;	NTSTATUS status;	if (!cache->tdb)		goto do_query;	centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));		/* If we have an access denied cache entry and a cached info3 in the           samlogon cache then do a query.  This will force the rpc back end

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?