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 <[EMAIL PROTECTED]>   |
|*BSD, GNU/Linux and Samba                                  /
|__________________________________________________________/
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__ */

Reply via email to