lsa_enum_trust_dom functionality

Rafal Szczesniak mimir at diament.ists.pwr.wroc.pl
Thu Apr 11 05:17:02 GMT 2002


Here's the patch that adds server side of lsa_enum_trust_dom call to
samba. Memory leak causing segfault to smbd in some cases is already
fixed. Major changes include:

 1. tdb_search_keys() is the new utility function searching the keys that
    match given pattern. (tdbutil.c and tdbutil.h)
 2. tdb_search_list_free() is a clean-up function for results returned by
    tdb_search_keys (tdbutil.c and tdbutil.h)
 3. secrets_get_trusted_domains() is function that returns given range of
    trusted domain entries. The result is required list of trusted domains
    (unicode name and sid)
 4. stored trusted domain entry (struct trusted_dom_pass) now contains
    unicode name together with trust password, last change time and domain
    sid.
 5. init_r_enum_trust_dom() function is modified (as well as
    _lsa_enum_trust_dom() ) to return variable-length response


There's yet one more thing to change, but it's important only when samba
returns large number of entries, so this part of code may be commited now.


cheers,
+------------------------------------------------------------+
|Rafal 'Mimir' Szczesniak <mimir at diament.ists.pwr.wroc.pl>   |
|*BSD, GNU/Linux and Samba                                  /
|__________________________________________________________/
-------------- next part --------------
Index: auth/auth_domain.c
===================================================================
RCS file: /cvsroot/samba/source/auth/auth_domain.c,v
retrieving revision 1.33
diff -u -r1.33 auth_domain.c
--- auth/auth_domain.c	27 Mar 2002 00:02:48 -0000	1.33
+++ auth/auth_domain.c	11 Apr 2002 10:30:59 -0000
@@ -527,7 +527,7 @@
 	}
 
 	/*
-	 * Get the machine account password for the trusted domain
+	 * Get the trusted account password for the trusted domain
 	 * No need to become_root() as secrets_init() is done at startup.
 	 */
 
Index: include/includes.h
===================================================================
RCS file: /cvsroot/samba/source/include/includes.h,v
retrieving revision 1.261
diff -u -r1.261 includes.h
--- include/includes.h	27 Mar 2002 23:17:50 -0000	1.261
+++ include/includes.h	11 Apr 2002 10:30:59 -0000
@@ -696,6 +696,7 @@
 #include "dlinklist.h"
 #include "../tdb/tdb.h"
 #include "../tdb/spinlock.h"
+#include "../tdb/tdbutil.h"
 #include "talloc.h"
 #include "ads.h"
 #include "interfaces.h"
Index: include/rpc_lsa.h
===================================================================
RCS file: /cvsroot/samba/source/include/rpc_lsa.h,v
retrieving revision 1.39
diff -u -r1.39 rpc_lsa.h
--- include/rpc_lsa.h	30 Jan 2002 06:08:15 -0000	1.39
+++ include/rpc_lsa.h	11 Apr 2002 10:30:59 -0000
@@ -278,8 +278,8 @@
 typedef struct lsa_enum_trust_dom_info
 {
 	POLICY_HND pol; /* policy handle */
-    uint32 enum_context; /* enumeration context handle */
-    uint32 preferred_len; /* preferred maximum length */
+	uint32 enum_context; /* enumeration context handle */
+	uint32 preferred_len; /* preferred maximum length */
 
 } LSA_Q_ENUM_TRUST_DOM;
 
Index: include/secrets.h
===================================================================
RCS file: /cvsroot/samba/source/include/secrets.h,v
retrieving revision 1.9
diff -u -r1.9 secrets.h
--- include/secrets.h	10 Apr 2002 00:34:59 -0000	1.9
+++ include/secrets.h	11 Apr 2002 10:30:59 -0000
@@ -48,12 +48,27 @@
 	time_t mod_time;
 };
 
-/* structure for storing trusted domain password */
+/*
+ * storage structure for trusted domain
+ */
 struct trusted_dom_pass {
-	int pass_len;
-	fstring pass;
+	size_t uni_name_len;
+	smb_ucs2_t uni_name[32]; /* unicode domain name */
+	size_t pass_len;
+	fstring pass;		/* trust relationship's password */
 	time_t mod_time;
-	DOM_SID domain_sid; /* remote domain's sid */
+	DOM_SID domain_sid;	/* remote domain's sid */
 };
+
+/*
+ * trusted domain entry/entries returned by secrets_get_trusted_domains
+ * (used in _lsa_enum_trust_dom call)
+ */
+typedef struct trustdom {
+	UNISTR2 name;
+	DOM_SID sid;
+	struct trustdom *next;
+} TRUSTDOM;
+
 
 #endif /* _SECRETS_H */
Index: lib/util_unistr.c
===================================================================
RCS file: /cvsroot/samba/source/lib/util_unistr.c,v
retrieving revision 1.92
diff -u -r1.92 util_unistr.c
--- lib/util_unistr.c	26 Mar 2002 03:15:29 -0000	1.92
+++ lib/util_unistr.c	11 Apr 2002 10:30:59 -0000
@@ -775,3 +775,42 @@
 
 	return num_wchars;
 }
+
+/**
+ * Samba ucs2 type to UNISTR2 conversion
+ *
+ * @param dst UNISTR2 destination. If equals null, then it's allocated.
+ * @param src smb_ucs2_t source.
+ * @param max_len maximum number of unicode characters to copy. If equals
+ *        null, then null-termination of src is taken
+ *
+ * @return copied UNISTR2 destination
+ **/
+UNISTR2* ucs2_to_unistr2(UNISTR2* dst, smb_ucs2_t* src)
+{
+	size_t len;
+
+	if (!src) return NULL;
+	len = strlen_w(src);
+	
+	/* allocate UNISTR2 destination if not given */
+	if (!dst) {
+		dst = (UNISTR2*) malloc(sizeof(UNISTR2));
+		if (!dst) return NULL;
+	}
+	if (!dst->buffer) {
+		dst->buffer = (uint16*) malloc(sizeof(uint16) * (len + 1));
+		if (!dst->buffer) return NULL;
+	}
+	
+	/* set UNISTR2 parameters */
+	dst->uni_max_len = len + 1;
+	dst->undoc = 0;
+	dst->uni_str_len = len;
+	
+	/* copy the actual unicode string */
+	strncpy_w(dst->buffer, src, dst->uni_max_len);
+	
+	return dst;
+};
+
Index: passdb/secrets.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/secrets.c,v
retrieving revision 1.32
diff -u -r1.32 secrets.c
--- passdb/secrets.c	10 Mar 2002 01:43:04 -0000	1.32
+++ passdb/secrets.c	11 Apr 2002 10:30:59 -0000
@@ -124,9 +124,13 @@
 }
 
 
-/************************************************************************
-form a key for fetching the machine trust account password
-************************************************************************/
+/**
+ * Form a key for fetching the machine trust account password
+ *
+ * @param domain domain name
+ *
+ * @return stored password's key
+ **/
 char *trust_keystr(char *domain)
 {
 	static fstring keystr;
@@ -141,7 +145,7 @@
 /**
  * Form a key for fetching a trusted domain password
  *
- * @param domain domain name
+ * @param domain trusted domain name
  *
  * @return stored password's key
  **/
@@ -194,21 +198,23 @@
  Routine to get account password to trusted domain
 ************************************************************************/
 BOOL secrets_fetch_trusted_domain_password(char *domain, char** pwd,
-				DOM_SID *sid, time_t *pass_last_set_time)
+					   DOM_SID *sid, time_t *pass_last_set_time)
 {
 	struct trusted_dom_pass *pass;
 	size_t size;
 
+	/* fetching trusted domain password structure */
 	if (!(pass = secrets_fetch(trustdom_keystr(domain), &size))) {
 		DEBUG(5, ("secrets_fetch failed!\n"));
 		return False;
 	}
-	
+
 	if (size != sizeof(*pass)) {
 		DEBUG(0, ("secrets were of incorrect size!\n"));
 		return False;
 	}
-	
+
+	/* the trust's password */	
 	if (pwd) {
 		*pwd = strdup(pass->pass);
 		if (!*pwd) {
@@ -216,9 +222,12 @@
 		}
 	}
 
+	/* last change time */
 	if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
 
+	/* domain sid */
 	memcpy(&sid, &(pass->domain_sid), sizeof(sid));
+	
 	SAFE_FREE(pass);
 	
 	return True;
@@ -247,19 +256,30 @@
  * @return true if succeeded
  **/
 
-BOOL secrets_store_trusted_domain_password(char* domain, char* pwd,
+BOOL secrets_store_trusted_domain_password(char* domain, uint16* uni_dom_name,
+					   size_t uni_name_len, char* pwd,
 					   DOM_SID sid)
 {
 	struct trusted_dom_pass pass;
 	ZERO_STRUCT(pass);
 
+	/* unicode domain name and its length */
+	if (!uni_dom_name)
+		return False;
+		
+	strncpy_w(pass.uni_name, uni_dom_name, sizeof(pass.uni_name));
+	pass.uni_name_len = uni_name_len;
+
+	/* last change time */
 	pass.mod_time = time(NULL);
 
+	/* password of the trust */
 	pass.pass_len = strlen(pwd);
 	fstrcpy(pass.pass, pwd);
 
+	/* domain sid */
 	memcpy(&(pass.domain_sid), &sid, sizeof(sid));
-	
+
 	return secrets_store(trustdom_keystr(domain), (void *)&pass, sizeof(pass));
 }
 
@@ -355,5 +375,65 @@
 		if (*p == ',') *p = '/';
 	
 	return secrets_store(key, pw, strlen(pw));
+}
+
+
+/**
+ * The caller must take care of doing a proper free of returned list
+ *
+ * @param start_idx starting index, eg. we can start fetching
+ *	  at third or sixth trusted domain entry
+ * @param num_domains number of domain entries to fetch at one call
+ *
+ * @return list of trusted domains structs (unicode name, sid and password)
+ **/ 
+
+TRUSTDOM* secrets_get_trusted_domains(TALLOC_CTX* ctx, int start_idx, int num_domains)
+{
+	TDB_LIST_NODE *keys, *k;
+	TRUSTDOM *domains = NULL;
+	char *pattern;
+	int idx = 1;
+	struct trusted_dom_pass *pass;
+	
+	/* generate searching pattern */
+	if (!asprintf(&pattern, "%s/*", SECRETS_DOMTRUST_ACCT_PASS))
+		return NULL;
+
+	/* searching for keys in sectrets db -- way to go ... */
+	keys = tdb_search_keys(tdb, pattern);
+
+	/* fetching trusted domains' data and collecting them in a list */
+	k = keys;
+	while (k) {
+		if (idx >= start_idx && idx < start_idx + num_domains) {
+			TRUSTDOM* dom = (TRUSTDOM*) talloc(ctx, sizeof(*domains));
+			dom->next = domains;
+
+			/* important: ensure null-termination of the key string */
+			k->node_key.dptr[k->node_key.dsize] = 0;
+			pass = secrets_fetch(k->node_key.dptr, &k->node_key.dsize);
+
+			/* copy domain sid */
+			memcpy(&dom->sid, (void*)&pass->domain_sid, sizeof(dom->sid));
+			
+			/* copy unicode domain name */
+			dom->name.buffer = (smb_ucs2_t*) talloc(ctx, (pass->uni_name_len + 1) * sizeof(uint16));
+			ucs2_to_unistr2(&dom->name, pass->uni_name);
+
+			/* place domain info in the list */
+			domains = dom;
+			
+			/* free returned tdb record */
+			SAFE_FREE(pass);
+		};
+
+		k = k->next;
+	}
+	
+	/* free the results of searching the keys */
+	tdb_search_list_free(keys);
+		
+	return domains;
 }
 
Index: rpc_parse/parse_lsa.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_parse/parse_lsa.c,v
retrieving revision 1.75
diff -u -r1.75 parse_lsa.c
--- rpc_parse/parse_lsa.c	4 Apr 2002 02:39:57 -0000	1.75
+++ rpc_parse/parse_lsa.c	11 Apr 2002 10:31:00 -0000
@@ -523,40 +523,57 @@
  Inits an LSA_R_ENUM_TRUST_DOM structure.
 ********************************************************************/
 
-void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *r_e, uint32 enum_context, 
-			   char *domain_name, DOM_SID *domain_sid,
-                           NTSTATUS status)
+void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *r_e, uint32 enum_context,
+			   uint32 max_num_domains, TRUSTDOM* td)
 {
+	NTSTATUS status;
+	int i = 0;
+
         DEBUG(5, ("init_r_enum_trust_dom\n"));
 	
         r_e->enum_context = enum_context;
-	
-        if (NT_STATUS_IS_OK(status)) {
-                int len_domain_name = strlen(domain_name) + 1;
+	r_e->num_domains = 0;
+	r_e->ptr_enum_domains = 0;
+	r_e->num_domains2 = 0;
+
+	/* 
+	 * allocating empty arrays of unicode headers, strings
+	 * and sids of enumerated trusted domains
+	 */
+	if (!(r_e->hdr_domain_name = (UNIHDR2 *)talloc(ctx,sizeof(UNIHDR2) * max_num_domains)))
+		return;
+			
+	if (!(r_e->uni_domain_name = (UNISTR2 *)talloc(ctx,sizeof(UNISTR2) * max_num_domains)))
+		return;
+
+	if (!(r_e->domain_sid = (DOM_SID2 *)talloc(ctx,sizeof(DOM_SID2) * max_num_domains)))
+		return;
+
+	status = NT_STATUS_NO_MORE_ENTRIES;
+
+	while (td) {
+		r_e->num_domains = i + 1;
+		r_e->num_domains2 = i + 1;
+		/* don't know what actually is this for, but pointer is a pointer... :) */
+		r_e->ptr_enum_domains = (uint32) &(r_e->num_domains);
 		
-                r_e->num_domains  = 1;
-                r_e->ptr_enum_domains = 1;
-                r_e->num_domains2 = 1;
-		
-		if (!(r_e->hdr_domain_name = (UNIHDR2 *)talloc(ctx,sizeof(UNIHDR2))))
-			return;
+		init_uni_hdr2(&r_e->hdr_domain_name[i], td->name.uni_str_len);
+		init_dom_sid2(&r_e->domain_sid[i], &td->sid);
 
-		if (!(r_e->uni_domain_name = (UNISTR2 *)talloc(ctx,sizeof(UNISTR2))))
-			return;
+		/*
+		 * important: ensure copy_unistr2 will allocate the buffer
+		 * by explicitly setting it to NULL
+		 */
+		r_e->uni_domain_name[i].buffer = NULL;
+		copy_unistr2(&r_e->uni_domain_name[i], &td->name);
+
+		i++;
+		td = td->next;
+		status = NT_STATUS_OK;
 
-		if (!(r_e->domain_sid = (DOM_SID2 *)talloc(ctx,sizeof(DOM_SID2))))
-			return;
+	};
 
-		init_uni_hdr2(&r_e->hdr_domain_name[0], len_domain_name);
-		init_unistr2 (&r_e->uni_domain_name[0], domain_name, 
-			      len_domain_name);
-		init_dom_sid2(&r_e->domain_sid[0], domain_sid);
-        } else {
-                r_e->num_domains = 0;
-                r_e->ptr_enum_domains = 0;
-        }
-	
-        r_e->status = status;
+	r_e->status = status;
 }
 
 /*******************************************************************
@@ -603,7 +620,7 @@
 		
 		for (i = 0; i < num_domains; i++) {
 			if(!smb_io_unistr2 ("", &r_e->uni_domain_name[i],
-					    r_e->hdr_domain_name[i].buffer, 
+					    r_e->hdr_domain_name[i].buffer,
 					    ps, depth))
 				return False;
 			if(!smb_io_dom_sid2("", &r_e->domain_sid[i], ps, 
Index: rpc_server/srv_lsa.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_server/srv_lsa.c,v
retrieving revision 1.78
diff -u -r1.78 srv_lsa.c
--- rpc_server/srv_lsa.c	30 Jan 2002 06:08:33 -0000	1.78
+++ rpc_server/srv_lsa.c	11 Apr 2002 10:31:00 -0000
@@ -105,8 +105,10 @@
 	if(!lsa_io_q_enum_trust_dom("", &q_u, data, 0))
 		return False;
 
+	/* get required trusted domains information */
 	r_u.status = _lsa_enum_trust_dom(p, &q_u, &r_u);
 
+	/* prepare the response */
 	if(!lsa_io_r_enum_trust_dom("", &r_u, rdata, 0))
 		return False;
 
Index: rpc_server/srv_lsa_nt.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_server/srv_lsa_nt.c,v
retrieving revision 1.52
diff -u -r1.52 srv_lsa_nt.c
--- rpc_server/srv_lsa_nt.c	9 Apr 2002 04:59:34 -0000	1.52
+++ rpc_server/srv_lsa_nt.c	11 Apr 2002 10:31:00 -0000
@@ -416,14 +416,16 @@
 
 /***************************************************************************
  _lsa_enum_trust_dom - this needs fixing to do more than return NULL ! JRA.
+ ufff, done :)  mimir
  ***************************************************************************/
 
 NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, LSA_R_ENUM_TRUST_DOM *r_u)
 {
 	struct lsa_info *info;
-	uint32 enum_context = 0;
-	char *dom_name = NULL;
-	DOM_SID *dom_sid = NULL;
+	uint32 enum_context = q_u->enum_context;
+	/* it's set to 10 as a "our" preferred length */
+	uint32 max_num_domains = q_u->preferred_len < 10 ? q_u->preferred_len : 10;
+	TRUSTDOM *trust_doms;
 
 	if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
 		return NT_STATUS_INVALID_HANDLE;
@@ -432,9 +434,10 @@
 	if (!(info->access & POLICY_VIEW_LOCAL_INFORMATION))
 		return NT_STATUS_ACCESS_DENIED;
 
-	/* set up the LSA QUERY INFO response */
-	init_r_enum_trust_dom(p->mem_ctx, r_u, enum_context, dom_name, dom_sid,
-	      dom_name != NULL ? NT_STATUS_OK : NT_STATUS_NO_MORE_ENTRIES);
+	trust_doms = secrets_get_trusted_domains(p->mem_ctx, enum_context, max_num_domains);
+
+	/* set up the lsa_enum_trust_dom response */
+	init_r_enum_trust_dom(p->mem_ctx, r_u, enum_context, max_num_domains, trust_doms);
 
 	return r_u->status;
 }
Index: tdb/tdbutil.c
===================================================================
RCS file: /cvsroot/samba/source/tdb/tdbutil.c,v
retrieving revision 1.38
diff -u -r1.38 tdbutil.c
--- tdb/tdbutil.c	9 Apr 2002 23:03:17 -0000	1.38
+++ tdb/tdbutil.c	11 Apr 2002 10:31:00 -0000
@@ -19,6 +19,7 @@
 */
 
 #include "includes.h"
+#include <fnmatch.h>
 
 /* these are little tdb utility functions that are meant to make
    dealing with a tdb database a little less cumbersome in Samba */
@@ -509,3 +510,65 @@
 {
     return tdb_delete(the_tdb, key);
 }
+
+
+
+/**
+ * Search across the whole tdb for keys that match the given pattern
+ * return the result as a list of keys
+ *
+ * @param tdb pointer to opened tdb file context
+ * @param pattern searching pattern used by fnmatch(3) functions
+ *
+ * @return list of keys found by looking up with given pattern
+ **/
+TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
+{
+	TDB_DATA key, next;
+	TDB_LIST_NODE *list = NULL;
+	
+	for (key = tdb_firstkey(tdb); key.dptr; key = next) {
+		/* duplicate key string to ensure null-termination */
+		char *key_str = (char*) strndup(key.dptr, key.dsize);
+		
+		next = tdb_nextkey(tdb, key);
+		
+		/* do the pattern checking */
+		if (fnmatch(pattern, key_str, 0) == 0) {
+			TDB_LIST_NODE* rec;
+			rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
+			
+			/* have doubts about this one */
+			rec->next = list;
+			rec->node_key = key;
+			list = rec;
+		} else {
+			free(key.dptr);
+		}
+		
+		/* free duplicated key string */
+		free(key_str);
+	}
+	
+	return list;
+
+};
+
+
+/**
+ * Free the list returned by tdb_search_keys
+ *
+ * @param node list of results found by tdb_search_keys
+ **/
+void tdb_search_list_free(TDB_LIST_NODE* node)
+{
+	TDB_LIST_NODE *next_node;
+	
+	while (node) {
+		next_node = node->next;
+		SAFE_FREE(node);
+		node = next_node;
+	};
+};
+
+
Index: utils/net_rpc.c
===================================================================
RCS file: /cvsroot/samba/source/utils/net_rpc.c,v
retrieving revision 1.14
diff -u -r1.14 net_rpc.c
--- utils/net_rpc.c	5 Apr 2002 01:36:28 -0000	1.14
+++ utils/net_rpc.c	11 Apr 2002 10:31:00 -0000
@@ -1061,10 +1061,8 @@
 		return -1;
 	}
 
-	if (cli->nt_pipe_fnum) {
+	if (cli->nt_pipe_fnum)
 		cli_nt_session_close(cli);
-		talloc_destroy(mem_ctx);
-	}
 
 
 	/*
@@ -1116,20 +1114,20 @@
 
 	if (cli->nt_pipe_fnum)
 		cli_nt_session_close(cli);
-
-	talloc_destroy(mem_ctx);
-	 
 	 
 	/*
 	 * Store the password in secrets db
 	 */
 
-	if (!secrets_store_trusted_domain_password(domain_name, opt_password,
+	if (!secrets_store_trusted_domain_password(domain_name, wks_info.uni_lan_grp.buffer,
+						   wks_info.uni_lan_grp.uni_str_len, opt_password,
 						   domain_sid)) {
 		DEBUG(0, ("Storing password for trusted domain failed.\n"));
 		return -1;
 	}
 	
+	talloc_destroy(mem_ctx);
+	 
 	DEBUG(0, ("Success!\n"));
 	return 0;
 }
diff -Nur samba/source/tdb/tdbutil.h head/source/tdb/tdbutil.h
--- tdb/tdbutil.h	Thu Jan  1 01:00:00 1970
+++ tdb/tdbutil.h	Wed Apr 10 18:13:25 2002
@@ -0,0 +1,37 @@
+/* 
+   Unix SMB/CIFS implementation.
+   tdb utility functions
+   Copyright (C) Andrew Tridgell 1999
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDBUTIL_H__
+#define __TDBUTIL_H__
+
+
+/* single node of a list returned by tdb_search_keys */
+typedef struct keys_node 
+{
+	struct keys_node *next;
+	TDB_DATA node_key;
+} TDB_LIST_NODE;
+
+
+TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT*, const char*);
+void tdb_search_list_free(TDB_LIST_NODE*);
+
+
+#endif /* __TDBUTIL_H__ */


More information about the samba-technical mailing list