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 domain groups */
76 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
79 struct acct_info
**info
)
81 return enum_groups_internal(domain
,
88 /* List all local groups (aliases) */
89 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
92 struct acct_info
**info
)
94 return enum_groups_internal(domain
,
101 /* convert a single name to a sid in a domain */
102 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
104 enum winbindd_cmd original_cmd
,
105 const char *domain_name
,
108 enum lsa_SidType
*type
)
110 uint32 flags
= LOOKUP_NAME_ALL
;
112 switch ( original_cmd
) {
113 case WINBINDD_LOOKUPNAME
:
114 /* This call is ok */
117 /* Avoid any NSS calls in the lookup_name by default */
118 flags
|= LOOKUP_NAME_EXPLICIT
;
119 DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
123 DEBUG(10, ("Finding name %s\n", name
));
125 if ( !lookup_name( mem_ctx
, name
, flags
, NULL
, NULL
, sid
, type
) ) {
126 return NT_STATUS_NONE_MAPPED
;
133 convert a domain SID to a user or group name
135 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
140 enum lsa_SidType
*type
)
142 const char *dom
, *nam
;
144 DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid
)));
147 if (!sid_check_is_in_builtin(sid
) &&
148 !sid_check_is_in_our_domain(sid
) &&
149 !sid_check_is_in_unix_users(sid
) &&
150 !sid_check_is_unix_users(sid
) &&
151 !sid_check_is_in_unix_groups(sid
) &&
152 !sid_check_is_unix_groups(sid
) &&
153 !sid_check_is_in_wellknown_domain(sid
))
155 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
156 "passdb backend\n", sid_string_dbg(sid
)));
157 return NT_STATUS_NONE_MAPPED
;
160 if (!lookup_sid(mem_ctx
, sid
, &dom
, &nam
, type
)) {
161 return NT_STATUS_NONE_MAPPED
;
164 *domain_name
= talloc_strdup(mem_ctx
, dom
);
165 *name
= talloc_strdup(mem_ctx
, nam
);
170 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
177 enum lsa_SidType
**types
)
192 if (!sid_check_is_in_builtin(sid
) &&
193 !sid_check_is_in_our_domain(sid
) &&
194 !sid_check_is_in_unix_users(sid
) &&
195 !sid_check_is_unix_users(sid
) &&
196 !sid_check_is_in_unix_groups(sid
) &&
197 !sid_check_is_unix_groups(sid
) &&
198 !sid_check_is_in_wellknown_domain(sid
))
200 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
201 "passdb backend\n", sid_string_dbg(sid
)));
202 return NT_STATUS_NONE_MAPPED
;
205 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
206 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
208 if ((*names
== NULL
) || (*types
== NULL
)) {
209 return NT_STATUS_NO_MEMORY
;
212 have_mapped
= have_unmapped
= false;
214 for (i
=0; i
<num_rids
; i
++) {
216 const char *dom
= NULL
, *nam
= NULL
;
217 enum lsa_SidType type
= SID_NAME_UNKNOWN
;
219 if (!sid_compose(&lsid
, sid
, rids
[i
])) {
220 return NT_STATUS_INTERNAL_ERROR
;
223 if (!lookup_sid(mem_ctx
, &lsid
, &dom
, &nam
, &type
)) {
224 have_unmapped
= true;
225 (*types
)[i
] = SID_NAME_UNKNOWN
;
226 (*names
)[i
] = talloc_strdup(mem_ctx
, "");
230 (*names
)[i
] = CONST_DISCARD(char *, nam
);
233 if (domain_name
== NULL
) {
234 *domain_name
= CONST_DISCARD(char *, dom
);
236 char *dname
= CONST_DISCARD(char *, dom
);
242 return NT_STATUS_NONE_MAPPED
;
244 if (!have_unmapped
) {
247 return STATUS_SOME_UNMAPPED
;
250 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
251 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
253 const DOM_SID
*user_sid
,
254 uint32
*num_groups
, DOM_SID
**user_gids
)
257 DOM_SID
*groups
= NULL
;
262 if ( (user
= samu_new(mem_ctx
)) == NULL
) {
263 return NT_STATUS_NO_MEMORY
;
266 if ( !pdb_getsampwsid( user
, user_sid
) ) {
267 return NT_STATUS_NO_SUCH_USER
;
270 result
= pdb_enum_group_memberships( mem_ctx
, user
, &groups
, &gids
, &ngroups
);
274 *num_groups
= (uint32
)ngroups
;
280 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
282 uint32 num_sids
, const DOM_SID
*sids
,
283 uint32
*p_num_aliases
, uint32
**rids
)
286 size_t num_aliases
= 0;
288 result
= pdb_enum_alias_memberships(mem_ctx
, &domain
->sid
,
289 sids
, num_sids
, rids
, &num_aliases
);
291 *p_num_aliases
= num_aliases
;
295 /* find the sequence number for a domain */
296 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
301 result
= pdb_get_seq_num(&seq_num
);
306 *seq
= (int) seq_num
;
311 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
313 struct samr_DomInfo12
*policy
)
315 /* actually we have that */
316 return NT_STATUS_NOT_IMPLEMENTED
;
319 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
321 struct samr_DomInfo1
*policy
)
323 uint32 min_pass_len
,pass_hist
,password_properties
;
324 time_t u_expire
, u_min_age
;
325 NTTIME nt_expire
, nt_min_age
;
326 uint32 account_policy_temp
;
328 if ((policy
= TALLOC_ZERO_P(mem_ctx
, struct samr_DomInfo1
)) == NULL
) {
329 return NT_STATUS_NO_MEMORY
;
332 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN
, &account_policy_temp
)) {
333 return NT_STATUS_ACCESS_DENIED
;
335 min_pass_len
= account_policy_temp
;
337 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY
, &account_policy_temp
)) {
338 return NT_STATUS_ACCESS_DENIED
;
340 pass_hist
= account_policy_temp
;
342 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS
, &account_policy_temp
)) {
343 return NT_STATUS_ACCESS_DENIED
;
345 password_properties
= account_policy_temp
;
347 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE
, &account_policy_temp
)) {
348 return NT_STATUS_ACCESS_DENIED
;
350 u_expire
= account_policy_temp
;
352 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE
, &account_policy_temp
)) {
353 return NT_STATUS_ACCESS_DENIED
;
355 u_min_age
= account_policy_temp
;
357 unix_to_nt_time_abs(&nt_expire
, u_expire
);
358 unix_to_nt_time_abs(&nt_min_age
, u_min_age
);
360 init_samr_DomInfo1(policy
,
361 (uint16
)min_pass_len
,
370 /*********************************************************************
371 BUILTIN specific functions.
372 *********************************************************************/
374 /* Query display info for a domain. This returns enough information plus a
375 bit extra to give an overview of domain users for the User Manager
377 static NTSTATUS
builtin_query_user_list(struct winbindd_domain
*domain
,
380 WINBIND_USERINFO
**info
)
382 /* We don't have users */
388 /* Lookup user information from a rid or username. */
389 static NTSTATUS
builtin_query_user(struct winbindd_domain
*domain
,
391 const DOM_SID
*user_sid
,
392 WINBIND_USERINFO
*user_info
)
394 return NT_STATUS_NO_SUCH_USER
;
397 static NTSTATUS
builtin_lookup_groupmem(struct winbindd_domain
*domain
,
399 const DOM_SID
*group_sid
, uint32
*num_names
,
400 DOM_SID
**sid_mem
, char ***names
,
407 return NT_STATUS_NO_SUCH_GROUP
;
410 /* get a list of trusted domains - builtin domain */
411 static NTSTATUS
builtin_trusted_domains(struct winbindd_domain
*domain
,
425 /*********************************************************************
426 SAM specific functions.
427 *********************************************************************/
429 static NTSTATUS
sam_query_user_list(struct winbindd_domain
*domain
,
432 WINBIND_USERINFO
**info
)
434 struct pdb_search
*ps
= pdb_search_users(ACB_NORMAL
);
435 struct samr_displayentry
*entries
= NULL
;
442 return NT_STATUS_NO_MEMORY
;
445 *num_entries
= pdb_search_entries(ps
,
449 *info
= TALLOC_ZERO_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
451 pdb_search_destroy(ps
);
452 return NT_STATUS_NO_MEMORY
;
455 for (i
= 0; i
< *num_entries
; i
++) {
456 struct samr_displayentry
*e
= &entries
[i
];
458 (*info
)[i
].acct_name
= talloc_strdup(mem_ctx
, e
->account_name
);
459 (*info
)[i
].full_name
= talloc_strdup(mem_ctx
, e
->fullname
);
460 (*info
)[i
].homedir
= NULL
;
461 (*info
)[i
].shell
= NULL
;
462 sid_compose(&(*info
)[i
].user_sid
, &domain
->sid
, e
->rid
);
464 /* For the moment we set the primary group for
465 every user to be the Domain Users group.
466 There are serious problems with determining
467 the actual primary group for large domains.
468 This should really be made into a 'winbind
469 force group' smb.conf parameter or
470 something like that. */
472 sid_compose(&(*info
)[i
].group_sid
, &domain
->sid
,
473 DOMAIN_GROUP_RID_USERS
);
476 pdb_search_destroy(ps
);
480 /* Lookup user information from a rid or username. */
481 static NTSTATUS
sam_query_user(struct winbindd_domain
*domain
,
483 const DOM_SID
*user_sid
,
484 WINBIND_USERINFO
*user_info
)
486 struct samu
*sampass
= NULL
;
488 ZERO_STRUCTP(user_info
);
490 if (!sid_check_is_in_our_domain(user_sid
)) {
491 return NT_STATUS_NO_SUCH_USER
;
494 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
495 sid_string_dbg(user_sid
) ));
497 if (!(sampass
= samu_new(mem_ctx
))) {
498 return NT_STATUS_NO_MEMORY
;
501 if (!pdb_getsampwsid(sampass
, user_sid
)) {
502 TALLOC_FREE(sampass
);
503 return NT_STATUS_NO_SUCH_USER
;
506 if (pdb_get_group_sid(sampass
) == NULL
) {
507 TALLOC_FREE(sampass
);
508 return NT_STATUS_NO_SUCH_GROUP
;
511 DEBUG(10,("sam_query_user: group sid %s\n",
512 sid_string_dbg(sampass
->group_sid
) ));
514 sid_copy(&user_info
->user_sid
, user_sid
);
515 sid_copy(&user_info
->group_sid
, sampass
->group_sid
);
517 user_info
->acct_name
= talloc_strdup(mem_ctx
, sampass
->username
?
518 sampass
->username
: "");
519 user_info
->full_name
= talloc_strdup(mem_ctx
, sampass
->full_name
?
520 sampass
->full_name
: "");
521 user_info
->homedir
= talloc_strdup(mem_ctx
, sampass
->home_dir
?
522 sampass
->home_dir
: "");
523 if (sampass
->unix_pw
&& sampass
->unix_pw
->pw_shell
) {
524 user_info
->shell
= talloc_strdup(mem_ctx
, sampass
->unix_pw
->pw_shell
);
526 user_info
->shell
= talloc_strdup(mem_ctx
, "");
528 user_info
->primary_gid
= sampass
->unix_pw
? sampass
->unix_pw
->pw_gid
: (gid_t
)-1;
530 TALLOC_FREE(sampass
);
534 /* Lookup group membership given a rid. */
535 static NTSTATUS
sam_lookup_groupmem(struct winbindd_domain
*domain
,
537 const DOM_SID
*group_sid
, uint32
*num_names
,
538 DOM_SID
**sid_mem
, char ***names
,
541 size_t i
, num_members
, num_mapped
;
544 const DOM_SID
**sids
;
545 struct lsa_dom_info
*lsa_domains
;
546 struct lsa_name_info
*lsa_names
;
549 if (!sid_check_is_in_our_domain(group_sid
)) {
550 /* There's no groups, only aliases in BUILTIN */
551 return NT_STATUS_NO_SUCH_GROUP
;
554 if (!(tmp_ctx
= talloc_init("lookup_groupmem"))) {
555 return NT_STATUS_NO_MEMORY
;
558 result
= pdb_enum_group_members(tmp_ctx
, group_sid
, &rids
,
560 if (!NT_STATUS_IS_OK(result
)) {
561 TALLOC_FREE(tmp_ctx
);
565 if (num_members
== 0) {
570 TALLOC_FREE(tmp_ctx
);
574 *sid_mem
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, num_members
);
575 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_members
);
576 *name_types
= TALLOC_ARRAY(mem_ctx
, uint32
, num_members
);
577 sids
= TALLOC_ARRAY(tmp_ctx
, const DOM_SID
*, num_members
);
579 if (((*sid_mem
) == NULL
) || ((*names
) == NULL
) ||
580 ((*name_types
) == NULL
) || (sids
== NULL
)) {
581 TALLOC_FREE(tmp_ctx
);
582 return NT_STATUS_NO_MEMORY
;
586 * Prepare an array of sid pointers for the lookup_sids calling
590 for (i
=0; i
<num_members
; i
++) {
591 DOM_SID
*sid
= &((*sid_mem
)[i
]);
592 if (!sid_compose(sid
, &domain
->sid
, rids
[i
])) {
593 TALLOC_FREE(tmp_ctx
);
594 return NT_STATUS_INTERNAL_ERROR
;
599 result
= lookup_sids(tmp_ctx
, num_members
, sids
, 1,
600 &lsa_domains
, &lsa_names
);
601 if (!NT_STATUS_IS_OK(result
)) {
602 TALLOC_FREE(tmp_ctx
);
607 for (i
=0; i
<num_members
; i
++) {
608 if (lsa_names
[i
].type
!= SID_NAME_USER
) {
609 DEBUG(2, ("Got %s as group member -- ignoring\n",
610 sid_type_lookup(lsa_names
[i
].type
)));
613 if (!((*names
)[i
] = talloc_strdup((*names
),
614 lsa_names
[i
].name
))) {
615 TALLOC_FREE(tmp_ctx
);
616 return NT_STATUS_NO_MEMORY
;
619 (*name_types
)[i
] = lsa_names
[i
].type
;
624 *num_names
= num_mapped
;
626 TALLOC_FREE(tmp_ctx
);
630 /* get a list of trusted domains */
631 static NTSTATUS
sam_trusted_domains(struct winbindd_domain
*domain
,
639 struct trustdom_info
**domains
;
648 if (!(tmp_ctx
= talloc_init("trusted_domains"))) {
649 return NT_STATUS_NO_MEMORY
;
652 nt_status
= pdb_enum_trusteddoms(tmp_ctx
, num_domains
, &domains
);
653 if (!NT_STATUS_IS_OK(nt_status
)) {
654 TALLOC_FREE(tmp_ctx
);
659 *names
= TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
660 *alt_names
= TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
661 *dom_sids
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
663 if ((*alt_names
== NULL
) || (*names
== NULL
) || (*dom_sids
== NULL
)) {
664 TALLOC_FREE(tmp_ctx
);
665 return NT_STATUS_NO_MEMORY
;
673 for (i
=0; i
<*num_domains
; i
++) {
674 (*alt_names
)[i
] = NULL
;
675 if (!((*names
)[i
] = talloc_strdup((*names
),
676 domains
[i
]->name
))) {
677 TALLOC_FREE(tmp_ctx
);
678 return NT_STATUS_NO_MEMORY
;
680 sid_copy(&(*dom_sids
)[i
], &domains
[i
]->sid
);
683 TALLOC_FREE(tmp_ctx
);
687 /* the rpc backend methods are exposed via this structure */
688 struct winbindd_methods builtin_passdb_methods
= {
690 builtin_query_user_list
,
699 builtin_lookup_groupmem
,
703 builtin_trusted_domains
,
706 /* the rpc backend methods are exposed via this structure */
707 struct winbindd_methods sam_passdb_methods
= {