4 * Provider for RFC2307 and SFU AD Forests
6 * Copyright (C) Gerald (Jerry) Carter 2006-2008
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "idmap_adex.h"
27 #include "../libcli/ldap/ldap_ndr.h"
28 #include "../libcli/security/dom_sid.h"
31 #define DBGC_CLASS DBGC_IDMAP
33 /* Information needed by the LDAP search filters */
35 enum filterType
{ SidFilter
, IdFilter
, AliasFilter
};
39 enum filterType ftype
;
51 /********************************************************************
52 *******************************************************************/
54 static char* build_id_filter(TALLOC_CTX
*mem_ctx
,
57 uint32_t search_flags
)
60 char *oc_filter
, *attr_filter
;
62 TALLOC_CTX
*frame
= talloc_stackframe();
63 bool use2307
= ((search_flags
& LWCELL_FLAG_USE_RFC2307_ATTRS
)
64 == LWCELL_FLAG_USE_RFC2307_ATTRS
);
65 bool use_gc
= ((search_flags
& LWCELL_FLAG_SEARCH_FOREST
)
66 == LWCELL_FLAG_SEARCH_FOREST
);
69 /* Construct search filter for objectclass and attributes */
75 oc
= ADEX_OC_POSIX_USER
;
80 oc_filter
= talloc_asprintf(frame
, "objectclass=%s", oc
);
81 attr_filter
= talloc_asprintf(frame
, "%s=%u",
82 ADEX_ATTR_UIDNUM
, id
);
88 oc
= ADEX_OC_POSIX_GROUP
;
93 oc_filter
= talloc_asprintf(frame
, "objectclass=%s", oc
);
94 attr_filter
= talloc_asprintf(frame
, "%s=%u",
95 ADEX_ATTR_GIDNUM
, id
);
101 if (oc_filter
== NULL
) {
104 if (attr_filter
== NULL
) {
108 /* Use "keywords=%s" for non-schema cells */
111 filter
= talloc_asprintf(mem_ctx
,
116 filter
= talloc_asprintf(mem_ctx
,
117 "(&(keywords=%s)(keywords=%s))",
123 talloc_destroy(frame
);
128 /********************************************************************
129 *******************************************************************/
131 static char* build_alias_filter(TALLOC_CTX
*mem_ctx
,
133 uint32_t search_flags
)
136 char *user_attr_filter
, *group_attr_filter
;
137 TALLOC_CTX
*frame
= talloc_stackframe();
138 bool use2307
= ((search_flags
& LWCELL_FLAG_USE_RFC2307_ATTRS
)
139 == LWCELL_FLAG_USE_RFC2307_ATTRS
);
140 bool search_forest
= ((search_flags
& LWCELL_FLAG_SEARCH_FOREST
)
141 == LWCELL_FLAG_SEARCH_FOREST
);
143 /* Construct search filter for objectclass and attributes */
145 user_attr_filter
= talloc_asprintf(frame
, "%s=%s",
146 ADEX_ATTR_UID
, alias
);
147 group_attr_filter
= talloc_asprintf(frame
, "%s=%s",
148 ADEX_ATTR_DISPLAYNAME
, alias
);
149 if (user_attr_filter
== NULL
) {
152 if (group_attr_filter
== NULL
) {
156 /* Use "keywords=%s" for non-schema cells */
159 filter
= talloc_asprintf(mem_ctx
,
160 "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))",
162 search_forest
? AD_USER
: ADEX_OC_POSIX_USER
,
164 search_forest
? AD_GROUP
: ADEX_OC_POSIX_GROUP
);
166 filter
= talloc_asprintf(mem_ctx
,
167 "(|(keywords=%s)(keywords=%s))",
173 talloc_destroy(frame
);
179 /********************************************************************
180 *******************************************************************/
182 static NTSTATUS
search_cell(struct likewise_cell
*c
,
184 const struct lwcell_filter
*fdata
)
186 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
187 TALLOC_CTX
* frame
= talloc_stackframe();
189 const char *base
= NULL
;
190 ADS_STATUS ads_status
= ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
191 const char *attrs
[] = { "*", NULL
};
195 /* get the filter and other search parameters */
197 switch (fdata
->ftype
) {
199 sid_str
= sid_string_talloc(frame
, &fdata
->filter
.sid
);
200 BAIL_ON_PTR_ERROR(sid_str
, nt_status
);
202 filter
= talloc_asprintf(frame
, "(keywords=backLink=%s)",
206 filter
= build_id_filter(frame
,
208 fdata
->filter
.id
.type
,
212 filter
= build_alias_filter(frame
,
217 nt_status
= NT_STATUS_INVALID_PARAMETER
;
220 BAIL_ON_PTR_ERROR(filter
, nt_status
);
222 base
= cell_search_base(c
);
223 BAIL_ON_PTR_ERROR(base
, nt_status
);
225 ads_status
= cell_do_search(c
, base
, LDAP_SCOPE_SUBTREE
,
228 nt_status
= ads_ntstatus(ads_status
);
229 BAIL_ON_NTSTATUS_ERROR(nt_status
);
231 /* Now check that we got only one reply */
233 count
= ads_count_replies(c
->conn
, *msg
);
235 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
236 BAIL_ON_NTSTATUS_ERROR(nt_status
);
240 nt_status
= NT_STATUS_DUPLICATE_NAME
;
241 BAIL_ON_NTSTATUS_ERROR(nt_status
);
245 PRINT_NTSTATUS_ERROR(nt_status
, "search_cell", 4);
247 talloc_destroy(discard_const_p(char, base
));
248 talloc_destroy(frame
);
253 /********************************************************************
254 *******************************************************************/
256 static NTSTATUS
search_domain(struct likewise_cell
**cell
,
259 const struct dom_sid
*sid
)
261 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
262 TALLOC_CTX
* frame
= talloc_stackframe();
265 nt_status
= dc_search_domains(cell
, msg
, dn
, sid
);
266 BAIL_ON_NTSTATUS_ERROR(nt_status
);
268 /* Now check that we got only one reply */
270 count
= ads_count_replies(cell_connection(*cell
), *msg
);
272 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
273 BAIL_ON_NTSTATUS_ERROR(nt_status
);
277 nt_status
= NT_STATUS_DUPLICATE_NAME
;
278 BAIL_ON_NTSTATUS_ERROR(nt_status
);
282 PRINT_NTSTATUS_ERROR(nt_status
, "search_domain", 4);
283 talloc_destroy(frame
);
289 /********************************************************************
290 Check that a DN is within the forest scope.
291 *******************************************************************/
293 static bool check_forest_scope(const char *dn
)
295 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
296 TALLOC_CTX
*frame
= talloc_stackframe();
299 char *dns_domain
= NULL
;
300 struct winbindd_tdc_domain
*domain
;
302 /* If the DN does *not* contain "$LikewiseIdentityCell",
303 assume this is a schema mode forest and it is in the
304 forest scope by definition. */
306 if ((p
= strstr_m(dn
, ADEX_CELL_RDN
)) == NULL
) {
307 nt_status
= NT_STATUS_OK
;
311 /* If this is a non-schema forest, then make sure that the DN
312 is in the form "...,cn=$LikewiseIdentityCell,DC=..." */
314 if ((q
= strchr_m(p
, ',')) == NULL
) {
315 nt_status
= NT_STATUS_OBJECT_NAME_INVALID
;
316 BAIL_ON_NTSTATUS_ERROR(nt_status
);
320 if (strncasecmp_m(q
, "dc=", 3) != 0) {
321 nt_status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
322 BAIL_ON_NTSTATUS_ERROR(nt_status
);
326 dns_domain
= cell_dn_to_dns(q
);
327 BAIL_ON_PTR_ERROR(dns_domain
, nt_status
);
329 domain
= wcache_tdc_fetch_domain(frame
, dns_domain
);
331 nt_status
= NT_STATUS_TRUSTED_DOMAIN_FAILURE
;
332 BAIL_ON_NTSTATUS_ERROR(nt_status
);
335 nt_status
= NT_STATUS_OK
;
338 talloc_destroy(frame
);
339 SAFE_FREE(dns_domain
);
341 return NT_STATUS_IS_OK(nt_status
);
346 /********************************************************************
347 Check that only one result was returned within the forest cell
349 *******************************************************************/
351 static NTSTATUS
check_result_unique_scoped(ADS_STRUCT
**ads_list
,
352 LDAPMessage
**msg_list
,
355 struct dom_sid
*user_sid
)
357 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
359 ADS_STRUCT
*ads
= NULL
;
360 LDAPMessage
*msg
= NULL
;
362 char *entry_dn
= NULL
;
363 TALLOC_CTX
*frame
= talloc_stackframe();
365 if (!dn
|| !user_sid
) {
366 nt_status
= NT_STATUS_INVALID_PARAMETER
;
367 BAIL_ON_NTSTATUS_ERROR(nt_status
);
372 if (!ads_list
|| !msg_list
|| (num_resp
== 0)) {
373 nt_status
= NT_STATUS_NO_SUCH_FILE
;
374 BAIL_ON_NTSTATUS_ERROR(nt_status
);
377 /* Loop over all msgs */
379 for (i
=0; i
<num_resp
; i
++) {
380 LDAPMessage
*e
= ads_first_entry(ads_list
[i
], msg_list
[i
]);
383 entry_dn
= ads_get_dn(ads_list
[i
], talloc_tos(), e
);
384 BAIL_ON_PTR_ERROR(entry_dn
, nt_status
);
386 if (check_forest_scope(entry_dn
)) {
389 /* If we've already broken the condition, no
393 nt_status
= NT_STATUS_DUPLICATE_NAME
;
394 BAIL_ON_NTSTATUS_ERROR(nt_status
);
399 *dn
= SMB_STRDUP(entry_dn
);
400 BAIL_ON_PTR_ERROR((*dn
), nt_status
);
403 e
= ads_next_entry(ads_list
[i
], e
);
404 TALLOC_FREE(entry_dn
);
409 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
410 BAIL_ON_NTSTATUS_ERROR(nt_status
);
413 /* If we made is through the loop, then grab the user_sid and
417 Try and get the SID from either objectSid or keywords.
418 We cannot use pull_sid() here since we want to try
419 both methods and not only one or the other (and we
420 have no full likewise_cell struct.
422 Fail if both are unavailable
425 if (!ads_pull_sid(ads
, msg
, "objectSid", user_sid
)) {
428 size_t num_lines
= 0;
430 keywords
= ads_pull_strings(ads
, frame
, msg
, "keywords",
432 BAIL_ON_PTR_ERROR(keywords
, nt_status
);
434 s
= find_attr_string(keywords
, num_lines
, "backLink");
436 nt_status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
437 BAIL_ON_NTSTATUS_ERROR(nt_status
);
440 if (!string_to_sid(user_sid
, s
)) {
441 nt_status
= NT_STATUS_INVALID_SID
;
442 BAIL_ON_NTSTATUS_ERROR(nt_status
);
446 nt_status
= NT_STATUS_OK
;
449 if (!NT_STATUS_IS_OK(nt_status
)) {
453 talloc_destroy(frame
);
458 /********************************************************************
459 Search all forests. Each forest can have it's own forest-cell
460 settings so we have to generate the filter for each search.
461 We don't use gc_search_all_forests() since we may have a different
462 schema model in each forest and need to construct the search
463 filter for each GC search.
464 *******************************************************************/
466 static NTSTATUS
search_forest(struct likewise_cell
*forest_cell
,
468 const struct lwcell_filter
*fdata
)
470 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
471 TALLOC_CTX
*frame
= talloc_stackframe();
474 struct gc_info
*gc
= NULL
;
475 ADS_STRUCT
**ads_list
= NULL
;
476 LDAPMessage
**msg_list
= NULL
;
479 struct dom_sid user_sid
;
480 struct likewise_cell
*domain_cell
= NULL
;
482 if ((gc
= gc_search_start()) == NULL
) {
483 nt_status
= NT_STATUS_INVALID_DOMAIN_STATE
;
484 BAIL_ON_NTSTATUS_ERROR(nt_status
);
488 char *sid_binstr
= NULL
;
489 uint32_t flags
= LWCELL_FLAG_SEARCH_FOREST
;
493 flags
|= cell_flags(gc
->forest_cell
);
495 switch (fdata
->ftype
) {
497 sid_binstr
= ldap_encode_ndr_dom_sid(frame
, &fdata
->filter
.sid
);
498 BAIL_ON_PTR_ERROR(sid_binstr
, nt_status
);
500 filter
= talloc_asprintf(frame
, "(objectSid=%s)", sid_binstr
);
501 TALLOC_FREE(sid_binstr
);
504 filter
= build_id_filter(frame
,
506 fdata
->filter
.id
.type
, flags
);
509 filter
= build_alias_filter(frame
,
515 /* First find the sparse object in GC */
516 nt_status
= gc_search_forest(gc
, &m
, filter
);
517 if (!NT_STATUS_IS_OK(nt_status
)) {
522 nt_status
= add_ads_result_to_array(cell_connection(gc
->forest_cell
),
523 m
, &ads_list
, &msg_list
,
525 BAIL_ON_NTSTATUS_ERROR(nt_status
);
530 /* Uniqueness check across forests */
532 nt_status
= check_result_unique_scoped(ads_list
, msg_list
, num_resp
,
534 BAIL_ON_NTSTATUS_ERROR(nt_status
);
536 nt_status
= search_domain(&domain_cell
, &m
, dn
, &user_sid
);
537 BAIL_ON_NTSTATUS_ERROR(nt_status
);
539 /* Save the connection and results in the return parameters */
541 forest_cell
->gc_search_cell
= domain_cell
;
545 PRINT_NTSTATUS_ERROR(nt_status
, "search_forest", 4);
549 free_result_array(ads_list
, msg_list
, num_resp
);
550 talloc_destroy(frame
);
555 /********************************************************************
556 *******************************************************************/
558 static NTSTATUS
search_cell_list(struct likewise_cell
**c
,
560 const struct lwcell_filter
*fdata
)
562 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
563 struct likewise_cell
*cell
= NULL
;
564 LDAPMessage
*msg
= NULL
;
565 struct likewise_cell
*result_cell
= NULL
;
567 if ((cell
= cell_list_head()) == NULL
) {
568 nt_status
= NT_STATUS_INVALID_SERVER_STATE
;
569 BAIL_ON_NTSTATUS_ERROR(nt_status
);
573 /* Clear any previous GC search results */
575 cell
->gc_search_cell
= NULL
;
577 if (cell_search_forest(cell
)) {
578 nt_status
= search_forest(cell
, &msg
, fdata
);
580 nt_status
= search_cell(cell
, &msg
, fdata
);
583 /* Always point to the search result cell.
584 In forests this might be for another domain
585 which means the schema model may be different */
587 result_cell
= cell
->gc_search_cell
?
588 cell
->gc_search_cell
: cell
;
590 /* Check if we are done */
592 if (NT_STATUS_IS_OK(nt_status
)) {
596 /* No luck. Free memory and hit the next cell.
597 Forest searches always set the gc_search_cell
598 so give preference to that connection if possible. */
600 ads_msgfree(cell_connection(result_cell
), msg
);
606 /* This might be assigning NULL but that is ok as long as we
607 give back the proper error code */
613 PRINT_NTSTATUS_ERROR(nt_status
, "search_cell_list", 3);
618 /********************************************************************
619 Pull the SID from an object which is always stored in the keywords
620 attribute as "backLink=S-1-5-21-..."
621 *******************************************************************/
623 static NTSTATUS
pull_sid(struct likewise_cell
*c
,
627 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
628 TALLOC_CTX
*frame
= talloc_stackframe();
629 ADS_STRUCT
*ads
= NULL
;
631 ads
= cell_connection(c
);
634 We have two ways of getting the sid:
635 (a) from the objectSID in case of a GC search,
636 (b) from backLink in the case of a cell search.
637 Pull the keywords attributes and grab the backLink.
640 if (!ads_pull_sid(ads
, msg
, "objectSid", sid
)) {
643 size_t num_lines
= 0;
645 keywords
= ads_pull_strings(ads
, frame
, msg
,
646 "keywords", &num_lines
);
647 BAIL_ON_PTR_ERROR(keywords
, nt_status
);
649 s
= find_attr_string(keywords
, num_lines
, "backLink");
651 nt_status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
652 BAIL_ON_NTSTATUS_ERROR(nt_status
);
655 if (!string_to_sid(sid
, s
)) {
656 nt_status
= NT_STATUS_INVALID_SID
;
657 BAIL_ON_NTSTATUS_ERROR(nt_status
);
661 nt_status
= NT_STATUS_OK
;
664 talloc_destroy(frame
);
669 /********************************************************************
670 *******************************************************************/
672 static NTSTATUS
get_object_type(struct likewise_cell
*c
,
676 TALLOC_CTX
*ctx
= talloc_stackframe();
677 char **oc_list
= NULL
;
678 NTSTATUS nt_status
= NT_STATUS_OK
;
679 size_t list_size
= 0;
681 ADS_STRUCT
*ads
= NULL
;
683 ads
= cell_connection(c
);
685 /* Deal with RFC 2307 support first */
687 if (cell_flags(c
) & LWCELL_FLAG_USE_RFC2307_ATTRS
) {
688 oc_list
= ads_pull_strings(ads
, ctx
, msg
,
689 "objectClass", &list_size
);
691 nt_status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
695 /* Check for posix classes and AD classes */
697 if (is_object_class(oc_list
, list_size
, ADEX_OC_POSIX_USER
)
698 || is_object_class(oc_list
, list_size
, AD_USER
)) {
700 } else if (is_object_class(oc_list
, list_size
, ADEX_OC_POSIX_GROUP
)
701 || is_object_class(oc_list
, list_size
, AD_GROUP
)) {
704 *type
= ID_TYPE_NOT_SPECIFIED
;
705 nt_status
= NT_STATUS_INVALID_PARAMETER
;
708 /* Default to non-schema mode */
710 oc_list
= ads_pull_strings(ads
, ctx
, msg
,
711 "keywords", &list_size
);
713 nt_status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
717 s
= find_attr_string(oc_list
, list_size
, "objectClass");
719 nt_status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
723 if (strequal(s
, ADEX_OC_USER
)) {
725 } else if (strequal(s
, ADEX_OC_GROUP
)) {
728 *type
= ID_TYPE_NOT_SPECIFIED
;
729 nt_status
= NT_STATUS_INVALID_PARAMETER
;
733 nt_status
= NT_STATUS_OK
;
741 /********************************************************************
742 Pull an attribute uint32_t value
743 *******************************************************************/
745 static NTSTATUS
get_object_uint32(struct likewise_cell
*c
,
750 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
751 char **keywords
= NULL
;
752 size_t list_size
= 0;
753 TALLOC_CTX
*frame
= talloc_stackframe();
754 ADS_STRUCT
*ads
= NULL
;
756 ads
= cell_connection(c
);
758 /* Deal with RFC2307 schema */
760 if (cell_flags(c
) & LWCELL_FLAG_USE_RFC2307_ATTRS
) {
761 if (!ads_pull_uint32(ads
, msg
, attrib
, x
)) {
762 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
763 BAIL_ON_NTSTATUS_ERROR(nt_status
);
766 /* Non-schema mode */
770 keywords
= ads_pull_strings(ads
, frame
, msg
, "keywords",
772 BAIL_ON_PTR_ERROR(keywords
, nt_status
);
774 s
= find_attr_string(keywords
, list_size
, attrib
);
776 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
777 BAIL_ON_NTSTATUS_ERROR(nt_status
);
780 num
= strtoll(s
, NULL
, 10);
781 if (errno
== ERANGE
) {
782 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
783 BAIL_ON_NTSTATUS_ERROR(nt_status
);
788 nt_status
= NT_STATUS_OK
;
791 talloc_destroy(frame
);
796 /********************************************************************
797 *******************************************************************/
799 static NTSTATUS
get_object_id(struct likewise_cell
*c
,
804 NTSTATUS nt_status
= NT_STATUS_OK
;
807 /* Figure out which attribute we need to pull */
811 id_attr
= ADEX_ATTR_UIDNUM
;
814 id_attr
= ADEX_ATTR_GIDNUM
;
817 nt_status
= NT_STATUS_INVALID_PARAMETER
;
818 BAIL_ON_NTSTATUS_ERROR(nt_status
);
822 nt_status
= get_object_uint32(c
, msg
, id_attr
, id
);
823 BAIL_ON_NTSTATUS_ERROR(nt_status
);
829 /********************************************************************
830 Pull the uid/gid and type from an object. This differs depending on
832 *******************************************************************/
834 static NTSTATUS
pull_id(struct likewise_cell
*c
,
841 nt_status
= get_object_type(c
, msg
, type
);
842 BAIL_ON_NTSTATUS_ERROR(nt_status
);
844 nt_status
= get_object_id(c
, msg
, *type
, id
);
845 BAIL_ON_NTSTATUS_ERROR(nt_status
);
851 /********************************************************************
852 Pull an attribute string value
853 *******************************************************************/
855 static NTSTATUS
get_object_string(struct likewise_cell
*c
,
861 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
862 char **keywords
= NULL
;
863 size_t list_size
= 0;
864 TALLOC_CTX
*frame
= talloc_stackframe();
865 ADS_STRUCT
*ads
= NULL
;
869 ads
= cell_connection(c
);
871 /* Deal with RFC2307 schema */
873 if (cell_flags(c
) & LWCELL_FLAG_USE_RFC2307_ATTRS
) {
874 *string
= ads_pull_string(ads
, ctx
, msg
, attrib
);
876 /* Non-schema mode */
880 keywords
= ads_pull_strings(ads
, frame
, msg
,
881 "keywords", &list_size
);
883 nt_status
= NT_STATUS_NO_MEMORY
;
884 BAIL_ON_NTSTATUS_ERROR(nt_status
);
886 s
= find_attr_string(keywords
, list_size
, attrib
);
888 *string
= talloc_strdup(ctx
, s
);
893 nt_status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
894 BAIL_ON_NTSTATUS_ERROR(nt_status
);
897 nt_status
= NT_STATUS_OK
;
900 talloc_destroy(frame
);
905 /********************************************************************
906 Pull the struct passwd fields for a user
907 *******************************************************************/
909 static NTSTATUS
pull_nss_info(struct likewise_cell
*c
,
912 const char **homedir
,
920 nt_status
= get_object_string(c
, msg
, ctx
, ADEX_ATTR_HOMEDIR
, &tmp
);
921 BAIL_ON_NTSTATUS_ERROR(nt_status
);
924 nt_status
= get_object_string(c
, msg
, ctx
, ADEX_ATTR_SHELL
, &tmp
);
925 BAIL_ON_NTSTATUS_ERROR(nt_status
);
928 nt_status
= get_object_string(c
, msg
, ctx
, ADEX_ATTR_GECOS
, &tmp
);
929 /* Gecos is often not set so ignore failures */
932 nt_status
= get_object_uint32(c
, msg
, ADEX_ATTR_GIDNUM
, p_gid
);
933 BAIL_ON_NTSTATUS_ERROR(nt_status
);
939 /********************************************************************
940 Pull the struct passwd fields for a user
941 *******************************************************************/
943 static NTSTATUS
pull_alias(struct likewise_cell
*c
,
948 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
950 const char *attr
= NULL
;
952 /* Figure out if this is a user or a group */
954 nt_status
= get_object_type(c
, msg
, &type
);
955 BAIL_ON_NTSTATUS_ERROR(nt_status
);
959 attr
= ADEX_ATTR_UID
;
962 /* What is the group attr for RFC2307 Forests? */
963 attr
= ADEX_ATTR_DISPLAYNAME
;
966 nt_status
= NT_STATUS_INVALID_PARAMETER
;
967 BAIL_ON_NTSTATUS_ERROR(nt_status
);
971 nt_status
= get_object_string(c
, msg
, ctx
, attr
, alias
);
972 BAIL_ON_NTSTATUS_ERROR(nt_status
);
978 /********************************************************************
979 *******************************************************************/
981 static NTSTATUS
_ccp_get_sid_from_id(struct dom_sid
* sid
,
982 uint32_t id
, enum id_type type
)
984 struct likewise_cell
*cell
= NULL
;
985 LDAPMessage
*msg
= NULL
;
987 struct lwcell_filter filter
;
989 filter
.ftype
= IdFilter
;
990 filter
.filter
.id
.id
= id
;
991 filter
.filter
.id
.type
= type
;
993 nt_status
= search_cell_list(&cell
, &msg
, &filter
);
994 BAIL_ON_NTSTATUS_ERROR(nt_status
);
996 nt_status
= pull_sid(cell
, msg
, sid
);
997 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1000 ads_msgfree(cell
->conn
, msg
);
1005 /********************************************************************
1006 *******************************************************************/
1008 static NTSTATUS
_ccp_get_id_from_sid(uint32_t * id
,
1010 const struct dom_sid
* sid
)
1012 struct likewise_cell
*cell
= NULL
;
1013 LDAPMessage
*msg
= NULL
;
1015 struct lwcell_filter filter
;
1017 filter
.ftype
= SidFilter
;
1018 sid_copy(&filter
.filter
.sid
, sid
);
1020 nt_status
= search_cell_list(&cell
, &msg
, &filter
);
1021 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1023 nt_status
= pull_id(cell
, msg
, id
, type
);
1024 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1026 if (*id
< min_id_value()) {
1027 nt_status
= NT_STATUS_INVALID_PARAMETER
;
1028 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1032 ads_msgfree(cell
->conn
, msg
);
1037 /********************************************************************
1038 *******************************************************************/
1040 static NTSTATUS
_ccp_nss_get_info(const struct dom_sid
* sid
,
1042 const char **homedir
,
1044 const char **gecos
, gid_t
* p_gid
)
1046 struct likewise_cell
*cell
= NULL
;
1047 LDAPMessage
*msg
= NULL
;
1049 struct lwcell_filter filter
;
1052 filter
.ftype
= SidFilter
;
1053 sid_copy(&filter
.filter
.sid
, sid
);
1055 nt_status
= search_cell_list(&cell
, &msg
, &filter
);
1056 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1058 nt_status
= get_object_type(cell
, msg
, &type
);
1059 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1061 if (type
!= ID_TYPE_UID
) {
1062 nt_status
= NT_STATUS_NO_SUCH_USER
;
1063 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1066 nt_status
= pull_nss_info(cell
, msg
, ctx
, homedir
, shell
, gecos
,
1068 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1071 ads_msgfree(cell
->conn
, msg
);
1076 /**********************************************************************
1077 *********************************************************************/
1079 static NTSTATUS
_ccp_map_to_alias(TALLOC_CTX
*ctx
,
1081 const char *name
, char **alias
)
1083 TALLOC_CTX
*frame
= talloc_stackframe();
1084 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1086 struct likewise_cell
*cell
= NULL
;
1087 LDAPMessage
*msg
= NULL
;
1088 struct lwcell_filter filter
;
1089 enum lsa_SidType sid_type
;
1091 /* Convert the name to a SID */
1093 nt_status
= gc_name_to_sid(domain
, name
, &sid
, &sid_type
);
1094 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1096 /* Find the user/group */
1098 filter
.ftype
= SidFilter
;
1099 sid_copy(&filter
.filter
.sid
, &sid
);
1101 nt_status
= search_cell_list(&cell
, &msg
, &filter
);
1102 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1104 /* Pull the alias and return */
1106 nt_status
= pull_alias(cell
, msg
, ctx
, alias
);
1107 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1110 PRINT_NTSTATUS_ERROR(nt_status
, "map_to_alias", 3);
1112 talloc_destroy(frame
);
1113 ads_msgfree(cell_connection(cell
), msg
);
1118 /**********************************************************************
1119 Map from an alias name to the canonical, qualified name.
1120 Ensure that the alias is only pull from the closest in which
1121 the user or gorup is enabled in
1122 *********************************************************************/
1124 static NTSTATUS
_ccp_map_from_alias(TALLOC_CTX
*mem_ctx
,
1126 const char *alias
, char **name
)
1128 TALLOC_CTX
*frame
= talloc_stackframe();
1129 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1131 struct likewise_cell
*cell_alias
= NULL
;
1132 LDAPMessage
*msg_alias
= NULL
;
1133 struct likewise_cell
*cell_sid
= NULL
;
1134 LDAPMessage
*msg_sid
= NULL
;
1135 struct lwcell_filter filter
;
1136 char *canonical_name
= NULL
;
1137 enum lsa_SidType type
;
1139 /* Find the user/group */
1141 filter
.ftype
= AliasFilter
;
1142 fstrcpy(filter
.filter
.alias
, alias
);
1144 nt_status
= search_cell_list(&cell_alias
, &msg_alias
, &filter
);
1145 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1147 nt_status
= pull_sid(cell_alias
, msg_alias
, &sid
);
1148 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1150 /* Now search again for the SID according to the cell list.
1151 Verify that the cell of both search results is the same
1152 so that we only match an alias from the closest cell
1153 in which a user/group has been instantied. */
1155 filter
.ftype
= SidFilter
;
1156 sid_copy(&filter
.filter
.sid
, &sid
);
1158 nt_status
= search_cell_list(&cell_sid
, &msg_sid
, &filter
);
1159 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1161 if (cell_alias
!= cell_sid
) {
1162 nt_status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1163 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1166 /* Finally do the GC sid/name conversion */
1168 nt_status
= gc_sid_to_name(&sid
, &canonical_name
, &type
);
1169 BAIL_ON_NTSTATUS_ERROR(nt_status
);
1171 *name
= talloc_strdup(mem_ctx
, canonical_name
);
1172 BAIL_ON_PTR_ERROR((*name
), nt_status
);
1174 nt_status
= NT_STATUS_OK
;
1177 PRINT_NTSTATUS_ERROR(nt_status
, "map_from_alias", 3);
1179 ads_msgfree(cell_connection(cell_alias
), msg_alias
);
1180 ads_msgfree(cell_connection(cell_sid
), msg_sid
);
1182 SAFE_FREE(canonical_name
);
1184 talloc_destroy(frame
);
1189 /********************************************************************
1190 *******************************************************************/
1192 struct cell_provider_api ccp_unified
= {
1193 .get_sid_from_id
= _ccp_get_sid_from_id
,
1194 .get_id_from_sid
= _ccp_get_id_from_sid
,
1195 .get_nss_info
= _ccp_nss_get_info
,
1196 .map_to_alias
= _ccp_map_to_alias
,
1197 .map_from_alias
= _ccp_map_from_alias