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 2 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, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #define DBGC_CLASS DBGC_WINBIND
32 static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
35 struct acct_info **info,
36 enum lsa_SidType sidtype)
38 struct pdb_search *search;
39 struct samr_displayentry *entries;
41 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
43 if (sidtype == SID_NAME_ALIAS) {
44 search = pdb_search_aliases(&domain->sid);
46 search = pdb_search_groups();
49 if (search == NULL) goto done;
51 *num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
52 if (*num_entries == 0) {
53 /* Zero entries isn't an error */
54 result = NT_STATUS_OK;
58 *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
60 result = NT_STATUS_NO_MEMORY;
64 for (i=0; i<*num_entries; i++) {
65 fstrcpy((*info)[i].acct_name, entries[i].account_name);
66 fstrcpy((*info)[i].acct_desc, entries[i].description);
67 (*info)[i].rid = entries[i].rid;
70 result = NT_STATUS_OK;
72 pdb_search_destroy(search);
76 /* List all local groups (aliases) */
77 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
80 struct acct_info **info)
82 return enum_groups_internal(domain,
89 /* convert a single name to a sid in a domain */
90 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
92 const char *domain_name,
95 enum lsa_SidType *type)
97 DEBUG(10, ("Finding name %s\n", name));
99 if ( !lookup_name( mem_ctx, name, LOOKUP_NAME_ALL,
100 NULL, NULL, sid, type ) )
102 return NT_STATUS_NONE_MAPPED;
109 convert a domain SID to a user or group name
111 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
116 enum lsa_SidType *type)
118 const char *dom, *nam;
120 DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
123 if (!sid_check_is_in_builtin(sid) &&
124 !sid_check_is_in_our_domain(sid)) {
125 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
126 "passdb backend\n", sid_string_static(sid)));
127 return NT_STATUS_NONE_MAPPED;
130 if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
131 return NT_STATUS_NONE_MAPPED;
134 *domain_name = talloc_strdup(mem_ctx, dom);
135 *name = talloc_strdup(mem_ctx, nam);
140 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
142 const DOM_SID *domain_sid,
147 enum lsa_SidType **types)
161 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
162 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
164 if ((*names == NULL) || (*types == NULL)) {
165 return NT_STATUS_NO_MEMORY;
168 have_mapped = have_unmapped = false;
170 for (i=0; i<num_rids; i++) {
172 const char *dom = NULL, *nam = NULL;
173 enum lsa_SidType type = SID_NAME_UNKNOWN;
175 if (!sid_compose(&sid, domain_sid, rids[i])) {
176 return NT_STATUS_INTERNAL_ERROR;
179 if (!lookup_sid(mem_ctx, &sid, &dom, &nam, &type)) {
180 have_unmapped = true;
181 (*types)[i] = SID_NAME_UNKNOWN;
182 (*names)[i] = talloc_strdup(mem_ctx, "");
186 (*names)[i] = CONST_DISCARD(char *, nam);
189 if (domain_name == NULL) {
190 *domain_name = CONST_DISCARD(char *, dom);
192 char *dname = CONST_DISCARD(char *, dom);
198 return NT_STATUS_NONE_MAPPED;
200 if (!have_unmapped) {
203 return STATUS_SOME_UNMAPPED;
206 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
207 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
209 const DOM_SID *user_sid,
210 uint32 *num_groups, DOM_SID **user_gids)
213 DOM_SID *groups = NULL;
218 if ( (user = samu_new(mem_ctx)) == NULL ) {
219 return NT_STATUS_NO_MEMORY;
222 if (!pdb_getsampwsid(user, user_sid ) ) {
224 return NT_STATUS_NO_SUCH_USER;
227 result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
231 *num_groups = (uint32)ngroups;
237 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
239 uint32 num_sids, const DOM_SID *sids,
240 uint32 *p_num_aliases, uint32 **rids)
243 size_t num_aliases = 0;
245 result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
246 sids, num_sids, rids, &num_aliases);
248 *p_num_aliases = num_aliases;
252 /* find the sequence number for a domain */
253 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
258 result = pdb_get_seq_num(&seq_num);
263 *seq = (int) seq_num;
268 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
270 SAM_UNK_INFO_12 *policy)
272 /* actually we have that */
273 return NT_STATUS_NOT_IMPLEMENTED;
276 static NTSTATUS password_policy(struct winbindd_domain *domain,
278 SAM_UNK_INFO_1 *policy)
280 uint32 min_pass_len,pass_hist,password_properties;
281 time_t u_expire, u_min_age;
282 NTTIME nt_expire, nt_min_age;
283 uint32 account_policy_temp;
285 if ((policy = TALLOC_ZERO_P(mem_ctx, SAM_UNK_INFO_1)) == NULL) {
286 return NT_STATUS_NO_MEMORY;
289 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
290 return NT_STATUS_ACCESS_DENIED;
292 min_pass_len = account_policy_temp;
294 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
295 return NT_STATUS_ACCESS_DENIED;
297 pass_hist = account_policy_temp;
299 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
300 return NT_STATUS_ACCESS_DENIED;
302 password_properties = account_policy_temp;
304 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
305 return NT_STATUS_ACCESS_DENIED;
307 u_expire = account_policy_temp;
309 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
310 return NT_STATUS_ACCESS_DENIED;
312 u_min_age = account_policy_temp;
314 unix_to_nt_time_abs(&nt_expire, u_expire);
315 unix_to_nt_time_abs(&nt_min_age, u_min_age);
317 init_unk_info1(policy, (uint16)min_pass_len, (uint16)pass_hist,
318 password_properties, nt_expire, nt_min_age);
323 /*********************************************************************
324 BUILTIN specific functions.
325 *********************************************************************/
327 /* list all domain groups */
328 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
331 struct acct_info **info)
333 /* BUILTIN doesn't have domain groups */
339 /* Query display info for a domain. This returns enough information plus a
340 bit extra to give an overview of domain users for the User Manager
342 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
345 WINBIND_USERINFO **info)
347 /* We don't have users */
353 /* Lookup user information from a rid or username. */
354 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
356 const DOM_SID *user_sid,
357 WINBIND_USERINFO *user_info)
359 return NT_STATUS_NO_SUCH_USER;
362 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
364 const DOM_SID *group_sid, uint32 *num_names,
365 DOM_SID **sid_mem, char ***names,
372 return NT_STATUS_NO_SUCH_GROUP;
375 /* get a list of trusted domains - builtin domain */
376 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
390 /*********************************************************************
391 SAM specific functions.
392 *********************************************************************/
394 /* list all domain groups */
395 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
398 struct acct_info **info)
400 return enum_groups_internal(domain,
407 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
410 WINBIND_USERINFO **info)
412 struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
413 struct samr_displayentry *entries = NULL;
420 return NT_STATUS_NO_MEMORY;
423 *num_entries = pdb_search_entries(ps,
427 *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
429 pdb_search_destroy(ps);
430 return NT_STATUS_NO_MEMORY;
433 for (i = 0; i < *num_entries; i++) {
434 struct samr_displayentry *e = &entries[i];
436 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
437 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
438 (*info)[i].homedir = NULL;
439 (*info)[i].shell = NULL;
440 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
442 /* For the moment we set the primary group for
443 every user to be the Domain Users group.
444 There are serious problems with determining
445 the actual primary group for large domains.
446 This should really be made into a 'winbind
447 force group' smb.conf parameter or
448 something like that. */
450 sid_compose(&(*info)[i].group_sid, &domain->sid,
451 DOMAIN_GROUP_RID_USERS);
454 pdb_search_destroy(ps);
458 /* Lookup user information from a rid or username. */
459 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
461 const DOM_SID *user_sid,
462 WINBIND_USERINFO *user_info)
464 struct samu *sampass = NULL;
467 ZERO_STRUCTP(user_info);
469 if (!sid_check_is_in_our_domain(user_sid)) {
470 return NT_STATUS_NO_SUCH_USER;
473 sid_to_string(sidstr, user_sid);
474 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
477 if (!(sampass = samu_new(mem_ctx))) {
478 return NT_STATUS_NO_MEMORY;
481 if (!pdb_getsampwsid(sampass, user_sid)) {
482 TALLOC_FREE(sampass);
483 return NT_STATUS_NO_SUCH_USER;
486 if (pdb_get_group_sid(sampass) == NULL) {
487 TALLOC_FREE(sampass);
488 return NT_STATUS_NO_SUCH_GROUP;
491 sid_to_string(sidstr, sampass->group_sid);
492 DEBUG(10,("sam_query_user: group sid %s\n", sidstr ));
494 sid_copy(&user_info->user_sid, user_sid);
495 sid_copy(&user_info->group_sid, sampass->group_sid);
497 user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
498 sampass->username : "");
499 user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
500 sampass->full_name : "");
501 user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
502 sampass->home_dir : "");
503 if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
504 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
506 user_info->shell = talloc_strdup(mem_ctx, "");
508 user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
510 TALLOC_FREE(sampass);
514 /* Lookup group membership given a rid. */
515 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
517 const DOM_SID *group_sid, uint32 *num_names,
518 DOM_SID **sid_mem, char ***names,
521 size_t i, num_members, num_mapped;
524 const DOM_SID **sids;
525 struct lsa_dom_info *lsa_domains;
526 struct lsa_name_info *lsa_names;
529 if (!sid_check_is_in_our_domain(group_sid)) {
530 /* There's no groups, only aliases in BUILTIN */
531 return NT_STATUS_NO_SUCH_GROUP;
534 if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
535 return NT_STATUS_NO_MEMORY;
538 result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
540 if (!NT_STATUS_IS_OK(result)) {
541 TALLOC_FREE(tmp_ctx);
545 if (num_members == 0) {
550 TALLOC_FREE(tmp_ctx);
554 *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
555 *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
556 *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
557 sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
559 if (((*sid_mem) == NULL) || ((*names) == NULL) ||
560 ((*name_types) == NULL) || (sids == NULL)) {
561 TALLOC_FREE(tmp_ctx);
562 return NT_STATUS_NO_MEMORY;
566 * Prepare an array of sid pointers for the lookup_sids calling
570 for (i=0; i<num_members; i++) {
571 DOM_SID *sid = &((*sid_mem)[i]);
572 if (!sid_compose(sid, &domain->sid, rids[i])) {
573 TALLOC_FREE(tmp_ctx);
574 return NT_STATUS_INTERNAL_ERROR;
579 result = lookup_sids(tmp_ctx, num_members, sids, 1,
580 &lsa_domains, &lsa_names);
581 if (!NT_STATUS_IS_OK(result)) {
582 TALLOC_FREE(tmp_ctx);
587 for (i=0; i<num_members; i++) {
588 if (lsa_names[i].type != SID_NAME_USER) {
589 DEBUG(2, ("Got %s as group member -- ignoring\n",
590 sid_type_lookup(lsa_names[i].type)));
593 if (!((*names)[i] = talloc_strdup((*names),
594 lsa_names[i].name))) {
595 TALLOC_FREE(tmp_ctx);
596 return NT_STATUS_NO_MEMORY;
599 (*name_types)[i] = lsa_names[i].type;
604 *num_names = num_mapped;
606 TALLOC_FREE(tmp_ctx);
610 /* get a list of trusted domains - sam */
611 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
619 struct trustdom_info **domains;
628 if (!(tmp_ctx = talloc_init("trusted_domains"))) {
629 return NT_STATUS_NO_MEMORY;
632 nt_status = secrets_trusted_domains(tmp_ctx, num_domains,
634 if (!NT_STATUS_IS_OK(nt_status)) {
635 TALLOC_FREE(tmp_ctx);
640 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
641 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
642 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
644 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
645 TALLOC_FREE(tmp_ctx);
646 return NT_STATUS_NO_MEMORY;
654 for (i=0; i<*num_domains; i++) {
655 (*alt_names)[i] = NULL;
656 if (!((*names)[i] = talloc_strdup((*names),
657 domains[i]->name))) {
658 TALLOC_FREE(tmp_ctx);
659 return NT_STATUS_NO_MEMORY;
661 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
664 TALLOC_FREE(tmp_ctx);
668 /* the rpc backend methods are exposed via this structure */
669 struct winbindd_methods builtin_passdb_methods = {
671 builtin_query_user_list,
672 builtin_enum_dom_groups,
680 builtin_lookup_groupmem,
684 builtin_trusted_domains,
687 /* the rpc backend methods are exposed via this structure */
688 struct winbindd_methods sam_passdb_methods = {