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
;
99 switch ( original_cmd
) {
100 case WINBINDD_LOOKUPNAME
:
101 /* This call is ok */
104 /* Avoid any NSS calls in the lookup_name by default */
105 flags
|= LOOKUP_NAME_EXPLICIT
;
106 DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
110 DEBUG(10, ("Finding name %s\n", name
));
112 if ( !lookup_name( mem_ctx
, name
, flags
, NULL
, NULL
, sid
, type
) ) {
113 return NT_STATUS_NONE_MAPPED
;
120 convert a domain SID to a user or group name
122 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
127 enum lsa_SidType
*type
)
129 const char *dom
, *nam
;
131 DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid
)));
134 if (!sid_check_is_in_builtin(sid
) &&
135 !sid_check_is_in_our_domain(sid
) &&
136 !sid_check_is_in_unix_users(sid
) &&
137 !sid_check_is_unix_users(sid
) &&
138 !sid_check_is_in_unix_groups(sid
) &&
139 !sid_check_is_unix_groups(sid
) &&
140 !sid_check_is_in_wellknown_domain(sid
))
142 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
143 "passdb backend\n", sid_string_dbg(sid
)));
144 return NT_STATUS_NONE_MAPPED
;
147 if (!lookup_sid(mem_ctx
, sid
, &dom
, &nam
, type
)) {
148 return NT_STATUS_NONE_MAPPED
;
151 *domain_name
= talloc_strdup(mem_ctx
, dom
);
152 *name
= talloc_strdup(mem_ctx
, nam
);
157 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
164 enum lsa_SidType
**types
)
179 if (!sid_check_is_in_builtin(sid
) &&
180 !sid_check_is_in_our_domain(sid
) &&
181 !sid_check_is_in_unix_users(sid
) &&
182 !sid_check_is_unix_users(sid
) &&
183 !sid_check_is_in_unix_groups(sid
) &&
184 !sid_check_is_unix_groups(sid
) &&
185 !sid_check_is_in_wellknown_domain(sid
))
187 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
188 "passdb backend\n", sid_string_dbg(sid
)));
189 return NT_STATUS_NONE_MAPPED
;
192 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
193 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
195 if ((*names
== NULL
) || (*types
== NULL
)) {
196 return NT_STATUS_NO_MEMORY
;
199 have_mapped
= have_unmapped
= false;
201 for (i
=0; i
<num_rids
; i
++) {
203 const char *dom
= NULL
, *nam
= NULL
;
204 enum lsa_SidType type
= SID_NAME_UNKNOWN
;
206 if (!sid_compose(&lsid
, sid
, rids
[i
])) {
207 return NT_STATUS_INTERNAL_ERROR
;
210 if (!lookup_sid(mem_ctx
, &lsid
, &dom
, &nam
, &type
)) {
211 have_unmapped
= true;
212 (*types
)[i
] = SID_NAME_UNKNOWN
;
213 (*names
)[i
] = talloc_strdup(mem_ctx
, "");
217 (*names
)[i
] = CONST_DISCARD(char *, nam
);
220 if (domain_name
== NULL
) {
221 *domain_name
= CONST_DISCARD(char *, dom
);
223 char *dname
= CONST_DISCARD(char *, dom
);
229 return NT_STATUS_NONE_MAPPED
;
231 if (!have_unmapped
) {
234 return STATUS_SOME_UNMAPPED
;
237 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
238 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
240 const DOM_SID
*user_sid
,
241 uint32
*num_groups
, DOM_SID
**user_gids
)
244 DOM_SID
*groups
= NULL
;
249 if ( (user
= samu_new(mem_ctx
)) == NULL
) {
250 return NT_STATUS_NO_MEMORY
;
253 if ( !pdb_getsampwsid( user
, user_sid
) ) {
254 return NT_STATUS_NO_SUCH_USER
;
257 result
= pdb_enum_group_memberships( mem_ctx
, user
, &groups
, &gids
, &ngroups
);
261 *num_groups
= (uint32
)ngroups
;
267 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
269 uint32 num_sids
, const DOM_SID
*sids
,
270 uint32
*p_num_aliases
, uint32
**rids
)
273 size_t num_aliases
= 0;
275 result
= pdb_enum_alias_memberships(mem_ctx
, &domain
->sid
,
276 sids
, num_sids
, rids
, &num_aliases
);
278 *p_num_aliases
= num_aliases
;
282 /* find the sequence number for a domain */
283 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
288 result
= pdb_get_seq_num(&seq_num
);
293 *seq
= (int) seq_num
;
298 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
300 struct samr_DomInfo12
*policy
)
302 /* actually we have that */
303 return NT_STATUS_NOT_IMPLEMENTED
;
306 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
308 struct samr_DomInfo1
*policy
)
310 uint32 min_pass_len
,pass_hist
,password_properties
;
311 time_t u_expire
, u_min_age
;
312 NTTIME nt_expire
, nt_min_age
;
313 uint32 account_policy_temp
;
315 if ((policy
= TALLOC_ZERO_P(mem_ctx
, struct samr_DomInfo1
)) == NULL
) {
316 return NT_STATUS_NO_MEMORY
;
319 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN
, &account_policy_temp
)) {
320 return NT_STATUS_ACCESS_DENIED
;
322 min_pass_len
= account_policy_temp
;
324 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY
, &account_policy_temp
)) {
325 return NT_STATUS_ACCESS_DENIED
;
327 pass_hist
= account_policy_temp
;
329 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS
, &account_policy_temp
)) {
330 return NT_STATUS_ACCESS_DENIED
;
332 password_properties
= account_policy_temp
;
334 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE
, &account_policy_temp
)) {
335 return NT_STATUS_ACCESS_DENIED
;
337 u_expire
= account_policy_temp
;
339 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE
, &account_policy_temp
)) {
340 return NT_STATUS_ACCESS_DENIED
;
342 u_min_age
= account_policy_temp
;
344 unix_to_nt_time_abs(&nt_expire
, u_expire
);
345 unix_to_nt_time_abs(&nt_min_age
, u_min_age
);
347 init_samr_DomInfo1(policy
,
348 (uint16
)min_pass_len
,
357 /*********************************************************************
358 BUILTIN specific functions.
359 *********************************************************************/
361 /* list all domain groups */
362 static NTSTATUS
builtin_enum_dom_groups(struct winbindd_domain
*domain
,
365 struct acct_info
**info
)
367 /* BUILTIN doesn't have domain groups */
373 /* Query display info for a domain. This returns enough information plus a
374 bit extra to give an overview of domain users for the User Manager
376 static NTSTATUS
builtin_query_user_list(struct winbindd_domain
*domain
,
379 WINBIND_USERINFO
**info
)
381 /* We don't have users */
387 /* Lookup user information from a rid or username. */
388 static NTSTATUS
builtin_query_user(struct winbindd_domain
*domain
,
390 const DOM_SID
*user_sid
,
391 WINBIND_USERINFO
*user_info
)
393 return NT_STATUS_NO_SUCH_USER
;
396 static NTSTATUS
builtin_lookup_groupmem(struct winbindd_domain
*domain
,
398 const DOM_SID
*group_sid
, uint32
*num_names
,
399 DOM_SID
**sid_mem
, char ***names
,
406 return NT_STATUS_NO_SUCH_GROUP
;
409 /* get a list of trusted domains - builtin domain */
410 static NTSTATUS
builtin_trusted_domains(struct winbindd_domain
*domain
,
424 /*********************************************************************
425 SAM specific functions.
426 *********************************************************************/
428 /* list all domain groups */
429 static NTSTATUS
sam_enum_dom_groups(struct winbindd_domain
*domain
,
432 struct acct_info
**info
)
434 return enum_groups_internal(domain
,
441 static NTSTATUS
sam_query_user_list(struct winbindd_domain
*domain
,
444 WINBIND_USERINFO
**info
)
446 struct pdb_search
*ps
= pdb_search_users(ACB_NORMAL
);
447 struct samr_displayentry
*entries
= NULL
;
454 return NT_STATUS_NO_MEMORY
;
457 *num_entries
= pdb_search_entries(ps
,
461 *info
= TALLOC_ZERO_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
463 pdb_search_destroy(ps
);
464 return NT_STATUS_NO_MEMORY
;
467 for (i
= 0; i
< *num_entries
; i
++) {
468 struct samr_displayentry
*e
= &entries
[i
];
470 (*info
)[i
].acct_name
= talloc_strdup(mem_ctx
, e
->account_name
);
471 (*info
)[i
].full_name
= talloc_strdup(mem_ctx
, e
->fullname
);
472 (*info
)[i
].homedir
= NULL
;
473 (*info
)[i
].shell
= NULL
;
474 sid_compose(&(*info
)[i
].user_sid
, &domain
->sid
, e
->rid
);
476 /* For the moment we set the primary group for
477 every user to be the Domain Users group.
478 There are serious problems with determining
479 the actual primary group for large domains.
480 This should really be made into a 'winbind
481 force group' smb.conf parameter or
482 something like that. */
484 sid_compose(&(*info
)[i
].group_sid
, &domain
->sid
,
485 DOMAIN_GROUP_RID_USERS
);
488 pdb_search_destroy(ps
);
492 /* Lookup user information from a rid or username. */
493 static NTSTATUS
sam_query_user(struct winbindd_domain
*domain
,
495 const DOM_SID
*user_sid
,
496 WINBIND_USERINFO
*user_info
)
498 struct samu
*sampass
= NULL
;
500 ZERO_STRUCTP(user_info
);
502 if (!sid_check_is_in_our_domain(user_sid
)) {
503 return NT_STATUS_NO_SUCH_USER
;
506 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
507 sid_string_dbg(user_sid
) ));
509 if (!(sampass
= samu_new(mem_ctx
))) {
510 return NT_STATUS_NO_MEMORY
;
513 if (!pdb_getsampwsid(sampass
, user_sid
)) {
514 TALLOC_FREE(sampass
);
515 return NT_STATUS_NO_SUCH_USER
;
518 if (pdb_get_group_sid(sampass
) == NULL
) {
519 TALLOC_FREE(sampass
);
520 return NT_STATUS_NO_SUCH_GROUP
;
523 DEBUG(10,("sam_query_user: group sid %s\n",
524 sid_string_dbg(sampass
->group_sid
) ));
526 sid_copy(&user_info
->user_sid
, user_sid
);
527 sid_copy(&user_info
->group_sid
, sampass
->group_sid
);
529 user_info
->acct_name
= talloc_strdup(mem_ctx
, sampass
->username
?
530 sampass
->username
: "");
531 user_info
->full_name
= talloc_strdup(mem_ctx
, sampass
->full_name
?
532 sampass
->full_name
: "");
533 user_info
->homedir
= talloc_strdup(mem_ctx
, sampass
->home_dir
?
534 sampass
->home_dir
: "");
535 if (sampass
->unix_pw
&& sampass
->unix_pw
->pw_shell
) {
536 user_info
->shell
= talloc_strdup(mem_ctx
, sampass
->unix_pw
->pw_shell
);
538 user_info
->shell
= talloc_strdup(mem_ctx
, "");
540 user_info
->primary_gid
= sampass
->unix_pw
? sampass
->unix_pw
->pw_gid
: (gid_t
)-1;
542 TALLOC_FREE(sampass
);
546 /* Lookup group membership given a rid. */
547 static NTSTATUS
sam_lookup_groupmem(struct winbindd_domain
*domain
,
549 const DOM_SID
*group_sid
, uint32
*num_names
,
550 DOM_SID
**sid_mem
, char ***names
,
553 size_t i
, num_members
, num_mapped
;
556 const DOM_SID
**sids
;
557 struct lsa_dom_info
*lsa_domains
;
558 struct lsa_name_info
*lsa_names
;
561 if (!sid_check_is_in_our_domain(group_sid
)) {
562 /* There's no groups, only aliases in BUILTIN */
563 return NT_STATUS_NO_SUCH_GROUP
;
566 if (!(tmp_ctx
= talloc_init("lookup_groupmem"))) {
567 return NT_STATUS_NO_MEMORY
;
570 result
= pdb_enum_group_members(tmp_ctx
, group_sid
, &rids
,
572 if (!NT_STATUS_IS_OK(result
)) {
573 TALLOC_FREE(tmp_ctx
);
577 if (num_members
== 0) {
582 TALLOC_FREE(tmp_ctx
);
586 *sid_mem
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, num_members
);
587 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_members
);
588 *name_types
= TALLOC_ARRAY(mem_ctx
, uint32
, num_members
);
589 sids
= TALLOC_ARRAY(tmp_ctx
, const DOM_SID
*, num_members
);
591 if (((*sid_mem
) == NULL
) || ((*names
) == NULL
) ||
592 ((*name_types
) == NULL
) || (sids
== NULL
)) {
593 TALLOC_FREE(tmp_ctx
);
594 return NT_STATUS_NO_MEMORY
;
598 * Prepare an array of sid pointers for the lookup_sids calling
602 for (i
=0; i
<num_members
; i
++) {
603 DOM_SID
*sid
= &((*sid_mem
)[i
]);
604 if (!sid_compose(sid
, &domain
->sid
, rids
[i
])) {
605 TALLOC_FREE(tmp_ctx
);
606 return NT_STATUS_INTERNAL_ERROR
;
611 result
= lookup_sids(tmp_ctx
, num_members
, sids
, 1,
612 &lsa_domains
, &lsa_names
);
613 if (!NT_STATUS_IS_OK(result
)) {
614 TALLOC_FREE(tmp_ctx
);
619 for (i
=0; i
<num_members
; i
++) {
620 if (lsa_names
[i
].type
!= SID_NAME_USER
) {
621 DEBUG(2, ("Got %s as group member -- ignoring\n",
622 sid_type_lookup(lsa_names
[i
].type
)));
625 if (!((*names
)[i
] = talloc_strdup((*names
),
626 lsa_names
[i
].name
))) {
627 TALLOC_FREE(tmp_ctx
);
628 return NT_STATUS_NO_MEMORY
;
631 (*name_types
)[i
] = lsa_names
[i
].type
;
636 *num_names
= num_mapped
;
638 TALLOC_FREE(tmp_ctx
);
642 /* get a list of trusted domains */
643 static NTSTATUS
sam_trusted_domains(struct winbindd_domain
*domain
,
651 struct trustdom_info
**domains
;
660 if (!(tmp_ctx
= talloc_init("trusted_domains"))) {
661 return NT_STATUS_NO_MEMORY
;
664 nt_status
= pdb_enum_trusteddoms(tmp_ctx
, num_domains
, &domains
);
665 if (!NT_STATUS_IS_OK(nt_status
)) {
666 TALLOC_FREE(tmp_ctx
);
671 *names
= TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
672 *alt_names
= TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
673 *dom_sids
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
675 if ((*alt_names
== NULL
) || (*names
== NULL
) || (*dom_sids
== NULL
)) {
676 TALLOC_FREE(tmp_ctx
);
677 return NT_STATUS_NO_MEMORY
;
685 for (i
=0; i
<*num_domains
; i
++) {
686 (*alt_names
)[i
] = NULL
;
687 if (!((*names
)[i
] = talloc_strdup((*names
),
688 domains
[i
]->name
))) {
689 TALLOC_FREE(tmp_ctx
);
690 return NT_STATUS_NO_MEMORY
;
692 sid_copy(&(*dom_sids
)[i
], &domains
[i
]->sid
);
695 TALLOC_FREE(tmp_ctx
);
699 /* the rpc backend methods are exposed via this structure */
700 struct winbindd_methods builtin_passdb_methods
= {
702 builtin_query_user_list
,
703 builtin_enum_dom_groups
,
711 builtin_lookup_groupmem
,
715 builtin_trusted_domains
,
718 /* the rpc backend methods are exposed via this structure */
719 struct winbindd_methods sam_passdb_methods
= {