lib/registry/util.c - Reorder the registry datatypes of the conversion functions
[Samba/ekacnet.git] / source3 / winbindd / idmap_adex / provider_unified.c
blobaf334057471b93635cfd162d29326e0c6a637922
1 /*
2 * idmap_adex
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.
23 #include "includes.h"
24 #include "idmap_adex.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_IDMAP
29 /* Information needed by the LDAP search filters */
31 enum filterType { SidFilter, IdFilter, AliasFilter };
33 struct lwcell_filter
35 enum filterType ftype;
36 bool use2307;
37 union {
38 DOM_SID sid;
39 struct {
40 uint32_t id;
41 enum id_type type;
42 } id;
43 fstring alias;
44 } filter;
47 /********************************************************************
48 *******************************************************************/
50 static char* build_id_filter(TALLOC_CTX *mem_ctx,
51 uint32_t id,
52 enum id_type type,
53 uint32_t search_flags)
55 char *filter = NULL;
56 char *oc_filter, *attr_filter;
57 NTSTATUS nt_status;
58 TALLOC_CTX *frame = talloc_stackframe();
59 bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
60 == LWCELL_FLAG_USE_RFC2307_ATTRS);
61 bool use_gc = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
62 == LWCELL_FLAG_SEARCH_FOREST);
63 const char *oc;
65 /* Construct search filter for objectclass and attributes */
67 switch (type) {
68 case ID_TYPE_UID:
69 oc = ADEX_OC_USER;
70 if (use2307) {
71 oc = ADEX_OC_POSIX_USER;
72 if (use_gc) {
73 oc = AD_USER;
76 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
77 attr_filter = talloc_asprintf(frame, "%s=%u",
78 ADEX_ATTR_UIDNUM, id);
79 break;
81 case ID_TYPE_GID:
82 oc = ADEX_OC_GROUP;
83 if (use2307) {
84 oc = ADEX_OC_POSIX_GROUP;
85 if (use_gc) {
86 oc = AD_GROUP;
89 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
90 attr_filter = talloc_asprintf(frame, "%s=%u",
91 ADEX_ATTR_GIDNUM, id);
92 break;
93 default:
94 return NULL;
97 BAIL_ON_PTR_ERROR(oc_filter, nt_status);
98 BAIL_ON_PTR_ERROR(attr_filter, nt_status);
100 /* Use "keywords=%s" for non-schema cells */
102 if (use2307) {
103 filter = talloc_asprintf(mem_ctx,
104 "(&(%s)(%s))",
105 oc_filter,
106 attr_filter);
107 } else {
108 filter = talloc_asprintf(mem_ctx,
109 "(&(keywords=%s)(keywords=%s))",
110 oc_filter,
111 attr_filter);
114 done:
115 talloc_destroy(frame);
117 return filter;
120 /********************************************************************
121 *******************************************************************/
123 static char* build_alias_filter(TALLOC_CTX *mem_ctx,
124 const char *alias,
125 uint32_t search_flags)
127 char *filter = NULL;
128 char *user_attr_filter, *group_attr_filter;
129 NTSTATUS nt_status;
130 TALLOC_CTX *frame = talloc_stackframe();
131 bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
132 == LWCELL_FLAG_USE_RFC2307_ATTRS);
133 bool search_forest = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
134 == LWCELL_FLAG_SEARCH_FOREST);
136 /* Construct search filter for objectclass and attributes */
138 user_attr_filter = talloc_asprintf(frame, "%s=%s",
139 ADEX_ATTR_UID, alias);
140 group_attr_filter = talloc_asprintf(frame, "%s=%s",
141 ADEX_ATTR_DISPLAYNAME, alias);
142 BAIL_ON_PTR_ERROR(user_attr_filter, nt_status);
143 BAIL_ON_PTR_ERROR(group_attr_filter, nt_status);
145 /* Use "keywords=%s" for non-schema cells */
147 if (use2307) {
148 filter = talloc_asprintf(mem_ctx,
149 "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))",
150 user_attr_filter,
151 search_forest ? AD_USER : ADEX_OC_POSIX_USER,
152 group_attr_filter,
153 search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP);
154 } else {
155 filter = talloc_asprintf(mem_ctx,
156 "(|(keywords=%s)(keywords=%s))",
157 user_attr_filter,
158 group_attr_filter);
161 done:
162 talloc_destroy(frame);
164 return filter;
168 /********************************************************************
169 *******************************************************************/
171 static NTSTATUS search_cell(struct likewise_cell *c,
172 LDAPMessage **msg,
173 const struct lwcell_filter *fdata)
175 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
176 TALLOC_CTX* frame = talloc_stackframe();
177 char *filter = NULL;
178 const char *base = NULL;
179 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
180 const char *attrs[] = { "*", NULL };
181 int count;
182 char *sid_str;
184 /* get the filter and other search parameters */
186 switch (fdata->ftype) {
187 case SidFilter:
188 sid_str = sid_string_talloc(frame, &fdata->filter.sid);
189 BAIL_ON_PTR_ERROR(sid_str, nt_status);
191 filter = talloc_asprintf(frame, "(keywords=backLink=%s)",
192 sid_str);
193 break;
194 case IdFilter:
195 filter = build_id_filter(frame,
196 fdata->filter.id.id,
197 fdata->filter.id.type,
198 cell_flags(c));
199 break;
200 case AliasFilter:
201 filter = build_alias_filter(frame,
202 fdata->filter.alias,
203 cell_flags(c));
204 break;
205 default:
206 nt_status = NT_STATUS_INVALID_PARAMETER;
207 break;
209 BAIL_ON_PTR_ERROR(filter, nt_status);
211 base = cell_search_base(c);
212 BAIL_ON_PTR_ERROR(base, nt_status);
214 ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE,
215 filter, attrs, msg);
217 nt_status = ads_ntstatus(ads_status);
218 BAIL_ON_NTSTATUS_ERROR(nt_status);
220 /* Now check that we got only one reply */
222 count = ads_count_replies(c->conn, *msg);
223 if (count < 1) {
224 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
225 BAIL_ON_NTSTATUS_ERROR(nt_status);
228 if ( count > 1) {
229 nt_status = NT_STATUS_DUPLICATE_NAME;
230 BAIL_ON_NTSTATUS_ERROR(nt_status);
233 done:
234 PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4);
236 talloc_destroy(CONST_DISCARD(char*, base));
237 talloc_destroy(frame);
239 return nt_status;
242 /********************************************************************
243 *******************************************************************/
245 static NTSTATUS search_domain(struct likewise_cell **cell,
246 LDAPMessage **msg,
247 const char *dn,
248 const DOM_SID *sid)
250 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
251 TALLOC_CTX* frame = talloc_stackframe();
252 int count;
254 nt_status = dc_search_domains(cell, msg, dn, sid);
255 BAIL_ON_NTSTATUS_ERROR(nt_status);
257 /* Now check that we got only one reply */
259 count = ads_count_replies(cell_connection(*cell), *msg);
260 if (count < 1) {
261 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
262 BAIL_ON_NTSTATUS_ERROR(nt_status);
265 if ( count > 1) {
266 nt_status = NT_STATUS_DUPLICATE_NAME;
267 BAIL_ON_NTSTATUS_ERROR(nt_status);
270 done:
271 PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4);
272 talloc_destroy(frame);
274 return nt_status;
278 /********************************************************************
279 Check that a DN is within the forest scope.
280 *******************************************************************/
282 static bool check_forest_scope(const char *dn)
284 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
285 TALLOC_CTX *frame = talloc_stackframe();
286 char *p = NULL;
287 char *q = NULL;
288 char *dns_domain = NULL;
289 struct winbindd_tdc_domain *domain;
291 /* If the DN does *not* contain "$LikewiseIdentityCell",
292 assume this is a schema mode forest and it is in the
293 forest scope by definition. */
295 if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) {
296 nt_status = NT_STATUS_OK;
297 goto done;
300 /* If this is a non-schema forest, then make sure that the DN
301 is in the form "...,cn=$LikewiseIdentityCell,DC=..." */
303 if ((q = strchr_m(p, ',')) == NULL) {
304 nt_status = NT_STATUS_OBJECT_NAME_INVALID;
305 BAIL_ON_NTSTATUS_ERROR(nt_status);
308 q++;
309 if (StrnCaseCmp(q, "dc=", 3) != 0) {
310 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
311 BAIL_ON_NTSTATUS_ERROR(nt_status);
315 dns_domain = cell_dn_to_dns(q);
316 BAIL_ON_PTR_ERROR(dns_domain, nt_status);
318 domain = wcache_tdc_fetch_domain(frame, dns_domain);
319 if (!domain) {
320 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
321 BAIL_ON_NTSTATUS_ERROR(nt_status);
324 nt_status = NT_STATUS_OK;
326 done:
327 talloc_destroy(frame);
328 SAFE_FREE(dns_domain);
330 return NT_STATUS_IS_OK(nt_status);
335 /********************************************************************
336 Check that only one result was returned within the forest cell
337 scope.
338 *******************************************************************/
340 static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list,
341 LDAPMessage **msg_list,
342 int num_resp,
343 char **dn,
344 DOM_SID *user_sid)
346 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
347 int i;
348 ADS_STRUCT *ads = NULL;
349 LDAPMessage *msg = NULL;
350 int count = 0;
351 char *entry_dn = NULL;
352 TALLOC_CTX *frame = talloc_stackframe();
354 if (!dn || !user_sid) {
355 nt_status = NT_STATUS_INVALID_PARAMETER;
356 BAIL_ON_NTSTATUS_ERROR(nt_status);
359 *dn = NULL;
361 if (!ads_list || !msg_list || (num_resp == 0)) {
362 nt_status = NT_STATUS_NO_SUCH_FILE;
363 BAIL_ON_NTSTATUS_ERROR(nt_status);
366 /* Loop over all msgs */
368 for (i=0; i<num_resp; i++) {
369 LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]);
371 while (e) {
372 entry_dn = ads_get_dn(ads_list[i], talloc_tos(), e);
373 BAIL_ON_PTR_ERROR(entry_dn, nt_status);
375 if (check_forest_scope(entry_dn)) {
376 count++;
378 /* If we've already broken the condition, no
379 need to continue */
381 if (count > 1) {
382 nt_status = NT_STATUS_DUPLICATE_NAME;
383 BAIL_ON_NTSTATUS_ERROR(nt_status);
386 ads = ads_list[i];
387 msg = e;
388 *dn = SMB_STRDUP(entry_dn);
389 BAIL_ON_PTR_ERROR((*dn), nt_status);
392 e = ads_next_entry(ads_list[i], e);
393 TALLOC_FREE(entry_dn);
397 if (!ads || !msg) {
398 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
399 BAIL_ON_NTSTATUS_ERROR(nt_status);
402 /* If we made is through the loop, then grab the user_sid and
403 run home to base */
406 Try and get the SID from either objectSid or keywords.
407 We cannot use pull_sid() here since we want to try
408 both methods and not only one or the other (and we
409 have no full likewise_cell struct.
411 Fail if both are unavailable
414 if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) {
415 char **keywords;
416 char *s;
417 size_t num_lines = 0;
419 keywords = ads_pull_strings(ads, frame, msg, "keywords",
420 &num_lines);
421 BAIL_ON_PTR_ERROR(keywords, nt_status);
423 s = find_attr_string(keywords, num_lines, "backLink");
424 if (!s) {
425 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
426 BAIL_ON_NTSTATUS_ERROR(nt_status);
429 if (!string_to_sid(user_sid, s)) {
430 nt_status = NT_STATUS_INVALID_SID;
431 BAIL_ON_NTSTATUS_ERROR(nt_status);
435 nt_status = NT_STATUS_OK;
437 done:
438 if (!NT_STATUS_IS_OK(nt_status)) {
439 SAFE_FREE(*dn);
442 talloc_destroy(frame);
444 return nt_status;
447 /********************************************************************
448 Search all forests. Each forest can have it's own forest-cell
449 settings so we have to generate the filter for each search.
450 We don't use gc_search_all_forests() since we may have a different
451 schema model in each forest and need to construct the search
452 filter for each GC search.
453 *******************************************************************/
455 static NTSTATUS search_forest(struct likewise_cell *forest_cell,
456 LDAPMessage **msg,
457 const struct lwcell_filter *fdata)
459 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
460 TALLOC_CTX *frame = talloc_stackframe();
461 char *filter = NULL;
462 char *dn = NULL;
463 struct gc_info *gc = NULL;
464 ADS_STRUCT **ads_list = NULL;
465 LDAPMessage **msg_list = NULL;
466 int num_resp = 0;
467 LDAPMessage *m;
468 DOM_SID user_sid;
469 struct likewise_cell *domain_cell = NULL;
471 if ((gc = gc_search_start()) == NULL) {
472 nt_status = NT_STATUS_INVALID_DOMAIN_STATE;
473 BAIL_ON_NTSTATUS_ERROR(nt_status);
476 while (gc) {
477 char *sid_binstr = NULL;
478 uint32_t flags = LWCELL_FLAG_SEARCH_FOREST;
480 m = NULL;
482 flags |= cell_flags(gc->forest_cell);
484 switch (fdata->ftype) {
485 case SidFilter:
486 sid_binstr = sid_binstring(frame, &fdata->filter.sid);
487 BAIL_ON_PTR_ERROR(sid_binstr, nt_status);
489 filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr);
490 TALLOC_FREE(sid_binstr);
491 break;
492 case IdFilter:
493 filter = build_id_filter(frame,
494 fdata->filter.id.id,
495 fdata->filter.id.type, flags);
496 break;
497 case AliasFilter:
498 filter = build_alias_filter(frame,
499 fdata->filter.alias,
500 flags);
501 break;
504 /* First find the sparse object in GC */
505 nt_status = gc_search_forest(gc, &m, filter);
506 if (!NT_STATUS_IS_OK(nt_status)) {
507 gc = gc->next;
508 continue;
511 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
512 m, &ads_list, &msg_list,
513 &num_resp);
514 BAIL_ON_NTSTATUS_ERROR(nt_status);
516 gc = gc->next;
519 /* Uniqueness check across forests */
521 nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp,
522 &dn, &user_sid);
523 BAIL_ON_NTSTATUS_ERROR(nt_status);
525 nt_status = search_domain(&domain_cell, &m, dn, &user_sid);
526 BAIL_ON_NTSTATUS_ERROR(nt_status);
528 /* Save the connection and results in the return parameters */
530 forest_cell->gc_search_cell = domain_cell;
531 *msg = m;
533 done:
534 PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4);
536 SAFE_FREE(dn);
538 free_result_array(ads_list, msg_list, num_resp);
539 talloc_destroy(frame);
541 return nt_status;
544 /********************************************************************
545 *******************************************************************/
547 static NTSTATUS search_cell_list(struct likewise_cell **c,
548 LDAPMessage **m,
549 const struct lwcell_filter *fdata)
551 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
552 struct likewise_cell *cell = NULL;
553 LDAPMessage *msg = NULL;
554 struct likewise_cell *result_cell = NULL;
556 if ((cell = cell_list_head()) == NULL) {
557 nt_status = NT_STATUS_INVALID_SERVER_STATE;
558 BAIL_ON_NTSTATUS_ERROR(nt_status);
561 while (cell) {
562 /* Clear any previous GC search results */
564 cell->gc_search_cell = NULL;
566 if (cell_search_forest(cell)) {
567 nt_status = search_forest(cell, &msg, fdata);
568 } else {
569 nt_status = search_cell(cell, &msg, fdata);
572 /* Always point to the search result cell.
573 In forests this might be for another domain
574 which means the schema model may be different */
576 result_cell = cell->gc_search_cell ?
577 cell->gc_search_cell : cell;
579 /* Check if we are done */
581 if (NT_STATUS_IS_OK(nt_status)) {
582 break;
585 /* No luck. Free memory and hit the next cell.
586 Forest searches always set the gc_search_cell
587 so give preference to that connection if possible. */
589 ads_msgfree(cell_connection(result_cell), msg);
590 msg = NULL;
592 cell = cell->next;
595 /* This might be assigning NULL but that is ok as long as we
596 give back the proper error code */
598 *c = result_cell;
599 *m = msg;
601 done:
602 PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3);
604 return nt_status;
607 /********************************************************************
608 Pull the SID from an object which is always stored in the keywords
609 attribute as "backLink=S-1-5-21-..."
610 *******************************************************************/
612 static NTSTATUS pull_sid(struct likewise_cell *c,
613 LDAPMessage *msg,
614 DOM_SID *sid)
616 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
617 TALLOC_CTX *frame = talloc_stackframe();
618 ADS_STRUCT *ads = NULL;
620 ads = cell_connection(c);
623 We have two ways of getting the sid:
624 (a) from the objectSID in case of a GC search,
625 (b) from backLink in the case of a cell search.
626 Pull the keywords attributes and grab the backLink.
629 if (!ads_pull_sid(ads, msg, "objectSid", sid)) {
630 char **keywords;
631 char *s;
632 size_t num_lines = 0;
634 keywords = ads_pull_strings(ads, frame, msg,
635 "keywords", &num_lines);
636 BAIL_ON_PTR_ERROR(keywords, nt_status);
638 s = find_attr_string(keywords, num_lines, "backLink");
639 if (!s) {
640 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
641 BAIL_ON_NTSTATUS_ERROR(nt_status);
644 if (!string_to_sid(sid, s)) {
645 nt_status = NT_STATUS_INVALID_SID;
646 BAIL_ON_NTSTATUS_ERROR(nt_status);
650 nt_status = NT_STATUS_OK;
652 done:
653 talloc_destroy(frame);
655 return nt_status;
658 /********************************************************************
659 *******************************************************************/
661 static NTSTATUS get_object_type(struct likewise_cell *c,
662 LDAPMessage *msg,
663 enum id_type *type)
665 TALLOC_CTX *ctx = talloc_stackframe();
666 char **oc_list = NULL;
667 NTSTATUS nt_status = NT_STATUS_OK;
668 size_t list_size = 0;
669 char *s = NULL;
670 ADS_STRUCT *ads = NULL;
672 ads = cell_connection(c);
674 /* Deal with RFC 2307 support first */
676 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
677 oc_list = ads_pull_strings(ads, ctx, msg,
678 "objectClass", &list_size);
679 if (!oc_list) {
680 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
681 goto done;
684 /* Check for posix classes and AD classes */
686 if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER)
687 || is_object_class(oc_list, list_size, AD_USER)) {
688 *type = ID_TYPE_UID;
689 } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP)
690 || is_object_class(oc_list, list_size, AD_GROUP)) {
691 *type = ID_TYPE_GID;
692 } else {
693 *type = ID_TYPE_NOT_SPECIFIED;
694 nt_status = NT_STATUS_INVALID_PARAMETER;
696 } else {
697 /* Default to non-schema mode */
699 oc_list = ads_pull_strings(ads, ctx, msg,
700 "keywords", &list_size);
701 if (!oc_list) {
702 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
703 goto done;
706 s = find_attr_string(oc_list, list_size, "objectClass");
707 if (!s) {
708 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
709 goto done;
712 if (strequal(s, ADEX_OC_USER)) {
713 *type = ID_TYPE_UID;
714 } else if (strequal(s, ADEX_OC_GROUP)) {
715 *type = ID_TYPE_GID;
716 } else {
717 *type = ID_TYPE_NOT_SPECIFIED;
718 nt_status = NT_STATUS_INVALID_PARAMETER;
722 nt_status = NT_STATUS_OK;
724 done:
725 talloc_destroy(ctx);
727 return nt_status;
730 /********************************************************************
731 Pull an attribute uint32_t value
732 *******************************************************************/
734 static NTSTATUS get_object_uint32(struct likewise_cell *c,
735 LDAPMessage *msg,
736 const char *attrib,
737 uint32_t *x)
739 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
740 char **keywords = NULL;
741 size_t list_size = 0;
742 TALLOC_CTX *frame = talloc_stackframe();
743 ADS_STRUCT *ads = NULL;
745 ads = cell_connection(c);
747 /* Deal with RFC2307 schema */
749 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
750 if (!ads_pull_uint32(ads, msg, attrib, x)) {
751 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
752 BAIL_ON_NTSTATUS_ERROR(nt_status);
754 } else {
755 /* Non-schema mode */
756 char *s = NULL;
757 uint32_t num;
759 keywords = ads_pull_strings(ads, frame, msg, "keywords",
760 &list_size);
761 BAIL_ON_PTR_ERROR(keywords, nt_status);
763 s = find_attr_string(keywords, list_size, attrib);
764 if (!s) {
765 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
766 BAIL_ON_NTSTATUS_ERROR(nt_status);
769 num = strtoll(s, NULL, 10);
770 if (errno == ERANGE) {
771 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
772 BAIL_ON_NTSTATUS_ERROR(nt_status);
774 *x = num;
777 nt_status = NT_STATUS_OK;
779 done:
780 talloc_destroy(frame);
782 return nt_status;
785 /********************************************************************
786 *******************************************************************/
788 static NTSTATUS get_object_id(struct likewise_cell *c,
789 LDAPMessage *msg,
790 enum id_type type,
791 uint32_t *id)
793 NTSTATUS nt_status = NT_STATUS_OK;
794 const char *id_attr;
796 /* Figure out which attribute we need to pull */
798 switch (type) {
799 case ID_TYPE_UID:
800 id_attr = ADEX_ATTR_UIDNUM;
801 break;
802 case ID_TYPE_GID:
803 id_attr = ADEX_ATTR_GIDNUM;
804 break;
805 default:
806 nt_status = NT_STATUS_INVALID_PARAMETER;
807 BAIL_ON_NTSTATUS_ERROR(nt_status);
808 break;
811 nt_status = get_object_uint32(c, msg, id_attr, id);
812 BAIL_ON_NTSTATUS_ERROR(nt_status);
814 done:
815 return nt_status;
818 /********************************************************************
819 Pull the uid/gid and type from an object. This differs depending on
820 the cell flags.
821 *******************************************************************/
823 static NTSTATUS pull_id(struct likewise_cell *c,
824 LDAPMessage *msg,
825 uint32_t *id,
826 enum id_type *type)
828 NTSTATUS nt_status;
830 nt_status = get_object_type(c, msg, type);
831 BAIL_ON_NTSTATUS_ERROR(nt_status);
833 nt_status = get_object_id(c, msg, *type, id);
834 BAIL_ON_NTSTATUS_ERROR(nt_status);
836 done:
837 return nt_status;
840 /********************************************************************
841 Pull an attribute string value
842 *******************************************************************/
844 static NTSTATUS get_object_string(struct likewise_cell *c,
845 LDAPMessage *msg,
846 TALLOC_CTX *ctx,
847 const char *attrib,
848 char **string)
850 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
851 char **keywords = NULL;
852 size_t list_size = 0;
853 TALLOC_CTX *frame = talloc_stackframe();
854 ADS_STRUCT *ads = NULL;
856 *string = NULL;
858 ads = cell_connection(c);
860 /* Deal with RFC2307 schema */
862 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
863 *string = ads_pull_string(ads, ctx, msg, attrib);
864 } else {
865 /* Non-schema mode */
867 char *s = NULL;
869 keywords = ads_pull_strings(ads, frame, msg,
870 "keywords", &list_size);
871 if (!keywords) {
872 nt_status = NT_STATUS_NO_MEMORY;
873 BAIL_ON_NTSTATUS_ERROR(nt_status);
875 s = find_attr_string(keywords, list_size, attrib);
876 if (s) {
877 *string = talloc_strdup(ctx, s);
881 if (!*string) {
882 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
883 BAIL_ON_NTSTATUS_ERROR(nt_status);
886 nt_status = NT_STATUS_OK;
888 done:
889 talloc_destroy(frame);
891 return nt_status;
894 /********************************************************************
895 Pull the struct passwd fields for a user
896 *******************************************************************/
898 static NTSTATUS pull_nss_info(struct likewise_cell *c,
899 LDAPMessage *msg,
900 TALLOC_CTX *ctx,
901 const char **homedir,
902 const char **shell,
903 const char **gecos,
904 gid_t *p_gid)
906 NTSTATUS nt_status;
907 char *tmp;
909 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, &tmp);
910 BAIL_ON_NTSTATUS_ERROR(nt_status);
911 *homedir = tmp;
913 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, &tmp);
914 BAIL_ON_NTSTATUS_ERROR(nt_status);
915 *shell = tmp;
917 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, &tmp);
918 /* Gecos is often not set so ignore failures */
919 *gecos = tmp;
921 nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid);
922 BAIL_ON_NTSTATUS_ERROR(nt_status);
924 done:
925 return nt_status;
928 /********************************************************************
929 Pull the struct passwd fields for a user
930 *******************************************************************/
932 static NTSTATUS pull_alias(struct likewise_cell *c,
933 LDAPMessage *msg,
934 TALLOC_CTX *ctx,
935 char **alias)
937 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
938 enum id_type type;
939 const char *attr = NULL;
941 /* Figure out if this is a user or a group */
943 nt_status = get_object_type(c, msg, &type);
944 BAIL_ON_NTSTATUS_ERROR(nt_status);
946 switch (type) {
947 case ID_TYPE_UID:
948 attr = ADEX_ATTR_UID;
949 break;
950 case ID_TYPE_GID:
951 /* What is the group attr for RFC2307 Forests? */
952 attr = ADEX_ATTR_DISPLAYNAME;
953 break;
954 default:
955 nt_status = NT_STATUS_INVALID_PARAMETER;
956 BAIL_ON_NTSTATUS_ERROR(nt_status);
957 break;
960 nt_status = get_object_string(c, msg, ctx, attr, alias);
961 BAIL_ON_NTSTATUS_ERROR(nt_status);
963 done:
964 return nt_status;
967 /********************************************************************
968 *******************************************************************/
970 static NTSTATUS _ccp_get_sid_from_id(DOM_SID * sid,
971 uint32_t id, enum id_type type)
973 struct likewise_cell *cell = NULL;
974 LDAPMessage *msg = NULL;
975 NTSTATUS nt_status;
976 struct lwcell_filter filter;
978 filter.ftype = IdFilter;
979 filter.filter.id.id = id;
980 filter.filter.id.type = type;
982 nt_status = search_cell_list(&cell, &msg, &filter);
983 BAIL_ON_NTSTATUS_ERROR(nt_status);
985 nt_status = pull_sid(cell, msg, sid);
986 BAIL_ON_NTSTATUS_ERROR(nt_status);
988 done:
989 ads_msgfree(cell->conn, msg);
991 return nt_status;
994 /********************************************************************
995 *******************************************************************/
997 static NTSTATUS _ccp_get_id_from_sid(uint32_t * id,
998 enum id_type *type,
999 const DOM_SID * sid)
1001 struct likewise_cell *cell = NULL;
1002 LDAPMessage *msg = NULL;
1003 NTSTATUS nt_status;
1004 struct lwcell_filter filter;
1006 filter.ftype = SidFilter;
1007 sid_copy(&filter.filter.sid, sid);
1009 nt_status = search_cell_list(&cell, &msg, &filter);
1010 BAIL_ON_NTSTATUS_ERROR(nt_status);
1012 nt_status = pull_id(cell, msg, id, type);
1013 BAIL_ON_NTSTATUS_ERROR(nt_status);
1015 if (*id < min_id_value()) {
1016 nt_status = NT_STATUS_INVALID_PARAMETER;
1017 BAIL_ON_NTSTATUS_ERROR(nt_status);
1020 done:
1021 ads_msgfree(cell->conn, msg);
1023 return nt_status;
1026 /********************************************************************
1027 *******************************************************************/
1029 static NTSTATUS _ccp_nss_get_info(const DOM_SID * sid,
1030 TALLOC_CTX * ctx,
1031 const char **homedir,
1032 const char **shell,
1033 const char **gecos, gid_t * p_gid)
1035 struct likewise_cell *cell = NULL;
1036 LDAPMessage *msg = NULL;
1037 NTSTATUS nt_status;
1038 struct lwcell_filter filter;
1039 enum id_type type;
1041 filter.ftype = SidFilter;
1042 sid_copy(&filter.filter.sid, sid);
1044 nt_status = search_cell_list(&cell, &msg, &filter);
1045 BAIL_ON_NTSTATUS_ERROR(nt_status);
1047 nt_status = get_object_type(cell, msg, &type);
1048 BAIL_ON_NTSTATUS_ERROR(nt_status);
1050 if (type != ID_TYPE_UID) {
1051 nt_status = NT_STATUS_NO_SUCH_USER;
1052 BAIL_ON_NTSTATUS_ERROR(nt_status);
1055 nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos,
1056 (uint32_t*) p_gid);
1057 BAIL_ON_NTSTATUS_ERROR(nt_status);
1059 done:
1060 ads_msgfree(cell->conn, msg);
1062 return nt_status;
1065 /**********************************************************************
1066 *********************************************************************/
1068 static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx,
1069 const char *domain,
1070 const char *name, char **alias)
1072 TALLOC_CTX *frame = talloc_stackframe();
1073 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1074 DOM_SID sid;
1075 struct likewise_cell *cell = NULL;
1076 LDAPMessage *msg = NULL;
1077 struct lwcell_filter filter;
1078 enum lsa_SidType sid_type;
1080 /* Convert the name to a SID */
1082 nt_status = gc_name_to_sid(domain, name, &sid, &sid_type);
1083 BAIL_ON_NTSTATUS_ERROR(nt_status);
1085 /* Find the user/group */
1087 filter.ftype = SidFilter;
1088 sid_copy(&filter.filter.sid, &sid);
1090 nt_status = search_cell_list(&cell, &msg, &filter);
1091 BAIL_ON_NTSTATUS_ERROR(nt_status);
1093 /* Pull the alias and return */
1095 nt_status = pull_alias(cell, msg, ctx, alias);
1096 BAIL_ON_NTSTATUS_ERROR(nt_status);
1098 done:
1099 PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3);
1101 talloc_destroy(frame);
1102 ads_msgfree(cell_connection(cell), msg);
1104 return nt_status;
1107 /**********************************************************************
1108 Map from an alias name to the canonical, qualified name.
1109 Ensure that the alias is only pull from the closest in which
1110 the user or gorup is enabled in
1111 *********************************************************************/
1113 static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx,
1114 const char *domain,
1115 const char *alias, char **name)
1117 TALLOC_CTX *frame = talloc_stackframe();
1118 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1119 DOM_SID sid;
1120 struct likewise_cell *cell_alias = NULL;
1121 LDAPMessage *msg_alias = NULL;
1122 struct likewise_cell *cell_sid = NULL;
1123 LDAPMessage *msg_sid = NULL;
1124 struct lwcell_filter filter;
1125 char *canonical_name = NULL;
1126 enum lsa_SidType type;
1128 /* Find the user/group */
1130 filter.ftype = AliasFilter;
1131 fstrcpy(filter.filter.alias, alias);
1133 nt_status = search_cell_list(&cell_alias, &msg_alias, &filter);
1134 BAIL_ON_NTSTATUS_ERROR(nt_status);
1136 nt_status = pull_sid(cell_alias, msg_alias, &sid);
1137 BAIL_ON_NTSTATUS_ERROR(nt_status);
1139 /* Now search again for the SID according to the cell list.
1140 Verify that the cell of both search results is the same
1141 so that we only match an alias from the closest cell
1142 in which a user/group has been instantied. */
1144 filter.ftype = SidFilter;
1145 sid_copy(&filter.filter.sid, &sid);
1147 nt_status = search_cell_list(&cell_sid, &msg_sid, &filter);
1148 BAIL_ON_NTSTATUS_ERROR(nt_status);
1150 if (cell_alias != cell_sid) {
1151 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1152 BAIL_ON_NTSTATUS_ERROR(nt_status);
1155 /* Finally do the GC sid/name conversion */
1157 nt_status = gc_sid_to_name(&sid, &canonical_name, &type);
1158 BAIL_ON_NTSTATUS_ERROR(nt_status);
1160 *name = talloc_strdup(mem_ctx, canonical_name);
1161 BAIL_ON_PTR_ERROR((*name), nt_status);
1163 nt_status = NT_STATUS_OK;
1165 done:
1166 PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3);
1168 ads_msgfree(cell_connection(cell_alias), msg_alias);
1169 ads_msgfree(cell_connection(cell_sid), msg_sid);
1171 SAFE_FREE(canonical_name);
1173 talloc_destroy(frame);
1175 return nt_status;
1178 /********************************************************************
1179 *******************************************************************/
1181 struct cell_provider_api ccp_unified = {
1182 .get_sid_from_id = _ccp_get_sid_from_id,
1183 .get_id_from_sid = _ccp_get_id_from_sid,
1184 .get_nss_info = _ccp_nss_get_info,
1185 .map_to_alias = _ccp_map_to_alias,
1186 .map_from_alias = _ccp_map_from_alias