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 ) ) {
223 return NT_STATUS_NO_SUCH_USER;
226 result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
230 *num_groups = (uint32)ngroups;
236 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
238 uint32 num_sids, const DOM_SID *sids,
239 uint32 *p_num_aliases, uint32 **rids)
242 size_t num_aliases = 0;
244 result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
245 sids, num_sids, rids, &num_aliases);
247 *p_num_aliases = num_aliases;
251 /* find the sequence number for a domain */
252 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
257 result = pdb_get_seq_num(&seq_num);
262 *seq = (int) seq_num;
267 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
269 SAM_UNK_INFO_12 *policy)
271 /* actually we have that */
272 return NT_STATUS_NOT_IMPLEMENTED;
275 static NTSTATUS password_policy(struct winbindd_domain *domain,
277 SAM_UNK_INFO_1 *policy)
279 uint32 min_pass_len,pass_hist,password_properties;
280 time_t u_expire, u_min_age;
281 NTTIME nt_expire, nt_min_age;
282 uint32 account_policy_temp;
284 if ((policy = TALLOC_ZERO_P(mem_ctx, SAM_UNK_INFO_1)) == NULL) {
285 return NT_STATUS_NO_MEMORY;
288 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
289 return NT_STATUS_ACCESS_DENIED;
291 min_pass_len = account_policy_temp;
293 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
294 return NT_STATUS_ACCESS_DENIED;
296 pass_hist = account_policy_temp;
298 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
299 return NT_STATUS_ACCESS_DENIED;
301 password_properties = account_policy_temp;
303 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
304 return NT_STATUS_ACCESS_DENIED;
306 u_expire = account_policy_temp;
308 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
309 return NT_STATUS_ACCESS_DENIED;
311 u_min_age = account_policy_temp;
313 unix_to_nt_time_abs(&nt_expire, u_expire);
314 unix_to_nt_time_abs(&nt_min_age, u_min_age);
316 init_unk_info1(policy, (uint16)min_pass_len, (uint16)pass_hist,
317 password_properties, nt_expire, nt_min_age);
322 /*********************************************************************
323 BUILTIN specific functions.
324 *********************************************************************/
326 /* list all domain groups */
327 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
330 struct acct_info **info)
332 /* BUILTIN doesn't have domain groups */
338 /* Query display info for a domain. This returns enough information plus a
339 bit extra to give an overview of domain users for the User Manager
341 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
344 WINBIND_USERINFO **info)
346 /* We don't have users */
352 /* Lookup user information from a rid or username. */
353 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
355 const DOM_SID *user_sid,
356 WINBIND_USERINFO *user_info)
358 return NT_STATUS_NO_SUCH_USER;
361 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
363 const DOM_SID *group_sid, uint32 *num_names,
364 DOM_SID **sid_mem, char ***names,
371 return NT_STATUS_NO_SUCH_GROUP;
374 /* get a list of trusted domains - builtin domain */
375 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
389 /*********************************************************************
390 SAM specific functions.
391 *********************************************************************/
393 /* list all domain groups */
394 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
397 struct acct_info **info)
399 return enum_groups_internal(domain,
406 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
409 WINBIND_USERINFO **info)
411 struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
412 struct samr_displayentry *entries = NULL;
419 return NT_STATUS_NO_MEMORY;
422 *num_entries = pdb_search_entries(ps,
426 *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
428 pdb_search_destroy(ps);
429 return NT_STATUS_NO_MEMORY;
432 for (i = 0; i < *num_entries; i++) {
433 struct samr_displayentry *e = &entries[i];
435 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
436 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
437 (*info)[i].homedir = NULL;
438 (*info)[i].shell = NULL;
439 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
441 /* For the moment we set the primary group for
442 every user to be the Domain Users group.
443 There are serious problems with determining
444 the actual primary group for large domains.
445 This should really be made into a 'winbind
446 force group' smb.conf parameter or
447 something like that. */
449 sid_compose(&(*info)[i].group_sid, &domain->sid,
450 DOMAIN_GROUP_RID_USERS);
453 pdb_search_destroy(ps);
457 /* Lookup user information from a rid or username. */
458 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
460 const DOM_SID *user_sid,
461 WINBIND_USERINFO *user_info)
463 struct samu *sampass = NULL;
466 ZERO_STRUCTP(user_info);
468 if (!sid_check_is_in_our_domain(user_sid)) {
469 return NT_STATUS_NO_SUCH_USER;
472 sid_to_string(sidstr, user_sid);
473 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
476 if (!(sampass = samu_new(mem_ctx))) {
477 return NT_STATUS_NO_MEMORY;
480 if (!pdb_getsampwsid(sampass, user_sid)) {
481 TALLOC_FREE(sampass);
482 return NT_STATUS_NO_SUCH_USER;
485 if (pdb_get_group_sid(sampass) == NULL) {
486 TALLOC_FREE(sampass);
487 return NT_STATUS_NO_SUCH_GROUP;
490 sid_to_string(sidstr, sampass->group_sid);
491 DEBUG(10,("sam_query_user: group sid %s\n", sidstr ));
493 sid_copy(&user_info->user_sid, user_sid);
494 sid_copy(&user_info->group_sid, sampass->group_sid);
496 user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
497 sampass->username : "");
498 user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
499 sampass->full_name : "");
500 user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
501 sampass->home_dir : "");
502 if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
503 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
505 user_info->shell = talloc_strdup(mem_ctx, "");
507 user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
509 TALLOC_FREE(sampass);
513 /* Lookup group membership given a rid. */
514 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
516 const DOM_SID *group_sid, uint32 *num_names,
517 DOM_SID **sid_mem, char ***names,
520 size_t i, num_members, num_mapped;
523 const DOM_SID **sids;
524 struct lsa_dom_info *lsa_domains;
525 struct lsa_name_info *lsa_names;
528 if (!sid_check_is_in_our_domain(group_sid)) {
529 /* There's no groups, only aliases in BUILTIN */
530 return NT_STATUS_NO_SUCH_GROUP;
533 if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
534 return NT_STATUS_NO_MEMORY;
537 result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
539 if (!NT_STATUS_IS_OK(result)) {
540 TALLOC_FREE(tmp_ctx);
544 if (num_members == 0) {
549 TALLOC_FREE(tmp_ctx);
553 *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
554 *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
555 *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
556 sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
558 if (((*sid_mem) == NULL) || ((*names) == NULL) ||
559 ((*name_types) == NULL) || (sids == NULL)) {
560 TALLOC_FREE(tmp_ctx);
561 return NT_STATUS_NO_MEMORY;
565 * Prepare an array of sid pointers for the lookup_sids calling
569 for (i=0; i<num_members; i++) {
570 DOM_SID *sid = &((*sid_mem)[i]);
571 if (!sid_compose(sid, &domain->sid, rids[i])) {
572 TALLOC_FREE(tmp_ctx);
573 return NT_STATUS_INTERNAL_ERROR;
578 result = lookup_sids(tmp_ctx, num_members, sids, 1,
579 &lsa_domains, &lsa_names);
580 if (!NT_STATUS_IS_OK(result)) {
581 TALLOC_FREE(tmp_ctx);
586 for (i=0; i<num_members; i++) {
587 if (lsa_names[i].type != SID_NAME_USER) {
588 DEBUG(2, ("Got %s as group member -- ignoring\n",
589 sid_type_lookup(lsa_names[i].type)));
592 if (!((*names)[i] = talloc_strdup((*names),
593 lsa_names[i].name))) {
594 TALLOC_FREE(tmp_ctx);
595 return NT_STATUS_NO_MEMORY;
598 (*name_types)[i] = lsa_names[i].type;
603 *num_names = num_mapped;
605 TALLOC_FREE(tmp_ctx);
609 /* get a list of trusted domains - sam */
610 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
618 struct trustdom_info **domains;
627 if (!(tmp_ctx = talloc_init("trusted_domains"))) {
628 return NT_STATUS_NO_MEMORY;
631 nt_status = secrets_trusted_domains(tmp_ctx, num_domains,
633 if (!NT_STATUS_IS_OK(nt_status)) {
634 TALLOC_FREE(tmp_ctx);
639 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
640 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
641 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
643 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
644 TALLOC_FREE(tmp_ctx);
645 return NT_STATUS_NO_MEMORY;
653 for (i=0; i<*num_domains; i++) {
654 (*alt_names)[i] = NULL;
655 if (!((*names)[i] = talloc_strdup((*names),
656 domains[i]->name))) {
657 TALLOC_FREE(tmp_ctx);
658 return NT_STATUS_NO_MEMORY;
660 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
663 TALLOC_FREE(tmp_ctx);
667 /* the rpc backend methods are exposed via this structure */
668 struct winbindd_methods builtin_passdb_methods = {
670 builtin_query_user_list,
671 builtin_enum_dom_groups,
679 builtin_lookup_groupmem,
683 builtin_trusted_domains,
686 /* the rpc backend methods are exposed via this structure */
687 struct winbindd_methods sam_passdb_methods = {