Make error message clearer on fail.
[Samba.git] / source3 / winbindd / idmap_adex / provider_unified.c
blobf9d73f5f954538b16705f616932a2a7aaaee52ec
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(uint32_t id,
51 enum id_type type,
52 uint32_t search_flags)
54 char *filter = NULL;
55 char *oc_filter, *attr_filter;
56 NTSTATUS nt_status;
57 TALLOC_CTX *frame = talloc_stackframe();
58 bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
59 == LWCELL_FLAG_USE_RFC2307_ATTRS);
60 bool use_gc = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
61 == LWCELL_FLAG_SEARCH_FOREST);
62 const char *oc;
64 /* Construct search filter for objectclass and attributes */
66 switch (type) {
67 case ID_TYPE_UID:
68 oc = ADEX_OC_USER;
69 if (use2307) {
70 oc = ADEX_OC_POSIX_USER;
71 if (use_gc) {
72 oc = AD_USER;
75 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
76 attr_filter = talloc_asprintf(frame, "%s=%u",
77 ADEX_ATTR_UIDNUM, id);
78 break;
80 case ID_TYPE_GID:
81 oc = ADEX_OC_GROUP;
82 if (use2307) {
83 oc = ADEX_OC_POSIX_GROUP;
84 if (use_gc) {
85 oc = AD_GROUP;
88 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
89 attr_filter = talloc_asprintf(frame, "%s=%u",
90 ADEX_ATTR_GIDNUM, id);
91 break;
92 default:
93 return NULL;
96 BAIL_ON_PTR_ERROR(oc_filter, nt_status);
97 BAIL_ON_PTR_ERROR(attr_filter, nt_status);
99 /* Use "keywords=%s" for non-schema cells */
101 if (use2307) {
102 filter = talloc_asprintf(frame, "(&(%s)(%s))",
103 oc_filter, attr_filter);
104 } else {
105 filter = talloc_asprintf(frame, "(&(keywords=%s)(keywords=%s))",
106 oc_filter, attr_filter);
109 talloc_destroy(oc_filter);
110 talloc_destroy(attr_filter);
112 done:
113 /* Don't destroy the stackframe CTX since we are returning
114 memory from it */
116 return filter;
119 /********************************************************************
120 *******************************************************************/
122 static char* build_alias_filter(const char *alias, uint32_t search_flags)
124 char *filter = NULL;
125 char *user_attr_filter, *group_attr_filter;
126 NTSTATUS nt_status;
127 TALLOC_CTX *frame = talloc_stackframe();
128 bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
129 == LWCELL_FLAG_USE_RFC2307_ATTRS);
130 bool search_forest = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
131 == LWCELL_FLAG_SEARCH_FOREST);
133 /* Construct search filter for objectclass and attributes */
135 user_attr_filter = talloc_asprintf(frame, "%s=%s",
136 ADEX_ATTR_UID, alias);
137 group_attr_filter = talloc_asprintf(frame, "%s=%s",
138 ADEX_ATTR_DISPLAYNAME, alias);
139 BAIL_ON_PTR_ERROR(user_attr_filter, nt_status);
140 BAIL_ON_PTR_ERROR(group_attr_filter, nt_status);
142 /* Use "keywords=%s" for non-schema cells */
144 if (use2307) {
145 filter = talloc_asprintf(frame,
146 "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))",
147 user_attr_filter,
148 search_forest ? AD_USER : ADEX_OC_POSIX_USER,
149 group_attr_filter,
150 search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP);
151 } else {
152 filter = talloc_asprintf(frame,
153 "(|(keywords=%s)(keywords=%s))",
154 user_attr_filter,
155 group_attr_filter);
158 talloc_destroy(user_attr_filter);
159 talloc_destroy(group_attr_filter);
161 done:
162 /* Don't destroy the stackframe CTX since we are returning
163 memory from it */
165 return filter;
169 /********************************************************************
170 *******************************************************************/
172 static NTSTATUS search_cell(struct likewise_cell *c,
173 LDAPMessage **msg,
174 const struct lwcell_filter *fdata)
176 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
177 TALLOC_CTX* frame = talloc_stackframe();
178 char *filter = NULL;
179 const char *base = NULL;
180 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
181 const char *attrs[] = { "*", NULL };
182 int count;
183 char *sid_str;
185 /* get the filter and other search parameters */
187 switch (fdata->ftype) {
188 case SidFilter:
189 sid_str = sid_string_talloc(frame, &fdata->filter.sid);
190 BAIL_ON_PTR_ERROR(sid_str, nt_status);
192 filter = talloc_asprintf(frame, "(keywords=backLink=%s)",
193 sid_str);
194 break;
195 case IdFilter:
196 filter = build_id_filter(fdata->filter.id.id,
197 fdata->filter.id.type,
198 cell_flags(c));
199 break;
200 case AliasFilter:
201 filter = build_alias_filter(fdata->filter.alias,
202 cell_flags(c));
203 break;
204 default:
205 nt_status = NT_STATUS_INVALID_PARAMETER;
206 break;
208 BAIL_ON_PTR_ERROR(filter, nt_status);
210 base = cell_search_base(c);
211 BAIL_ON_PTR_ERROR(base, nt_status);
213 ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE,
214 filter, attrs, msg);
216 nt_status = ads_ntstatus(ads_status);
217 BAIL_ON_NTSTATUS_ERROR(nt_status);
219 /* Now check that we got only one reply */
221 count = ads_count_replies(c->conn, *msg);
222 if (count < 1) {
223 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
224 BAIL_ON_NTSTATUS_ERROR(nt_status);
227 if ( count > 1) {
228 nt_status = NT_STATUS_DUPLICATE_NAME;
229 BAIL_ON_NTSTATUS_ERROR(nt_status);
232 done:
233 PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4);
235 talloc_destroy(CONST_DISCARD(char*, base));
236 talloc_destroy(frame);
238 return nt_status;
241 /********************************************************************
242 *******************************************************************/
244 static NTSTATUS search_domain(struct likewise_cell **cell,
245 LDAPMessage **msg,
246 const char *dn,
247 const DOM_SID *sid)
249 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
250 TALLOC_CTX* frame = talloc_stackframe();
251 int count;
253 nt_status = dc_search_domains(cell, msg, dn, sid);
254 BAIL_ON_NTSTATUS_ERROR(nt_status);
256 /* Now check that we got only one reply */
258 count = ads_count_replies(cell_connection(*cell), *msg);
259 if (count < 1) {
260 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
261 BAIL_ON_NTSTATUS_ERROR(nt_status);
264 if ( count > 1) {
265 nt_status = NT_STATUS_DUPLICATE_NAME;
266 BAIL_ON_NTSTATUS_ERROR(nt_status);
269 done:
270 PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4);
271 talloc_destroy(frame);
273 return nt_status;
277 /********************************************************************
278 Check that a DN is within the forest scope.
279 *******************************************************************/
281 static bool check_forest_scope(const char *dn)
283 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
284 TALLOC_CTX *frame = talloc_stackframe();
285 char *p = NULL;
286 char *q = NULL;
287 char *dns_domain = NULL;
288 struct winbindd_tdc_domain *domain;
290 /* If the DN does *not* contain "$LikewiseIdentityCell",
291 assume this is a schema mode forest and it is in the
292 forest scope by definition. */
294 if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) {
295 nt_status = NT_STATUS_OK;
296 goto done;
299 /* If this is a non-schema forest, then make sure that the DN
300 is in the form "...,cn=$LikewiseIdentityCell,DC=..." */
302 if ((q = strchr_m(p, ',')) == NULL) {
303 nt_status = NT_STATUS_OBJECT_NAME_INVALID;
304 BAIL_ON_NTSTATUS_ERROR(nt_status);
307 q++;
308 if (StrnCaseCmp(q, "dc=", 3) != 0) {
309 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
310 BAIL_ON_NTSTATUS_ERROR(nt_status);
314 dns_domain = cell_dn_to_dns(q);
315 BAIL_ON_PTR_ERROR(dns_domain, nt_status);
317 domain = wcache_tdc_fetch_domain(frame, dns_domain);
318 if (!domain) {
319 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
320 BAIL_ON_NTSTATUS_ERROR(nt_status);
323 nt_status = NT_STATUS_OK;
325 done:
326 talloc_destroy(frame);
327 SAFE_FREE(dns_domain);
329 return NT_STATUS_IS_OK(nt_status);
334 /********************************************************************
335 Check that only one result was returned within the forest cell
336 scope.
337 *******************************************************************/
339 static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list,
340 LDAPMessage **msg_list,
341 int num_resp,
342 char **dn,
343 DOM_SID *user_sid)
345 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
346 int i;
347 ADS_STRUCT *ads = NULL;
348 LDAPMessage *msg = NULL;
349 int count = 0;
350 char *entry_dn = NULL;
351 TALLOC_CTX *frame = talloc_stackframe();
353 if (!dn || !user_sid) {
354 nt_status = NT_STATUS_INVALID_PARAMETER;
355 BAIL_ON_NTSTATUS_ERROR(nt_status);
358 *dn = NULL;
360 if (!ads_list || !msg_list || (num_resp == 0)) {
361 nt_status = NT_STATUS_NO_SUCH_FILE;
362 BAIL_ON_NTSTATUS_ERROR(nt_status);
365 /* Loop over all msgs */
367 for (i=0; i<num_resp; i++) {
368 LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]);
370 while (e) {
371 entry_dn = ads_get_dn(ads_list[i], talloc_tos(), e);
372 BAIL_ON_PTR_ERROR(entry_dn, nt_status);
374 if (check_forest_scope(entry_dn)) {
375 count++;
377 /* If we've already broken the condition, no
378 need to continue */
380 if (count > 1) {
381 nt_status = NT_STATUS_DUPLICATE_NAME;
382 BAIL_ON_NTSTATUS_ERROR(nt_status);
385 ads = ads_list[i];
386 msg = e;
387 *dn = SMB_STRDUP(entry_dn);
388 BAIL_ON_PTR_ERROR((*dn), nt_status);
391 e = ads_next_entry(ads_list[i], e);
392 TALLOC_FREE(entry_dn);
396 if (!ads || !msg) {
397 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
398 BAIL_ON_NTSTATUS_ERROR(nt_status);
401 /* If we made is through the loop, then grab the user_sid and
402 run home to base */
405 Try and get the SID from either objectSid or keywords.
406 We cannot use pull_sid() here since we want to try
407 both methods and not only one or the other (and we
408 have no full likewise_cell struct.
410 Fail if both are unavailable
413 if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) {
414 char **keywords;
415 char *s;
416 size_t num_lines = 0;
418 keywords = ads_pull_strings(ads, frame, msg, "keywords",
419 &num_lines);
420 BAIL_ON_PTR_ERROR(keywords, nt_status);
422 s = find_attr_string(keywords, num_lines, "backLink");
423 if (!s) {
424 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
425 BAIL_ON_NTSTATUS_ERROR(nt_status);
428 if (!string_to_sid(user_sid, s)) {
429 nt_status = NT_STATUS_INVALID_SID;
430 BAIL_ON_NTSTATUS_ERROR(nt_status);
434 nt_status = NT_STATUS_OK;
436 done:
437 if (!NT_STATUS_IS_OK(nt_status)) {
438 SAFE_FREE(*dn);
441 talloc_destroy(frame);
442 TALLOC_FREE(entry_dn);
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(&fdata->filter.sid);
487 BAIL_ON_PTR_ERROR(sid_binstr, nt_status);
489 filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr);
490 SAFE_FREE(sid_binstr);
491 break;
492 case IdFilter:
493 filter = build_id_filter(fdata->filter.id.id,
494 fdata->filter.id.type, flags);
495 break;
496 case AliasFilter:
497 filter = build_alias_filter(fdata->filter.alias, flags);
498 break;
501 /* First find the sparse object in GC */
502 nt_status = gc_search_forest(gc, &m, filter);
503 if (!NT_STATUS_IS_OK(nt_status)) {
504 gc = gc->next;
505 continue;
508 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
509 m, &ads_list, &msg_list,
510 &num_resp);
511 BAIL_ON_NTSTATUS_ERROR(nt_status);
513 gc = gc->next;
516 /* Uniqueness check across forests */
518 nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp,
519 &dn, &user_sid);
520 BAIL_ON_NTSTATUS_ERROR(nt_status);
522 nt_status = search_domain(&domain_cell, &m, dn, &user_sid);
523 BAIL_ON_NTSTATUS_ERROR(nt_status);
525 /* Save the connection and results in the return parameters */
527 forest_cell->gc_search_cell = domain_cell;
528 *msg = m;
530 done:
531 PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4);
533 SAFE_FREE(dn);
535 free_result_array(ads_list, msg_list, num_resp);
536 talloc_destroy(frame);
538 return nt_status;
541 /********************************************************************
542 *******************************************************************/
544 static NTSTATUS search_cell_list(struct likewise_cell **c,
545 LDAPMessage **m,
546 const struct lwcell_filter *fdata)
548 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
549 struct likewise_cell *cell = NULL;
550 LDAPMessage *msg = NULL;
551 struct likewise_cell *result_cell = NULL;
553 if ((cell = cell_list_head()) == NULL) {
554 nt_status = NT_STATUS_INVALID_SERVER_STATE;
555 BAIL_ON_NTSTATUS_ERROR(nt_status);
558 while (cell) {
559 /* Clear any previous GC search results */
561 cell->gc_search_cell = NULL;
563 if (cell_search_forest(cell)) {
564 nt_status = search_forest(cell, &msg, fdata);
565 } else {
566 nt_status = search_cell(cell, &msg, fdata);
569 /* Always point to the search result cell.
570 In forests this might be for another domain
571 which means the schema model may be different */
573 result_cell = cell->gc_search_cell ?
574 cell->gc_search_cell : cell;
576 /* Check if we are done */
578 if (NT_STATUS_IS_OK(nt_status)) {
579 break;
582 /* No luck. Free memory and hit the next cell.
583 Forest searches always set the gc_search_cell
584 so give preference to that connection if possible. */
586 ads_msgfree(cell_connection(result_cell), msg);
587 msg = NULL;
589 cell = cell->next;
592 /* This might be assigning NULL but that is ok as long as we
593 give back the proper error code */
595 *c = result_cell;
596 *m = msg;
598 done:
599 PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3);
601 return nt_status;
604 /********************************************************************
605 Pull the SID from an object which is always stored in the keywords
606 attribute as "backLink=S-1-5-21-..."
607 *******************************************************************/
609 static NTSTATUS pull_sid(struct likewise_cell *c,
610 LDAPMessage *msg,
611 DOM_SID *sid)
613 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
614 TALLOC_CTX *frame = talloc_stackframe();
615 ADS_STRUCT *ads = NULL;
617 ads = cell_connection(c);
620 We have two ways of getting the sid:
621 (a) from the objectSID in case of a GC search,
622 (b) from backLink in the case of a cell search.
623 Pull the keywords attributes and grab the backLink.
626 if (!ads_pull_sid(ads, msg, "objectSid", sid)) {
627 char **keywords;
628 char *s;
629 size_t num_lines = 0;
631 keywords = ads_pull_strings(ads, frame, msg,
632 "keywords", &num_lines);
633 BAIL_ON_PTR_ERROR(keywords, nt_status);
635 s = find_attr_string(keywords, num_lines, "backLink");
636 if (!s) {
637 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
638 BAIL_ON_NTSTATUS_ERROR(nt_status);
641 if (!string_to_sid(sid, s)) {
642 nt_status = NT_STATUS_INVALID_SID;
643 BAIL_ON_NTSTATUS_ERROR(nt_status);
647 nt_status = NT_STATUS_OK;
649 done:
650 talloc_destroy(frame);
652 return nt_status;
655 /********************************************************************
656 *******************************************************************/
658 static NTSTATUS get_object_type(struct likewise_cell *c,
659 LDAPMessage *msg,
660 enum id_type *type)
662 TALLOC_CTX *ctx = talloc_stackframe();
663 char **oc_list = NULL;
664 NTSTATUS nt_status = NT_STATUS_OK;
665 size_t list_size = 0;
666 char *s = NULL;
667 ADS_STRUCT *ads = NULL;
669 ads = cell_connection(c);
671 /* Deal with RFC 2307 support first */
673 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
674 oc_list = ads_pull_strings(ads, ctx, msg,
675 "objectClass", &list_size);
676 if (!oc_list) {
677 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
678 goto done;
681 /* Check for posix classes and AD classes */
683 if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER)
684 || is_object_class(oc_list, list_size, AD_USER)) {
685 *type = ID_TYPE_UID;
686 } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP)
687 || is_object_class(oc_list, list_size, AD_GROUP)) {
688 *type = ID_TYPE_GID;
689 } else {
690 *type = ID_TYPE_NOT_SPECIFIED;
691 nt_status = NT_STATUS_INVALID_PARAMETER;
693 } else {
694 /* Default to non-schema mode */
696 oc_list = ads_pull_strings(ads, ctx, msg,
697 "keywords", &list_size);
698 if (!oc_list) {
699 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
700 goto done;
703 s = find_attr_string(oc_list, list_size, "objectClass");
704 if (!s) {
705 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
706 goto done;
709 if (strequal(s, ADEX_OC_USER)) {
710 *type = ID_TYPE_UID;
711 } else if (strequal(s, ADEX_OC_GROUP)) {
712 *type = ID_TYPE_GID;
713 } else {
714 *type = ID_TYPE_NOT_SPECIFIED;
715 nt_status = NT_STATUS_INVALID_PARAMETER;
719 nt_status = NT_STATUS_OK;
721 done:
722 talloc_destroy(ctx);
724 return nt_status;
727 /********************************************************************
728 Pull an attribute uint32_t value
729 *******************************************************************/
731 static NTSTATUS get_object_uint32(struct likewise_cell *c,
732 LDAPMessage *msg,
733 const char *attrib,
734 uint32_t *x)
736 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
737 char **keywords = NULL;
738 size_t list_size = 0;
739 TALLOC_CTX *frame = talloc_stackframe();
740 ADS_STRUCT *ads = NULL;
742 ads = cell_connection(c);
744 /* Deal with RFC2307 schema */
746 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
747 if (!ads_pull_uint32(ads, msg, attrib, x)) {
748 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
749 BAIL_ON_NTSTATUS_ERROR(nt_status);
751 } else {
752 /* Non-schema mode */
753 char *s = NULL;
754 uint32_t num;
756 keywords = ads_pull_strings(ads, frame, msg, "keywords",
757 &list_size);
758 BAIL_ON_PTR_ERROR(keywords, nt_status);
760 s = find_attr_string(keywords, list_size, attrib);
761 if (!s) {
762 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
763 BAIL_ON_NTSTATUS_ERROR(nt_status);
766 num = strtoll(s, NULL, 10);
767 if (errno == ERANGE) {
768 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
769 BAIL_ON_NTSTATUS_ERROR(nt_status);
771 *x = num;
774 nt_status = NT_STATUS_OK;
776 done:
777 talloc_destroy(frame);
779 return nt_status;
782 /********************************************************************
783 *******************************************************************/
785 static NTSTATUS get_object_id(struct likewise_cell *c,
786 LDAPMessage *msg,
787 enum id_type type,
788 uint32_t *id)
790 NTSTATUS nt_status = NT_STATUS_OK;
791 const char *id_attr;
793 /* Figure out which attribute we need to pull */
795 switch (type) {
796 case ID_TYPE_UID:
797 id_attr = ADEX_ATTR_UIDNUM;
798 break;
799 case ID_TYPE_GID:
800 id_attr = ADEX_ATTR_GIDNUM;
801 break;
802 default:
803 nt_status = NT_STATUS_INVALID_PARAMETER;
804 BAIL_ON_NTSTATUS_ERROR(nt_status);
805 break;
808 nt_status = get_object_uint32(c, msg, id_attr, id);
809 BAIL_ON_NTSTATUS_ERROR(nt_status);
811 done:
812 return nt_status;
815 /********************************************************************
816 Pull the uid/gid and type from an object. This differs depending on
817 the cell flags.
818 *******************************************************************/
820 static NTSTATUS pull_id(struct likewise_cell *c,
821 LDAPMessage *msg,
822 uint32_t *id,
823 enum id_type *type)
825 NTSTATUS nt_status;
827 nt_status = get_object_type(c, msg, type);
828 BAIL_ON_NTSTATUS_ERROR(nt_status);
830 nt_status = get_object_id(c, msg, *type, id);
831 BAIL_ON_NTSTATUS_ERROR(nt_status);
833 done:
834 return nt_status;
837 /********************************************************************
838 Pull an attribute string value
839 *******************************************************************/
841 static NTSTATUS get_object_string(struct likewise_cell *c,
842 LDAPMessage *msg,
843 TALLOC_CTX *ctx,
844 const char *attrib,
845 char **string)
847 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
848 char **keywords = NULL;
849 size_t list_size = 0;
850 TALLOC_CTX *frame = talloc_stackframe();
851 ADS_STRUCT *ads = NULL;
853 *string = NULL;
855 ads = cell_connection(c);
857 /* Deal with RFC2307 schema */
859 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
860 *string = ads_pull_string(ads, ctx, msg, attrib);
861 } else {
862 /* Non-schema mode */
864 char *s = NULL;
866 keywords = ads_pull_strings(ads, frame, msg,
867 "keywords", &list_size);
868 if (!keywords) {
869 nt_status = NT_STATUS_NO_MEMORY;
870 BAIL_ON_NTSTATUS_ERROR(nt_status);
872 s = find_attr_string(keywords, list_size, attrib);
873 if (s) {
874 *string = talloc_strdup(ctx, s);
878 if (!*string) {
879 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
880 BAIL_ON_NTSTATUS_ERROR(nt_status);
883 nt_status = NT_STATUS_OK;
885 done:
886 talloc_destroy(frame);
888 return nt_status;
891 /********************************************************************
892 Pull the struct passwd fields for a user
893 *******************************************************************/
895 static NTSTATUS pull_nss_info(struct likewise_cell *c,
896 LDAPMessage *msg,
897 TALLOC_CTX *ctx,
898 char **homedir,
899 char **shell,
900 char **gecos,
901 gid_t *p_gid)
903 NTSTATUS nt_status;
905 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, homedir);
906 BAIL_ON_NTSTATUS_ERROR(nt_status);
908 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, shell);
909 BAIL_ON_NTSTATUS_ERROR(nt_status);
911 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, gecos);
912 /* Gecos is often not set so ignore failures */
914 nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid);
915 BAIL_ON_NTSTATUS_ERROR(nt_status);
917 done:
918 return nt_status;
921 /********************************************************************
922 Pull the struct passwd fields for a user
923 *******************************************************************/
925 static NTSTATUS pull_alias(struct likewise_cell *c,
926 LDAPMessage *msg,
927 TALLOC_CTX *ctx,
928 char **alias)
930 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
931 enum id_type type;
932 const char *attr = NULL;
934 /* Figure out if this is a user or a group */
936 nt_status = get_object_type(c, msg, &type);
937 BAIL_ON_NTSTATUS_ERROR(nt_status);
939 switch (type) {
940 case ID_TYPE_UID:
941 attr = ADEX_ATTR_UID;
942 break;
943 case ID_TYPE_GID:
944 /* What is the group attr for RFC2307 Forests? */
945 attr = ADEX_ATTR_DISPLAYNAME;
946 break;
947 default:
948 nt_status = NT_STATUS_INVALID_PARAMETER;
949 BAIL_ON_NTSTATUS_ERROR(nt_status);
950 break;
953 nt_status = get_object_string(c, msg, ctx, attr, alias);
954 BAIL_ON_NTSTATUS_ERROR(nt_status);
956 done:
957 return nt_status;
960 /********************************************************************
961 *******************************************************************/
963 static NTSTATUS _ccp_get_sid_from_id(DOM_SID * sid,
964 uint32_t id, enum id_type type)
966 struct likewise_cell *cell = NULL;
967 LDAPMessage *msg = NULL;
968 NTSTATUS nt_status;
969 struct lwcell_filter filter;
971 filter.ftype = IdFilter;
972 filter.filter.id.id = id;
973 filter.filter.id.type = type;
975 nt_status = search_cell_list(&cell, &msg, &filter);
976 BAIL_ON_NTSTATUS_ERROR(nt_status);
978 nt_status = pull_sid(cell, msg, sid);
979 BAIL_ON_NTSTATUS_ERROR(nt_status);
981 done:
982 ads_msgfree(cell->conn, msg);
984 return nt_status;
987 /********************************************************************
988 *******************************************************************/
990 static NTSTATUS _ccp_get_id_from_sid(uint32_t * id,
991 enum id_type *type,
992 const DOM_SID * sid)
994 struct likewise_cell *cell = NULL;
995 LDAPMessage *msg = NULL;
996 NTSTATUS nt_status;
997 struct lwcell_filter filter;
999 filter.ftype = SidFilter;
1000 sid_copy(&filter.filter.sid, sid);
1002 nt_status = search_cell_list(&cell, &msg, &filter);
1003 BAIL_ON_NTSTATUS_ERROR(nt_status);
1005 nt_status = pull_id(cell, msg, id, type);
1006 BAIL_ON_NTSTATUS_ERROR(nt_status);
1008 if (*id < min_id_value()) {
1009 nt_status = NT_STATUS_INVALID_PARAMETER;
1010 BAIL_ON_NTSTATUS_ERROR(nt_status);
1013 done:
1014 ads_msgfree(cell->conn, msg);
1016 return nt_status;
1019 /********************************************************************
1020 *******************************************************************/
1022 static NTSTATUS _ccp_nss_get_info(const DOM_SID * sid,
1023 TALLOC_CTX * ctx,
1024 char **homedir,
1025 char **shell,
1026 char **gecos, gid_t * p_gid)
1028 struct likewise_cell *cell = NULL;
1029 LDAPMessage *msg = NULL;
1030 NTSTATUS nt_status;
1031 struct lwcell_filter filter;
1032 enum id_type type;
1034 filter.ftype = SidFilter;
1035 sid_copy(&filter.filter.sid, sid);
1037 nt_status = search_cell_list(&cell, &msg, &filter);
1038 BAIL_ON_NTSTATUS_ERROR(nt_status);
1040 nt_status = get_object_type(cell, msg, &type);
1041 BAIL_ON_NTSTATUS_ERROR(nt_status);
1043 if (type != ID_TYPE_UID) {
1044 nt_status = NT_STATUS_NO_SUCH_USER;
1045 BAIL_ON_NTSTATUS_ERROR(nt_status);
1048 nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos,
1049 (uint32_t*) p_gid);
1050 BAIL_ON_NTSTATUS_ERROR(nt_status);
1052 done:
1053 ads_msgfree(cell->conn, msg);
1055 return nt_status;
1058 /**********************************************************************
1059 *********************************************************************/
1061 static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx,
1062 const char *domain,
1063 const char *name, char **alias)
1065 TALLOC_CTX *frame = talloc_stackframe();
1066 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1067 DOM_SID sid;
1068 struct likewise_cell *cell = NULL;
1069 LDAPMessage *msg = NULL;
1070 struct lwcell_filter filter;
1071 enum lsa_SidType sid_type;
1073 /* Convert the name to a SID */
1075 nt_status = gc_name_to_sid(domain, name, &sid, &sid_type);
1076 BAIL_ON_NTSTATUS_ERROR(nt_status);
1078 /* Find the user/group */
1080 filter.ftype = SidFilter;
1081 sid_copy(&filter.filter.sid, &sid);
1083 nt_status = search_cell_list(&cell, &msg, &filter);
1084 BAIL_ON_NTSTATUS_ERROR(nt_status);
1086 /* Pull the alias and return */
1088 nt_status = pull_alias(cell, msg, ctx, alias);
1089 BAIL_ON_NTSTATUS_ERROR(nt_status);
1091 done:
1092 PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3);
1094 talloc_destroy(frame);
1095 ads_msgfree(cell_connection(cell), msg);
1097 return nt_status;
1100 /**********************************************************************
1101 Map from an alias name to the canonical, qualified name.
1102 Ensure that the alias is only pull from the closest in which
1103 the user or gorup is enabled in
1104 *********************************************************************/
1106 static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx,
1107 const char *domain,
1108 const char *alias, char **name)
1110 TALLOC_CTX *frame = talloc_stackframe();
1111 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1112 DOM_SID sid;
1113 struct likewise_cell *cell_alias = NULL;
1114 LDAPMessage *msg_alias = NULL;
1115 struct likewise_cell *cell_sid = NULL;
1116 LDAPMessage *msg_sid = NULL;
1117 struct lwcell_filter filter;
1118 char *canonical_name = NULL;
1119 enum lsa_SidType type;
1121 /* Find the user/group */
1123 filter.ftype = AliasFilter;
1124 fstrcpy(filter.filter.alias, alias);
1126 nt_status = search_cell_list(&cell_alias, &msg_alias, &filter);
1127 BAIL_ON_NTSTATUS_ERROR(nt_status);
1129 nt_status = pull_sid(cell_alias, msg_alias, &sid);
1130 BAIL_ON_NTSTATUS_ERROR(nt_status);
1132 /* Now search again for the SID according to the cell list.
1133 Verify that the cell of both search results is the same
1134 so that we only match an alias from the closest cell
1135 in which a user/group has been instantied. */
1137 filter.ftype = SidFilter;
1138 sid_copy(&filter.filter.sid, &sid);
1140 nt_status = search_cell_list(&cell_sid, &msg_sid, &filter);
1141 BAIL_ON_NTSTATUS_ERROR(nt_status);
1143 if (cell_alias != cell_sid) {
1144 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1145 BAIL_ON_NTSTATUS_ERROR(nt_status);
1148 /* Finally do the GC sid/name conversion */
1150 nt_status = gc_sid_to_name(&sid, &canonical_name, &type);
1151 BAIL_ON_NTSTATUS_ERROR(nt_status);
1153 *name = talloc_strdup(mem_ctx, canonical_name);
1154 BAIL_ON_PTR_ERROR((*name), nt_status);
1156 nt_status = NT_STATUS_OK;
1158 done:
1159 PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3);
1161 ads_msgfree(cell_connection(cell_alias), msg_alias);
1162 ads_msgfree(cell_connection(cell_sid), msg_sid);
1164 SAFE_FREE(canonical_name);
1166 talloc_destroy(frame);
1168 return nt_status;
1171 /********************************************************************
1172 *******************************************************************/
1174 struct cell_provider_api ccp_unified = {
1175 .get_sid_from_id = _ccp_get_sid_from_id,
1176 .get_id_from_sid = _ccp_get_id_from_sid,
1177 .get_nss_info = _ccp_nss_get_info,
1178 .map_to_alias = _ccp_map_to_alias,
1179 .map_from_alias = _ccp_map_from_alias