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
)
98 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 if (domain_name
&& domain_name
[0] && strchr_m(name
, '\\') == NULL
) {
112 fullname
= talloc_asprintf(mem_ctx
, "%s\\%s",
114 if (fullname
== NULL
) {
115 return NT_STATUS_NO_MEMORY
;
121 DEBUG(10, ("Finding fullname %s\n", fullname
));
123 if ( !lookup_name( mem_ctx
, fullname
, flags
, NULL
, NULL
, sid
, type
) ) {
124 return NT_STATUS_NONE_MAPPED
;
127 DEBUG(10, ("name_to_sid for %s returned %s (%s)\n",
130 sid_type_lookup((uint32
)*type
)));
136 convert a domain SID to a user or group name
138 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
143 enum lsa_SidType
*type
)
145 const char *dom
, *nam
;
147 DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid
)));
150 if (!sid_check_is_in_builtin(sid
) &&
151 !sid_check_is_in_our_domain(sid
) &&
152 !sid_check_is_in_unix_users(sid
) &&
153 !sid_check_is_unix_users(sid
) &&
154 !sid_check_is_in_unix_groups(sid
) &&
155 !sid_check_is_unix_groups(sid
) &&
156 !sid_check_is_in_wellknown_domain(sid
))
158 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
159 "passdb backend\n", sid_string_dbg(sid
)));
160 return NT_STATUS_NONE_MAPPED
;
163 if (!lookup_sid(mem_ctx
, sid
, &dom
, &nam
, type
)) {
164 return NT_STATUS_NONE_MAPPED
;
167 *domain_name
= talloc_strdup(mem_ctx
, dom
);
168 *name
= talloc_strdup(mem_ctx
, nam
);
173 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
180 enum lsa_SidType
**types
)
195 if (!sid_check_is_in_builtin(sid
) &&
196 !sid_check_is_in_our_domain(sid
) &&
197 !sid_check_is_in_unix_users(sid
) &&
198 !sid_check_is_unix_users(sid
) &&
199 !sid_check_is_in_unix_groups(sid
) &&
200 !sid_check_is_unix_groups(sid
) &&
201 !sid_check_is_in_wellknown_domain(sid
))
203 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
204 "passdb backend\n", sid_string_dbg(sid
)));
205 return NT_STATUS_NONE_MAPPED
;
208 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
209 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
211 if ((*names
== NULL
) || (*types
== NULL
)) {
212 return NT_STATUS_NO_MEMORY
;
215 have_mapped
= have_unmapped
= false;
217 for (i
=0; i
<num_rids
; i
++) {
219 const char *dom
= NULL
, *nam
= NULL
;
220 enum lsa_SidType type
= SID_NAME_UNKNOWN
;
222 if (!sid_compose(&lsid
, sid
, rids
[i
])) {
223 return NT_STATUS_INTERNAL_ERROR
;
226 if (!lookup_sid(mem_ctx
, &lsid
, &dom
, &nam
, &type
)) {
227 have_unmapped
= true;
228 (*types
)[i
] = SID_NAME_UNKNOWN
;
229 (*names
)[i
] = talloc_strdup(mem_ctx
, "");
233 (*names
)[i
] = CONST_DISCARD(char *, nam
);
236 if (*domain_name
== NULL
) {
237 *domain_name
= CONST_DISCARD(char *, dom
);
239 char *dname
= CONST_DISCARD(char *, dom
);
245 return NT_STATUS_NONE_MAPPED
;
247 if (!have_unmapped
) {
250 return STATUS_SOME_UNMAPPED
;
253 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
254 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
256 const DOM_SID
*user_sid
,
257 uint32
*num_groups
, DOM_SID
**user_gids
)
260 DOM_SID
*groups
= NULL
;
265 if ( (user
= samu_new(mem_ctx
)) == NULL
) {
266 return NT_STATUS_NO_MEMORY
;
269 if ( !pdb_getsampwsid( user
, user_sid
) ) {
270 return NT_STATUS_NO_SUCH_USER
;
273 result
= pdb_enum_group_memberships( mem_ctx
, user
, &groups
, &gids
, &ngroups
);
277 *num_groups
= (uint32
)ngroups
;
283 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
285 uint32 num_sids
, const DOM_SID
*sids
,
286 uint32
*p_num_aliases
, uint32
**rids
)
289 size_t num_aliases
= 0;
291 result
= pdb_enum_alias_memberships(mem_ctx
, &domain
->sid
,
292 sids
, num_sids
, rids
, &num_aliases
);
294 *p_num_aliases
= num_aliases
;
298 /* find the sequence number for a domain */
299 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
304 result
= pdb_get_seq_num(&seq_num
);
309 *seq
= (int) seq_num
;
314 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
316 struct samr_DomInfo12
*policy
)
318 /* actually we have that */
319 return NT_STATUS_NOT_IMPLEMENTED
;
322 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
324 struct samr_DomInfo1
*policy
)
326 uint32 min_pass_len
,pass_hist
,password_properties
;
327 time_t u_expire
, u_min_age
;
328 NTTIME nt_expire
, nt_min_age
;
329 uint32 account_policy_temp
;
331 if ((policy
= TALLOC_ZERO_P(mem_ctx
, struct samr_DomInfo1
)) == NULL
) {
332 return NT_STATUS_NO_MEMORY
;
335 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN
, &account_policy_temp
)) {
336 return NT_STATUS_ACCESS_DENIED
;
338 min_pass_len
= account_policy_temp
;
340 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY
, &account_policy_temp
)) {
341 return NT_STATUS_ACCESS_DENIED
;
343 pass_hist
= account_policy_temp
;
345 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS
, &account_policy_temp
)) {
346 return NT_STATUS_ACCESS_DENIED
;
348 password_properties
= account_policy_temp
;
350 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE
, &account_policy_temp
)) {
351 return NT_STATUS_ACCESS_DENIED
;
353 u_expire
= account_policy_temp
;
355 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE
, &account_policy_temp
)) {
356 return NT_STATUS_ACCESS_DENIED
;
358 u_min_age
= account_policy_temp
;
360 unix_to_nt_time_abs(&nt_expire
, u_expire
);
361 unix_to_nt_time_abs(&nt_min_age
, u_min_age
);
363 init_samr_DomInfo1(policy
,
364 (uint16
)min_pass_len
,
373 /*********************************************************************
374 BUILTIN specific functions.
375 *********************************************************************/
377 /* list all domain groups */
378 static NTSTATUS
builtin_enum_dom_groups(struct winbindd_domain
*domain
,
381 struct acct_info
**info
)
383 /* BUILTIN doesn't have domain groups */
389 /* Query display info for a domain. This returns enough information plus a
390 bit extra to give an overview of domain users for the User Manager
392 static NTSTATUS
builtin_query_user_list(struct winbindd_domain
*domain
,
395 WINBIND_USERINFO
**info
)
397 /* We don't have users */
403 /* Lookup user information from a rid or username. */
404 static NTSTATUS
builtin_query_user(struct winbindd_domain
*domain
,
406 const DOM_SID
*user_sid
,
407 WINBIND_USERINFO
*user_info
)
409 return NT_STATUS_NO_SUCH_USER
;
412 static NTSTATUS
builtin_lookup_groupmem(struct winbindd_domain
*domain
,
414 const DOM_SID
*group_sid
, uint32
*num_names
,
415 DOM_SID
**sid_mem
, char ***names
,
422 return NT_STATUS_NO_SUCH_GROUP
;
425 /* get a list of trusted domains - builtin domain */
426 static NTSTATUS
builtin_trusted_domains(struct winbindd_domain
*domain
,
440 /*********************************************************************
441 SAM specific functions.
442 *********************************************************************/
444 /* list all domain groups */
445 static NTSTATUS
sam_enum_dom_groups(struct winbindd_domain
*domain
,
448 struct acct_info
**info
)
450 return enum_groups_internal(domain
,
457 static NTSTATUS
sam_query_user_list(struct winbindd_domain
*domain
,
460 WINBIND_USERINFO
**info
)
462 struct pdb_search
*ps
= pdb_search_users(ACB_NORMAL
);
463 struct samr_displayentry
*entries
= NULL
;
470 return NT_STATUS_NO_MEMORY
;
473 *num_entries
= pdb_search_entries(ps
,
477 *info
= TALLOC_ZERO_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
479 pdb_search_destroy(ps
);
480 return NT_STATUS_NO_MEMORY
;
483 for (i
= 0; i
< *num_entries
; i
++) {
484 struct samr_displayentry
*e
= &entries
[i
];
486 (*info
)[i
].acct_name
= talloc_strdup(mem_ctx
, e
->account_name
);
487 (*info
)[i
].full_name
= talloc_strdup(mem_ctx
, e
->fullname
);
488 (*info
)[i
].homedir
= NULL
;
489 (*info
)[i
].shell
= NULL
;
490 sid_compose(&(*info
)[i
].user_sid
, &domain
->sid
, e
->rid
);
492 /* For the moment we set the primary group for
493 every user to be the Domain Users group.
494 There are serious problems with determining
495 the actual primary group for large domains.
496 This should really be made into a 'winbind
497 force group' smb.conf parameter or
498 something like that. */
500 sid_compose(&(*info
)[i
].group_sid
, &domain
->sid
,
501 DOMAIN_GROUP_RID_USERS
);
504 pdb_search_destroy(ps
);
508 /* Lookup user information from a rid or username. */
509 static NTSTATUS
sam_query_user(struct winbindd_domain
*domain
,
511 const DOM_SID
*user_sid
,
512 WINBIND_USERINFO
*user_info
)
514 struct samu
*sampass
= NULL
;
516 ZERO_STRUCTP(user_info
);
518 if (!sid_check_is_in_our_domain(user_sid
)) {
519 return NT_STATUS_NO_SUCH_USER
;
522 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
523 sid_string_dbg(user_sid
) ));
525 if (!(sampass
= samu_new(mem_ctx
))) {
526 return NT_STATUS_NO_MEMORY
;
529 if (!pdb_getsampwsid(sampass
, user_sid
)) {
530 TALLOC_FREE(sampass
);
531 return NT_STATUS_NO_SUCH_USER
;
534 if (pdb_get_group_sid(sampass
) == NULL
) {
535 TALLOC_FREE(sampass
);
536 return NT_STATUS_NO_SUCH_GROUP
;
539 DEBUG(10,("sam_query_user: group sid %s\n",
540 sid_string_dbg(sampass
->group_sid
) ));
542 sid_copy(&user_info
->user_sid
, user_sid
);
543 sid_copy(&user_info
->group_sid
, sampass
->group_sid
);
545 user_info
->acct_name
= talloc_strdup(mem_ctx
, sampass
->username
?
546 sampass
->username
: "");
547 user_info
->full_name
= talloc_strdup(mem_ctx
, sampass
->full_name
?
548 sampass
->full_name
: "");
549 user_info
->homedir
= talloc_strdup(mem_ctx
, sampass
->home_dir
?
550 sampass
->home_dir
: "");
551 if (sampass
->unix_pw
&& sampass
->unix_pw
->pw_shell
) {
552 user_info
->shell
= talloc_strdup(mem_ctx
, sampass
->unix_pw
->pw_shell
);
554 user_info
->shell
= talloc_strdup(mem_ctx
, "");
556 user_info
->primary_gid
= sampass
->unix_pw
? sampass
->unix_pw
->pw_gid
: (gid_t
)-1;
558 TALLOC_FREE(sampass
);
562 /* Lookup group membership given a rid. */
563 static NTSTATUS
sam_lookup_groupmem(struct winbindd_domain
*domain
,
565 const DOM_SID
*group_sid
, uint32
*num_names
,
566 DOM_SID
**sid_mem
, char ***names
,
569 size_t i
, num_members
, num_mapped
;
572 const DOM_SID
**sids
;
573 struct lsa_dom_info
*lsa_domains
;
574 struct lsa_name_info
*lsa_names
;
577 if (!sid_check_is_in_our_domain(group_sid
)) {
578 /* There's no groups, only aliases in BUILTIN */
579 return NT_STATUS_NO_SUCH_GROUP
;
582 if (!(tmp_ctx
= talloc_init("lookup_groupmem"))) {
583 return NT_STATUS_NO_MEMORY
;
586 result
= pdb_enum_group_members(tmp_ctx
, group_sid
, &rids
,
588 if (!NT_STATUS_IS_OK(result
)) {
589 TALLOC_FREE(tmp_ctx
);
593 if (num_members
== 0) {
598 TALLOC_FREE(tmp_ctx
);
602 *sid_mem
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, num_members
);
603 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_members
);
604 *name_types
= TALLOC_ARRAY(mem_ctx
, uint32
, num_members
);
605 sids
= TALLOC_ARRAY(tmp_ctx
, const DOM_SID
*, num_members
);
607 if (((*sid_mem
) == NULL
) || ((*names
) == NULL
) ||
608 ((*name_types
) == NULL
) || (sids
== NULL
)) {
609 TALLOC_FREE(tmp_ctx
);
610 return NT_STATUS_NO_MEMORY
;
614 * Prepare an array of sid pointers for the lookup_sids calling
618 for (i
=0; i
<num_members
; i
++) {
619 DOM_SID
*sid
= &((*sid_mem
)[i
]);
620 if (!sid_compose(sid
, &domain
->sid
, rids
[i
])) {
621 TALLOC_FREE(tmp_ctx
);
622 return NT_STATUS_INTERNAL_ERROR
;
627 result
= lookup_sids(tmp_ctx
, num_members
, sids
, 1,
628 &lsa_domains
, &lsa_names
);
629 if (!NT_STATUS_IS_OK(result
)) {
630 TALLOC_FREE(tmp_ctx
);
635 for (i
=0; i
<num_members
; i
++) {
636 if (lsa_names
[i
].type
!= SID_NAME_USER
) {
637 DEBUG(2, ("Got %s as group member -- ignoring\n",
638 sid_type_lookup(lsa_names
[i
].type
)));
641 if (!((*names
)[i
] = talloc_strdup((*names
),
642 lsa_names
[i
].name
))) {
643 TALLOC_FREE(tmp_ctx
);
644 return NT_STATUS_NO_MEMORY
;
647 (*name_types
)[i
] = lsa_names
[i
].type
;
652 *num_names
= num_mapped
;
654 TALLOC_FREE(tmp_ctx
);
658 /* get a list of trusted domains */
659 static NTSTATUS
sam_trusted_domains(struct winbindd_domain
*domain
,
667 struct trustdom_info
**domains
;
676 if (!(tmp_ctx
= talloc_init("trusted_domains"))) {
677 return NT_STATUS_NO_MEMORY
;
680 nt_status
= pdb_enum_trusteddoms(tmp_ctx
, num_domains
, &domains
);
681 if (!NT_STATUS_IS_OK(nt_status
)) {
682 TALLOC_FREE(tmp_ctx
);
687 *names
= TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
688 *alt_names
= TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
689 *dom_sids
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
691 if ((*alt_names
== NULL
) || (*names
== NULL
) || (*dom_sids
== NULL
)) {
692 TALLOC_FREE(tmp_ctx
);
693 return NT_STATUS_NO_MEMORY
;
701 for (i
=0; i
<*num_domains
; i
++) {
702 (*alt_names
)[i
] = NULL
;
703 if (!((*names
)[i
] = talloc_strdup((*names
),
704 domains
[i
]->name
))) {
705 TALLOC_FREE(tmp_ctx
);
706 return NT_STATUS_NO_MEMORY
;
708 sid_copy(&(*dom_sids
)[i
], &domains
[i
]->sid
);
711 TALLOC_FREE(tmp_ctx
);
715 /* the rpc backend methods are exposed via this structure */
716 struct winbindd_methods builtin_passdb_methods
= {
718 builtin_query_user_list
,
719 builtin_enum_dom_groups
,
727 builtin_lookup_groupmem
,
731 builtin_trusted_domains
,
734 /* the rpc backend methods are exposed via this structure */
735 struct winbindd_methods sam_passdb_methods
= {