ldb: bump version due to header and internal implementation changes
[Samba/id10ts.git] / source3 / winbindd / idmap_adex / provider_unified.c
blob438fb7c978e428fa4c8411d3a0e3e5af615900e1
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 "ads.h"
25 #include "idmap.h"
26 #include "idmap_adex.h"
27 #include "../libcli/ldap/ldap_ndr.h"
28 #include "../libcli/security/dom_sid.h"
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_IDMAP
33 /* Information needed by the LDAP search filters */
35 enum filterType { SidFilter, IdFilter, AliasFilter };
37 struct lwcell_filter
39 enum filterType ftype;
40 bool use2307;
41 union {
42 struct dom_sid sid;
43 struct {
44 uint32_t id;
45 enum id_type type;
46 } id;
47 fstring alias;
48 } filter;
51 /********************************************************************
52 *******************************************************************/
54 static char* build_id_filter(TALLOC_CTX *mem_ctx,
55 uint32_t id,
56 enum id_type type,
57 uint32_t search_flags)
59 char *filter = NULL;
60 char *oc_filter, *attr_filter;
61 NTSTATUS nt_status;
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);
67 const char *oc;
69 /* Construct search filter for objectclass and attributes */
71 switch (type) {
72 case ID_TYPE_UID:
73 oc = ADEX_OC_USER;
74 if (use2307) {
75 oc = ADEX_OC_POSIX_USER;
76 if (use_gc) {
77 oc = AD_USER;
80 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
81 attr_filter = talloc_asprintf(frame, "%s=%u",
82 ADEX_ATTR_UIDNUM, id);
83 break;
85 case ID_TYPE_GID:
86 oc = ADEX_OC_GROUP;
87 if (use2307) {
88 oc = ADEX_OC_POSIX_GROUP;
89 if (use_gc) {
90 oc = AD_GROUP;
93 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
94 attr_filter = talloc_asprintf(frame, "%s=%u",
95 ADEX_ATTR_GIDNUM, id);
96 break;
97 default:
98 return NULL;
101 if (oc_filter == NULL) {
102 goto done;
104 if (attr_filter == NULL) {
105 goto done;
108 /* Use "keywords=%s" for non-schema cells */
110 if (use2307) {
111 filter = talloc_asprintf(mem_ctx,
112 "(&(%s)(%s))",
113 oc_filter,
114 attr_filter);
115 } else {
116 filter = talloc_asprintf(mem_ctx,
117 "(&(keywords=%s)(keywords=%s))",
118 oc_filter,
119 attr_filter);
122 done:
123 talloc_destroy(frame);
125 return filter;
128 /********************************************************************
129 *******************************************************************/
131 static char* build_alias_filter(TALLOC_CTX *mem_ctx,
132 const char *alias,
133 uint32_t search_flags)
135 char *filter = NULL;
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) {
150 goto done;
152 if (group_attr_filter == NULL) {
153 goto done;
156 /* Use "keywords=%s" for non-schema cells */
158 if (use2307) {
159 filter = talloc_asprintf(mem_ctx,
160 "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))",
161 user_attr_filter,
162 search_forest ? AD_USER : ADEX_OC_POSIX_USER,
163 group_attr_filter,
164 search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP);
165 } else {
166 filter = talloc_asprintf(mem_ctx,
167 "(|(keywords=%s)(keywords=%s))",
168 user_attr_filter,
169 group_attr_filter);
172 done:
173 talloc_destroy(frame);
175 return filter;
179 /********************************************************************
180 *******************************************************************/
182 static NTSTATUS search_cell(struct likewise_cell *c,
183 LDAPMessage **msg,
184 const struct lwcell_filter *fdata)
186 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
187 TALLOC_CTX* frame = talloc_stackframe();
188 char *filter = NULL;
189 const char *base = NULL;
190 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
191 const char *attrs[] = { "*", NULL };
192 int count;
193 char *sid_str;
195 /* get the filter and other search parameters */
197 switch (fdata->ftype) {
198 case SidFilter:
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)",
203 sid_str);
204 break;
205 case IdFilter:
206 filter = build_id_filter(frame,
207 fdata->filter.id.id,
208 fdata->filter.id.type,
209 cell_flags(c));
210 break;
211 case AliasFilter:
212 filter = build_alias_filter(frame,
213 fdata->filter.alias,
214 cell_flags(c));
215 break;
216 default:
217 nt_status = NT_STATUS_INVALID_PARAMETER;
218 break;
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,
226 filter, attrs, msg);
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);
234 if (count < 1) {
235 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
236 BAIL_ON_NTSTATUS_ERROR(nt_status);
239 if ( count > 1) {
240 nt_status = NT_STATUS_DUPLICATE_NAME;
241 BAIL_ON_NTSTATUS_ERROR(nt_status);
244 done:
245 PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4);
247 talloc_destroy(discard_const_p(char, base));
248 talloc_destroy(frame);
250 return nt_status;
253 /********************************************************************
254 *******************************************************************/
256 static NTSTATUS search_domain(struct likewise_cell **cell,
257 LDAPMessage **msg,
258 const char *dn,
259 const struct dom_sid *sid)
261 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
262 TALLOC_CTX* frame = talloc_stackframe();
263 int count;
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);
271 if (count < 1) {
272 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
273 BAIL_ON_NTSTATUS_ERROR(nt_status);
276 if ( count > 1) {
277 nt_status = NT_STATUS_DUPLICATE_NAME;
278 BAIL_ON_NTSTATUS_ERROR(nt_status);
281 done:
282 PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4);
283 talloc_destroy(frame);
285 return nt_status;
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();
297 char *p = NULL;
298 char *q = NULL;
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;
308 goto done;
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);
319 q++;
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);
330 if (!domain) {
331 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
332 BAIL_ON_NTSTATUS_ERROR(nt_status);
335 nt_status = NT_STATUS_OK;
337 done:
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
348 scope.
349 *******************************************************************/
351 static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list,
352 LDAPMessage **msg_list,
353 int num_resp,
354 char **dn,
355 struct dom_sid *user_sid)
357 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
358 int i;
359 ADS_STRUCT *ads = NULL;
360 LDAPMessage *msg = NULL;
361 int count = 0;
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);
370 *dn = NULL;
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]);
382 while (e) {
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)) {
387 count++;
389 /* If we've already broken the condition, no
390 need to continue */
392 if (count > 1) {
393 nt_status = NT_STATUS_DUPLICATE_NAME;
394 BAIL_ON_NTSTATUS_ERROR(nt_status);
397 ads = ads_list[i];
398 msg = e;
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);
408 if (!ads || !msg) {
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
414 run home to base */
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)) {
426 char **keywords;
427 char *s;
428 size_t num_lines = 0;
430 keywords = ads_pull_strings(ads, frame, msg, "keywords",
431 &num_lines);
432 BAIL_ON_PTR_ERROR(keywords, nt_status);
434 s = find_attr_string(keywords, num_lines, "backLink");
435 if (!s) {
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;
448 done:
449 if (!NT_STATUS_IS_OK(nt_status)) {
450 SAFE_FREE(*dn);
453 talloc_destroy(frame);
455 return nt_status;
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,
467 LDAPMessage **msg,
468 const struct lwcell_filter *fdata)
470 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
471 TALLOC_CTX *frame = talloc_stackframe();
472 char *filter = NULL;
473 char *dn = NULL;
474 struct gc_info *gc = NULL;
475 ADS_STRUCT **ads_list = NULL;
476 LDAPMessage **msg_list = NULL;
477 int num_resp = 0;
478 LDAPMessage *m;
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);
487 while (gc) {
488 char *sid_binstr = NULL;
489 uint32_t flags = LWCELL_FLAG_SEARCH_FOREST;
491 m = NULL;
493 flags |= cell_flags(gc->forest_cell);
495 switch (fdata->ftype) {
496 case SidFilter:
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);
502 break;
503 case IdFilter:
504 filter = build_id_filter(frame,
505 fdata->filter.id.id,
506 fdata->filter.id.type, flags);
507 break;
508 case AliasFilter:
509 filter = build_alias_filter(frame,
510 fdata->filter.alias,
511 flags);
512 break;
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)) {
518 gc = gc->next;
519 continue;
522 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
523 m, &ads_list, &msg_list,
524 &num_resp);
525 BAIL_ON_NTSTATUS_ERROR(nt_status);
527 gc = gc->next;
530 /* Uniqueness check across forests */
532 nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp,
533 &dn, &user_sid);
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;
542 *msg = m;
544 done:
545 PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4);
547 SAFE_FREE(dn);
549 free_result_array(ads_list, msg_list, num_resp);
550 talloc_destroy(frame);
552 return nt_status;
555 /********************************************************************
556 *******************************************************************/
558 static NTSTATUS search_cell_list(struct likewise_cell **c,
559 LDAPMessage **m,
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);
572 while (cell) {
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);
579 } else {
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)) {
593 break;
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);
601 msg = NULL;
603 cell = cell->next;
606 /* This might be assigning NULL but that is ok as long as we
607 give back the proper error code */
609 *c = result_cell;
610 *m = msg;
612 done:
613 PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3);
615 return nt_status;
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,
624 LDAPMessage *msg,
625 struct dom_sid *sid)
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)) {
641 char **keywords;
642 char *s;
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");
650 if (!s) {
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;
663 done:
664 talloc_destroy(frame);
666 return nt_status;
669 /********************************************************************
670 *******************************************************************/
672 static NTSTATUS get_object_type(struct likewise_cell *c,
673 LDAPMessage *msg,
674 enum id_type *type)
676 TALLOC_CTX *ctx = talloc_stackframe();
677 char **oc_list = NULL;
678 NTSTATUS nt_status = NT_STATUS_OK;
679 size_t list_size = 0;
680 char *s = NULL;
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);
690 if (!oc_list) {
691 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
692 goto done;
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)) {
699 *type = ID_TYPE_UID;
700 } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP)
701 || is_object_class(oc_list, list_size, AD_GROUP)) {
702 *type = ID_TYPE_GID;
703 } else {
704 *type = ID_TYPE_NOT_SPECIFIED;
705 nt_status = NT_STATUS_INVALID_PARAMETER;
707 } else {
708 /* Default to non-schema mode */
710 oc_list = ads_pull_strings(ads, ctx, msg,
711 "keywords", &list_size);
712 if (!oc_list) {
713 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
714 goto done;
717 s = find_attr_string(oc_list, list_size, "objectClass");
718 if (!s) {
719 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
720 goto done;
723 if (strequal(s, ADEX_OC_USER)) {
724 *type = ID_TYPE_UID;
725 } else if (strequal(s, ADEX_OC_GROUP)) {
726 *type = ID_TYPE_GID;
727 } else {
728 *type = ID_TYPE_NOT_SPECIFIED;
729 nt_status = NT_STATUS_INVALID_PARAMETER;
733 nt_status = NT_STATUS_OK;
735 done:
736 talloc_destroy(ctx);
738 return nt_status;
741 /********************************************************************
742 Pull an attribute uint32_t value
743 *******************************************************************/
745 static NTSTATUS get_object_uint32(struct likewise_cell *c,
746 LDAPMessage *msg,
747 const char *attrib,
748 uint32_t *x)
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);
765 } else {
766 /* Non-schema mode */
767 char *s = NULL;
768 uint32_t num;
770 keywords = ads_pull_strings(ads, frame, msg, "keywords",
771 &list_size);
772 BAIL_ON_PTR_ERROR(keywords, nt_status);
774 s = find_attr_string(keywords, list_size, attrib);
775 if (!s) {
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);
785 *x = num;
788 nt_status = NT_STATUS_OK;
790 done:
791 talloc_destroy(frame);
793 return nt_status;
796 /********************************************************************
797 *******************************************************************/
799 static NTSTATUS get_object_id(struct likewise_cell *c,
800 LDAPMessage *msg,
801 enum id_type type,
802 uint32_t *id)
804 NTSTATUS nt_status = NT_STATUS_OK;
805 const char *id_attr;
807 /* Figure out which attribute we need to pull */
809 switch (type) {
810 case ID_TYPE_UID:
811 id_attr = ADEX_ATTR_UIDNUM;
812 break;
813 case ID_TYPE_GID:
814 id_attr = ADEX_ATTR_GIDNUM;
815 break;
816 default:
817 nt_status = NT_STATUS_INVALID_PARAMETER;
818 BAIL_ON_NTSTATUS_ERROR(nt_status);
819 break;
822 nt_status = get_object_uint32(c, msg, id_attr, id);
823 BAIL_ON_NTSTATUS_ERROR(nt_status);
825 done:
826 return nt_status;
829 /********************************************************************
830 Pull the uid/gid and type from an object. This differs depending on
831 the cell flags.
832 *******************************************************************/
834 static NTSTATUS pull_id(struct likewise_cell *c,
835 LDAPMessage *msg,
836 uint32_t *id,
837 enum id_type *type)
839 NTSTATUS nt_status;
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);
847 done:
848 return nt_status;
851 /********************************************************************
852 Pull an attribute string value
853 *******************************************************************/
855 static NTSTATUS get_object_string(struct likewise_cell *c,
856 LDAPMessage *msg,
857 TALLOC_CTX *ctx,
858 const char *attrib,
859 char **string)
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;
867 *string = 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);
875 } else {
876 /* Non-schema mode */
878 char *s = NULL;
880 keywords = ads_pull_strings(ads, frame, msg,
881 "keywords", &list_size);
882 if (!keywords) {
883 nt_status = NT_STATUS_NO_MEMORY;
884 BAIL_ON_NTSTATUS_ERROR(nt_status);
886 s = find_attr_string(keywords, list_size, attrib);
887 if (s) {
888 *string = talloc_strdup(ctx, s);
892 if (!*string) {
893 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
894 BAIL_ON_NTSTATUS_ERROR(nt_status);
897 nt_status = NT_STATUS_OK;
899 done:
900 talloc_destroy(frame);
902 return nt_status;
905 /********************************************************************
906 Pull the struct passwd fields for a user
907 *******************************************************************/
909 static NTSTATUS pull_nss_info(struct likewise_cell *c,
910 LDAPMessage *msg,
911 TALLOC_CTX *ctx,
912 const char **homedir,
913 const char **shell,
914 const char **gecos,
915 gid_t *p_gid)
917 NTSTATUS nt_status;
918 char *tmp;
920 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, &tmp);
921 BAIL_ON_NTSTATUS_ERROR(nt_status);
922 *homedir = tmp;
924 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, &tmp);
925 BAIL_ON_NTSTATUS_ERROR(nt_status);
926 *shell = tmp;
928 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, &tmp);
929 /* Gecos is often not set so ignore failures */
930 *gecos = tmp;
932 nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid);
933 BAIL_ON_NTSTATUS_ERROR(nt_status);
935 done:
936 return nt_status;
939 /********************************************************************
940 Pull the struct passwd fields for a user
941 *******************************************************************/
943 static NTSTATUS pull_alias(struct likewise_cell *c,
944 LDAPMessage *msg,
945 TALLOC_CTX *ctx,
946 char **alias)
948 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
949 enum id_type type;
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);
957 switch (type) {
958 case ID_TYPE_UID:
959 attr = ADEX_ATTR_UID;
960 break;
961 case ID_TYPE_GID:
962 /* What is the group attr for RFC2307 Forests? */
963 attr = ADEX_ATTR_DISPLAYNAME;
964 break;
965 default:
966 nt_status = NT_STATUS_INVALID_PARAMETER;
967 BAIL_ON_NTSTATUS_ERROR(nt_status);
968 break;
971 nt_status = get_object_string(c, msg, ctx, attr, alias);
972 BAIL_ON_NTSTATUS_ERROR(nt_status);
974 done:
975 return 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;
986 NTSTATUS nt_status;
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);
999 done:
1000 ads_msgfree(cell->conn, msg);
1002 return nt_status;
1005 /********************************************************************
1006 *******************************************************************/
1008 static NTSTATUS _ccp_get_id_from_sid(uint32_t * id,
1009 enum id_type *type,
1010 const struct dom_sid * sid)
1012 struct likewise_cell *cell = NULL;
1013 LDAPMessage *msg = NULL;
1014 NTSTATUS nt_status;
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);
1031 done:
1032 ads_msgfree(cell->conn, msg);
1034 return nt_status;
1037 /********************************************************************
1038 *******************************************************************/
1040 static NTSTATUS _ccp_nss_get_info(const struct dom_sid * sid,
1041 TALLOC_CTX * ctx,
1042 const char **homedir,
1043 const char **shell,
1044 const char **gecos, gid_t * p_gid)
1046 struct likewise_cell *cell = NULL;
1047 LDAPMessage *msg = NULL;
1048 NTSTATUS nt_status;
1049 struct lwcell_filter filter;
1050 enum id_type type;
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,
1067 (uint32_t*) p_gid);
1068 BAIL_ON_NTSTATUS_ERROR(nt_status);
1070 done:
1071 ads_msgfree(cell->conn, msg);
1073 return nt_status;
1076 /**********************************************************************
1077 *********************************************************************/
1079 static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx,
1080 const char *domain,
1081 const char *name, char **alias)
1083 TALLOC_CTX *frame = talloc_stackframe();
1084 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1085 struct dom_sid sid;
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);
1109 done:
1110 PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3);
1112 talloc_destroy(frame);
1113 ads_msgfree(cell_connection(cell), msg);
1115 return nt_status;
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,
1125 const char *domain,
1126 const char *alias, char **name)
1128 TALLOC_CTX *frame = talloc_stackframe();
1129 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1130 struct dom_sid sid;
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;
1176 done:
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);
1186 return nt_status;
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