diff options
-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); |