/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- build_id_filter
- build_alias_filter
- search_cell
- search_domain
- check_forest_scope
- check_result_unique_scoped
- search_forest
- search_cell_list
- pull_sid
- get_object_type
- get_object_uint32
- get_object_id
- pull_id
- get_object_string
- pull_nss_info
- pull_alias
- _ccp_get_sid_from_id
- _ccp_get_id_from_sid
- _ccp_nss_get_info
- _ccp_map_to_alias
- _ccp_map_from_alias
1 /*
2 * idmap_adex
3 *
4 * Provider for RFC2307 and SFU AD Forests
5 *
6 * Copyright (C) Gerald (Jerry) Carter 2006-2008
7 *
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.
12 *
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.
17 *
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.
21 */
22
23 #include "includes.h"
24 #include "idmap_adex.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_IDMAP
28
29 /* Information needed by the LDAP search filters */
30
31 enum filterType { SidFilter, IdFilter, AliasFilter };
32
33 struct lwcell_filter
34 {
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;
45 };
46
47 /********************************************************************
48 *******************************************************************/
49
50 static char* build_id_filter(uint32_t id,
/* [<][>][^][v][top][bottom][index][help] */
51 enum id_type type,
52 uint32_t search_flags)
53 {
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;
63
64 /* Construct search filter for objectclass and attributes */
65
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;
73 }
74 }
75 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
76 attr_filter = talloc_asprintf(frame, "%s=%u",
77 ADEX_ATTR_UIDNUM, id);
78 break;
79
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;
86 }
87 }
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;
94 }
95
96 BAIL_ON_PTR_ERROR(oc_filter, nt_status);
97 BAIL_ON_PTR_ERROR(attr_filter, nt_status);
98
99 /* Use "keywords=%s" for non-schema cells */
100
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);
107 }
108
109 talloc_destroy(oc_filter);
110 talloc_destroy(attr_filter);
111
112 done:
113 /* Don't destroy the stackframe CTX since we are returning
114 memory from it */
115
116 return filter;
117 }
118
119 /********************************************************************
120 *******************************************************************/
121
122 static char* build_alias_filter(const char *alias, uint32_t search_flags)
/* [<][>][^][v][top][bottom][index][help] */
123 {
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);
132
133 /* Construct search filter for objectclass and attributes */
134
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);
141
142 /* Use "keywords=%s" for non-schema cells */
143
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);
156 }
157
158 talloc_destroy(user_attr_filter);
159 talloc_destroy(group_attr_filter);
160
161 done:
162 /* Don't destroy the stackframe CTX since we are returning
163 memory from it */
164
165 return filter;
166 }
167
168
169 /********************************************************************
170 *******************************************************************/
171
172 static NTSTATUS search_cell(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
173 LDAPMessage **msg,
174 const struct lwcell_filter *fdata)
175 {
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;
184
185 /* get the filter and other search parameters */
186
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);
191
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;
207 }
208 BAIL_ON_PTR_ERROR(filter, nt_status);
209
210 base = cell_search_base(c);
211 BAIL_ON_PTR_ERROR(base, nt_status);
212
213 ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE,
214 filter, attrs, msg);
215
216 nt_status = ads_ntstatus(ads_status);
217 BAIL_ON_NTSTATUS_ERROR(nt_status);
218
219 /* Now check that we got only one reply */
220
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);
225 }
226
227 if ( count > 1) {
228 nt_status = NT_STATUS_DUPLICATE_NAME;
229 BAIL_ON_NTSTATUS_ERROR(nt_status);
230 }
231
232 done:
233 PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4);
234
235 talloc_destroy(CONST_DISCARD(char*, base));
236 talloc_destroy(frame);
237
238 return nt_status;
239 }
240
241 /********************************************************************
242 *******************************************************************/
243
244 static NTSTATUS search_domain(struct likewise_cell **cell,
/* [<][>][^][v][top][bottom][index][help] */
245 LDAPMessage **msg,
246 const char *dn,
247 const DOM_SID *sid)
248 {
249 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
250 TALLOC_CTX* frame = talloc_stackframe();
251 int count;
252
253 nt_status = dc_search_domains(cell, msg, dn, sid);
254 BAIL_ON_NTSTATUS_ERROR(nt_status);
255
256 /* Now check that we got only one reply */
257
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);
262 }
263
264 if ( count > 1) {
265 nt_status = NT_STATUS_DUPLICATE_NAME;
266 BAIL_ON_NTSTATUS_ERROR(nt_status);
267 }
268
269 done:
270 PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4);
271 talloc_destroy(frame);
272
273 return nt_status;
274 }
275
276
277 /********************************************************************
278 Check that a DN is within the forest scope.
279 *******************************************************************/
280
281 static bool check_forest_scope(const char *dn)
/* [<][>][^][v][top][bottom][index][help] */
282 {
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;
289
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. */
293
294 if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) {
295 nt_status = NT_STATUS_OK;
296 goto done;
297 }
298
299 /* If this is a non-schema forest, then make sure that the DN
300 is in the form "...,cn=$LikewiseIdentityCell,DC=..." */
301
302 if ((q = strchr_m(p, ',')) == NULL) {
303 nt_status = NT_STATUS_OBJECT_NAME_INVALID;
304 BAIL_ON_NTSTATUS_ERROR(nt_status);
305 }
306
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);
311 }
312
313
314 dns_domain = cell_dn_to_dns(q);
315 BAIL_ON_PTR_ERROR(dns_domain, nt_status);
316
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);
321 }
322
323 nt_status = NT_STATUS_OK;
324
325 done:
326 talloc_destroy(frame);
327 SAFE_FREE(dns_domain);
328
329 return NT_STATUS_IS_OK(nt_status);
330 }
331
332
333
334 /********************************************************************
335 Check that only one result was returned within the forest cell
336 scope.
337 *******************************************************************/
338
339 static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list,
/* [<][>][^][v][top][bottom][index][help] */
340 LDAPMessage **msg_list,
341 int num_resp,
342 char **dn,
343 DOM_SID *user_sid)
344 {
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();
352
353 if (!dn || !user_sid) {
354 nt_status = NT_STATUS_INVALID_PARAMETER;
355 BAIL_ON_NTSTATUS_ERROR(nt_status);
356 }
357
358 *dn = NULL;
359
360 if (!ads_list || !msg_list || (num_resp == 0)) {
361 nt_status = NT_STATUS_NO_SUCH_FILE;
362 BAIL_ON_NTSTATUS_ERROR(nt_status);
363 }
364
365 /* Loop over all msgs */
366
367 for (i=0; i<num_resp; i++) {
368 LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]);
369
370 while (e) {
371 entry_dn = ads_get_dn(ads_list[i], talloc_tos(), e);
372 BAIL_ON_PTR_ERROR(entry_dn, nt_status);
373
374 if (check_forest_scope(entry_dn)) {
375 count++;
376
377 /* If we've already broken the condition, no
378 need to continue */
379
380 if (count > 1) {
381 nt_status = NT_STATUS_DUPLICATE_NAME;
382 BAIL_ON_NTSTATUS_ERROR(nt_status);
383 }
384
385 ads = ads_list[i];
386 msg = e;
387 *dn = SMB_STRDUP(entry_dn);
388 BAIL_ON_PTR_ERROR((*dn), nt_status);
389 }
390
391 e = ads_next_entry(ads_list[i], e);
392 TALLOC_FREE(entry_dn);
393 }
394 }
395
396 if (!ads || !msg) {
397 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
398 BAIL_ON_NTSTATUS_ERROR(nt_status);
399 }
400
401 /* If we made is through the loop, then grab the user_sid and
402 run home to base */
403
404 /*
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.
409
410 Fail if both are unavailable
411 */
412
413 if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) {
414 char **keywords;
415 char *s;
416 size_t num_lines = 0;
417
418 keywords = ads_pull_strings(ads, frame, msg, "keywords",
419 &num_lines);
420 BAIL_ON_PTR_ERROR(keywords, nt_status);
421
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);
426 }
427
428 if (!string_to_sid(user_sid, s)) {
429 nt_status = NT_STATUS_INVALID_SID;
430 BAIL_ON_NTSTATUS_ERROR(nt_status);
431 }
432 }
433
434 nt_status = NT_STATUS_OK;
435
436 done:
437 if (!NT_STATUS_IS_OK(nt_status)) {
438 SAFE_FREE(*dn);
439 }
440
441 talloc_destroy(frame);
442
443 return nt_status;
444 }
445
446 /********************************************************************
447 Search all forests. Each forest can have it's own forest-cell
448 settings so we have to generate the filter for each search.
449 We don't use gc_search_all_forests() since we may have a different
450 schema model in each forest and need to construct the search
451 filter for each GC search.
452 *******************************************************************/
453
454 static NTSTATUS search_forest(struct likewise_cell *forest_cell,
/* [<][>][^][v][top][bottom][index][help] */
455 LDAPMessage **msg,
456 const struct lwcell_filter *fdata)
457 {
458 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
459 TALLOC_CTX *frame = talloc_stackframe();
460 char *filter = NULL;
461 char *dn = NULL;
462 struct gc_info *gc = NULL;
463 ADS_STRUCT **ads_list = NULL;
464 LDAPMessage **msg_list = NULL;
465 int num_resp = 0;
466 LDAPMessage *m;
467 DOM_SID user_sid;
468 struct likewise_cell *domain_cell = NULL;
469
470 if ((gc = gc_search_start()) == NULL) {
471 nt_status = NT_STATUS_INVALID_DOMAIN_STATE;
472 BAIL_ON_NTSTATUS_ERROR(nt_status);
473 }
474
475 while (gc) {
476 char *sid_binstr = NULL;
477 uint32_t flags = LWCELL_FLAG_SEARCH_FOREST;
478
479 m = NULL;
480
481 flags |= cell_flags(gc->forest_cell);
482
483 switch (fdata->ftype) {
484 case SidFilter:
485 sid_binstr = sid_binstring(&fdata->filter.sid);
486 BAIL_ON_PTR_ERROR(sid_binstr, nt_status);
487
488 filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr);
489 SAFE_FREE(sid_binstr);
490 break;
491 case IdFilter:
492 filter = build_id_filter(fdata->filter.id.id,
493 fdata->filter.id.type, flags);
494 break;
495 case AliasFilter:
496 filter = build_alias_filter(fdata->filter.alias, flags);
497 break;
498 }
499
500 /* First find the sparse object in GC */
501 nt_status = gc_search_forest(gc, &m, filter);
502 if (!NT_STATUS_IS_OK(nt_status)) {
503 gc = gc->next;
504 continue;
505 }
506
507 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
508 m, &ads_list, &msg_list,
509 &num_resp);
510 BAIL_ON_NTSTATUS_ERROR(nt_status);
511
512 gc = gc->next;
513 }
514
515 /* Uniqueness check across forests */
516
517 nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp,
518 &dn, &user_sid);
519 BAIL_ON_NTSTATUS_ERROR(nt_status);
520
521 nt_status = search_domain(&domain_cell, &m, dn, &user_sid);
522 BAIL_ON_NTSTATUS_ERROR(nt_status);
523
524 /* Save the connection and results in the return parameters */
525
526 forest_cell->gc_search_cell = domain_cell;
527 *msg = m;
528
529 done:
530 PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4);
531
532 SAFE_FREE(dn);
533
534 free_result_array(ads_list, msg_list, num_resp);
535 talloc_destroy(frame);
536
537 return nt_status;
538 }
539
540 /********************************************************************
541 *******************************************************************/
542
543 static NTSTATUS search_cell_list(struct likewise_cell **c,
/* [<][>][^][v][top][bottom][index][help] */
544 LDAPMessage **m,
545 const struct lwcell_filter *fdata)
546 {
547 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
548 struct likewise_cell *cell = NULL;
549 LDAPMessage *msg = NULL;
550 struct likewise_cell *result_cell = NULL;
551
552 if ((cell = cell_list_head()) == NULL) {
553 nt_status = NT_STATUS_INVALID_SERVER_STATE;
554 BAIL_ON_NTSTATUS_ERROR(nt_status);
555 }
556
557 while (cell) {
558 /* Clear any previous GC search results */
559
560 cell->gc_search_cell = NULL;
561
562 if (cell_search_forest(cell)) {
563 nt_status = search_forest(cell, &msg, fdata);
564 } else {
565 nt_status = search_cell(cell, &msg, fdata);
566 }
567
568 /* Always point to the search result cell.
569 In forests this might be for another domain
570 which means the schema model may be different */
571
572 result_cell = cell->gc_search_cell ?
573 cell->gc_search_cell : cell;
574
575 /* Check if we are done */
576
577 if (NT_STATUS_IS_OK(nt_status)) {
578 break;
579 }
580
581 /* No luck. Free memory and hit the next cell.
582 Forest searches always set the gc_search_cell
583 so give preference to that connection if possible. */
584
585 ads_msgfree(cell_connection(result_cell), msg);
586 msg = NULL;
587
588 cell = cell->next;
589 }
590
591 /* This might be assigning NULL but that is ok as long as we
592 give back the proper error code */
593
594 *c = result_cell;
595 *m = msg;
596
597 done:
598 PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3);
599
600 return nt_status;
601 }
602
603 /********************************************************************
604 Pull the SID from an object which is always stored in the keywords
605 attribute as "backLink=S-1-5-21-..."
606 *******************************************************************/
607
608 static NTSTATUS pull_sid(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
609 LDAPMessage *msg,
610 DOM_SID *sid)
611 {
612 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
613 TALLOC_CTX *frame = talloc_stackframe();
614 ADS_STRUCT *ads = NULL;
615
616 ads = cell_connection(c);
617
618 /*
619 We have two ways of getting the sid:
620 (a) from the objectSID in case of a GC search,
621 (b) from backLink in the case of a cell search.
622 Pull the keywords attributes and grab the backLink.
623 */
624
625 if (!ads_pull_sid(ads, msg, "objectSid", sid)) {
626 char **keywords;
627 char *s;
628 size_t num_lines = 0;
629
630 keywords = ads_pull_strings(ads, frame, msg,
631 "keywords", &num_lines);
632 BAIL_ON_PTR_ERROR(keywords, nt_status);
633
634 s = find_attr_string(keywords, num_lines, "backLink");
635 if (!s) {
636 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
637 BAIL_ON_NTSTATUS_ERROR(nt_status);
638 }
639
640 if (!string_to_sid(sid, s)) {
641 nt_status = NT_STATUS_INVALID_SID;
642 BAIL_ON_NTSTATUS_ERROR(nt_status);
643 }
644 }
645
646 nt_status = NT_STATUS_OK;
647
648 done:
649 talloc_destroy(frame);
650
651 return nt_status;
652 }
653
654 /********************************************************************
655 *******************************************************************/
656
657 static NTSTATUS get_object_type(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
658 LDAPMessage *msg,
659 enum id_type *type)
660 {
661 TALLOC_CTX *ctx = talloc_stackframe();
662 char **oc_list = NULL;
663 NTSTATUS nt_status = NT_STATUS_OK;
664 size_t list_size = 0;
665 char *s = NULL;
666 ADS_STRUCT *ads = NULL;
667
668 ads = cell_connection(c);
669
670 /* Deal with RFC 2307 support first */
671
672 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
673 oc_list = ads_pull_strings(ads, ctx, msg,
674 "objectClass", &list_size);
675 if (!oc_list) {
676 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
677 goto done;
678 }
679
680 /* Check for posix classes and AD classes */
681
682 if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER)
683 || is_object_class(oc_list, list_size, AD_USER)) {
684 *type = ID_TYPE_UID;
685 } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP)
686 || is_object_class(oc_list, list_size, AD_GROUP)) {
687 *type = ID_TYPE_GID;
688 } else {
689 *type = ID_TYPE_NOT_SPECIFIED;
690 nt_status = NT_STATUS_INVALID_PARAMETER;
691 }
692 } else {
693 /* Default to non-schema mode */
694
695 oc_list = ads_pull_strings(ads, ctx, msg,
696 "keywords", &list_size);
697 if (!oc_list) {
698 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
699 goto done;
700 }
701
702 s = find_attr_string(oc_list, list_size, "objectClass");
703 if (!s) {
704 nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
705 goto done;
706 }
707
708 if (strequal(s, ADEX_OC_USER)) {
709 *type = ID_TYPE_UID;
710 } else if (strequal(s, ADEX_OC_GROUP)) {
711 *type = ID_TYPE_GID;
712 } else {
713 *type = ID_TYPE_NOT_SPECIFIED;
714 nt_status = NT_STATUS_INVALID_PARAMETER;
715 }
716 }
717
718 nt_status = NT_STATUS_OK;
719
720 done:
721 talloc_destroy(ctx);
722
723 return nt_status;
724 }
725
726 /********************************************************************
727 Pull an attribute uint32_t value
728 *******************************************************************/
729
730 static NTSTATUS get_object_uint32(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
731 LDAPMessage *msg,
732 const char *attrib,
733 uint32_t *x)
734 {
735 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
736 char **keywords = NULL;
737 size_t list_size = 0;
738 TALLOC_CTX *frame = talloc_stackframe();
739 ADS_STRUCT *ads = NULL;
740
741 ads = cell_connection(c);
742
743 /* Deal with RFC2307 schema */
744
745 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
746 if (!ads_pull_uint32(ads, msg, attrib, x)) {
747 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
748 BAIL_ON_NTSTATUS_ERROR(nt_status);
749 }
750 } else {
751 /* Non-schema mode */
752 char *s = NULL;
753 uint32_t num;
754
755 keywords = ads_pull_strings(ads, frame, msg, "keywords",
756 &list_size);
757 BAIL_ON_PTR_ERROR(keywords, nt_status);
758
759 s = find_attr_string(keywords, list_size, attrib);
760 if (!s) {
761 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
762 BAIL_ON_NTSTATUS_ERROR(nt_status);
763 }
764
765 num = strtoll(s, NULL, 10);
766 if (errno == ERANGE) {
767 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
768 BAIL_ON_NTSTATUS_ERROR(nt_status);
769 }
770 *x = num;
771 }
772
773 nt_status = NT_STATUS_OK;
774
775 done:
776 talloc_destroy(frame);
777
778 return nt_status;
779 }
780
781 /********************************************************************
782 *******************************************************************/
783
784 static NTSTATUS get_object_id(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
785 LDAPMessage *msg,
786 enum id_type type,
787 uint32_t *id)
788 {
789 NTSTATUS nt_status = NT_STATUS_OK;
790 const char *id_attr;
791
792 /* Figure out which attribute we need to pull */
793
794 switch (type) {
795 case ID_TYPE_UID:
796 id_attr = ADEX_ATTR_UIDNUM;
797 break;
798 case ID_TYPE_GID:
799 id_attr = ADEX_ATTR_GIDNUM;
800 break;
801 default:
802 nt_status = NT_STATUS_INVALID_PARAMETER;
803 BAIL_ON_NTSTATUS_ERROR(nt_status);
804 break;
805 }
806
807 nt_status = get_object_uint32(c, msg, id_attr, id);
808 BAIL_ON_NTSTATUS_ERROR(nt_status);
809
810 done:
811 return nt_status;
812 }
813
814 /********************************************************************
815 Pull the uid/gid and type from an object. This differs depending on
816 the cell flags.
817 *******************************************************************/
818
819 static NTSTATUS pull_id(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
820 LDAPMessage *msg,
821 uint32_t *id,
822 enum id_type *type)
823 {
824 NTSTATUS nt_status;
825
826 nt_status = get_object_type(c, msg, type);
827 BAIL_ON_NTSTATUS_ERROR(nt_status);
828
829 nt_status = get_object_id(c, msg, *type, id);
830 BAIL_ON_NTSTATUS_ERROR(nt_status);
831
832 done:
833 return nt_status;
834 }
835
836 /********************************************************************
837 Pull an attribute string value
838 *******************************************************************/
839
840 static NTSTATUS get_object_string(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
841 LDAPMessage *msg,
842 TALLOC_CTX *ctx,
843 const char *attrib,
844 char **string)
845 {
846 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
847 char **keywords = NULL;
848 size_t list_size = 0;
849 TALLOC_CTX *frame = talloc_stackframe();
850 ADS_STRUCT *ads = NULL;
851
852 *string = NULL;
853
854 ads = cell_connection(c);
855
856 /* Deal with RFC2307 schema */
857
858 if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
859 *string = ads_pull_string(ads, ctx, msg, attrib);
860 } else {
861 /* Non-schema mode */
862
863 char *s = NULL;
864
865 keywords = ads_pull_strings(ads, frame, msg,
866 "keywords", &list_size);
867 if (!keywords) {
868 nt_status = NT_STATUS_NO_MEMORY;
869 BAIL_ON_NTSTATUS_ERROR(nt_status);
870 }
871 s = find_attr_string(keywords, list_size, attrib);
872 if (s) {
873 *string = talloc_strdup(ctx, s);
874 }
875 }
876
877 if (!*string) {
878 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
879 BAIL_ON_NTSTATUS_ERROR(nt_status);
880 }
881
882 nt_status = NT_STATUS_OK;
883
884 done:
885 talloc_destroy(frame);
886
887 return nt_status;
888 }
889
890 /********************************************************************
891 Pull the struct passwd fields for a user
892 *******************************************************************/
893
894 static NTSTATUS pull_nss_info(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
895 LDAPMessage *msg,
896 TALLOC_CTX *ctx,
897 char **homedir,
898 char **shell,
899 char **gecos,
900 gid_t *p_gid)
901 {
902 NTSTATUS nt_status;
903
904 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, homedir);
905 BAIL_ON_NTSTATUS_ERROR(nt_status);
906
907 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, shell);
908 BAIL_ON_NTSTATUS_ERROR(nt_status);
909
910 nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, gecos);
911 /* Gecos is often not set so ignore failures */
912
913 nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid);
914 BAIL_ON_NTSTATUS_ERROR(nt_status);
915
916 done:
917 return nt_status;
918 }
919
920 /********************************************************************
921 Pull the struct passwd fields for a user
922 *******************************************************************/
923
924 static NTSTATUS pull_alias(struct likewise_cell *c,
/* [<][>][^][v][top][bottom][index][help] */
925 LDAPMessage *msg,
926 TALLOC_CTX *ctx,
927 char **alias)
928 {
929 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
930 enum id_type type;
931 const char *attr = NULL;
932
933 /* Figure out if this is a user or a group */
934
935 nt_status = get_object_type(c, msg, &type);
936 BAIL_ON_NTSTATUS_ERROR(nt_status);
937
938 switch (type) {
939 case ID_TYPE_UID:
940 attr = ADEX_ATTR_UID;
941 break;
942 case ID_TYPE_GID:
943 /* What is the group attr for RFC2307 Forests? */
944 attr = ADEX_ATTR_DISPLAYNAME;
945 break;
946 default:
947 nt_status = NT_STATUS_INVALID_PARAMETER;
948 BAIL_ON_NTSTATUS_ERROR(nt_status);
949 break;
950 }
951
952 nt_status = get_object_string(c, msg, ctx, attr, alias);
953 BAIL_ON_NTSTATUS_ERROR(nt_status);
954
955 done:
956 return nt_status;
957 }
958
959 /********************************************************************
960 *******************************************************************/
961
962 static NTSTATUS _ccp_get_sid_from_id(DOM_SID * sid,
/* [<][>][^][v][top][bottom][index][help] */
963 uint32_t id, enum id_type type)
964 {
965 struct likewise_cell *cell = NULL;
966 LDAPMessage *msg = NULL;
967 NTSTATUS nt_status;
968 struct lwcell_filter filter;
969
970 filter.ftype = IdFilter;
971 filter.filter.id.id = id;
972 filter.filter.id.type = type;
973
974 nt_status = search_cell_list(&cell, &msg, &filter);
975 BAIL_ON_NTSTATUS_ERROR(nt_status);
976
977 nt_status = pull_sid(cell, msg, sid);
978 BAIL_ON_NTSTATUS_ERROR(nt_status);
979
980 done:
981 ads_msgfree(cell->conn, msg);
982
983 return nt_status;
984 }
985
986 /********************************************************************
987 *******************************************************************/
988
989 static NTSTATUS _ccp_get_id_from_sid(uint32_t * id,
/* [<][>][^][v][top][bottom][index][help] */
990 enum id_type *type,
991 const DOM_SID * sid)
992 {
993 struct likewise_cell *cell = NULL;
994 LDAPMessage *msg = NULL;
995 NTSTATUS nt_status;
996 struct lwcell_filter filter;
997
998 filter.ftype = SidFilter;
999 sid_copy(&filter.filter.sid, sid);
1000
1001 nt_status = search_cell_list(&cell, &msg, &filter);
1002 BAIL_ON_NTSTATUS_ERROR(nt_status);
1003
1004 nt_status = pull_id(cell, msg, id, type);
1005 BAIL_ON_NTSTATUS_ERROR(nt_status);
1006
1007 if (*id < min_id_value()) {
1008 nt_status = NT_STATUS_INVALID_PARAMETER;
1009 BAIL_ON_NTSTATUS_ERROR(nt_status);
1010 }
1011
1012 done:
1013 ads_msgfree(cell->conn, msg);
1014
1015 return nt_status;
1016 }
1017
1018 /********************************************************************
1019 *******************************************************************/
1020
1021 static NTSTATUS _ccp_nss_get_info(const DOM_SID * sid,
/* [<][>][^][v][top][bottom][index][help] */
1022 TALLOC_CTX * ctx,
1023 char **homedir,
1024 char **shell,
1025 char **gecos, gid_t * p_gid)
1026 {
1027 struct likewise_cell *cell = NULL;
1028 LDAPMessage *msg = NULL;
1029 NTSTATUS nt_status;
1030 struct lwcell_filter filter;
1031 enum id_type type;
1032
1033 filter.ftype = SidFilter;
1034 sid_copy(&filter.filter.sid, sid);
1035
1036 nt_status = search_cell_list(&cell, &msg, &filter);
1037 BAIL_ON_NTSTATUS_ERROR(nt_status);
1038
1039 nt_status = get_object_type(cell, msg, &type);
1040 BAIL_ON_NTSTATUS_ERROR(nt_status);
1041
1042 if (type != ID_TYPE_UID) {
1043 nt_status = NT_STATUS_NO_SUCH_USER;
1044 BAIL_ON_NTSTATUS_ERROR(nt_status);
1045 }
1046
1047 nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos,
1048 (uint32_t*) p_gid);
1049 BAIL_ON_NTSTATUS_ERROR(nt_status);
1050
1051 done:
1052 ads_msgfree(cell->conn, msg);
1053
1054 return nt_status;
1055 }
1056
1057 /**********************************************************************
1058 *********************************************************************/
1059
1060 static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx,
/* [<][>][^][v][top][bottom][index][help] */
1061 const char *domain,
1062 const char *name, char **alias)
1063 {
1064 TALLOC_CTX *frame = talloc_stackframe();
1065 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1066 DOM_SID sid;
1067 struct likewise_cell *cell = NULL;
1068 LDAPMessage *msg = NULL;
1069 struct lwcell_filter filter;
1070 enum lsa_SidType sid_type;
1071
1072 /* Convert the name to a SID */
1073
1074 nt_status = gc_name_to_sid(domain, name, &sid, &sid_type);
1075 BAIL_ON_NTSTATUS_ERROR(nt_status);
1076
1077 /* Find the user/group */
1078
1079 filter.ftype = SidFilter;
1080 sid_copy(&filter.filter.sid, &sid);
1081
1082 nt_status = search_cell_list(&cell, &msg, &filter);
1083 BAIL_ON_NTSTATUS_ERROR(nt_status);
1084
1085 /* Pull the alias and return */
1086
1087 nt_status = pull_alias(cell, msg, ctx, alias);
1088 BAIL_ON_NTSTATUS_ERROR(nt_status);
1089
1090 done:
1091 PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3);
1092
1093 talloc_destroy(frame);
1094 ads_msgfree(cell_connection(cell), msg);
1095
1096 return nt_status;
1097 }
1098
1099 /**********************************************************************
1100 Map from an alias name to the canonical, qualified name.
1101 Ensure that the alias is only pull from the closest in which
1102 the user or gorup is enabled in
1103 *********************************************************************/
1104
1105 static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1106 const char *domain,
1107 const char *alias, char **name)
1108 {
1109 TALLOC_CTX *frame = talloc_stackframe();
1110 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1111 DOM_SID sid;
1112 struct likewise_cell *cell_alias = NULL;
1113 LDAPMessage *msg_alias = NULL;
1114 struct likewise_cell *cell_sid = NULL;
1115 LDAPMessage *msg_sid = NULL;
1116 struct lwcell_filter filter;
1117 char *canonical_name = NULL;
1118 enum lsa_SidType type;
1119
1120 /* Find the user/group */
1121
1122 filter.ftype = AliasFilter;
1123 fstrcpy(filter.filter.alias, alias);
1124
1125 nt_status = search_cell_list(&cell_alias, &msg_alias, &filter);
1126 BAIL_ON_NTSTATUS_ERROR(nt_status);
1127
1128 nt_status = pull_sid(cell_alias, msg_alias, &sid);
1129 BAIL_ON_NTSTATUS_ERROR(nt_status);
1130
1131 /* Now search again for the SID according to the cell list.
1132 Verify that the cell of both search results is the same
1133 so that we only match an alias from the closest cell
1134 in which a user/group has been instantied. */
1135
1136 filter.ftype = SidFilter;
1137 sid_copy(&filter.filter.sid, &sid);
1138
1139 nt_status = search_cell_list(&cell_sid, &msg_sid, &filter);
1140 BAIL_ON_NTSTATUS_ERROR(nt_status);
1141
1142 if (cell_alias != cell_sid) {
1143 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1144 BAIL_ON_NTSTATUS_ERROR(nt_status);
1145 }
1146
1147 /* Finally do the GC sid/name conversion */
1148
1149 nt_status = gc_sid_to_name(&sid, &canonical_name, &type);
1150 BAIL_ON_NTSTATUS_ERROR(nt_status);
1151
1152 *name = talloc_strdup(mem_ctx, canonical_name);
1153 BAIL_ON_PTR_ERROR((*name), nt_status);
1154
1155 nt_status = NT_STATUS_OK;
1156
1157 done:
1158 PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3);
1159
1160 ads_msgfree(cell_connection(cell_alias), msg_alias);
1161 ads_msgfree(cell_connection(cell_sid), msg_sid);
1162
1163 SAFE_FREE(canonical_name);
1164
1165 talloc_destroy(frame);
1166
1167 return nt_status;
1168 }
1169
1170 /********************************************************************
1171 *******************************************************************/
1172
1173 struct cell_provider_api ccp_unified = {
1174 .get_sid_from_id = _ccp_get_sid_from_id,
1175 .get_id_from_sid = _ccp_get_id_from_sid,
1176 .get_nss_info = _ccp_nss_get_info,
1177 .map_to_alias = _ccp_map_to_alias,
1178 .map_from_alias = _ccp_map_from_alias
1179 };