2 Unix SMB/CIFS implementation.
4 Winbind rpc backend functions
6 Copyright (C) Tim Potter 2000-2001,2003
7 Copyright (C) Simo Sorce 2003
8 Copyright (C) Volker Lendecke 2004
9 Copyright (C) Jeremy Allison 2008
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #define DBGC_CLASS DBGC_WINBIND
31 static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
34 struct acct_info **info,
35 enum lsa_SidType sidtype)
37 struct pdb_search *search;
38 struct samr_displayentry *entries;
40 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42 if (sidtype == SID_NAME_ALIAS) {
43 search = pdb_search_aliases(&domain->sid);
45 search = pdb_search_groups();
48 if (search == NULL) goto done;
50 *num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
51 if (*num_entries == 0) {
52 /* Zero entries isn't an error */
53 result = NT_STATUS_OK;
57 *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
59 result = NT_STATUS_NO_MEMORY;
63 for (i=0; i<*num_entries; i++) {
64 fstrcpy((*info)[i].acct_name, entries[i].account_name);
65 fstrcpy((*info)[i].acct_desc, entries[i].description);
66 (*info)[i].rid = entries[i].rid;
69 result = NT_STATUS_OK;
71 pdb_search_destroy(search);
75 /* List all local groups (aliases) */
76 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
79 struct acct_info **info)
81 return enum_groups_internal(domain,
88 /* convert a single name to a sid in a domain */
89 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
91 enum winbindd_cmd original_cmd,
92 const char *domain_name,
95 enum lsa_SidType *type)
97 uint32 flags = LOOKUP_NAME_ALL;
100 switch ( original_cmd ) {
101 case WINBINDD_LOOKUPNAME:
102 /* This call is ok */
105 /* Avoid any NSS calls in the lookup_name by default */
106 flags |= LOOKUP_NAME_EXPLICIT;
107 DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
111 DEBUG(10, ("looking up name [%s\\%s] (domain\\name) \n",
112 domain_name?domain_name:"(NULL)", name));
114 if (strchr_m(name, '\\')) {
115 res = lookup_name(mem_ctx, name, flags, NULL, NULL, sid, type);
117 res = lookup_domain_name(mem_ctx, domain_name, name, flags,
118 NULL, NULL, sid, type);
122 return NT_STATUS_NONE_MAPPED;
125 DEBUG(10, ("name_to_sid for [%s\\%s] returned %s (%s)\n",
126 domain_name?domain_name:"(NULL)", name,
128 sid_type_lookup((uint32)*type)));
134 convert a domain SID to a user or group name
136 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
141 enum lsa_SidType *type)
143 const char *dom, *nam;
145 DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid)));
148 if (!sid_check_is_in_builtin(sid) &&
149 !sid_check_is_in_our_domain(sid) &&
150 !sid_check_is_in_unix_users(sid) &&
151 !sid_check_is_unix_users(sid) &&
152 !sid_check_is_in_unix_groups(sid) &&
153 !sid_check_is_unix_groups(sid) &&
154 !sid_check_is_in_wellknown_domain(sid))
156 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
157 "passdb backend\n", sid_string_dbg(sid)));
158 return NT_STATUS_NONE_MAPPED;
161 if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
162 return NT_STATUS_NONE_MAPPED;
165 *domain_name = talloc_strdup(mem_ctx, dom);
166 *name = talloc_strdup(mem_ctx, nam);
171 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
178 enum lsa_SidType **types)
193 if (!sid_check_is_in_builtin(sid) &&
194 !sid_check_is_in_our_domain(sid) &&
195 !sid_check_is_in_unix_users(sid) &&
196 !sid_check_is_unix_users(sid) &&
197 !sid_check_is_in_unix_groups(sid) &&
198 !sid_check_is_unix_groups(sid) &&
199 !sid_check_is_in_wellknown_domain(sid))
201 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
202 "passdb backend\n", sid_string_dbg(sid)));
203 return NT_STATUS_NONE_MAPPED;
206 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
207 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
209 if ((*names == NULL) || (*types == NULL)) {
210 return NT_STATUS_NO_MEMORY;
213 have_mapped = have_unmapped = false;
215 for (i=0; i<num_rids; i++) {
217 const char *dom = NULL, *nam = NULL;
218 enum lsa_SidType type = SID_NAME_UNKNOWN;
220 if (!sid_compose(&lsid, sid, rids[i])) {
221 return NT_STATUS_INTERNAL_ERROR;
224 if (!lookup_sid(mem_ctx, &lsid, &dom, &nam, &type)) {
225 have_unmapped = true;
226 (*types)[i] = SID_NAME_UNKNOWN;
227 (*names)[i] = talloc_strdup(mem_ctx, "");
231 (*names)[i] = CONST_DISCARD(char *, nam);
234 if (*domain_name == NULL) {
235 *domain_name = CONST_DISCARD(char *, dom);
237 char *dname = CONST_DISCARD(char *, dom);
243 return NT_STATUS_NONE_MAPPED;
245 if (!have_unmapped) {
248 return STATUS_SOME_UNMAPPED;
251 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
252 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
254 const DOM_SID *user_sid,
255 uint32 *num_groups, DOM_SID **user_gids)
258 DOM_SID *groups = NULL;
263 if ( (user = samu_new(mem_ctx)) == NULL ) {
264 return NT_STATUS_NO_MEMORY;
267 if ( !pdb_getsampwsid( user, user_sid ) ) {
268 return NT_STATUS_NO_SUCH_USER;
271 result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
275 *num_groups = (uint32)ngroups;
281 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
283 uint32 num_sids, const DOM_SID *sids,
284 uint32 *p_num_aliases, uint32 **rids)
287 size_t num_aliases = 0;
289 result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
290 sids, num_sids, rids, &num_aliases);
292 *p_num_aliases = num_aliases;
296 /* find the sequence number for a domain */
297 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
302 result = pdb_get_seq_num(&seq_num);
307 *seq = (int) seq_num;
312 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
314 struct samr_DomInfo12 *policy)
316 /* actually we have that */
317 return NT_STATUS_NOT_IMPLEMENTED;
320 static NTSTATUS password_policy(struct winbindd_domain *domain,
322 struct samr_DomInfo1 *policy)
324 uint32 min_pass_len,pass_hist,password_properties;
325 time_t u_expire, u_min_age;
326 NTTIME nt_expire, nt_min_age;
327 uint32 account_policy_temp;
329 if ((policy = TALLOC_ZERO_P(mem_ctx, struct samr_DomInfo1)) == NULL) {
330 return NT_STATUS_NO_MEMORY;
333 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
334 return NT_STATUS_ACCESS_DENIED;
336 min_pass_len = account_policy_temp;
338 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
339 return NT_STATUS_ACCESS_DENIED;
341 pass_hist = account_policy_temp;
343 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
344 return NT_STATUS_ACCESS_DENIED;
346 password_properties = account_policy_temp;
348 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
349 return NT_STATUS_ACCESS_DENIED;
351 u_expire = account_policy_temp;
353 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
354 return NT_STATUS_ACCESS_DENIED;
356 u_min_age = account_policy_temp;
358 unix_to_nt_time_abs(&nt_expire, u_expire);
359 unix_to_nt_time_abs(&nt_min_age, u_min_age);
361 init_samr_DomInfo1(policy,
362 (uint16)min_pass_len,
371 /*********************************************************************
372 BUILTIN specific functions.
373 *********************************************************************/
375 /* list all domain groups */
376 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
379 struct acct_info **info)
381 /* BUILTIN doesn't have domain groups */
387 /* Query display info for a domain. This returns enough information plus a
388 bit extra to give an overview of domain users for the User Manager
390 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
393 WINBIND_USERINFO **info)
395 /* We don't have users */
401 /* Lookup user information from a rid or username. */
402 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
404 const DOM_SID *user_sid,
405 WINBIND_USERINFO *user_info)
407 return NT_STATUS_NO_SUCH_USER;
410 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
412 const DOM_SID *group_sid, uint32 *num_names,
413 DOM_SID **sid_mem, char ***names,
420 return NT_STATUS_NO_SUCH_GROUP;
423 /* get a list of trusted domains - builtin domain */
424 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
438 /*********************************************************************
439 SAM specific functions.
440 *********************************************************************/
442 /* list all domain groups */
443 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
446 struct acct_info **info)
448 return enum_groups_internal(domain,
455 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
458 WINBIND_USERINFO **info)
460 struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
461 struct samr_displayentry *entries = NULL;
468 return NT_STATUS_NO_MEMORY;
471 *num_entries = pdb_search_entries(ps,
475 *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
477 pdb_search_destroy(ps);
478 return NT_STATUS_NO_MEMORY;
481 for (i = 0; i < *num_entries; i++) {
482 struct samr_displayentry *e = &entries[i];
484 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
485 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
486 (*info)[i].homedir = NULL;
487 (*info)[i].shell = NULL;
488 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
490 /* For the moment we set the primary group for
491 every user to be the Domain Users group.
492 There are serious problems with determining
493 the actual primary group for large domains.
494 This should really be made into a 'winbind
495 force group' smb.conf parameter or
496 something like that. */
498 sid_compose(&(*info)[i].group_sid, &domain->sid,
499 DOMAIN_GROUP_RID_USERS);
502 pdb_search_destroy(ps);
506 /* Lookup user information from a rid or username. */
507 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
509 const DOM_SID *user_sid,
510 WINBIND_USERINFO *user_info)
512 struct samu *sampass = NULL;
514 ZERO_STRUCTP(user_info);
516 if (!sid_check_is_in_our_domain(user_sid)) {
517 return NT_STATUS_NO_SUCH_USER;
520 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
521 sid_string_dbg(user_sid) ));
523 if (!(sampass = samu_new(mem_ctx))) {
524 return NT_STATUS_NO_MEMORY;
527 if (!pdb_getsampwsid(sampass, user_sid)) {
528 TALLOC_FREE(sampass);
529 return NT_STATUS_NO_SUCH_USER;
532 if (pdb_get_group_sid(sampass) == NULL) {
533 TALLOC_FREE(sampass);
534 return NT_STATUS_NO_SUCH_GROUP;
537 DEBUG(10,("sam_query_user: group sid %s\n",
538 sid_string_dbg(sampass->group_sid) ));
540 sid_copy(&user_info->user_sid, user_sid);
541 sid_copy(&user_info->group_sid, sampass->group_sid);
543 user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
544 sampass->username : "");
545 user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
546 sampass->full_name : "");
547 user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
548 sampass->home_dir : "");
549 if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
550 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
552 user_info->shell = talloc_strdup(mem_ctx, "");
554 user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
556 TALLOC_FREE(sampass);
560 /* Lookup group membership given a rid. */
561 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
563 const DOM_SID *group_sid, uint32 *num_names,
564 DOM_SID **sid_mem, char ***names,
567 size_t i, num_members, num_mapped;
570 const DOM_SID **sids;
571 struct lsa_dom_info *lsa_domains;
572 struct lsa_name_info *lsa_names;
575 if (!sid_check_is_in_our_domain(group_sid)) {
576 /* There's no groups, only aliases in BUILTIN */
577 return NT_STATUS_NO_SUCH_GROUP;
580 if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
581 return NT_STATUS_NO_MEMORY;
584 result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
586 if (!NT_STATUS_IS_OK(result)) {
587 TALLOC_FREE(tmp_ctx);
591 if (num_members == 0) {
596 TALLOC_FREE(tmp_ctx);
600 *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
601 *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
602 *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
603 sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
605 if (((*sid_mem) == NULL) || ((*names) == NULL) ||
606 ((*name_types) == NULL) || (sids == NULL)) {
607 TALLOC_FREE(tmp_ctx);
608 return NT_STATUS_NO_MEMORY;
612 * Prepare an array of sid pointers for the lookup_sids calling
616 for (i=0; i<num_members; i++) {
617 DOM_SID *sid = &((*sid_mem)[i]);
618 if (!sid_compose(sid, &domain->sid, rids[i])) {
619 TALLOC_FREE(tmp_ctx);
620 return NT_STATUS_INTERNAL_ERROR;
625 result = lookup_sids(tmp_ctx, num_members, sids, 1,
626 &lsa_domains, &lsa_names);
627 if (!NT_STATUS_IS_OK(result)) {
628 TALLOC_FREE(tmp_ctx);
633 for (i=0; i<num_members; i++) {
634 if (lsa_names[i].type != SID_NAME_USER) {
635 DEBUG(2, ("Got %s as group member -- ignoring\n",
636 sid_type_lookup(lsa_names[i].type)));
639 if (!((*names)[i] = talloc_strdup((*names),
640 lsa_names[i].name))) {
641 TALLOC_FREE(tmp_ctx);
642 return NT_STATUS_NO_MEMORY;
645 (*name_types)[i] = lsa_names[i].type;
650 *num_names = num_mapped;
652 TALLOC_FREE(tmp_ctx);
656 /* get a list of trusted domains */
657 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
665 struct trustdom_info **domains;
674 if (!(tmp_ctx = talloc_init("trusted_domains"))) {
675 return NT_STATUS_NO_MEMORY;
678 nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
679 if (!NT_STATUS_IS_OK(nt_status)) {
680 TALLOC_FREE(tmp_ctx);
685 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
686 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
687 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
689 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
690 TALLOC_FREE(tmp_ctx);
691 return NT_STATUS_NO_MEMORY;
699 for (i=0; i<*num_domains; i++) {
700 (*alt_names)[i] = NULL;
701 if (!((*names)[i] = talloc_strdup((*names),
702 domains[i]->name))) {
703 TALLOC_FREE(tmp_ctx);
704 return NT_STATUS_NO_MEMORY;
706 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
709 TALLOC_FREE(tmp_ctx);
713 /* the rpc backend methods are exposed via this structure */
714 struct winbindd_methods builtin_passdb_methods = {
716 builtin_query_user_list,
717 builtin_enum_dom_groups,
725 builtin_lookup_groupmem,
729 builtin_trusted_domains,
732 /* the rpc backend methods are exposed via this structure */
733 struct winbindd_methods sam_passdb_methods = {