diff options
author | Volker Lendecke <vlendec@samba.org> | 2005-04-15 13:41:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:56:38 -0500 |
commit | d3d6126d94d55a69c45b2f7a63a7fa9b561baf48 (patch) | |
tree | ce4e45d5571fb0e1a090b59ffa74a56b8a883334 | |
parent | 496c6f088492e3f74bba11da21ffc8855b2eb7f9 (diff) | |
download | samba-d3d6126d94d55a69c45b2f7a63a7fa9b561baf48.tar.gz samba-d3d6126d94d55a69c45b2f7a63a7fa9b561baf48.tar.bz2 samba-d3d6126d94d55a69c45b2f7a63a7fa9b561baf48.zip |
r6351: This is quite a large and intrusive patch, but there are not many pieces that
can be taken out of it, so I decided to commit this in one lump. It changes
the passdb enumerating functions to use ldap paged results where possible. In
particular the samr calls querydispinfo, enumdomusers and friends have
undergone significant internal changes. I have tested this extensively with
rpcclient and a bit with usrmgr.exe. More tests and the merge to trunk will
follow later.
The code is based on a first implementation by Günther Deschner, but has
evolved quite a bit since then.
Volker
(This used to be commit f0bb44ac58e190e19eb4e92928979b0446e611c9)
-rw-r--r-- | source3/groupdb/mapping.c | 47 | ||||
-rw-r--r-- | source3/include/passdb.h | 86 | ||||
-rw-r--r-- | source3/include/smb_macros.h | 3 | ||||
-rw-r--r-- | source3/include/smbldap.h | 1 | ||||
-rw-r--r-- | source3/lib/smbldap.c | 158 | ||||
-rw-r--r-- | source3/lib/util.c | 50 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_passdb.c | 34 | ||||
-rw-r--r-- | source3/param/loadparm.c | 4 | ||||
-rw-r--r-- | source3/passdb/pdb_interface.c | 401 | ||||
-rw-r--r-- | source3/passdb/pdb_ldap.c | 469 | ||||
-rw-r--r-- | source3/rpc_parse/parse_samr.c | 221 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 818 |
12 files changed, 1317 insertions, 975 deletions
diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c index 6e9d9b8e6c..459c66bdf7 100644 --- a/source3/groupdb/mapping.c +++ b/source3/groupdb/mapping.c @@ -1247,53 +1247,6 @@ NTSTATUS pdb_default_delete_alias(struct pdb_methods *methods, NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; } -NTSTATUS pdb_default_enum_aliases(struct pdb_methods *methods, - const DOM_SID *sid, - uint32 start_idx, uint32 max_entries, - uint32 *num_aliases, - struct acct_info **info) -{ - GROUP_MAP *map; - int i, num_maps; - enum SID_NAME_USE type = SID_NAME_UNKNOWN; - - if (sid_compare(sid, get_global_sam_sid()) == 0) - type = SID_NAME_ALIAS; - - if (sid_compare(sid, &global_sid_Builtin) == 0) - type = SID_NAME_WKN_GRP; - - if (!pdb_enum_group_mapping(type, &map, &num_maps, False) || - (num_maps == 0)) { - *num_aliases = 0; - *info = NULL; - goto done; - } - - if (start_idx > num_maps) { - *num_aliases = 0; - *info = NULL; - goto done; - } - - *num_aliases = num_maps - start_idx; - - if (*num_aliases > max_entries) - *num_aliases = max_entries; - - *info = SMB_MALLOC_ARRAY(struct acct_info, *num_aliases); - - for (i=0; i<*num_aliases; i++) { - fstrcpy((*info)[i].acct_name, map[i+start_idx].nt_name); - fstrcpy((*info)[i].acct_desc, map[i+start_idx].comment); - sid_peek_rid(&map[i].sid, &(*info)[i+start_idx].rid); - } - - done: - SAFE_FREE(map); - return NT_STATUS_OK; -} - NTSTATUS pdb_default_get_aliasinfo(struct pdb_methods *methods, const DOM_SID *sid, struct acct_info *info) diff --git a/source3/include/passdb.h b/source3/include/passdb.h index 624f0c5fea..0c816271b0 100644 --- a/source3/include/passdb.h +++ b/source3/include/passdb.h @@ -232,6 +232,30 @@ struct acct_info uint32 rid; /* domain-relative RID */ }; +struct samr_displayentry { + uint32 rid; + uint16 acct_flags; + const char *account_name; + const char *fullname; + const char *description; +}; + +enum pdb_search_type { + PDB_USER_SEARCH, + PDB_GROUP_SEARCH, + PDB_ALIAS_SEARCH +}; + +struct pdb_search { + TALLOC_CTX *mem_ctx; + enum pdb_search_type type; + struct samr_displayentry *cache; + uint32 num_entries; + ssize_t cache_size; + BOOL search_ended; + void *private; +}; + /***************************************************************** Functions to be implemented by the new (v2) passdb API ****************************************************************/ @@ -310,12 +334,6 @@ typedef struct pdb_context NTSTATUS (*pdb_delete_alias)(struct pdb_context *context, const DOM_SID *sid); - NTSTATUS (*pdb_enum_aliases)(struct pdb_context *context, - const DOM_SID *domain_sid, - uint32 start_idx, uint32 num_entries, - uint32 *num_aliases, - struct acct_info **aliases); - NTSTATUS (*pdb_get_aliasinfo)(struct pdb_context *context, const DOM_SID *sid, struct acct_info *info); @@ -352,6 +370,20 @@ typedef struct pdb_context const char ***names, uint32 **attrs); + BOOL (*pdb_search_users)(struct pdb_context *context, + struct pdb_search *search, + uint16 acct_flags); + BOOL (*pdb_search_groups)(struct pdb_context *context, + struct pdb_search *search); + BOOL (*pdb_search_aliases)(struct pdb_context *context, + struct pdb_search *search, + const DOM_SID *sid); + BOOL (*pdb_search_next_entry)(struct pdb_context *context, + struct pdb_search *search, + struct samr_displayentry *entry); + void (*pdb_search_end)(struct pdb_context *context, + struct pdb_search *search); + void (*free_fn)(struct pdb_context **); TALLOC_CTX *mem_ctx; @@ -426,11 +458,6 @@ typedef struct pdb_methods NTSTATUS (*delete_alias)(struct pdb_methods *methods, const DOM_SID *sid); - NTSTATUS (*enum_aliases)(struct pdb_methods *methods, - const DOM_SID *domain_sid, - uint32 start_idx, uint32 max_entries, - uint32 *num_aliases, struct acct_info **info); - NTSTATUS (*get_aliasinfo)(struct pdb_methods *methods, const DOM_SID *sid, struct acct_info *info); @@ -461,6 +488,20 @@ typedef struct pdb_methods const char ***names, uint32 **attrs); + BOOL (*search_users)(struct pdb_methods *methods, + struct pdb_search *search, + uint16 acct_flags); + BOOL (*search_groups)(struct pdb_methods *methods, + struct pdb_search *search); + BOOL (*search_aliases)(struct pdb_methods *methods, + struct pdb_search *search, + const DOM_SID *sid); + BOOL (*search_next_entry)(struct pdb_methods *methods, + struct pdb_search *search, + struct samr_displayentry *entry); + void (*search_end)(struct pdb_methods *methods, + struct pdb_search *search); + void *private_data; /* Private data of some kind */ void (*free_private_data)(void **); @@ -480,27 +521,4 @@ struct pdb_init_function_entry { enum sql_search_field { SQL_SEARCH_NONE = 0, SQL_SEARCH_USER_SID = 1, SQL_SEARCH_USER_NAME = 2}; -struct samr_displayentry { - uint32 rid; - uint16 acct_flags; - const char *account_name; - const char *fullname; - const char *description; -}; - -enum pdb_search_type { - PDB_USER_SEARCH, - PDB_GROUP_SEARCH, - PDB_ALIAS_SEARCH -}; - -struct pdb_search { - TALLOC_CTX *mem_ctx; - enum pdb_search_type type; - struct samr_displayentry *cache; - uint32 cache_size; - BOOL search_ended; - void *private; -}; - #endif /* _PASSDB_H */ diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index b7a3a68bec..04616eb8ab 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -362,4 +362,7 @@ do { \ (*(num)) += 1; \ } while (0) +#define ADD_TO_LARGE_ARRAY(mem_ctx, type, elem, array, num, size) \ + add_to_large_array((mem_ctx), sizeof(type), &(elem), (void **)(array), (num), (size)); + #endif /* _SMB_MACROS_H */ diff --git a/source3/include/smbldap.h b/source3/include/smbldap.h index e6a6a1b7c6..b54b3f4325 100644 --- a/source3/include/smbldap.h +++ b/source3/include/smbldap.h @@ -185,5 +185,6 @@ struct ldapsam_privates { struct smbldap_state; #define LDAP_CONNECT_DEFAULT_TIMEOUT 15 +#define LDAP_PAGE_SIZE 1024 #endif /* _SMBLDAP_H */ diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index cf2f03e0a2..e2d78e0ecc 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -856,6 +856,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_ } ldap_state->num_failures = 0; + ldap_state->paged_results = False; ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version); @@ -864,7 +865,8 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_ } DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n")); - DEBUGADD(3, ("ldap_connect_system: LDAP server %s support paged results\n", ldap_state->paged_results?"does":"does not")); + DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n", + ldap_state->paged_results ? "does" : "does not")); return rc; } @@ -1022,20 +1024,22 @@ static int another_ldap_try(struct smbldap_state *ldap_state, int *rc, /********************************************************************* ********************************************************************/ -int smbldap_search(struct smbldap_state *ldap_state, - const char *base, int scope, const char *filter, - const char *attrs[], int attrsonly, - LDAPMessage **res) +static int smbldap_search_ext(struct smbldap_state *ldap_state, + const char *base, int scope, const char *filter, + const char *attrs[], int attrsonly, + LDAPControl **sctrls, LDAPControl **cctrls, + int sizelimit, LDAPMessage **res) { int rc = LDAP_SERVER_DOWN; int attempts = 0; char *utf8_filter; time_t endtime = time(NULL)+lp_ldap_timeout(); + struct timeval timeout; SMB_ASSERT(ldap_state); - DEBUG(5,("smbldap_search: base => [%s], filter => [%s], scope => [%d]\n", - base, filter, scope)); + DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], " + "scope => [%d]\n", base, filter, scope)); if (ldap_state->last_rebind.tv_sec > 0) { struct timeval tval; @@ -1053,9 +1057,10 @@ int smbldap_search(struct smbldap_state *ldap_state, if (sleep_time > 0) { /* we wait for the LDAP replication */ - DEBUG(5,("smbldap_search: waiting %d milliseconds for LDAP replication.\n",sleep_time)); + DEBUG(5,("smbldap_search_ext: waiting %d milliseconds " + "for LDAP replication.\n",sleep_time)); smb_msleep(sleep_time); - DEBUG(5,("smbldap_search: go on!\n")); + DEBUG(5,("smbldap_search_ext: go on!\n")); } ZERO_STRUCT(ldap_state->last_rebind); } @@ -1064,13 +1069,138 @@ int smbldap_search(struct smbldap_state *ldap_state, return LDAP_NO_MEMORY; } + /* Setup timeout for the ldap_search_ext_s call - local and remote. */ + timeout.tv_sec = lp_ldap_timeout(); + timeout.tv_usec = 0; + + /* Setup alarm timeout.... Do we need both of these ? JRA. + * Yes, I think we do need both of these. The server timeout only + * covers the case where the server's operation takes too long. It + * does not cover the case where the request hangs on its way to the + * server. The server side timeout is not strictly necessary, it's + * just a bit more kind to the server. VL. */ + + got_alarm = 0; + CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); + alarm(lp_ldap_timeout()); + /* End setup timeout. */ + while (another_ldap_try(ldap_state, &rc, &attempts, endtime)) - rc = ldap_search_s(ldap_state->ldap_struct, base, scope, - utf8_filter, - CONST_DISCARD(char **, attrs), - attrsonly, res); - + rc = ldap_search_ext_s(ldap_state->ldap_struct, base, scope, + utf8_filter, + CONST_DISCARD(char **, attrs), + attrsonly, sctrls, cctrls, &timeout, + sizelimit, res); + SAFE_FREE(utf8_filter); + + /* Teardown timeout. */ + CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); + alarm(0); + + if (got_alarm != 0) + return LDAP_TIMELIMIT_EXCEEDED; + + return rc; +} + +int smbldap_search(struct smbldap_state *ldap_state, + const char *base, int scope, const char *filter, + const char *attrs[], int attrsonly, + LDAPMessage **res) +{ + return smbldap_search_ext(ldap_state, base, scope, filter, attrs, + attrsonly, NULL, NULL, LDAP_NO_LIMIT, res); +} + +int smbldap_search_paged(struct smbldap_state *ldap_state, + const char *base, int scope, const char *filter, + const char **attrs, int attrsonly, int pagesize, + LDAPMessage **res, void **cookie) +{ + LDAPControl pr; + LDAPControl **rcontrols; + LDAPControl *controls[2] = { NULL, NULL}; + BerElement *cookie_be = NULL; + struct berval *cookie_bv = NULL; + int tmp = 0, i, rc; + BOOL critical = True; + + *res = NULL; + + DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s]," + "scope => [%d], pagesize => [%d]\n", + base, filter, scope, pagesize)); + + cookie_be = ber_alloc_t(LBER_USE_DER); + if (cookie_be == NULL) { + DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns " + "NULL\n")); + return LDAP_NO_MEMORY; + } + + /* construct cookie */ + if (*cookie != NULL) { + ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie); + ber_bvfree(*cookie); /* don't need it from last time */ + *cookie = NULL; + } else { + ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0); + } + ber_flatten(cookie_be, &cookie_bv); + + pr.ldctl_oid = CONST_DISCARD(char *, ADS_PAGE_CTL_OID); + pr.ldctl_iscritical = (char) critical; + pr.ldctl_value.bv_len = cookie_bv->bv_len; + pr.ldctl_value.bv_val = cookie_bv->bv_val; + + controls[0] = ≺ + controls[1] = NULL; + + rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs, + 0, controls, NULL, LDAP_NO_LIMIT, res); + + ber_free(cookie_be, 1); + ber_bvfree(cookie_bv); + + if (rc != 0) { + DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) " + "failed with [%s]\n", filter, ldap_err2string(rc))); + goto done; + } + + DEBUG(3,("smbldap_search_paged: search was successfull\n")); + + rc = ldap_parse_result(ldap_state->ldap_struct, *res, NULL, NULL, + NULL, NULL, &rcontrols, 0); + if (rc != 0) { + DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \ + "with [%s]\n", ldap_err2string(rc))); + goto done; + } + + if (rcontrols == NULL) + goto done; + + for (i=0; rcontrols[i]; i++) { + + if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0) + continue; + + cookie_be = ber_init(&rcontrols[i]->ldctl_value); + ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv); + /* the berval is the cookie, but must be freed when it is all + done */ + if (cookie_bv->bv_len) + *cookie=ber_bvdup(cookie_bv); + else + *cookie=NULL; + ber_bvfree(cookie_bv); + ber_free(cookie_be, 1); + break; + } + ldap_controls_free(rcontrols); +done: return rc; } diff --git a/source3/lib/util.c b/source3/lib/util.c index d244e390d2..52cf15da1e 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -978,6 +978,56 @@ void *realloc_array(void *p,size_t el_size, unsigned int count) } /**************************************************************************** + (Hopefully) efficient array append +****************************************************************************/ +void add_to_large_array(TALLOC_CTX *mem_ctx, size_t element_size, + void *element, void **array, uint32 *num_elements, + ssize_t *array_size) +{ + if (*array_size == -1) + return; + + if (*array == NULL) { + if (*array_size == 0) + *array_size = 128; + + if (mem_ctx != NULL) + *array = talloc_array(mem_ctx, element_size, + *array_size); + else + *array = malloc_array(element_size, *array_size); + + if (*array == NULL) + goto error; + } + + if (*num_elements == *array_size) { + *array_size *= 2; + + if (mem_ctx != NULL) + *array = talloc_realloc_array(mem_ctx, *array, + element_size, + *array_size); + else + *array = realloc_array(*array, element_size, + *array_size); + + if (*array == NULL) + goto error; + } + + memcpy((char *)(*array) + element_size*(*num_elements), + element, element_size); + *num_elements += 1; + + return; + + error: + *num_elements = 0; + *array_size = -1; +} + +/**************************************************************************** Free memory, checks for NULL. Use directly SAFE_FREE() Exists only because we need to pass a function pointer somewhere --SSS diff --git a/source3/nsswitch/winbindd_passdb.c b/source3/nsswitch/winbindd_passdb.c index bd15777bd3..23a56e4ea6 100644 --- a/source3/nsswitch/winbindd_passdb.c +++ b/source3/nsswitch/winbindd_passdb.c @@ -207,23 +207,33 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, uint32 *num_entries, struct acct_info **info) { - struct acct_info *talloced_info; + struct pdb_search *search; + struct samr_displayentry *aliases; + int i; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - /* Hmm. One billion aliases should be enough for a start */ + search = pdb_search_aliases(&domain->sid); + if (search == NULL) goto done; - if (!pdb_enum_aliases(&domain->sid, 0, 1000000000, - num_entries, info)) { - /* Nothing to report, just exit. */ - return NT_STATUS_OK; - } + *num_entries = pdb_search_entries(search, 0, 0xffffffff, &aliases); + if (*num_entries == 0) goto done; - talloced_info = (struct acct_info *)TALLOC_MEMDUP(mem_ctx, *info, - *num_entries * sizeof(struct acct_info)); + *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries); + if (*info == NULL) { + result = NT_STATUS_NO_MEMORY; + goto done; + } - SAFE_FREE(*info); - *info = talloced_info; + for (i=0; i<*num_entries; i++) { + fstrcpy((*info)[i].acct_name, aliases[i].account_name); + fstrcpy((*info)[i].acct_desc, aliases[i].description); + (*info)[i].rid = aliases[i].rid; + } - return NT_STATUS_OK; + result = NT_STATUS_OK; + done: + pdb_search_destroy(search); + return result; } /* convert a single name to a sid in a domain */ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 619a9ccb3d..06070b0700 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -246,6 +246,7 @@ typedef struct int ldap_passwd_sync; int ldap_replication_sleep; int ldap_timeout; /* This is initialised in init_globals */ + int ldap_page_size; BOOL ldap_delete_dn; BOOL bMsAddPrinterWizard; BOOL bDNSproxy; @@ -1121,6 +1122,7 @@ static struct parm_struct parm_table[] = { {"ldap suffix", P_STRING, P_GLOBAL, &Globals.szLdapSuffix, NULL, NULL, FLAG_ADVANCED}, {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, FLAG_ADVANCED}, {"ldap timeout", P_INTEGER, P_GLOBAL, &Globals.ldap_timeout, NULL, NULL, FLAG_ADVANCED}, + {"ldap page size", P_INTEGER, P_GLOBAL, &Globals.ldap_page_size, NULL, NULL, FLAG_ADVANCED}, {"ldap user suffix", P_STRING, P_GLOBAL, &Globals.szLdapUserSuffix, NULL, NULL, FLAG_ADVANCED}, {N_("Miscellaneous Options"), P_SEP, P_SEPARATOR}, @@ -1512,6 +1514,7 @@ static void init_globals(void) Globals.ldap_delete_dn = False; Globals.ldap_replication_sleep = 1000; /* wait 1 sec for replication */ Globals.ldap_timeout = LDAP_CONNECT_DEFAULT_TIMEOUT; + Globals.ldap_page_size = LDAP_PAGE_SIZE; /* This is what we tell the afs client. in reality we set the token * to never expire, though, when this runs out the afs client will @@ -1770,6 +1773,7 @@ FN_GLOBAL_INTEGER(lp_ldap_passwd_sync, &Globals.ldap_passwd_sync) FN_GLOBAL_BOOL(lp_ldap_delete_dn, &Globals.ldap_delete_dn) FN_GLOBAL_INTEGER(lp_ldap_replication_sleep, &Globals.ldap_replication_sleep) FN_GLOBAL_INTEGER(lp_ldap_timeout, &Globals.ldap_timeout) +FN_GLOBAL_INTEGER(lp_ldap_page_size, &Globals.ldap_page_size) FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand) FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand) FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand) diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index 301dc101eb..edcd1c9222 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -549,24 +549,6 @@ static NTSTATUS context_delete_alias(struct pdb_context *context, return context->pdb_methods->delete_alias(context->pdb_methods, sid); } -static NTSTATUS context_enum_aliases(struct pdb_context *context, - const DOM_SID *sid, - uint32 start_idx, uint32 max_entries, - uint32 *num_aliases, - struct acct_info **info) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - - if ((!context) || (!context->pdb_methods)) { - DEBUG(0, ("invalid pdb_context specified!\n")); - return ret; - } - - return context->pdb_methods->enum_aliases(context->pdb_methods, - sid, start_idx, max_entries, - num_aliases, info); -} - static NTSTATUS context_get_aliasinfo(struct pdb_context *context, const DOM_SID *sid, struct acct_info *info) @@ -683,6 +665,68 @@ static NTSTATUS context_lookup_rids(struct pdb_context *context, rids, names, attrs); } +static BOOL context_search_users(struct pdb_context *context, + struct pdb_search *search, uint16 acct_flags) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_users(context->pdb_methods, + search, acct_flags); +} + +static BOOL context_search_groups(struct pdb_context *context, + struct pdb_search *search) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_groups(context->pdb_methods, + search); +} + +static BOOL context_search_aliases(struct pdb_context *context, + struct pdb_search *search, + const DOM_SID *sid) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_aliases(context->pdb_methods, + search, sid); +} + +static BOOL context_search_next_entry(struct pdb_context *context, + struct pdb_search *search, + struct samr_displayentry *entry) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return False; + } + + return context->pdb_methods->search_next_entry(context->pdb_methods, + search, entry); +} + +static void context_search_end(struct pdb_context *context, + struct pdb_search *search) +{ + if ((!context) || (!context->pdb_methods)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return; + } + + context->pdb_methods->search_end(context->pdb_methods, search); + return; +} + /****************************************************************** Free and cleanup a pdb context, any associated data and anything that the attached modules might have associated. @@ -805,7 +849,6 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*context)->pdb_find_alias = context_find_alias; (*context)->pdb_create_alias = context_create_alias; (*context)->pdb_delete_alias = context_delete_alias; - (*context)->pdb_enum_aliases = context_enum_aliases; (*context)->pdb_get_aliasinfo = context_get_aliasinfo; (*context)->pdb_set_aliasinfo = context_set_aliasinfo; (*context)->pdb_add_aliasmem = context_add_aliasmem; @@ -814,6 +857,12 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*context)->pdb_enum_alias_memberships = context_enum_alias_memberships; (*context)->pdb_lookup_rids = context_lookup_rids; + (*context)->pdb_search_users = context_search_users; + (*context)->pdb_search_groups = context_search_groups; + (*context)->pdb_search_aliases = context_search_aliases; + (*context)->pdb_search_next_entry = context_search_next_entry; + (*context)->pdb_search_end = context_search_end; + (*context)->free_fn = free_pdb_context; return NT_STATUS_OK; @@ -1199,22 +1248,6 @@ BOOL pdb_delete_alias(const DOM_SID *sid) } -BOOL pdb_enum_aliases(const DOM_SID *sid, uint32 start_idx, uint32 max_entries, - uint32 *num_aliases, struct acct_info **info) -{ - struct pdb_context *pdb_context = pdb_get_static_context(False); - - if (!pdb_context) { - return False; - } - - return NT_STATUS_IS_OK(pdb_context->pdb_enum_aliases(pdb_context, sid, - start_idx, - max_entries, - num_aliases, - info)); -} - BOOL pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info) { struct pdb_context *pdb_context = pdb_get_static_context(False); @@ -1543,56 +1576,6 @@ NTSTATUS pdb_default_lookup_rids(struct pdb_methods *methods, return result; } -NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) -{ - *methods = TALLOC_P(mem_ctx, struct pdb_methods); - - if (!*methods) { - return NT_STATUS_NO_MEMORY; - } - - ZERO_STRUCTP(*methods); - - (*methods)->setsampwent = pdb_default_setsampwent; - (*methods)->endsampwent = pdb_default_endsampwent; - (*methods)->getsampwent = pdb_default_getsampwent; - (*methods)->getsampwnam = pdb_default_getsampwnam; - (*methods)->getsampwsid = pdb_default_getsampwsid; - (*methods)->add_sam_account = pdb_default_add_sam_account; - (*methods)->update_sam_account = pdb_default_update_sam_account; - (*methods)->delete_sam_account = pdb_default_delete_sam_account; - (*methods)->update_login_attempts = pdb_default_update_login_attempts; - - (*methods)->getgrsid = pdb_default_getgrsid; - (*methods)->getgrgid = pdb_default_getgrgid; - (*methods)->getgrnam = pdb_default_getgrnam; - (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry; - (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry; - (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry; - (*methods)->enum_group_mapping = pdb_default_enum_group_mapping; - (*methods)->enum_group_members = pdb_default_enum_group_members; - (*methods)->enum_group_memberships = pdb_default_enum_group_memberships; - (*methods)->find_alias = pdb_default_find_alias; - (*methods)->create_alias = pdb_default_create_alias; - (*methods)->delete_alias = pdb_default_delete_alias; - (*methods)->enum_aliases = pdb_default_enum_aliases; - (*methods)->get_aliasinfo = pdb_default_get_aliasinfo; - (*methods)->set_aliasinfo = pdb_default_set_aliasinfo; - (*methods)->add_aliasmem = pdb_default_add_aliasmem; - (*methods)->del_aliasmem = pdb_default_del_aliasmem; - (*methods)->enum_aliasmem = pdb_default_enum_aliasmem; - (*methods)->enum_alias_memberships = pdb_default_alias_memberships; - (*methods)->lookup_rids = pdb_default_lookup_rids; - - return NT_STATUS_OK; -} - -struct pdb_search *pdb_search_users(uint16 acct_flags); -struct pdb_search *pdb_search_groups(void); -struct pdb_search *pdb_search_aliases(const DOM_SID *sid); -uint32 pdb_search_entries(struct pdb_search *search, uint32 start_idx, uint32 max_entries, struct samr_displayentry **result); -void pdb_search_destroy(struct pdb_search *search); - static struct pdb_search *pdb_search_init(enum pdb_search_type type) { TALLOC_CTX *mem_ctx; @@ -1613,6 +1596,7 @@ static struct pdb_search *pdb_search_init(enum pdb_search_type type) result->mem_ctx = mem_ctx; result->type = type; result->cache = NULL; + result->num_entries = 0; result->cache_size = 0; result->search_ended = False; @@ -1631,12 +1615,18 @@ static void fill_displayentry(TALLOC_CTX *mem_ctx, uint32 rid, if (account_name != NULL) entry->account_name = talloc_strdup(mem_ctx, account_name); + else + entry->account_name = ""; if (fullname != NULL) entry->fullname = talloc_strdup(mem_ctx, fullname); + else + entry->fullname = ""; if (description != NULL) entry->description = talloc_strdup(mem_ctx, description); + else + entry->description = ""; } static BOOL user_search_in_progress = False; @@ -1644,40 +1634,38 @@ struct user_search { uint16 acct_flags; }; -struct pdb_search *pdb_search_users(uint16 acct_flags) +static BOOL pdb_default_search_users(struct pdb_methods *methods, + struct pdb_search *search, + uint16 acct_flags) { - struct pdb_search *result; struct user_search *state; if (user_search_in_progress) { DEBUG(1, ("user search in progress\n")); - return NULL; + return False; } - if (!pdb_setsampwent(False, acct_flags)) - return NULL; + if (!pdb_setsampwent(False, acct_flags)) { + DEBUG(5, ("Could not start search\n")); + return False; + } user_search_in_progress = True; - result = pdb_search_init(PDB_USER_SEARCH); - if (result == NULL) - return NULL; - - state = TALLOC_P(result->mem_ctx, struct user_search); + state = TALLOC_P(search->mem_ctx, struct user_search); if (state == NULL) { DEBUG(0, ("talloc failed\n")); - talloc_destroy(result->mem_ctx); - return NULL; + return False; } state->acct_flags = acct_flags; - result->private = state; - return result; + search->private = state; + return True; } -static BOOL pdb_search_entry_users(struct pdb_search *s, TALLOC_CTX *mem_ctx, - struct samr_displayentry *entry) +static BOOL pdb_search_next_entry_users(struct pdb_search *s, + struct samr_displayentry *entry) { struct user_search *state = s->private; SAM_ACCOUNT *user = NULL; @@ -1701,7 +1689,7 @@ static BOOL pdb_search_entry_users(struct pdb_search *s, TALLOC_CTX *mem_ctx, goto next; } - fill_displayentry(mem_ctx, pdb_get_user_rid(user), + fill_displayentry(s->mem_ctx, pdb_get_user_rid(user), pdb_get_acct_ctrl(user), pdb_get_username(user), pdb_get_fullname(user), pdb_get_acct_desc(user), entry); @@ -1721,36 +1709,30 @@ struct group_search { int num_groups, current_group; }; -struct pdb_search *pdb_search_groups(void) +static BOOL pdb_default_search_groups(struct pdb_methods *methods, + struct pdb_search *search) { - struct pdb_search *result; struct group_search *state; - result = pdb_search_init(PDB_GROUP_SEARCH); - if (result == NULL) - return NULL; - - state = TALLOC_P(result->mem_ctx, struct group_search); + state = TALLOC_P(search->mem_ctx, struct group_search); if (state == NULL) { DEBUG(0, ("talloc failed\n")); - talloc_destroy(result->mem_ctx); - return NULL; + return False; } if (!pdb_enum_group_mapping(SID_NAME_DOM_GRP, &state->groups, &state->num_groups, True)) { DEBUG(0, ("Could not enum groups\n")); - talloc_destroy(result->mem_ctx); - return NULL; + return False; } state->current_group = 0; - result->private = state; - return result; + search->private = state; + return True; } -static BOOL pdb_search_entry_group(struct pdb_search *s, TALLOC_CTX *mem_ctx, - struct samr_displayentry *entry) +static BOOL pdb_search_next_entry_group(struct pdb_search *s, + struct samr_displayentry *entry) { struct group_search *state = s->private; uint32 rid; @@ -1761,7 +1743,7 @@ static BOOL pdb_search_entry_group(struct pdb_search *s, TALLOC_CTX *mem_ctx, sid_peek_rid(&map->sid, &rid); - fill_displayentry(mem_ctx, rid, 0, map->nt_name, NULL, map->comment, + fill_displayentry(s->mem_ctx, rid, 0, map->nt_name, NULL, map->comment, entry); state->current_group += 1; @@ -1779,51 +1761,43 @@ struct alias_search { int num_aliases, current_alias; }; -struct pdb_search *pdb_search_aliases(const DOM_SID *sid) +static BOOL pdb_default_search_aliases(struct pdb_methods *methods, + struct pdb_search *search, + const DOM_SID *sid) { - struct pdb_search *result; struct alias_search *state; enum SID_NAME_USE type = SID_NAME_UNKNOWN; - DOM_SID builtin_sid; if (sid_equal(sid, get_global_sam_sid())) type = SID_NAME_ALIAS; - string_to_sid(&builtin_sid, "S-1-5-32"); - - if (sid_equal(sid, &builtin_sid)) + if (sid_equal(sid, &global_sid_Builtin)) type = SID_NAME_WKN_GRP; if (type == SID_NAME_UNKNOWN) { DEBUG(3, ("unknown domain sid: %s\n", sid_string_static(sid))); - return NULL; + return False; } - result = pdb_search_init(PDB_ALIAS_SEARCH); - if (result == NULL) - return NULL; - - state = TALLOC_P(result->mem_ctx, struct alias_search); + state = TALLOC_P(search->mem_ctx, struct alias_search); if (state == NULL) { DEBUG(0, ("talloc failed\n")); - talloc_destroy(result->mem_ctx); - return NULL; + return False; } if (!pdb_enum_group_mapping(type, &state->aliases, &state->num_aliases, False)) { DEBUG(0, ("Could not enum aliases\n")); - talloc_destroy(result->mem_ctx); - return NULL; + return False; } state->current_alias = 0; - result->private = state; - return result; + search->private = state; + return True; } -static BOOL pdb_search_entry_alias(struct pdb_search *s, TALLOC_CTX *mem_ctx, - struct samr_displayentry *entry) +static BOOL pdb_search_next_entry_alias(struct pdb_search *s, + struct samr_displayentry *entry) { struct alias_search *state = s->private; uint32 rid; @@ -1834,7 +1808,7 @@ static BOOL pdb_search_entry_alias(struct pdb_search *s, TALLOC_CTX *mem_ctx, sid_peek_rid(&map->sid, &rid); - fill_displayentry(mem_ctx, rid, 0, map->nt_name, NULL, map->comment, + fill_displayentry(s->mem_ctx, rid, 0, map->nt_name, NULL, map->comment, entry); state->current_alias += 1; @@ -1847,19 +1821,20 @@ static void pdb_search_end_aliases(struct pdb_search *search) SAFE_FREE(state->aliases); } -static BOOL pdb_search_entry(struct pdb_search *search, TALLOC_CTX *mem_ctx, - struct samr_displayentry *entry) +static BOOL pdb_default_search_next_entry(struct pdb_methods *pdb_methods, + struct pdb_search *search, + struct samr_displayentry *entry) { BOOL result = False; switch (search->type) { case PDB_USER_SEARCH: - result = pdb_search_entry_users(search, mem_ctx, entry); + result = pdb_search_next_entry_users(search, entry); break; case PDB_GROUP_SEARCH: - result = pdb_search_entry_group(search, mem_ctx, entry); + result = pdb_search_next_entry_group(search, entry); break; case PDB_ALIAS_SEARCH: - result = pdb_search_entry_alias(search, mem_ctx, entry); + result = pdb_search_next_entry_alias(search, entry); break; default: DEBUG(0, ("unknown search type: %d\n", search->type)); @@ -1868,7 +1843,18 @@ static BOOL pdb_search_entry(struct pdb_search *search, TALLOC_CTX *mem_ctx, return result; } -static void pdb_search_end(struct pdb_search *search) +static BOOL pdb_search_next_entry(struct pdb_search *search, + struct samr_displayentry *entry) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (pdb_context == NULL) return False; + + return pdb_context->pdb_search_next_entry(pdb_context, search, entry); +} + +static void pdb_default_search_end(struct pdb_methods *pdb_methods, + struct pdb_search *search) { switch (search->type) { case PDB_USER_SEARCH: @@ -1886,29 +1872,90 @@ static void pdb_search_end(struct pdb_search *search) } } +static void pdb_search_end(struct pdb_search *search) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (pdb_context == NULL) return; + + pdb_context->pdb_search_end(pdb_context, search); +} + static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search, uint32 idx) { - if (idx < search->cache_size) + if (idx < search->num_entries) return &search->cache[idx]; if (search->search_ended) return NULL; - while (idx >= search->cache_size) { + while (idx >= search->num_entries) { struct samr_displayentry entry; - if (!pdb_search_entry(search, search->mem_ctx, &entry)) { + if (!pdb_search_next_entry(search, &entry)) { pdb_search_end(search); search->search_ended = True; break; } - ADD_TO_ARRAY(search->mem_ctx, struct samr_displayentry, - entry, &search->cache, &search->cache_size); + ADD_TO_LARGE_ARRAY(search->mem_ctx, struct samr_displayentry, + entry, &search->cache, &search->num_entries, + &search->cache_size); + } + + return (search->num_entries > idx) ? &search->cache[idx] : NULL; +} + +struct pdb_search *pdb_search_users(uint16 acct_flags) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_search *result; + + if (pdb_context == NULL) return NULL; + + result = pdb_search_init(PDB_USER_SEARCH); + if (result == NULL) return NULL; + + if (!pdb_context->pdb_search_users(pdb_context, result, acct_flags)) { + talloc_destroy(result->mem_ctx); + return NULL; + } + return result; +} + +struct pdb_search *pdb_search_groups(void) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_search *result; + + if (pdb_context == NULL) return NULL; + + result = pdb_search_init(PDB_GROUP_SEARCH); + if (result == NULL) return NULL; + + if (!pdb_context->pdb_search_groups(pdb_context, result)) { + talloc_destroy(result->mem_ctx); + return NULL; } + return result; +} + +struct pdb_search *pdb_search_aliases(const DOM_SID *sid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + struct pdb_search *result; - return (search->cache_size > idx) ? &search->cache[idx] : NULL; + if (pdb_context == NULL) return NULL; + + result = pdb_search_init(PDB_ALIAS_SEARCH); + if (result == NULL) return NULL; + + if (!pdb_context->pdb_search_aliases(pdb_context, result, sid)) { + talloc_destroy(result->mem_ctx); + return NULL; + } + return result; } uint32 pdb_search_entries(struct pdb_search *search, @@ -1928,10 +1975,10 @@ uint32 pdb_search_entries(struct pdb_search *search, if (end_entry != NULL) return max_entries; - if (start_idx >= search->cache_size) + if (start_idx >= search->num_entries) return 0; - return search->cache_size - start_idx; + return search->num_entries - start_idx; } void pdb_search_destroy(struct pdb_search *search) @@ -1944,3 +1991,51 @@ void pdb_search_destroy(struct pdb_search *search) talloc_destroy(search->mem_ctx); } + +NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) +{ + *methods = TALLOC_P(mem_ctx, struct pdb_methods); + + if (!*methods) { + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(*methods); + + (*methods)->setsampwent = pdb_default_setsampwent; + (*methods)->endsampwent = pdb_default_endsampwent; + (*methods)->getsampwent = pdb_default_getsampwent; + (*methods)->getsampwnam = pdb_default_getsampwnam; + (*methods)->getsampwsid = pdb_default_getsampwsid; + (*methods)->add_sam_account = pdb_default_add_sam_account; + (*methods)->update_sam_account = pdb_default_update_sam_account; + (*methods)->delete_sam_account = pdb_default_delete_sam_account; + (*methods)->update_login_attempts = pdb_default_update_login_attempts; + + (*methods)->getgrsid = pdb_default_getgrsid; + (*methods)->getgrgid = pdb_default_getgrgid; + (*methods)->getgrnam = pdb_default_getgrnam; + (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry; + (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry; + (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry; + (*methods)->enum_group_mapping = pdb_default_enum_group_mapping; + (*methods)->enum_group_members = pdb_default_enum_group_members; + (*methods)->enum_group_memberships = pdb_default_enum_group_memberships; + (*methods)->find_alias = pdb_default_find_alias; + (*methods)->create_alias = pdb_default_create_alias; + (*methods)->delete_alias = pdb_default_delete_alias; + (*methods)->get_aliasinfo = pdb_default_get_aliasinfo; + (*methods)->set_aliasinfo = pdb_default_set_aliasinfo; + (*methods)->add_aliasmem = pdb_default_add_aliasmem; + (*methods)->del_aliasmem = pdb_default_del_aliasmem; + (*methods)->enum_aliasmem = pdb_default_enum_aliasmem; + (*methods)->enum_alias_memberships = pdb_default_alias_memberships; + (*methods)->lookup_rids = pdb_default_lookup_rids; + (*methods)->search_users = pdb_default_search_users; + (*methods)->search_groups = pdb_default_search_groups; + (*methods)->search_aliases = pdb_default_search_aliases; + (*methods)->search_next_entry = pdb_default_search_next_entry; + (*methods)->search_end = pdb_default_search_end; + + return NT_STATUS_OK; +} diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 3899949058..752eb878b1 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -3323,6 +3323,470 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, return result; } +char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username) +{ + char *filter = NULL; + char *escaped = NULL; + char *result = NULL; + + asprintf(&filter, "(&%s(objectclass=sambaSamAccount))", + lp_ldap_filter()); + if (filter == NULL) goto done; + + escaped = escape_ldap_string_alloc(username); + if (escaped == NULL) goto done; + + filter = realloc_string_sub(filter, "%u", username); + result = talloc_strdup(mem_ctx, filter); + + done: + SAFE_FREE(filter); + SAFE_FREE(escaped); + + return result; +} + +const char **talloc_attrs(TALLOC_CTX *mem_ctx, ...) +{ + int i, num = 0; + va_list ap; + const char **result; + + va_start(ap, mem_ctx); + while (va_arg(ap, const char *) != NULL) + num += 1; + va_end(ap); + + result = TALLOC_ARRAY(mem_ctx, const char *, num+1); + + va_start(ap, mem_ctx); + for (i=0; i<num; i++) + result[i] = talloc_strdup(mem_ctx, va_arg(ap, const char*)); + va_end(ap); + + result[num] = NULL; + return result; +} + +struct ldap_search_state { + struct smbldap_state *connection; + + uint16 acct_flags; + + const char *base; + int scope; + const char *filter; + const char **attrs; + int attrsonly; + void *pagedresults_cookie; + + LDAPMessage *entries, *current_entry; + BOOL (*ldap2displayentry)(struct ldap_search_state *state, + TALLOC_CTX *mem_ctx, + LDAP *ld, LDAPMessage *entry, + struct samr_displayentry *result); +}; + +static BOOL ldapsam_search_firstpage(struct pdb_search *search) +{ + struct ldap_search_state *state = search->private; + LDAP *ld = state->connection->ldap_struct; + int rc = LDAP_OPERATIONS_ERROR; + + state->entries = NULL; + + if (state->connection->paged_results) { + rc = smbldap_search_paged(state->connection, state->base, + state->scope, state->filter, + state->attrs, state->attrsonly, + lp_ldap_page_size(), &state->entries, + &state->pagedresults_cookie); + } + + if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) { + + if (state->entries != NULL) { + /* Left over from unsuccessful paged attempt */ + ldap_msgfree(state->entries); + state->entries = NULL; + } + + rc = smbldap_search(state->connection, state->base, + state->scope, state->filter, state->attrs, + state->attrsonly, &state->entries); + + if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) + return False; + + /* Ok, the server was lying. It told us it could do paged + * searches when it could not. */ + state->connection->paged_results = False; + } + + state->current_entry = ldap_first_entry(ld, state->entries); + + if (state->current_entry == NULL) { + ldap_msgfree(state->entries); + state->entries = NULL; + } + + return True; +} + +static BOOL ldapsam_search_nextpage(struct pdb_search *search) +{ + struct ldap_search_state *state = search->private; + LDAP *ld = state->connection->ldap_struct; + int rc; + + if (!state->connection->paged_results) { + /* There is no next page when there are no paged results */ + return False; + } + + rc = smbldap_search_paged(state->connection, state->base, + state->scope, state->filter, state->attrs, + state->attrsonly, lp_ldap_page_size(), + &state->entries, + &state->pagedresults_cookie); + + if ((rc != LDAP_SUCCESS) || (state->entries == NULL)) + return False; + + state->current_entry = ldap_first_entry(ld, state->entries); + + if (state->current_entry == NULL) { + ldap_msgfree(state->entries); + state->entries = NULL; + } + + return True; +} + +static BOOL ldapsam_search_next_entry(struct pdb_methods *methods, + struct pdb_search *search, + struct samr_displayentry *entry) +{ + struct ldap_search_state *state = search->private; + LDAP *ld = state->connection->ldap_struct; + BOOL result; + + retry: + if ((state->entries == NULL) && (state->pagedresults_cookie == NULL)) + return False; + + if ((state->entries == NULL) && + !ldapsam_search_nextpage(search)) + return False; + + result = state->ldap2displayentry(state, search->mem_ctx, ld, + state->current_entry, entry); + + if (!result) { + char *dn; + dn = ldap_get_dn(ld, state->current_entry); + DEBUG(5, ("Skipping entry %s\n", dn != NULL ? dn : "<NULL>")); + if (dn != NULL) ldap_memfree(dn); + } + + state->current_entry = ldap_next_entry(ld, state->current_entry); + + if (state->current_entry == NULL) { + ldap_msgfree(state->entries); + state->entries = NULL; + } + + if (!result) goto retry; + + return True; +} + +static void ldapsam_search_end(struct pdb_methods *methods, + struct pdb_search *search) +{ + struct ldap_search_state *state = search->private; + int rc; + + if (state->pagedresults_cookie == NULL) + return; + + if (state->entries != NULL) + ldap_msgfree(state->entries); + + state->entries = NULL; + state->current_entry = NULL; + + if (!state->connection->paged_results) + return; + + /* Tell the LDAP server we're not interested in the rest anymore. */ + + rc = smbldap_search_paged(state->connection, state->base, state->scope, + state->filter, state->attrs, + state->attrsonly, 0, &state->entries, + &state->pagedresults_cookie); + + if (rc != LDAP_SUCCESS) + DEBUG(5, ("Could not end search properly\n")); + + return; +} + +static BOOL ldapuser2displayentry(struct ldap_search_state *state, + TALLOC_CTX *mem_ctx, + LDAP *ld, LDAPMessage *entry, + struct samr_displayentry *result) +{ + char **vals; + DOM_SID sid; + uint16 acct_flags; + + vals = ldap_get_values(ld, entry, "sambaAcctFlags"); + if ((vals == NULL) || (vals[0] == NULL)) { + DEBUG(5, ("\"sambaAcctFlags\" not found\n")); + return False; + } + acct_flags = pdb_decode_acct_ctrl(vals[0]); + ldap_value_free(vals); + + if ((state->acct_flags != 0) && + ((state->acct_flags & acct_flags) == 0)) + return False; + + result->acct_flags = acct_flags; + result->account_name = ""; + result->fullname = ""; + result->description = ""; + + vals = ldap_get_values(ld, entry, "uid"); + if ((vals == NULL) || (vals[0] == NULL)) { + DEBUG(5, ("\"uid\" not found\n")); + return False; + } + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->account_name), + vals[0]); + ldap_value_free(vals); + + vals = ldap_get_values(ld, entry, "displayName"); + if ((vals == NULL) || (vals[0] == NULL)) + DEBUG(8, ("\"displayName\" not found\n")); + else + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->fullname), + vals[0]); + ldap_value_free(vals); + + vals = ldap_get_values(ld, entry, "description"); + if ((vals == NULL) || (vals[0] == NULL)) + DEBUG(8, ("\"description\" not found\n")); + else + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->description), + vals[0]); + ldap_value_free(vals); + + if ((result->account_name == NULL) || + (result->fullname == NULL) || + (result->description == NULL)) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + vals = ldap_get_values(ld, entry, "sambaSid"); + if ((vals == NULL) || (vals[0] == NULL)) { + DEBUG(0, ("\"objectSid\" not found\n")); + return False; + } + + if (!string_to_sid(&sid, vals[0])) { + DEBUG(0, ("Could not convert %s to SID\n", vals[0])); + ldap_value_free(vals); + return False; + } + ldap_value_free(vals); + + if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) { + DEBUG(0, ("%s is not our domain\n", vals[0])); + return False; + } + + return True; +} + + +static BOOL ldapsam_search_users(struct pdb_methods *methods, + struct pdb_search *search, + uint16 acct_flags) +{ + struct ldapsam_privates *ldap_state = methods->private_data; + struct ldap_search_state *state; + + state = TALLOC_P(search->mem_ctx, struct ldap_search_state); + if (state == NULL) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + state->connection = ldap_state->smbldap_state; + + if ((acct_flags != 0) && ((acct_flags & ACB_NORMAL) != 0)) + state->base = lp_ldap_user_suffix(); + else if ((acct_flags != 0) && + ((acct_flags & (ACB_WSTRUST|ACB_SVRTRUST)) != 0)) + state->base = lp_ldap_machine_suffix(); + else + state->base = lp_ldap_suffix(); + + state->acct_flags = acct_flags; + state->base = talloc_strdup(search->mem_ctx, state->base); + state->scope = LDAP_SCOPE_SUBTREE; + state->filter = get_ldap_filter(search->mem_ctx, "*"); + state->attrs = talloc_attrs(search->mem_ctx, "uid", "sambaSid", + "displayName", "description", + "sambaAcctFlags", NULL); + state->attrsonly = 0; + state->pagedresults_cookie = NULL; + state->entries = NULL; + state->ldap2displayentry = ldapuser2displayentry; + + if ((state->filter == NULL) || (state->attrs == NULL)) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + search->private = state; + + return ldapsam_search_firstpage(search); +} + +static BOOL ldapgroup2displayentry(struct ldap_search_state *state, + TALLOC_CTX *mem_ctx, + LDAP *ld, LDAPMessage *entry, + struct samr_displayentry *result) +{ + char **vals; + DOM_SID sid; + + result->account_name = ""; + result->fullname = ""; + result->description = ""; + + vals = ldap_get_values(ld, entry, "cn"); + if ((vals == NULL) || (vals[0] == NULL)) { + DEBUG(5, ("\"cn\" not found\n")); + return False; + } + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->account_name), + vals[0]); + ldap_value_free(vals); + + vals = ldap_get_values(ld, entry, "displayName"); + if ((vals == NULL) || (vals[0] == NULL)) + DEBUG(8, ("\"displayName\" not found\n")); + else + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->fullname), + vals[0]); + ldap_value_free(vals); + + vals = ldap_get_values(ld, entry, "description"); + if ((vals == NULL) || (vals[0] == NULL)) + DEBUG(8, ("\"description\" not found\n")); + else + pull_utf8_talloc(mem_ctx, + CONST_DISCARD(char **, &result->description), + vals[0]); + ldap_value_free(vals); + + if ((result->account_name == NULL) || + (result->fullname == NULL) || + (result->description == NULL)) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + vals = ldap_get_values(ld, entry, "sambaSid"); + if ((vals == NULL) || (vals[0] == NULL)) { + DEBUG(0, ("\"objectSid\" not found\n")); + return False; + } + + if (!string_to_sid(&sid, vals[0])) { + DEBUG(0, ("Could not convert %s to SID\n", vals[0])); + return False; + } + + if (!sid_peek_check_rid(get_global_sam_sid(), &sid, &result->rid)) { + DEBUG(0, ("%s is not our domain\n", vals[0])); + return False; + } + ldap_value_free(vals); + + return True; +} + +static BOOL ldapsam_search_grouptype(struct pdb_methods *methods, + struct pdb_search *search, + enum SID_NAME_USE type) +{ + struct ldapsam_privates *ldap_state = methods->private_data; + struct ldap_search_state *state; + + state = TALLOC_P(search->mem_ctx, struct ldap_search_state); + if (state == NULL) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + state->connection = ldap_state->smbldap_state; + + state->base = talloc_strdup(search->mem_ctx, lp_ldap_group_suffix()); + state->connection = ldap_state->smbldap_state; + state->scope = LDAP_SCOPE_SUBTREE; + state->filter = talloc_asprintf(search->mem_ctx, + "(&(objectclass=sambaGroupMapping)" + "(sambaGroupType=%d))", type); + state->attrs = talloc_attrs(search->mem_ctx, "cn", "sambaSid", + "displayName", "description", NULL); + state->attrsonly = 0; + state->pagedresults_cookie = NULL; + state->entries = NULL; + state->ldap2displayentry = ldapgroup2displayentry; + + if ((state->filter == NULL) || (state->attrs == NULL)) { + DEBUG(0, ("talloc failed\n")); + return False; + } + + search->private = state; + + return ldapsam_search_firstpage(search); +} + +static BOOL ldapsam_search_groups(struct pdb_methods *methods, + struct pdb_search *search) +{ + return ldapsam_search_grouptype(methods, search, SID_NAME_DOM_GRP); +} + +static BOOL ldapsam_search_aliases(struct pdb_methods *methods, + struct pdb_search *search, + const DOM_SID *sid) +{ + if (sid_check_is_domain(sid)) + return ldapsam_search_grouptype(methods, search, + SID_NAME_ALIAS); + + if (sid_check_is_builtin(sid)) + return ldapsam_search_grouptype(methods, search, + SID_NAME_WKN_GRP); + + DEBUG(5, ("Don't know SID %s\n", sid_string_static(sid))); + return False; +} + /********************************************************************** Housekeeping *********************************************************************/ @@ -3381,6 +3845,11 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS ** (*pdb_method)->enum_group_members = ldapsam_enum_group_members; (*pdb_method)->enum_group_memberships = ldapsam_enum_group_memberships; (*pdb_method)->lookup_rids = ldapsam_lookup_rids; + (*pdb_method)->search_users = ldapsam_search_users; + (*pdb_method)->search_groups = ldapsam_search_groups; + (*pdb_method)->search_aliases = ldapsam_search_aliases; + (*pdb_method)->search_next_entry = ldapsam_search_next_entry; + (*pdb_method)->search_end = ldapsam_search_end; /* TODO: Setup private data and free */ diff --git a/source3/rpc_parse/parse_samr.c b/source3/rpc_parse/parse_samr.c index 14d4bb9fdf..d3f709c352 100644 --- a/source3/rpc_parse/parse_samr.c +++ b/source3/rpc_parse/parse_samr.c @@ -1516,75 +1516,42 @@ BOOL samr_io_q_query_dispinfo(const char *desc, SAMR_Q_QUERY_DISPINFO * q_e, inits a SAM_DISPINFO_1 structure. ********************************************************************/ -NTSTATUS init_sam_dispinfo_1(TALLOC_CTX *ctx, SAM_DISPINFO_1 *sam, uint32 num_entries, - uint32 start_idx, SAM_ACCOUNT *disp_user_info, - DOM_SID *domain_sid) +NTSTATUS init_sam_dispinfo_1(TALLOC_CTX *ctx, SAM_DISPINFO_1 **sam, + uint32 num_entries, uint32 start_idx, + struct samr_displayentry *entries) { uint32 i; - SAM_ACCOUNT *pwd = NULL; - ZERO_STRUCTP(sam); - DEBUG(10, ("init_sam_dispinfo_1: num_entries: %d\n", num_entries)); if (num_entries==0) return NT_STATUS_OK; - sam->sam=TALLOC_ARRAY(ctx, SAM_ENTRY1, num_entries); - if (!sam->sam) + *sam = TALLOC_ZERO_ARRAY(ctx, SAM_DISPINFO_1, num_entries); + if (*sam == NULL) return NT_STATUS_NO_MEMORY; - sam->str=TALLOC_ARRAY(ctx, SAM_STR1, num_entries); - if (!sam->str) + (*sam)->sam=TALLOC_ARRAY(ctx, SAM_ENTRY1, num_entries); + if ((*sam)->sam == NULL) return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(sam->sam); - ZERO_STRUCTP(sam->str); + (*sam)->str=TALLOC_ARRAY(ctx, SAM_STR1, num_entries); + if ((*sam)->str == NULL) + return NT_STATUS_NO_MEMORY; for (i = 0; i < num_entries ; i++) { - const char *username; - const char *fullname; - const char *acct_desc; - uint32 user_rid; - const DOM_SID *user_sid; - fstring user_sid_string, domain_sid_string; - - DEBUG(11, ("init_sam_dispinfo_1: entry: %d\n",i)); - - pwd=&disp_user_info[i+start_idx]; - - username = pdb_get_username(pwd); - fullname = pdb_get_fullname(pwd); - acct_desc = pdb_get_acct_desc(pwd); - - if (!username) - username = ""; - - if (!fullname) - fullname = ""; - - if (!acct_desc) - acct_desc = ""; - - user_sid = pdb_get_user_sid(pwd); - - if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) { - DEBUG(0, ("init_sam_dispinfo_1: User %s has SID %s, which conflicts with " - "the domain sid %s. Failing operation.\n", - username, - sid_to_string(user_sid_string, user_sid), - sid_to_string(domain_sid_string, domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - init_unistr2(&sam->str[i].uni_acct_name, pdb_get_username(pwd), UNI_FLAGS_NONE); - init_unistr2(&sam->str[i].uni_full_name, pdb_get_fullname(pwd), UNI_FLAGS_NONE); - init_unistr2(&sam->str[i].uni_acct_desc, pdb_get_acct_desc(pwd), UNI_FLAGS_NONE); - - init_sam_entry1(&sam->sam[i], start_idx + i + 1, - &sam->str[i].uni_acct_name, &sam->str[i].uni_full_name, &sam->str[i].uni_acct_desc, - user_rid, pdb_get_acct_ctrl(pwd)); - + init_unistr2(&(*sam)->str[i].uni_acct_name, + entries[i].account_name, UNI_FLAGS_NONE); + init_unistr2(&(*sam)->str[i].uni_full_name, + entries[i].fullname, UNI_FLAGS_NONE); + init_unistr2(&(*sam)->str[i].uni_acct_desc, + entries[i].description, UNI_FLAGS_NONE); + + init_sam_entry1(&(*sam)->sam[i], start_idx+i+1, + &(*sam)->str[i].uni_acct_name, + &(*sam)->str[i].uni_full_name, + &(*sam)->str[i].uni_acct_desc, + entries[i].rid, entries[i].acct_flags); } return NT_STATUS_OK; @@ -1639,58 +1606,39 @@ static BOOL sam_io_sam_dispinfo_1(const char *desc, SAM_DISPINFO_1 * sam, inits a SAM_DISPINFO_2 structure. ********************************************************************/ -NTSTATUS init_sam_dispinfo_2(TALLOC_CTX *ctx, SAM_DISPINFO_2 *sam, uint32 num_entries, - uint32 start_idx, SAM_ACCOUNT *disp_user_info, - DOM_SID *domain_sid ) +NTSTATUS init_sam_dispinfo_2(TALLOC_CTX *ctx, SAM_DISPINFO_2 **sam, + uint32 num_entries, uint32 start_idx, + struct samr_displayentry *entries) { uint32 i; - SAM_ACCOUNT *pwd = NULL; - ZERO_STRUCTP(sam); - DEBUG(10, ("init_sam_dispinfo_2: num_entries: %d\n", num_entries)); if (num_entries==0) return NT_STATUS_OK; - if (!(sam->sam=TALLOC_ARRAY(ctx, SAM_ENTRY2, num_entries))) + *sam = TALLOC_ZERO_ARRAY(ctx, SAM_DISPINFO_2, num_entries); + if (*sam == NULL) return NT_STATUS_NO_MEMORY; - if (!(sam->str=TALLOC_ARRAY(ctx, SAM_STR2, num_entries))) + (*sam)->sam = TALLOC_ARRAY(ctx, SAM_ENTRY2, num_entries); + if ((*sam)->sam == NULL) return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(sam->sam); - ZERO_STRUCTP(sam->str); + (*sam)->str=TALLOC_ARRAY(ctx, SAM_STR2, num_entries); + if ((*sam)->str == NULL) + return NT_STATUS_NO_MEMORY; for (i = 0; i < num_entries; i++) { - uint32 user_rid; - const DOM_SID *user_sid; - const char *username; - const char *acct_desc; - fstring user_sid_string, domain_sid_string; - - DEBUG(11, ("init_sam_dispinfo_2: entry: %d\n",i)); - pwd=&disp_user_info[i+start_idx]; - - username = pdb_get_username(pwd); - acct_desc = pdb_get_acct_desc(pwd); - user_sid = pdb_get_user_sid(pwd); - - if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) { - DEBUG(0, ("init_sam_dispinfo_2: User %s has SID %s, which conflicts with " - "the domain sid %s. Failing operation.\n", - username, - sid_to_string(user_sid_string, user_sid), - sid_to_string(domain_sid_string, domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - init_unistr2(&sam->str[i].uni_srv_name, username, UNI_FLAGS_NONE); - init_unistr2(&sam->str[i].uni_srv_desc, acct_desc, UNI_FLAGS_NONE); - - init_sam_entry2(&sam->sam[i], start_idx + i + 1, - &sam->str[i].uni_srv_name, &sam->str[i].uni_srv_desc, - user_rid, pdb_get_acct_ctrl(pwd)); + init_unistr2(&(*sam)->str[i].uni_srv_name, + entries[i].account_name, UNI_FLAGS_NONE); + init_unistr2(&(*sam)->str[i].uni_srv_desc, + entries[i].description, UNI_FLAGS_NONE); + + init_sam_entry2(&(*sam)->sam[i], start_idx + i + 1, + &(*sam)->str[i].uni_srv_name, + &(*sam)->str[i].uni_srv_desc, + entries[i].rid, entries[i].acct_flags); } return NT_STATUS_OK; @@ -1747,37 +1695,39 @@ static BOOL sam_io_sam_dispinfo_2(const char *desc, SAM_DISPINFO_2 * sam, inits a SAM_DISPINFO_3 structure. ********************************************************************/ -NTSTATUS init_sam_dispinfo_3(TALLOC_CTX *ctx, SAM_DISPINFO_3 *sam, uint32 num_entries, - uint32 start_idx, DOMAIN_GRP *disp_group_info) +NTSTATUS init_sam_dispinfo_3(TALLOC_CTX *ctx, SAM_DISPINFO_3 **sam, + uint32 num_entries, uint32 start_idx, + struct samr_displayentry *entries) { uint32 i; - ZERO_STRUCTP(sam); - DEBUG(5, ("init_sam_dispinfo_3: num_entries: %d\n", num_entries)); if (num_entries==0) return NT_STATUS_OK; - if (!(sam->sam=TALLOC_ARRAY(ctx, SAM_ENTRY3, num_entries))) + *sam = TALLOC_ZERO_ARRAY(ctx, SAM_DISPINFO_3, num_entries); + if (*sam == NULL) return NT_STATUS_NO_MEMORY; - if (!(sam->str=TALLOC_ARRAY(ctx, SAM_STR3, num_entries))) + if (!((*sam)->sam=TALLOC_ARRAY(ctx, SAM_ENTRY3, num_entries))) return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(sam->sam); - ZERO_STRUCTP(sam->str); + if (!((*sam)->str=TALLOC_ARRAY(ctx, SAM_STR3, num_entries))) + return NT_STATUS_NO_MEMORY; for (i = 0; i < num_entries; i++) { - DOMAIN_GRP *grp = &disp_group_info[i+start_idx]; - DEBUG(11, ("init_sam_dispinfo_3: entry: %d\n",i)); - init_unistr2(&sam->str[i].uni_grp_name, grp->name, UNI_FLAGS_NONE); - init_unistr2(&sam->str[i].uni_grp_desc, grp->comment, UNI_FLAGS_NONE); + init_unistr2(&(*sam)->str[i].uni_grp_name, + entries[i].account_name, UNI_FLAGS_NONE); + init_unistr2(&(*sam)->str[i].uni_grp_desc, + entries[i].description, UNI_FLAGS_NONE); - init_sam_entry3(&sam->sam[i], start_idx + i + 1, &sam->str[i].uni_grp_name, - &sam->str[i].uni_grp_desc, grp->rid); + init_sam_entry3(&(*sam)->sam[i], start_idx+i+1, + &(*sam)->str[i].uni_grp_name, + &(*sam)->str[i].uni_grp_desc, + entries[i].rid); } return NT_STATUS_OK; @@ -1834,38 +1784,40 @@ static BOOL sam_io_sam_dispinfo_3(const char *desc, SAM_DISPINFO_3 * sam, inits a SAM_DISPINFO_4 structure. ********************************************************************/ -NTSTATUS init_sam_dispinfo_4(TALLOC_CTX *ctx, SAM_DISPINFO_4 *sam, uint32 num_entries, - uint32 start_idx, SAM_ACCOUNT *disp_user_info) +NTSTATUS init_sam_dispinfo_4(TALLOC_CTX *ctx, SAM_DISPINFO_4 **sam, + uint32 num_entries, uint32 start_idx, + struct samr_displayentry *entries) { - uint32 len_sam_name; uint32 i; - SAM_ACCOUNT *pwd = NULL; - ZERO_STRUCTP(sam); - DEBUG(5, ("init_sam_dispinfo_4: num_entries: %d\n", num_entries)); if (num_entries==0) return NT_STATUS_OK; - if (!(sam->sam=TALLOC_ARRAY(ctx, SAM_ENTRY4, num_entries))) + *sam = TALLOC_ZERO_ARRAY(ctx, SAM_DISPINFO_4, num_entries); + if (*sam == NULL) return NT_STATUS_NO_MEMORY; - if (!(sam->str=TALLOC_ARRAY(ctx, SAM_STR4, num_entries))) + (*sam)->sam = TALLOC_ARRAY(ctx, SAM_ENTRY4, num_entries); + if ((*sam)->sam == NULL) return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(sam->sam); - ZERO_STRUCTP(sam->str); + (*sam)->str=TALLOC_ARRAY(ctx, SAM_STR4, num_entries); + if ((*sam)->str == NULL) + return NT_STATUS_NO_MEMORY; for (i = 0; i < num_entries; i++) { - DEBUG(11, ("init_sam_dispinfo_2: entry: %d\n",i)); - pwd=&disp_user_info[i+start_idx]; + size_t len_sam_name = strlen(entries[i].account_name); - len_sam_name = strlen(pdb_get_username(pwd)); + DEBUG(11, ("init_sam_dispinfo_2: entry: %d\n",i)); - init_sam_entry4(&sam->sam[i], start_idx + i + 1, len_sam_name); + init_sam_entry4(&(*sam)->sam[i], start_idx + i + 1, + len_sam_name); - init_string2(&sam->str[i].acct_name, pdb_get_username(pwd), len_sam_name+1, len_sam_name); + init_string2(&(*sam)->str[i].acct_name, + entries[i].account_name, len_sam_name+1, + len_sam_name); } return NT_STATUS_OK; @@ -1921,37 +1873,36 @@ static BOOL sam_io_sam_dispinfo_4(const char *desc, SAM_DISPINFO_4 * sam, inits a SAM_DISPINFO_5 structure. ********************************************************************/ -NTSTATUS init_sam_dispinfo_5(TALLOC_CTX *ctx, SAM_DISPINFO_5 *sam, uint32 num_entries, - uint32 start_idx, DOMAIN_GRP *disp_group_info) +NTSTATUS init_sam_dispinfo_5(TALLOC_CTX *ctx, SAM_DISPINFO_5 **sam, + uint32 num_entries, uint32 start_idx, + struct samr_displayentry *entries) { uint32 len_sam_name; uint32 i; - ZERO_STRUCTP(sam); - DEBUG(5, ("init_sam_dispinfo_5: num_entries: %d\n", num_entries)); if (num_entries==0) return NT_STATUS_OK; - if (!(sam->sam=TALLOC_ARRAY(ctx, SAM_ENTRY5, num_entries))) + *sam = TALLOC_ZERO_ARRAY(ctx, SAM_DISPINFO_5, num_entries); + if (*sam == NULL) return NT_STATUS_NO_MEMORY; - if (!(sam->str=TALLOC_ARRAY(ctx, SAM_STR5, num_entries))) + if (!((*sam)->sam=TALLOC_ARRAY(ctx, SAM_ENTRY5, num_entries))) return NT_STATUS_NO_MEMORY; - ZERO_STRUCTP(sam->sam); - ZERO_STRUCTP(sam->str); + if (!((*sam)->str=TALLOC_ARRAY(ctx, SAM_STR5, num_entries))) + return NT_STATUS_NO_MEMORY; for (i = 0; i < num_entries; i++) { - DOMAIN_GRP *grp = &disp_group_info[i+start_idx]; - DEBUG(11, ("init_sam_dispinfo_5: entry: %d\n",i)); - len_sam_name = strlen(grp->name); + len_sam_name = strlen(entries[i].account_name); - init_sam_entry5(&sam->sam[i], start_idx + i + 1, len_sam_name); - init_string2(&sam->str[i].grp_name, grp->name, len_sam_name+1, len_sam_name); + init_sam_entry5(&(*sam)->sam[i], start_idx+i+1, len_sam_name); + init_string2(&(*sam)->str[i].grp_name, entries[i].account_name, + len_sam_name+1, len_sam_name); } return NT_STATUS_OK; diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index 84c78eab64..fe54476cc9 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -43,14 +43,12 @@ extern rid_name domain_group_rids[]; extern rid_name domain_alias_rids[]; extern rid_name builtin_alias_rids[]; - -typedef struct _disp_info { - BOOL user_dbloaded; - uint32 num_user_account; - SAM_ACCOUNT *disp_user_info; - BOOL group_dbloaded; - uint32 num_group_account; - DOMAIN_GRP *disp_group_info; +typedef struct disp_info { + struct pdb_search *users; + struct pdb_search *machines; + struct pdb_search *groups; + struct pdb_search *aliases; + struct pdb_search *builtins; } DISP_INFO; struct samr_info { @@ -238,10 +236,9 @@ static struct samr_info *get_samr_info_by_sid(DOM_SID *psid) mem_ctx = talloc_init("samr_info for domain sid %s", sid_str); - if ((info = TALLOC_P(mem_ctx, struct samr_info)) == NULL) + if ((info = TALLOC_ZERO_P(mem_ctx, struct samr_info)) == NULL) return NULL; - ZERO_STRUCTP(info); DEBUG(10,("get_samr_info_by_sid: created new info for sid %s\n", sid_str)); if (psid) { sid_copy( &info->sid, psid); @@ -256,33 +253,22 @@ static struct samr_info *get_samr_info_by_sid(DOM_SID *psid) Function to free the per handle data. ********************************************************************/ -static void free_samr_users(struct samr_info *info) -{ - int i; - - if (info->disp_info.user_dbloaded){ - for (i=0; i<info->disp_info.num_user_account; i++) { - SAM_ACCOUNT *sam = &info->disp_info.disp_user_info[i]; - /* Not really a free, actually a 'clear' */ - pdb_free_sam(&sam); - } - } - info->disp_info.user_dbloaded=False; - info->disp_info.num_user_account=0; -} - /******************************************************************* Function to free the per handle data. ********************************************************************/ static void free_samr_db(struct samr_info *info) { - /* Groups are talloced */ - - free_samr_users(info); - - info->disp_info.group_dbloaded=False; - info->disp_info.num_group_account=0; + pdb_search_destroy(info->disp_info.users); + info->disp_info.users = NULL; + pdb_search_destroy(info->disp_info.machines); + info->disp_info.machines = NULL; + pdb_search_destroy(info->disp_info.groups); + info->disp_info.groups = NULL; + pdb_search_destroy(info->disp_info.aliases); + info->disp_info.aliases = NULL; + pdb_search_destroy(info->disp_info.builtins); + info->disp_info.builtins = NULL; } static void free_samr_info(void *ptr) @@ -309,154 +295,30 @@ static void samr_clear_sam_passwd(SAM_ACCOUNT *sam_pass) pdb_set_nt_passwd(sam_pass, NULL, PDB_DEFAULT); } - -static NTSTATUS load_sampwd_entries(struct samr_info *info, uint16 acb_mask, BOOL only_machines) +static uint32 count_sam_users(struct disp_info *info, uint16 acct_flags) { - SAM_ACCOUNT *pwd = NULL; - SAM_ACCOUNT *pwd_array = NULL; - NTSTATUS nt_status = NT_STATUS_OK; - TALLOC_CTX *mem_ctx = info->mem_ctx; - uint16 query_acb_mask = acb_mask; - - DEBUG(10,("load_sampwd_entries\n")); - - /* if the snapshoot is already loaded, return */ - if ((info->disp_info.user_dbloaded==True) - && (info->acb_mask == acb_mask) - && (info->only_machines == only_machines)) { - DEBUG(10,("load_sampwd_entries: already in memory\n")); - return NT_STATUS_OK; - } - - free_samr_users(info); - - if (only_machines) { - query_acb_mask |= ACB_WSTRUST; - query_acb_mask |= ACB_SVRTRUST; - } - - if (!pdb_setsampwent(False, query_acb_mask)) { - DEBUG(0, ("load_sampwd_entries: Unable to open passdb.\n")); - return NT_STATUS_ACCESS_DENIED; - } - - for (; (NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(mem_ctx, &pwd))) - && pdb_getsampwent(pwd) == True; pwd=NULL) { - - if (only_machines) { - if (!((pdb_get_acct_ctrl(pwd) & ACB_WSTRUST) - || (pdb_get_acct_ctrl(pwd) & ACB_SVRTRUST))) { - DEBUG(5,("load_sampwd_entries: '%s' is not a machine account - ACB: %x - skipping\n", pdb_get_username(pwd), acb_mask)); - pdb_free_sam(&pwd); - continue; - } - } else { - if (acb_mask != 0 && !(pdb_get_acct_ctrl(pwd) & acb_mask)) { - pdb_free_sam(&pwd); - DEBUG(5,(" acb_mask %x reject\n", acb_mask)); - continue; - } - } - - /* Realloc some memory for the array of ptr to the SAM_ACCOUNT structs */ - if (info->disp_info.num_user_account % MAX_SAM_ENTRIES == 0) { - - DEBUG(10,("load_sampwd_entries: allocating more memory\n")); - pwd_array=TALLOC_REALLOC_ARRAY(mem_ctx, info->disp_info.disp_user_info, SAM_ACCOUNT, - info->disp_info.num_user_account+MAX_SAM_ENTRIES); - - if (pwd_array==NULL) - return NT_STATUS_NO_MEMORY; - - info->disp_info.disp_user_info=pwd_array; - } - - /* Copy the SAM_ACCOUNT into the array */ - info->disp_info.disp_user_info[info->disp_info.num_user_account]=*pwd; - - DEBUG(10,("load_sampwd_entries: entry: %d\n", info->disp_info.num_user_account)); - - info->disp_info.num_user_account++; - } - - pdb_endsampwent(); - - /* the snapshoot is in memory, we're ready to enumerate fast */ - - info->acb_mask = acb_mask; - info->only_machines = only_machines; - info->disp_info.user_dbloaded=True; - - DEBUG(10,("load_sampwd_entries: done\n")); - - return nt_status; + struct samr_displayentry *entry; + if (info->users == NULL) + info->users = pdb_search_users(acct_flags); + if (info->users == NULL) + return 0; + /* Fetch the last possible entry, thus trigger an enumeration */ + pdb_search_entries(info->users, 0xffffffff, 1, &entry); + return info->users->num_entries; } -static NTSTATUS load_group_domain_entries(struct samr_info *info, DOM_SID *sid) +static uint32 count_sam_groups(struct disp_info *info) { - GROUP_MAP *map=NULL; - DOMAIN_GRP *grp_array = NULL; - uint32 group_entries = 0; - uint32 i; - TALLOC_CTX *mem_ctx = info->mem_ctx; - BOOL ret; - - DEBUG(10,("load_group_domain_entries\n")); - - /* if the snapshoot is already loaded, return */ - if (info->disp_info.group_dbloaded==True) { - DEBUG(10,("load_group_domain_entries: already in memory\n")); - return NT_STATUS_OK; - } - - if (sid_equal(sid, &global_sid_Builtin)) { - /* No domain groups for now in the BUILTIN domain */ - info->disp_info.num_group_account=0; - info->disp_info.disp_group_info=NULL; - info->disp_info.group_dbloaded=True; - return NT_STATUS_OK; - } - - become_root(); - ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED); - unbecome_root(); - - if ( !ret ) { - DEBUG(1, ("load_group_domain_entries: pdb_enum_group_mapping() failed!\n")); - return NT_STATUS_NO_MEMORY; - } - - - info->disp_info.num_group_account=group_entries; - - grp_array=TALLOC_ARRAY(mem_ctx, DOMAIN_GRP, info->disp_info.num_group_account); - if (group_entries!=0 && grp_array==NULL) { - DEBUG(1, ("load_group_domain_entries: talloc() failed for grp_array!\n")); - SAFE_FREE(map); - return NT_STATUS_NO_MEMORY; - } - - info->disp_info.disp_group_info=grp_array; - - for (i=0; i<group_entries; i++) { - fstrcpy(grp_array[i].name, map[i].nt_name); - fstrcpy(grp_array[i].comment, map[i].comment); - sid_split_rid(&map[i].sid, &grp_array[i].rid); - grp_array[i].attr=SID_NAME_DOM_GRP; - } - - SAFE_FREE(map); - - /* the snapshoot is in memory, we're ready to enumerate fast */ - - info->disp_info.group_dbloaded=True; - - DEBUG(10,("load_group_domain_entries: done\n")); - - return NT_STATUS_OK; + struct samr_displayentry *entry; + if (info->groups == NULL) + info->groups = pdb_search_groups(); + if (info->groups == NULL) + return 0; + /* Fetch the last possible entry, thus trigger an enumeration */ + pdb_search_entries(info->groups, 0xffffffff, 1, &entry); + return info->groups->num_entries; } - /******************************************************************* _samr_close_hnd ********************************************************************/ @@ -656,20 +518,14 @@ NTSTATUS _samr_query_sec_obj(pipes_struct *p, SAMR_Q_QUERY_SEC_OBJ *q_u, SAMR_R_ makes a SAM_ENTRY / UNISTR2* structure from a user list. ********************************************************************/ -static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNISTR2 **uni_name_pp, - uint32 num_entries, uint32 start_idx, SAM_ACCOUNT *disp_user_info, - DOM_SID *domain_sid) +static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, + UNISTR2 **uni_name_pp, + uint32 num_entries, uint32 start_idx, + struct samr_displayentry *entries) { uint32 i; SAM_ENTRY *sam; UNISTR2 *uni_name; - SAM_ACCOUNT *pwd = NULL; - UNISTR2 uni_temp_name; - const char *temp_name; - const DOM_SID *user_sid; - uint32 user_rid; - fstring user_sid_string; - fstring domain_sid_string; *sam_pp = NULL; *uni_name_pp = NULL; @@ -687,31 +543,20 @@ static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UN } for (i = 0; i < num_entries; i++) { - pwd = &disp_user_info[i+start_idx]; - temp_name = pdb_get_username(pwd); - + UNISTR2 uni_temp_name; /* * usrmgr expects a non-NULL terminated string with * trust relationships */ - if (pdb_get_acct_ctrl(pwd) & ACB_DOMTRUST) { - init_unistr2(&uni_temp_name, temp_name, UNI_FLAGS_NONE); + if (entries[i].acct_flags & ACB_DOMTRUST) { + init_unistr2(&uni_temp_name, entries[i].account_name, + UNI_FLAGS_NONE); } else { - init_unistr2(&uni_temp_name, temp_name, UNI_STR_TERMINATE); + init_unistr2(&uni_temp_name, entries[i].account_name, + UNI_STR_TERMINATE); } - user_sid = pdb_get_user_sid(pwd); - - if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) { - DEBUG(0, ("make_user_sam_entry_list: User %s has SID %s, which conflicts with " - "the domain sid %s. Failing operation.\n", - temp_name, - sid_to_string(user_sid_string, user_sid), - sid_to_string(domain_sid_string, domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - init_sam_entry(&sam[i], &uni_temp_name, user_rid); + init_sam_entry(&sam[i], &uni_temp_name, entries[i].rid); copy_unistr2(&uni_name[i], &uni_temp_name); } @@ -728,15 +573,12 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u, SAMR_R_ENUM_DOM_USERS *r_u) { struct samr_info *info = NULL; - uint32 struct_size=0x20; /* W2K always reply that, client doesn't care */ int num_account; uint32 enum_context=q_u->start_idx; - uint32 max_size=q_u->max_size; - uint32 temp_size; enum remote_arch_types ra_type = get_remote_arch(); int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K; uint32 max_entries = max_sam_entries; - DOM_SID domain_sid; + struct samr_displayentry *entries = NULL; r_u->status = NT_STATUS_OK; @@ -744,8 +586,6 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u, if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - domain_sid = info->sid; - if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(info->acc_granted, SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, "_samr_enum_dom_users"))) { @@ -755,60 +595,36 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u, DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__)); become_root(); - r_u->status=load_sampwd_entries(info, q_u->acb_mask, False); + if (info->disp_info.users == NULL) + info->disp_info.users = pdb_search_users(q_u->acb_mask); + if (info->disp_info.users == NULL) + return NT_STATUS_ACCESS_DENIED; + num_account = pdb_search_entries(info->disp_info.users, + enum_context, max_entries, + &entries); unbecome_root(); - - if (!NT_STATUS_IS_OK(r_u->status)) - return r_u->status; - - num_account = info->disp_info.num_user_account; - if (enum_context > num_account) { - DEBUG(5, ("_samr_enum_dom_users: enumeration handle over total entries\n")); + if (num_account == 0) { + DEBUG(5, ("_samr_enum_dom_users: enumeration handle over " + "total entries\n")); return NT_STATUS_OK; } - /* verify we won't overflow */ - if (max_entries > num_account-enum_context) { - max_entries = num_account-enum_context; - DEBUG(5, ("_samr_enum_dom_users: only %d entries to return\n", max_entries)); - } - - /* calculate the size and limit on the number of entries we will return */ - temp_size=max_entries*struct_size; - - if (temp_size>max_size) { - max_entries=MIN((max_size/struct_size),max_entries);; - DEBUG(5, ("_samr_enum_dom_users: buffer size limits to only %d entries\n", max_entries)); - } - - /* - * Note from JRA. total_entries is not being used here. Currently if there is a - * large user base then it looks like NT will enumerate until get_sampwd_entries - * returns False due to num_entries being zero. This will cause an access denied - * return. I don't think this is right and needs further investigation. Note that - * this is also the same in the TNG code (I don't think that has been tested with - * a very large user list as MAX_SAM_ENTRIES is set to 600). - * - * I also think that one of the 'num_entries' return parameters is probably - * the "max entries" parameter - but in the TNG code they're all currently set to the same - * value (again I think this is wrong). - */ - - r_u->status = make_user_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_acct_name, - max_entries, enum_context, - info->disp_info.disp_user_info, - &domain_sid); + r_u->status = make_user_sam_entry_list(p->mem_ctx, &r_u->sam, + &r_u->uni_acct_name, + num_account, enum_context, + entries); if (!NT_STATUS_IS_OK(r_u->status)) return r_u->status; - if (enum_context+max_entries < num_account) + if (max_entries <= num_account) r_u->status = STATUS_MORE_ENTRIES; DEBUG(5, ("_samr_enum_dom_users: %d\n", __LINE__)); - init_samr_r_enum_dom_users(r_u, q_u->start_idx + max_entries, max_entries); + init_samr_r_enum_dom_users(r_u, q_u->start_idx + num_account, + num_account); DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__)); @@ -819,8 +635,10 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u, makes a SAM_ENTRY / UNISTR2* structure from a group list. ********************************************************************/ -static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNISTR2 **uni_name_pp, - uint32 num_sam_entries, DOMAIN_GRP *grp) +static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, + UNISTR2 **uni_name_pp, + uint32 num_sam_entries, + struct samr_displayentry *entries) { uint32 i; SAM_ENTRY *sam; @@ -844,8 +662,9 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST /* * JRA. I think this should include the null. TNG does not. */ - init_unistr2(&uni_name[i], grp[i].name, UNI_STR_TERMINATE); - init_sam_entry(&sam[i], &uni_name[i], grp[i].rid); + init_unistr2(&uni_name[i], entries[i].account_name, + UNI_STR_TERMINATE); + init_sam_entry(&sam[i], &uni_name[i], entries[i].rid); } *sam_pp = sam; @@ -853,179 +672,107 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST } /******************************************************************* - Get the group entries - similar to get_sampwd_entries(). - ******************************************************************/ - -static NTSTATUS get_group_domain_entries( TALLOC_CTX *ctx, - DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx, - uint32 *p_num_entries, uint32 max_entries ) -{ - GROUP_MAP *map=NULL; - int i; - uint32 group_entries = 0; - uint32 num_entries = 0; - NTSTATUS result = NT_STATUS_OK; - - *p_num_entries = 0; - - /* access checks for the users were performed higher up. become/unbecome_root() - needed for some passdb backends to enumerate groups */ - - become_root(); - pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, - ENUM_ONLY_MAPPED); - unbecome_root(); - - num_entries=group_entries-start_idx; - - /* limit the number of entries */ - if (num_entries>max_entries) { - DEBUG(5,("Limiting to %d entries\n", max_entries)); - num_entries=max_entries; - result = STATUS_MORE_ENTRIES; - } - - *d_grp=TALLOC_ZERO_ARRAY(ctx, DOMAIN_GRP, num_entries); - if (num_entries!=0 && *d_grp==NULL){ - SAFE_FREE(map); - return NT_STATUS_NO_MEMORY; - } - - for (i=0; i<num_entries; i++) { - fstrcpy((*d_grp)[i].name, map[i+start_idx].nt_name); - fstrcpy((*d_grp)[i].comment, map[i+start_idx].comment); - sid_split_rid(&map[i+start_idx].sid, &(*d_grp)[i].rid); - (*d_grp)[i].attr=SID_NAME_DOM_GRP; - } - - SAFE_FREE(map); - - *p_num_entries = num_entries; - - DEBUG(10,("get_group_domain_entries: returning %d entries\n", - *p_num_entries)); - - return result; -} - -/******************************************************************* - Wrapper for enumerating local groups - ******************************************************************/ - -static NTSTATUS get_alias_entries( TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, - const DOM_SID *sid, uint32 start_idx, - uint32 *p_num_entries, uint32 max_entries ) -{ - struct acct_info *info; - int i; - BOOL res; - - become_root(); - res = pdb_enum_aliases(sid, start_idx, max_entries, - p_num_entries, &info); - unbecome_root(); - - if (!res) - return NT_STATUS_ACCESS_DENIED; - - if (*p_num_entries == 0) - return NT_STATUS_OK; - - *d_grp = TALLOC_ARRAY(ctx, DOMAIN_GRP, *p_num_entries); - - if (*d_grp == NULL) { - SAFE_FREE(info); - return NT_STATUS_NO_MEMORY; - } - - for (i=0; i<*p_num_entries; i++) { - fstrcpy((*d_grp)[i].name, info[i].acct_name); - fstrcpy((*d_grp)[i].comment, info[i].acct_desc); - (*d_grp)[i].rid = info[i].rid; - (*d_grp)[i].attr = SID_NAME_ALIAS; - } - - SAFE_FREE(info); - return NT_STATUS_OK; -} - -/******************************************************************* samr_reply_enum_dom_groups ********************************************************************/ NTSTATUS _samr_enum_dom_groups(pipes_struct *p, SAMR_Q_ENUM_DOM_GROUPS *q_u, SAMR_R_ENUM_DOM_GROUPS *r_u) { - DOMAIN_GRP *grp=NULL; - uint32 num_entries; - DOM_SID sid; - uint32 acc_granted; + struct samr_info *info = NULL; + struct samr_displayentry *groups; + uint32 num_groups; r_u->status = NT_STATUS_OK; - if (!get_lsa_policy_samr_sid(p, &q_u->pol, &sid, &acc_granted)) + /* find the policy handle. open a policy on it. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - - if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, "_samr_enum_dom_groups"))) { + + r_u->status = access_check_samr_function(info->acc_granted, + SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, + "_samr_enum_dom_groups"); + if (!NT_STATUS_IS_OK(r_u->status)) return r_u->status; - } DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__)); /* the domain group array is being allocated in the function below */ - r_u->status = get_group_domain_entries(p->mem_ctx, &grp, &sid, - q_u->start_idx, &num_entries, - MAX_SAM_ENTRIES); - if (!NT_STATUS_IS_OK(r_u->status) && - !NT_STATUS_EQUAL(r_u->status, STATUS_MORE_ENTRIES)) - return r_u->status; + become_root(); + if (info->disp_info.groups == NULL) + info->disp_info.groups = pdb_search_groups(); + unbecome_root(); + if (info->disp_info.groups == NULL) + return NT_STATUS_ACCESS_DENIED; + + become_root(); + num_groups = pdb_search_entries(info->disp_info.groups, q_u->start_idx, + MAX_SAM_ENTRIES, &groups); + unbecome_root(); + make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, - num_entries, grp); + num_groups, groups); - init_samr_r_enum_dom_groups(r_u, q_u->start_idx+num_entries, - num_entries); + init_samr_r_enum_dom_groups(r_u, q_u->start_idx, num_groups); DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__)); return r_u->status; } - /******************************************************************* samr_reply_enum_dom_aliases ********************************************************************/ NTSTATUS _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, SAMR_R_ENUM_DOM_ALIASES *r_u) { - DOMAIN_GRP *grp=NULL; - uint32 num_entries = 0; - fstring sid_str; - DOM_SID sid; + struct samr_info *info; + struct samr_displayentry *aliases; + struct pdb_search **search = NULL; + uint32 num_aliases = 0; NTSTATUS status; - uint32 acc_granted; - + r_u->status = NT_STATUS_OK; - if (!get_lsa_policy_samr_sid(p, &q_u->pol, &sid, &acc_granted)) + /* find the policy handle. open a policy on it. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, "_samr_enum_dom_aliases"))) { + r_u->status = access_check_samr_function(info->acc_granted, + SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, + "_samr_enum_dom_aliases"); + if (!NT_STATUS_IS_OK(r_u->status)) return r_u->status; - } - - sid_to_string(sid_str, &sid); - DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", sid_str)); - status = get_alias_entries(p->mem_ctx, &grp, &sid, q_u->start_idx, - &num_entries, MAX_SAM_ENTRIES); - if (!NT_STATUS_IS_OK(status)) return status; + DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", + sid_string_static(&info->sid))); + + if (sid_check_is_domain(&info->sid)) + search = &info->disp_info.aliases; + if (sid_check_is_builtin(&info->sid)) + search = &info->disp_info.builtins; + + if (search == NULL) return NT_STATUS_INVALID_HANDLE; + + become_root(); + if (*search == NULL) + *search = pdb_search_aliases(&info->sid); + unbecome_root(); + + if (*search == NULL) return NT_STATUS_ACCESS_DENIED; - make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, num_entries, grp); + become_root(); + num_aliases = pdb_search_entries(*search, q_u->start_idx, + MAX_SAM_ENTRIES, &aliases); + unbecome_root(); + + make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, + num_aliases, aliases); - /*safe_free(grp);*/ + if (!NT_STATUS_IS_OK(status)) return status; - init_samr_r_enum_dom_aliases(r_u, q_u->start_idx + num_entries, num_entries); + init_samr_r_enum_dom_aliases(r_u, q_u->start_idx + num_aliases, + num_aliases); DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__)); @@ -1053,6 +800,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, enum remote_arch_types ra_type = get_remote_arch(); int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K; DOM_SID domain_sid; + struct samr_displayentry *entries = NULL; DEBUG(5, ("samr_reply_query_dispinfo: %d\n", __LINE__)); r_u->status = NT_STATUS_OK; @@ -1091,68 +839,29 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, * JFM, 12/20/2001 */ - /* Get what we need from the password database */ - switch (q_u->switch_level) { - case 0x1: - /* When playing with usrmgr, this is necessary - if you want immediate refresh after editing - a user. I would like to do this after the - setuserinfo2, but we do not have access to - the domain handle in that call, only to the - user handle. Where else does this hurt? - -- Volker - */ -#if 0 - /* We cannot do this here - it kills performace. JRA. */ - free_samr_users(info); -#endif - case 0x2: - case 0x4: - become_root(); - /* Level 2 is for all machines, otherwise only 'normal' users */ - r_u->status=load_sampwd_entries(info, ACB_NORMAL, q_u->switch_level==2); - unbecome_root(); - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(5, ("_samr_query_dispinfo: load_sampwd_entries failed\n")); - return r_u->status; - } - num_account = info->disp_info.num_user_account; - break; - case 0x3: - case 0x5: - r_u->status = load_group_domain_entries(info, &info->sid); - if (!NT_STATUS_IS_OK(r_u->status)) - return r_u->status; - num_account = info->disp_info.num_group_account; - break; - default: - DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", (unsigned int)q_u->switch_level )); - return NT_STATUS_INVALID_INFO_CLASS; + if ((q_u->switch_level < 1) || (q_u->switch_level > 5)) { + DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", + (unsigned int)q_u->switch_level )); + return NT_STATUS_INVALID_INFO_CLASS; } /* first limit the number of entries we will return */ if(max_entries > max_sam_entries) { - DEBUG(5, ("samr_reply_query_dispinfo: client requested %d entries, limiting to %d\n", max_entries, max_sam_entries)); + DEBUG(5, ("samr_reply_query_dispinfo: client requested %d " + "entries, limiting to %d\n", max_entries, + max_sam_entries)); max_entries = max_sam_entries; } - if (enum_context > num_account) { - DEBUG(5, ("samr_reply_query_dispinfo: enumeration handle over total entries\n")); - return NT_STATUS_NO_MORE_ENTRIES; - } - - /* verify we won't overflow */ - if (max_entries > num_account-enum_context) { - max_entries = num_account-enum_context; - DEBUG(5, ("samr_reply_query_dispinfo: only %d entries to return\n", max_entries)); - } + /* calculate the size and limit on the number of entries we will + * return */ - /* calculate the size and limit on the number of entries we will return */ temp_size=max_entries*struct_size; if (temp_size>max_size) { max_entries=MIN((max_size/struct_size),max_entries);; - DEBUG(5, ("samr_reply_query_dispinfo: buffer size limits to only %d entries\n", max_entries)); + DEBUG(5, ("samr_reply_query_dispinfo: buffer size limits to " + "only %d entries\n", max_entries)); } if (!(ctr = TALLOC_ZERO_P(p->mem_ctx,SAM_DISPINFO_CTR))) @@ -1160,61 +869,80 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, ZERO_STRUCTP(ctr); + become_root(); + + switch (q_u->switch_level) { + case 0x1: + case 0x4: + if (info->disp_info.users == NULL) + info->disp_info.users = pdb_search_users(ACB_NORMAL); + if (info->disp_info.users == NULL) + return NT_STATUS_ACCESS_DENIED; + num_account = pdb_search_entries(info->disp_info.users, + enum_context, max_entries, + &entries); + break; + case 0x2: + if (info->disp_info.machines == NULL) + info->disp_info.machines = + pdb_search_users(ACB_WSTRUST|ACB_SVRTRUST); + if (info->disp_info.machines == NULL) + return NT_STATUS_ACCESS_DENIED; + num_account = pdb_search_entries(info->disp_info.machines, + enum_context, max_entries, + &entries); + break; + case 0x3: + case 0x5: + if (info->disp_info.groups == NULL) + info->disp_info.groups = pdb_search_groups(); + if (info->disp_info.groups == NULL) + return NT_STATUS_ACCESS_DENIED; + num_account = pdb_search_entries(info->disp_info.groups, + enum_context, max_entries, + &entries); + break; + default: + smb_panic("info class changed"); + break; + } + unbecome_root(); + /* Now create reply structure */ switch (q_u->switch_level) { case 0x1: - if (max_entries) { - if (!(ctr->sam.info1 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_1,max_entries))) - return NT_STATUS_NO_MEMORY; - } - disp_ret = init_sam_dispinfo_1(p->mem_ctx, ctr->sam.info1, max_entries, enum_context, - info->disp_info.disp_user_info, &domain_sid); - if (!NT_STATUS_IS_OK(disp_ret)) - return disp_ret; + disp_ret = init_sam_dispinfo_1(p->mem_ctx, &ctr->sam.info1, + num_account, enum_context, + entries); break; case 0x2: - if (max_entries) { - if (!(ctr->sam.info2 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_2,max_entries))) - return NT_STATUS_NO_MEMORY; - } - disp_ret = init_sam_dispinfo_2(p->mem_ctx, ctr->sam.info2, max_entries, enum_context, - info->disp_info.disp_user_info, &domain_sid); - if (!NT_STATUS_IS_OK(disp_ret)) - return disp_ret; + disp_ret = init_sam_dispinfo_2(p->mem_ctx, &ctr->sam.info2, + num_account, enum_context, + entries); break; case 0x3: - if (max_entries) { - if (!(ctr->sam.info3 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_3,max_entries))) - return NT_STATUS_NO_MEMORY; - } - disp_ret = init_sam_dispinfo_3(p->mem_ctx, ctr->sam.info3, max_entries, enum_context, info->disp_info.disp_group_info); - if (!NT_STATUS_IS_OK(disp_ret)) - return disp_ret; + disp_ret = init_sam_dispinfo_3(p->mem_ctx, &ctr->sam.info3, + num_account, enum_context, + entries); break; case 0x4: - if (max_entries) { - if (!(ctr->sam.info4 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_4,max_entries))) - return NT_STATUS_NO_MEMORY; - } - disp_ret = init_sam_dispinfo_4(p->mem_ctx, ctr->sam.info4, max_entries, enum_context, info->disp_info.disp_user_info); - if (!NT_STATUS_IS_OK(disp_ret)) - return disp_ret; + disp_ret = init_sam_dispinfo_4(p->mem_ctx, &ctr->sam.info4, + num_account, enum_context, + entries); break; case 0x5: - if (max_entries) { - if (!(ctr->sam.info5 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_5,max_entries))) - return NT_STATUS_NO_MEMORY; - } - disp_ret = init_sam_dispinfo_5(p->mem_ctx, ctr->sam.info5, max_entries, enum_context, info->disp_info.disp_group_info); - if (!NT_STATUS_IS_OK(disp_ret)) - return disp_ret; + disp_ret = init_sam_dispinfo_5(p->mem_ctx, &ctr->sam.info5, + num_account, enum_context, + entries); break; - default: - ctr->sam.info = NULL; - return NT_STATUS_INVALID_INFO_CLASS; + smb_panic("info class changed"); + break; } + if (!NT_STATUS_IS_OK(disp_ret)) + return disp_ret; + /* calculate the total size */ total_data_size=num_account*struct_size; @@ -1223,7 +951,9 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, DEBUG(5, ("_samr_query_dispinfo: %d\n", __LINE__)); - init_samr_r_query_dispinfo(r_u, max_entries, total_data_size, temp_size, q_u->switch_level, ctr, r_u->status); + init_samr_r_query_dispinfo(r_u, num_account, total_data_size, + temp_size, q_u->switch_level, ctr, + r_u->status); return r_u->status; @@ -2106,23 +1836,11 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA flag, nt_expire, nt_min_age); break; case 0x02: - become_root(); - r_u->status=load_sampwd_entries(info, ACB_NORMAL, False); + become_root(); + num_users=count_sam_users(&info->disp_info, + ACB_NORMAL); + num_groups=count_sam_groups(&info->disp_info); unbecome_root(); - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(5, ("_samr_query_dispinfo: load_sampwd_entries failed\n")); - return r_u->status; - } - num_users=info->disp_info.num_user_account; - free_samr_db(info); - - r_u->status=load_group_domain_entries(info, get_global_sam_sid()); - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(5, ("_samr_query_dispinfo: load_group_domain_entries failed\n")); - return r_u->status; - } - num_groups=info->disp_info.num_group_account; - free_samr_db(info); account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp); u_logout = account_policy_temp; @@ -4380,13 +4098,9 @@ NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p, SAMR_Q_REMOVE_SID_FOREIGN_DOMAIN *q_u, SAMR_R_REMOVE_SID_FOREIGN_DOMAIN *r_u) { - DOM_SID delete_sid, alias_sid; - SAM_ACCOUNT *sam_pass=NULL; + DOM_SID delete_sid, domain_sid; uint32 acc_granted; - GROUP_MAP map; - BOOL is_user = False; NTSTATUS result; - enum SID_NAME_USE type = SID_NAME_UNKNOWN; sid_copy( &delete_sid, &q_u->sid.sid ); @@ -4395,7 +4109,8 @@ NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p, /* Find the policy handle. Open a policy on it. */ - if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &alias_sid, &acc_granted)) + if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &domain_sid, + &acc_granted)) return NT_STATUS_INVALID_HANDLE; result = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS, @@ -4405,80 +4120,33 @@ NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p, return result; DEBUG(8, ("_samr_remove_sid_foreign_domain:sid is %s\n", - sid_string_static(&alias_sid))); - - /* make sure we can handle this */ - - if ( sid_check_is_domain(&alias_sid) ) - type = SID_NAME_DOM_GRP; - else if ( sid_check_is_builtin(&alias_sid) ) - type = SID_NAME_ALIAS; - - if ( type == SID_NAME_UNKNOWN ) { - DEBUG(10, ("_samr_remove_sid_foreign_domain: can't operate on what we don't own!\n")); - return NT_STATUS_OK; - } + sid_string_static(&domain_sid))); - /* check if the user exists before trying to delete */ - - pdb_init_sam(&sam_pass); - - if ( pdb_getsampwsid(sam_pass, &delete_sid) ) { - is_user = True; - } else { - /* maybe it is a group */ - if( !pdb_getgrsid(&map, delete_sid) ) { - DEBUG(3,("_samr_remove_sid_foreign_domain: %s is not a user or a group!\n", - sid_string_static(&delete_sid))); - result = NT_STATUS_INVALID_SID; - goto done; - } - } - /* we can only delete a user from a group since we don't have nested groups anyways. So in the latter case, just say OK */ - - if ( is_user ) { - GROUP_MAP *mappings = NULL; - int num_groups, i; - struct group *grp2; - - if ( pdb_enum_group_mapping(type, &mappings, &num_groups, False) && num_groups>0 ) { - - /* interate over the groups */ - for ( i=0; i<num_groups; i++ ) { - grp2 = getgrgid(mappings[i].gid); - - if ( !grp2 ) { - DEBUG(0,("_samr_remove_sid_foreign_domain: group mapping without UNIX group!\n")); - continue; - } - - if ( !user_in_unix_group_list(pdb_get_username(sam_pass), grp2->gr_name) ) - continue; - - smb_delete_user_group(grp2->gr_name, pdb_get_username(sam_pass)); - - if ( user_in_unix_group_list(pdb_get_username(sam_pass), grp2->gr_name) ) { - /* should we fail here ? */ - DEBUG(0,("_samr_remove_sid_foreign_domain: Delete user [%s] from group [%s] failed!\n", - pdb_get_username(sam_pass), grp2->gr_name )); - continue; - } - - DEBUG(10,("_samr_remove_sid_foreign_domain: Removed user [%s] from group [%s]!\n", - pdb_get_username(sam_pass), grp2->gr_name )); - } - - SAFE_FREE(mappings); - } + /* TODO: The above comment nowadays is bogus. Since we have nested + * groups now, and aliases members are never reported out of the unix + * group membership, the "just say OK" makes this call a no-op. For + * us. This needs fixing however. */ + + /* I've only ever seen this in the wild when deleting a user from + * usrmgr.exe. domain_sid is the builtin domain, and the sid to delete + * is the user about to be deleted. I very much suspect this is the + * only application of this call. To verify this, let people report + * other cases. */ + + if (!sid_check_is_builtin(&domain_sid)) { + DEBUG(1,("_samr_remove_sid_foreign_domain: domain_sid = %s, " + "global_sam_sid() = %s\n", + sid_string_static(&domain_sid), + sid_string_static(get_global_sam_sid()))); + DEBUGADD(1,("please report to samba-technical@samba.org!\n")); + return NT_STATUS_OK; } - - result = NT_STATUS_OK; -done: - pdb_free_sam(&sam_pass); + + result = NT_STATUS_OK; return result; } @@ -4545,21 +4213,11 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW break; case 0x02: become_root(); - r_u->status=load_sampwd_entries(info, ACB_NORMAL, False); + num_users = count_sam_users(&info->disp_info, + ACB_NORMAL); + num_groups = count_sam_groups(&info->disp_info); unbecome_root(); - if (!NT_STATUS_IS_OK(r_u->status)) { - DEBUG(5, ("_samr_unknown_2e: load_sampwd_entries failed\n")); - return r_u->status; - } - num_users=info->disp_info.num_user_account; - free_samr_db(info); - - r_u->status=load_group_domain_entries(info, get_global_sam_sid()); - if (NT_STATUS_IS_ERR(r_u->status)) { - DEBUG(5, ("_samr_unknown_2e: load_group_domain_entries failed\n")); - return r_u->status; - } - num_groups=info->disp_info.num_group_account; + free_samr_db(info); account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp); |