s3: piddir creation fix part 2.
[Samba/gebeck_regimport.git] / source3 / winbindd / idmap_adex / provider_unified.c
blob9e271a0db9ecdfca0078f2c7cf6eca034584382b
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 BAIL_ON_PTR_ERROR(oc_filter, nt_status);
102 BAIL_ON_PTR_ERROR(attr_filter, nt_status);
104 /* Use "keywords=%s" for non-schema cells */
106 if (use2307) {
107 filter = talloc_asprintf(mem_ctx,
108 "(&(%s)(%s))",
109 oc_filter,
110 attr_filter);
111 } else {
112 filter = talloc_asprintf(mem_ctx,
113 "(&(keywords=%s)(keywords=%s))",
114 oc_filter,
115 attr_filter);
118 done:
119 talloc_destroy(frame);
121 return filter;
124 /********************************************************************
125 *******************************************************************/
127 static char* build_alias_filter(TALLOC_CTX *mem_ctx,
128 const char *alias,
129 uint32_t search_flags)
131 char *filter = NULL;
132 char *user_attr_filter, *group_attr_filter;
133 NTSTATUS nt_status;
134 TALLOC_CTX *frame = talloc_stackframe();
135 bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
136 == LWCELL_FLAG_USE_RFC2307_ATTRS);
137 bool search_forest = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
138 == LWCELL_FLAG_SEARCH_FOREST);
140 /* Construct search filter for objectclass and attributes */
142 user_attr_filter = talloc_asprintf(frame, "%s=%s",
143 ADEX_ATTR_UID, alias);
144 group_attr_filter = talloc_asprintf(frame, "%s=%s",
145 ADEX_ATTR_DISPLAYNAME, alias);
146 BAIL_ON_PTR_ERROR(user_attr_filter, nt_status);
147 BAIL_ON_PTR_ERROR(group_attr_filter, nt_status);
149 /* Use "keywords=%s" for non-schema cells */
151 if (use2307) {
152 filter = talloc_asprintf(mem_ctx,
153 "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))",
154 user_attr_filter,
155 search_forest ? AD_USER : ADEX_OC_POSIX_USER,
156 group_attr_filter,
157 search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP);
158 } else {
159 filter = talloc_asprintf(mem_ctx,
160 "(|(keywords=%s)(keywords=%s))",
161 user_attr_filter,
162 group_attr_filter);
165 done:
166 talloc_destroy(frame);
168 return filter;
172 /********************************************************************
173 *******************************************************************/
175 static NTSTATUS search_cell(struct likewise_cell *c,
176 LDAPMessage **msg,
177 const struct lwcell_filter *fdata)
179 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
180 TALLOC_CTX* frame = talloc_stackframe();
181 char *filter = NULL;
182 const char *base = NULL;
183 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
184 const char *attrs[] = { "*", NULL };
185 int count;
186 char *sid_str;
188 /* get the filter and other search parameters */
190 switch (fdata->ftype) {
191 case SidFilter:
192 sid_str = sid_string_talloc(frame, &fdata->filter.sid);
193 BAIL_ON_PTR_ERROR(sid_str, nt_status);
195 filter = talloc_asprintf(frame, "(keywords=backLink=%s)",
196 sid_str);
197 break;
198 case IdFilter:
199 filter = build_id_filter(frame,
200 fdata->filter.id.id,
201 fdata->filter.id.type,
202 cell_flags(c));
203 break;
204 case AliasFilter:
205 filter = build_alias_filter(frame,
206 fdata->filter.alias,
207 cell_flags(c));
208 break;
209 default:
210 nt_status = NT_STATUS_INVALID_PARAMETER;
211 break;
213 BAIL_ON_PTR_ERROR(filter, nt_status);
215 base = cell_search_base(c);
216 BAIL_ON_PTR_ERROR(base, nt_status);
218 ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE,
219 filter, attrs, msg);
221 nt_status = ads_ntstatus(ads_status);
222 BAIL_ON_NTSTATUS_ERROR(nt_status);
224 /* Now check that we got only one reply */
226 count = ads_count_replies(c->conn, *msg);
227 if (count < 1) {
228 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
229 BAIL_ON_NTSTATUS_ERROR(nt_status);
232 if ( count > 1) {
233 nt_status = NT_STATUS_DUPLICATE_NAME;
234 BAIL_ON_NTSTATUS_ERROR(nt_status);
237 done:
238 PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4);
240 talloc_destroy(discard_const_p(char, base));
241 talloc_destroy(frame);
243 return nt_status;
246 /********************************************************************
247 *******************************************************************/
249 static NTSTATUS search_domain(struct likewise_cell **cell,
250 LDAPMessage **msg,
251 const char *dn,
252 const struct dom_sid *sid)
254 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
255 TALLOC_CTX* frame = talloc_stackframe();
256 int count;
258 nt_status = dc_search_domains(cell, msg, dn, sid);
259 BAIL_ON_NTSTATUS_ERROR(nt_status);
261 /* Now check that we got only one reply */
263 count = ads_count_replies(cell_connection(*cell), *msg);
264 if (count < 1) {
265 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
266 BAIL_ON_NTSTATUS_ERROR(nt_status);
269 if ( count > 1) {
270 nt_status = NT_STATUS_DUPLICATE_NAME;
271 BAIL_ON_NTSTATUS_ERROR(nt_status);
274 done:
275 PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4);
276 talloc_destroy(frame);
278 return nt_status;
282 /********************************************************************
283 Check that a DN is within the forest scope.
284 *******************************************************************/
286 static bool check_forest_scope(const char *dn)
288 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
289 TALLOC_CTX *frame = talloc_stackframe();
290 char *p = NULL;
291 char *q = NULL;
292 char *dns_domain = NULL;
293 struct winbindd_tdc_domain *domain;
295 /* If the DN does *not* contain "$LikewiseIdentityCell",
296 assume this is a schema mode forest and it is in the
297 forest scope by definition. */
299 if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) {
300 nt_status = NT_STATUS_OK;
301 goto done;
304 /* If this is a non-schema forest, then make sure that the DN
305 is in the form "...,cn=$LikewiseIdentityCell,DC=..." */
307 if ((q = strchr_m(p, ',')) == NULL) {
308 nt_status = NT_STATUS_OBJECT_NAME_INVALID;
309 BAIL_ON_NTSTATUS_ERROR(nt_status);
312 q++;
313 if (strncasecmp_m(q, "dc=", 3) != 0) {
314 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
315 BAIL_ON_NTSTATUS_ERROR(nt_status);
319 dns_domain = cell_dn_to_dns(q);
320 BAIL_ON_PTR_ERROR(dns_domain, nt_status);
322 domain = wcache_tdc_fetch_domain(frame, dns_domain);
323 if (!domain) {
324 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
325 BAIL_ON_NTSTATUS_ERROR(nt_status);
328 nt_status = NT_STATUS_OK;
330 done:
331 talloc_destroy(frame);
332 SAFE_FREE(dns_domain);
334 return NT_STATUS_IS_OK(nt_status);
339 /********************************************************************
340 Check that only one result was returned within the forest cell
341 scope.
342 *******************************************************************/
344 static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list,
345 LDAPMessage **msg_list,
346 int num_resp,
347 char **dn,
348 struct dom_sid *user_sid)
350 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
351 int i;
352 ADS_STRUCT *ads = NULL;
353 LDAPMessage *msg = NULL;
354 int count = 0;
355 char *entry_dn = NULL;
356 TALLOC_CTX *frame = talloc_stackframe();
358 if (!dn || !user_sid) {
359 nt_status = NT_STATUS_INVALID_PARAMETER;
360 BAIL_ON_NTSTATUS_ERROR(nt_status);
363 *dn = NULL;
365 if (!ads_list || !msg_list || (num_resp == 0)) {
366 nt_status = NT_STATUS_NO_SUCH_FILE;
367 BAIL_ON_NTSTATUS_ERROR(nt_status);
370 /* Loop over all msgs */
372 for (i=0; i<num_resp; i++) {
373 LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]);
375 while (e) {
376 entry_dn = ads_get_dn(ads_list[i], talloc_tos(), e);
377 BAIL_ON_PTR_ERROR(entry_dn, nt_status);
379 if (check_forest_scope(entry_dn)) {
380 count++;
382 /* If we've already broken the condition, no
383 need to continue */
385 if (count > 1) {
386 nt_status = NT_STATUS_DUPLICATE_NAME;
387 BAIL_ON_NTSTATUS_ERROR(nt_status);
390 ads = ads_list[i];
391 msg = e;
392 *dn = SMB_STRDUP(entry_dn);
393 BAIL_ON_PTR_ERROR((*dn), nt_status);
396 e = ads_next_entry(ads_list[i], e);
397 TALLOC_FREE(entry_dn);
401 if (!ads || !msg) {
402 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
403 BAIL_ON_NTSTATUS_ERROR(nt_status);
406 /* If we made is through the loop, then grab the user_sid and
407 run home to base */
410 Try and get the SID from either objectSid or keywords.
411 We cannot use pull_sid() here since we want to try
412 both methods and not only one or the other (and we
413 have no full likewise_cell struct.
415 Fail if both are unavailable
418 if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) {
419 char **keywords;
420 char *s;
421 size_t num_lines = 0;
423 keywords = ads_pull_strings(ads, frame, msg, "keywords",
424 &num_lines);
425 BAIL_ON_PTR_ERROR(keywords, nt_status);
427 s = find_attr_string(keywords, num_lines, "backLink");
428 if (!s) {
429 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
430 BAIL_ON_NTSTATUS_ERROR(nt_status);
433 if (!string_to_sid(user_sid, s)) {
434 nt_status = NT_STATUS_INVALID_SID;
435 BAIL_ON_NTSTATUS_ERROR(nt_status);
439 nt_status = NT_STATUS_OK;
441 done:
442 if (!NT_STATUS_IS_OK(nt_status)) {
443 SAFE_FREE(*dn);
446 talloc_destroy(frame);
448 return nt_status;
451 /********************************************************************
452 Search all forests. Each forest can have it's own forest-cell
453 settings so we have to generate the filter for each search.
454 We don't use gc_search_all_forests() since we may have a different
455 schema model in each forest and need to construct the search
456 filter for each GC search.
457 *******************************************************************/
459 static NTSTATUS search_forest(struct likewise_cell *forest_cell,
460 LDAPMessage **msg,
461 const struct lwcell_filter *fdata)
463 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
464 TALLOC_CTX *frame = talloc_stackframe();
465 char *filter = NULL;
466 char *dn = NULL;
467 struct gc_info *gc = NULL;
468 ADS_STRUCT **ads_list = NULL;
469 LDAPMessage **msg_list = NULL;
470 int num_resp = 0;
471 LDAPMessage *m;
472 struct dom_sid user_sid;
473 struct likewise_cell *domain_cell = NULL;
475 if ((gc = gc_search_start()) == NULL) {
476 nt_status = NT_STATUS_INVALID_DOMAIN_STATE;
477 BAIL_ON_NTSTATUS_ERROR(nt_status);
480 while (gc) {
481 char *sid_binstr = NULL;
482 uint32_t flags = LWCELL_FLAG_SEARCH_FOREST;
484 m = NULL;
486 flags |= cell_flags(gc->forest_cell);
488 switch (fdata->ftype) {
489 case SidFilter:
490 sid_binstr = ldap_encode_ndr_dom_sid(frame, &fdata->filter.sid);
491 BAIL_ON_PTR_ERROR(sid_binstr, nt_status);
493 filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr);
494 TALLOC_FREE(sid_binstr);
495 break;
496 case IdFilter:
497 filter = build_id_filter(frame,
498 fdata->filter.id.id,
499 fdata->filter.id.type, flags);
500 break;
501 case AliasFilter:
502 filter = build_alias_filter(frame,
503 fdata->filter.alias,
504 flags);
505 break;
508 /* First find the sparse object in GC */
509 nt_status = gc_search_forest(gc, &m, filter);
510 if (!NT_STATUS_IS_OK(nt_status)) {
511 gc = gc->next;
512 continue;
515 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
516 m, &ads_list, &msg_list,
517 &num_resp);
518 BAIL_ON_NTSTATUS_ERROR(nt_status);
520 gc = gc->next;
523 /* Uniqueness check across forests */
525 nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp,
526 &dn, &user_sid);
527 BAIL_ON_NTSTATUS_ERROR(nt_status);
529 nt_status = search_domain(&domain_cell, &m, dn, &user_sid);
530 BAIL_ON_NTSTATUS_ERROR(nt_status);
532 /* Save the connection and results in the return parameters */
534 forest_cell->gc_search_cell = domain_cell;
535 *msg = m;
537 done:
538 PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4);
540 SAFE_FREE(dn);
542 free_result_array(ads_list, msg_list, num_resp);
543 talloc_destroy(frame);
545 return nt_status;
548 /********************************************************************
549 *******************************************************************/
551 static NTSTATUS search_cell_list(struct likewise_cell **c,
552 LDAPMessage **m,
553 const struct lwcell_filter *fdata)
555 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
556 struct likewise_cell *cell = NULL;
557 LDAPMessage *msg = NULL;
558 struct likewise_cell *result_cell = NULL;
560 if ((cell = cell_list_head()) == NULL) {
561 nt_status = NT_STATUS_INVALID_SERVER_STATE;
562 BAIL_ON_NTSTATUS_ERROR(nt_status);
565 while (cell) {
566 /* Clear any previous GC search results */
568 cell->gc_search_cell = NULL;
570 if (cell_search_forest(cell)) {
571 nt_status = search_forest(cell, &msg, fdata);
572 } else {
573 nt_status = search_cell(cell, &msg, fdata);
576 /* Always point to the search result cell.
577 In forests this might be for another domain
578 which means the schema model may be different */
580 result_cell = cell->gc_search_cell ?
581 cell->gc_search_cell : cell;
583 /* Check if we are done */
585 if (NT_STATUS_IS_OK(nt_status)) {
586 break;
589 /* No luck. Free memory and hit the next cell.
590 Forest searches always set the gc_search_cell
591 so give preference to that connection if possible. */
593 ads_msgfree(cell_connection(result_cell), msg);
594 msg = NULL;
596 cell = cell->next;
599 /* This might be assigning NULL but that is ok as long as we
600 give back the proper error code */
602 *c = result_cell;
603 *m = msg;
605 done:
606 PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3);
608 return nt_status;
611 /********************************************************************
612 Pull the SID from an object which is always stored in the keywords
613 attribute as "backLink=S-1-5-21-..."
614 *******************************************************************/
616 static NTSTATUS pull_sid(struct likewise_cell *c,
617 LDAPMessage *msg,
618 struct dom_sid *sid)
620 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
621 TALLOC_CTX *frame = talloc_stackframe();
622 ADS_STRUCT *ads = NULL;
624 ads = cell_connection(c);
627 We have two ways of getting the sid:
628 (a) from the objectSID in case of a GC search,
629 (b) from backLink in the case of a cell search.
630 Pull the keywords attributes and grab the backLink.
633 if (!ads_pull_sid(ads, msg, "objectSid", sid)) {
634 char **keywords;
635 char *s;
636 size_t num_lines = 0;
638 keywords = ads_pull_strings(ads, frame, msg,
639 "keywords", &num_lines);
640 BAIL_ON_PTR_ERROR(keywords, nt_status);
642 s = find_attr_string(keywords, num_lines, "backLink");
643 if (!s) {
644 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
645 BAIL_ON_NTSTATUS_ERROR(nt_status);
648 if (!string_to_sid(sid, s)) {
649 nt_status = NT_STATUS_INVALID_SID;
650 BAIL_ON_NTSTATUS_ERROR(nt_status);
654 nt_status = NT_STATUS_OK;
656 done:
657 talloc_destroy(frame);
659 return nt_status;
662 /********************************************************************
663 *******************************************************************/
665 static NTSTATUS get_object_type(struct likewise_cell *c,
666 LDAPMessage *msg,
667 enum id_type *type)
669 TALLOC_CTX *ctx = talloc_stackframe();
670 char **oc_list = NULL;
671 NTSTATUS nt_status = NT_STATUS_OK;
672 size_t list_size = 0;
673 char *s = NULL;
674 ADS_STRUCT *ads = NULL;
676 ads = cell_connection(c);
678 /* Deal with RFC 2307 support first */
680 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
681 oc_list = ads_pull_strings(ads, ctx, msg,
682 "objectClass", &list_size);
683 if (!oc_list) {
684 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
685 goto done;
688 /* Check for posix classes and AD classes */
690 if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER)
691 || is_object_class(oc_list, list_size, AD_USER)) {
692 *type = ID_TYPE_UID;
693 } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP)
694 || is_object_class(oc_list, list_size, AD_GROUP)) {
695 *type = ID_TYPE_GID;
696 } else {
697 *type = ID_TYPE_NOT_SPECIFIED;
698 nt_status = NT_STATUS_INVALID_PARAMETER;
700 } else {
701 /* Default to non-schema mode */
703 oc_list = ads_pull_strings(ads, ctx, msg,
704 "keywords", &list_size);
705 if (!oc_list) {
706 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
707 goto done;
710 s = find_attr_string(oc_list, list_size, "objectClass");
711 if (!s) {
712 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
713 goto done;
716 if (strequal(s, ADEX_OC_USER)) {
717 *type = ID_TYPE_UID;
718 } else if (strequal(s, ADEX_OC_GROUP)) {
719 *type = ID_TYPE_GID;
720 } else {
721 *type = ID_TYPE_NOT_SPECIFIED;
722 nt_status = NT_STATUS_INVALID_PARAMETER;
726 nt_status = NT_STATUS_OK;
728 done:
729 talloc_destroy(ctx);
731 return nt_status;
734 /********************************************************************
735 Pull an attribute uint32_t value
736 *******************************************************************/
738 static NTSTATUS get_object_uint32(struct likewise_cell *c,
739 LDAPMessage *msg,
740 const char *attrib,
741 uint32_t *x)
743 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
744 char **keywords = NULL;
745 size_t list_size = 0;
746 TALLOC_CTX *frame = talloc_stackframe();
747 ADS_STRUCT *ads = NULL;
749 ads = cell_connection(c);
751 /* Deal with RFC2307 schema */
753 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
754 if (!ads_pull_uint32(ads, msg, attrib, x)) {
755 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
756 BAIL_ON_NTSTATUS_ERROR(nt_status);
758 } else {
759 /* Non-schema mode */
760 char *s = NULL;
761 uint32_t num;
763 keywords = ads_pull_strings(ads, frame, msg, "keywords",
764 &list_size);
765 BAIL_ON_PTR_ERROR(keywords, nt_status);
767 s = find_attr_string(keywords, list_size, attrib);
768 if (!s) {
769 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
770 BAIL_ON_NTSTATUS_ERROR(nt_status);
773 num = strtoll(s, NULL, 10);
774 if (errno == ERANGE) {
775 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
776 BAIL_ON_NTSTATUS_ERROR(nt_status);
778 *x = num;
781 nt_status = NT_STATUS_OK;
783 done:
784 talloc_destroy(frame);
786 return nt_status;
789 /********************************************************************
790 *******************************************************************/
792 static NTSTATUS get_object_id(struct likewise_cell *c,
793 LDAPMessage *msg,
794 enum id_type type,
795 uint32_t *id)
797 NTSTATUS nt_status = NT_STATUS_OK;
798 const char *id_attr;
800 /* Figure out which attribute we need to pull */
802 switch (type) {
803 case ID_TYPE_UID:
804 id_attr = ADEX_ATTR_UIDNUM;
805 break;
806 case ID_TYPE_GID:
807 id_attr = ADEX_ATTR_GIDNUM;
808 break;
809 default:
810 nt_status = NT_STATUS_INVALID_PARAMETER;
811 BAIL_ON_NTSTATUS_ERROR(nt_status);
812 break;
815 nt_status = get_object_uint32(c, msg, id_attr, id);
816 BAIL_ON_NTSTATUS_ERROR(nt_status);
818 done:
819 return nt_status;
822 /********************************************************************
823 Pull the uid/gid and type from an object. This differs depending on
824 the cell flags.
825 *******************************************************************/
827 static NTSTATUS pull_id(struct likewise_cell *c,
828 LDAPMessage *msg,
829 uint32_t *id,
830 enum id_type *type)
832 NTSTATUS nt_status;
834 nt_status = get_object_type(c, msg, type);
835 BAIL_ON_NTSTATUS_ERROR(nt_status);
837 nt_status = get_object_id(c, msg, *type, id);
838 BAIL_ON_NTSTATUS_ERROR(nt_status);
840 done:
841 return nt_status;
844 /********************************************************************
845 Pull an attribute string value
846 *******************************************************************/
848 static NTSTATUS get_object_string(struct likewise_cell *c,
849 LDAPMessage *msg,
850 TALLOC_CTX *ctx,
851 const char *attrib,
852 char **string)
854 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
855 char **keywords = NULL;
856 size_t list_size = 0;
857 TALLOC_CTX *frame = talloc_stackframe();
858 ADS_STRUCT *ads = NULL;
860 *string = NULL;
862 ads = cell_connection(c);
864 /* Deal with RFC2307 schema */
866 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
867 *string = ads_pull_string(ads, ctx, msg, attrib);
868 } else {
869 /* Non-schema mode */
871 char *s = NULL;
873 keywords = ads_pull_strings(ads, frame, msg,
874 "keywords", &list_size);
875 if (!keywords) {
876 nt_status = NT_STATUS_NO_MEMORY;
877 BAIL_ON_NTSTATUS_ERROR(nt_status);
879 s = find_attr_string(keywords, list_size, attrib);
880 if (s) {
881 *string = talloc_strdup(ctx, s);
885 if (!*string) {
886 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
887 BAIL_ON_NTSTATUS_ERROR(nt_status);
890 nt_status = NT_STATUS_OK;
892 done:
893 talloc_destroy(frame);
895 return nt_status;
898 /********************************************************************
899 Pull the struct passwd fields for a user
900 *******************************************************************/
902 static NTSTATUS pull_nss_info(struct likewise_cell *c,
903 LDAPMessage *msg,
904 TALLOC_CTX *ctx,
905 const char **homedir,
906 const char **shell,
907 const char **gecos,
908 gid_t *p_gid)
910 NTSTATUS nt_status;
911 char *tmp;
913 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, &tmp);
914 BAIL_ON_NTSTATUS_ERROR(nt_status);
915 *homedir = tmp;
917 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, &tmp);
918 BAIL_ON_NTSTATUS_ERROR(nt_status);
919 *shell = tmp;
921 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, &tmp);
922 /* Gecos is often not set so ignore failures */
923 *gecos = tmp;
925 nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid);
926 BAIL_ON_NTSTATUS_ERROR(nt_status);
928 done:
929 return nt_status;
932 /********************************************************************
933 Pull the struct passwd fields for a user
934 *******************************************************************/
936 static NTSTATUS pull_alias(struct likewise_cell *c,
937 LDAPMessage *msg,
938 TALLOC_CTX *ctx,
939 char **alias)
941 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
942 enum id_type type;
943 const char *attr = NULL;
945 /* Figure out if this is a user or a group */
947 nt_status = get_object_type(c, msg, &type);
948 BAIL_ON_NTSTATUS_ERROR(nt_status);
950 switch (type) {
951 case ID_TYPE_UID:
952 attr = ADEX_ATTR_UID;
953 break;
954 case ID_TYPE_GID:
955 /* What is the group attr for RFC2307 Forests? */
956 attr = ADEX_ATTR_DISPLAYNAME;
957 break;
958 default:
959 nt_status = NT_STATUS_INVALID_PARAMETER;
960 BAIL_ON_NTSTATUS_ERROR(nt_status);
961 break;
964 nt_status = get_object_string(c, msg, ctx, attr, alias);
965 BAIL_ON_NTSTATUS_ERROR(nt_status);
967 done:
968 return nt_status;
971 /********************************************************************
972 *******************************************************************/
974 static NTSTATUS _ccp_get_sid_from_id(struct dom_sid * sid,
975 uint32_t id, enum id_type type)
977 struct likewise_cell *cell = NULL;
978 LDAPMessage *msg = NULL;
979 NTSTATUS nt_status;
980 struct lwcell_filter filter;
982 filter.ftype = IdFilter;
983 filter.filter.id.id = id;
984 filter.filter.id.type = type;
986 nt_status = search_cell_list(&cell, &msg, &filter);
987 BAIL_ON_NTSTATUS_ERROR(nt_status);
989 nt_status = pull_sid(cell, msg, sid);
990 BAIL_ON_NTSTATUS_ERROR(nt_status);
992 done:
993 ads_msgfree(cell->conn, msg);
995 return nt_status;
998 /********************************************************************
999 *******************************************************************/
1001 static NTSTATUS _ccp_get_id_from_sid(uint32_t * id,
1002 enum id_type *type,
1003 const struct dom_sid * sid)
1005 struct likewise_cell *cell = NULL;
1006 LDAPMessage *msg = NULL;
1007 NTSTATUS nt_status;
1008 struct lwcell_filter filter;
1010 filter.ftype = SidFilter;
1011 sid_copy(&filter.filter.sid, sid);
1013 nt_status = search_cell_list(&cell, &msg, &filter);
1014 BAIL_ON_NTSTATUS_ERROR(nt_status);
1016 nt_status = pull_id(cell, msg, id, type);
1017 BAIL_ON_NTSTATUS_ERROR(nt_status);
1019 if (*id < min_id_value()) {
1020 nt_status = NT_STATUS_INVALID_PARAMETER;
1021 BAIL_ON_NTSTATUS_ERROR(nt_status);
1024 done:
1025 ads_msgfree(cell->conn, msg);
1027 return nt_status;
1030 /********************************************************************
1031 *******************************************************************/
1033 static NTSTATUS _ccp_nss_get_info(const struct dom_sid * sid,
1034 TALLOC_CTX * ctx,
1035 const char **homedir,
1036 const char **shell,
1037 const char **gecos, gid_t * p_gid)
1039 struct likewise_cell *cell = NULL;
1040 LDAPMessage *msg = NULL;
1041 NTSTATUS nt_status;
1042 struct lwcell_filter filter;
1043 enum id_type type;
1045 filter.ftype = SidFilter;
1046 sid_copy(&filter.filter.sid, sid);
1048 nt_status = search_cell_list(&cell, &msg, &filter);
1049 BAIL_ON_NTSTATUS_ERROR(nt_status);
1051 nt_status = get_object_type(cell, msg, &type);
1052 BAIL_ON_NTSTATUS_ERROR(nt_status);
1054 if (type != ID_TYPE_UID) {
1055 nt_status = NT_STATUS_NO_SUCH_USER;
1056 BAIL_ON_NTSTATUS_ERROR(nt_status);
1059 nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos,
1060 (uint32_t*) p_gid);
1061 BAIL_ON_NTSTATUS_ERROR(nt_status);
1063 done:
1064 ads_msgfree(cell->conn, msg);
1066 return nt_status;
1069 /**********************************************************************
1070 *********************************************************************/
1072 static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx,
1073 const char *domain,
1074 const char *name, char **alias)
1076 TALLOC_CTX *frame = talloc_stackframe();
1077 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1078 struct dom_sid sid;
1079 struct likewise_cell *cell = NULL;
1080 LDAPMessage *msg = NULL;
1081 struct lwcell_filter filter;
1082 enum lsa_SidType sid_type;
1084 /* Convert the name to a SID */
1086 nt_status = gc_name_to_sid(domain, name, &sid, &sid_type);
1087 BAIL_ON_NTSTATUS_ERROR(nt_status);
1089 /* Find the user/group */
1091 filter.ftype = SidFilter;
1092 sid_copy(&filter.filter.sid, &sid);
1094 nt_status = search_cell_list(&cell, &msg, &filter);
1095 BAIL_ON_NTSTATUS_ERROR(nt_status);
1097 /* Pull the alias and return */
1099 nt_status = pull_alias(cell, msg, ctx, alias);
1100 BAIL_ON_NTSTATUS_ERROR(nt_status);
1102 done:
1103 PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3);
1105 talloc_destroy(frame);
1106 ads_msgfree(cell_connection(cell), msg);
1108 return nt_status;
1111 /**********************************************************************
1112 Map from an alias name to the canonical, qualified name.
1113 Ensure that the alias is only pull from the closest in which
1114 the user or gorup is enabled in
1115 *********************************************************************/
1117 static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx,
1118 const char *domain,
1119 const char *alias, char **name)
1121 TALLOC_CTX *frame = talloc_stackframe();
1122 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1123 struct dom_sid sid;
1124 struct likewise_cell *cell_alias = NULL;
1125 LDAPMessage *msg_alias = NULL;
1126 struct likewise_cell *cell_sid = NULL;
1127 LDAPMessage *msg_sid = NULL;
1128 struct lwcell_filter filter;
1129 char *canonical_name = NULL;
1130 enum lsa_SidType type;
1132 /* Find the user/group */
1134 filter.ftype = AliasFilter;
1135 fstrcpy(filter.filter.alias, alias);
1137 nt_status = search_cell_list(&cell_alias, &msg_alias, &filter);
1138 BAIL_ON_NTSTATUS_ERROR(nt_status);
1140 nt_status = pull_sid(cell_alias, msg_alias, &sid);
1141 BAIL_ON_NTSTATUS_ERROR(nt_status);
1143 /* Now search again for the SID according to the cell list.
1144 Verify that the cell of both search results is the same
1145 so that we only match an alias from the closest cell
1146 in which a user/group has been instantied. */
1148 filter.ftype = SidFilter;
1149 sid_copy(&filter.filter.sid, &sid);
1151 nt_status = search_cell_list(&cell_sid, &msg_sid, &filter);
1152 BAIL_ON_NTSTATUS_ERROR(nt_status);
1154 if (cell_alias != cell_sid) {
1155 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1156 BAIL_ON_NTSTATUS_ERROR(nt_status);
1159 /* Finally do the GC sid/name conversion */
1161 nt_status = gc_sid_to_name(&sid, &canonical_name, &type);
1162 BAIL_ON_NTSTATUS_ERROR(nt_status);
1164 *name = talloc_strdup(mem_ctx, canonical_name);
1165 BAIL_ON_PTR_ERROR((*name), nt_status);
1167 nt_status = NT_STATUS_OK;
1169 done:
1170 PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3);
1172 ads_msgfree(cell_connection(cell_alias), msg_alias);
1173 ads_msgfree(cell_connection(cell_sid), msg_sid);
1175 SAFE_FREE(canonical_name);
1177 talloc_destroy(frame);
1179 return nt_status;
1182 /********************************************************************
1183 *******************************************************************/
1185 struct cell_provider_api ccp_unified = {
1186 .get_sid_from_id = _ccp_get_sid_from_id,
1187 .get_id_from_sid = _ccp_get_id_from_sid,
1188 .get_nss_info = _ccp_nss_get_info,
1189 .map_to_alias = _ccp_map_to_alias,
1190 .map_from_alias = _ccp_map_from_alias