Print this page
NEX-17849 idmap fails to lookup group SID in AD
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/idmap/idmapd/adutils.c
+++ new/usr/src/cmd/idmap/idmapd/adutils.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 + *
25 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 26 */
25 27
26 28 /*
27 29 * Processes name2sid & sid2name batched lookups for a given user or
28 30 * computer from an AD Directory server using GSSAPI authentication
29 31 */
30 32
31 33 #include <stdio.h>
32 34 #include <stdlib.h>
33 35 #include <alloca.h>
34 36 #include <string.h>
35 37 #include <strings.h>
36 38 #include <lber.h>
37 39 #include <ldap.h>
38 40 #include <sasl/sasl.h>
39 41 #include <string.h>
40 42 #include <ctype.h>
41 43 #include <pthread.h>
42 44 #include <synch.h>
43 45 #include <atomic.h>
44 46 #include <errno.h>
45 47 #include <assert.h>
46 48 #include <limits.h>
47 49 #include <time.h>
48 50 #include <sys/u8_textprep.h>
49 51 #include "libadutils.h"
50 52 #include "nldaputils.h"
51 53 #include "idmapd.h"
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
52 54
53 55 /* Attribute names and filter format strings */
54 56 #define SAN "sAMAccountName"
55 57 #define OBJSID "objectSid"
56 58 #define OBJCLASS "objectClass"
57 59 #define UIDNUMBER "uidNumber"
58 60 #define GIDNUMBER "gidNumber"
59 61 #define UIDNUMBERFILTER "(&(objectclass=user)(uidNumber=%u))"
60 62 #define GIDNUMBERFILTER "(&(objectclass=group)(gidNumber=%u))"
61 63 #define SANFILTER "(sAMAccountName=%s)"
62 -#define OBJSIDFILTER "(objectSid=%s)"
64 +#define OBJSIDFILTER "(|(objectSid=%s)(sIDHistory=%s))"
63 65
64 66 void idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
65 67 int qid, void *argp);
66 68
67 69 /*
68 70 * A place to put the results of a batched (async) query
69 71 *
70 72 * There is one of these for every query added to a batch object
71 73 * (idmap_query_state, see below).
72 74 */
73 75 typedef struct idmap_q {
74 76 /*
75 77 * data used for validating search result entries for name->SID
76 78 * lookups
77 79 */
78 80 char *ecanonname; /* expected canon name */
79 81 char *edomain; /* expected domain name */
80 82 idmap_id_type esidtype; /* expected SID type */
81 83 /* results */
82 84 char **canonname; /* actual canon name */
83 85 char **domain; /* name of domain of object */
84 86 char **sid; /* stringified SID */
85 87 rid_t *rid; /* RID */
86 88 idmap_id_type *sid_type; /* user or group SID? */
87 89 char **unixname; /* unixname for name mapping */
88 90 char **dn; /* DN of entry */
89 91 char **attr; /* Attr for name mapping */
90 92 char **value; /* value for name mapping */
91 93 posix_id_t *pid; /* Posix ID found via IDMU */
92 94 idmap_retcode *rc;
93 95 adutils_rc ad_rc;
94 96 adutils_result_t *result;
95 97
96 98 /*
97 99 * The LDAP search entry result is placed here to be processed
98 100 * when the search done result is received.
99 101 */
100 102 LDAPMessage *search_res; /* The LDAP search result */
101 103 } idmap_q_t;
102 104
103 105 /* Batch context structure; typedef is in header file */
104 106 struct idmap_query_state {
105 107 adutils_query_state_t *qs;
106 108 int qsize; /* Queue size */
107 109 uint32_t qcount; /* Number of queued requests */
108 110 const char *ad_unixuser_attr;
109 111 const char *ad_unixgroup_attr;
110 112 int directory_based_mapping; /* enum */
111 113 char *default_domain;
112 114 idmap_q_t queries[1]; /* array of query results */
113 115 };
114 116
115 117 static pthread_t reaperid = 0;
116 118
117 119 /*
118 120 * Keep connection management simple for now, extend or replace later
119 121 * with updated libsldap code.
120 122 */
121 123 #define ADREAPERSLEEP 60
122 124
123 125 /*
124 126 * Idle connection reaping side of connection management
125 127 *
126 128 * Every minute wake up and look for connections that have been idle for
127 129 * five minutes or more and close them.
128 130 */
129 131 /*ARGSUSED*/
130 132 static
131 133 void
132 134 adreaper(void *arg)
133 135 {
134 136 timespec_t ts;
135 137
136 138 ts.tv_sec = ADREAPERSLEEP;
137 139 ts.tv_nsec = 0;
138 140
139 141 for (;;) {
140 142 /*
141 143 * nanosleep(3RT) is thead-safe (no SIGALRM) and more
142 144 * portable than usleep(3C)
143 145 */
144 146 (void) nanosleep(&ts, NULL);
145 147 adutils_reap_idle_connections();
146 148 }
147 149 }
148 150
149 151 /*
150 152 * Take ad_host_config_t information, create a ad_host_t,
151 153 * populate it and add it to the list of hosts.
152 154 */
153 155
154 156 int
155 157 idmap_add_ds(adutils_ad_t *ad, const char *host, int port)
156 158 {
157 159 int ret = -1;
158 160
159 161 if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS)
160 162 ret = 0;
161 163
162 164 /* Start reaper if it doesn't exist */
163 165 if (ret == 0 && reaperid == 0)
164 166 (void) pthread_create(&reaperid, NULL,
165 167 (void *(*)(void *))adreaper, (void *)NULL);
166 168 return (ret);
167 169 }
168 170
169 171 static
170 172 idmap_retcode
171 173 map_adrc2idmaprc(adutils_rc adrc)
172 174 {
173 175 switch (adrc) {
174 176 case ADUTILS_SUCCESS:
175 177 return (IDMAP_SUCCESS);
176 178 case ADUTILS_ERR_NOTFOUND:
177 179 return (IDMAP_ERR_NOTFOUND);
178 180 case ADUTILS_ERR_MEMORY:
179 181 return (IDMAP_ERR_MEMORY);
180 182 case ADUTILS_ERR_DOMAIN:
181 183 return (IDMAP_ERR_DOMAIN);
182 184 case ADUTILS_ERR_OTHER:
183 185 return (IDMAP_ERR_OTHER);
184 186 case ADUTILS_ERR_RETRIABLE_NET_ERR:
185 187 return (IDMAP_ERR_RETRIABLE_NET_ERR);
186 188 default:
187 189 return (IDMAP_ERR_INTERNAL);
188 190 }
189 191 /* NOTREACHED */
190 192 }
191 193
192 194 idmap_retcode
193 195 idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
194 196 int directory_based_mapping, const char *default_domain,
195 197 idmap_query_state_t **state)
196 198 {
197 199 idmap_query_state_t *new_state;
198 200 adutils_rc rc;
199 201
200 202 *state = NULL;
201 203
202 204 assert(ad != NULL);
203 205
204 206 new_state = calloc(1, sizeof (idmap_query_state_t) +
205 207 (nqueries - 1) * sizeof (idmap_q_t));
206 208 if (new_state == NULL)
207 209 return (IDMAP_ERR_MEMORY);
208 210
209 211 if ((rc = adutils_lookup_batch_start(ad, nqueries,
210 212 idmap_ldap_res_search_cb, new_state, &new_state->qs))
211 213 != ADUTILS_SUCCESS) {
212 214 idmap_lookup_release_batch(&new_state);
213 215 return (map_adrc2idmaprc(rc));
214 216 }
215 217
216 218 new_state->default_domain = strdup(default_domain);
217 219 if (new_state->default_domain == NULL) {
218 220 idmap_lookup_release_batch(&new_state);
219 221 return (IDMAP_ERR_MEMORY);
220 222 }
221 223
222 224 new_state->directory_based_mapping = directory_based_mapping;
223 225 new_state->qsize = nqueries;
224 226 *state = new_state;
225 227 return (IDMAP_SUCCESS);
226 228 }
227 229
228 230 /*
229 231 * Set unixuser_attr and unixgroup_attr for AD-based name mapping
230 232 */
231 233 void
232 234 idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
233 235 const char *unixuser_attr, const char *unixgroup_attr)
234 236 {
235 237 state->ad_unixuser_attr = unixuser_attr;
236 238 state->ad_unixgroup_attr = unixgroup_attr;
237 239 }
238 240
239 241 /*
240 242 * Take parsed attribute values from a search result entry and check if
241 243 * it is the result that was desired and, if so, set the result fields
242 244 * of the given idmap_q_t.
243 245 *
244 246 * Except for dn and attr, all strings are consumed, either by transferring
245 247 * them over into the request results (where the caller will eventually free
246 248 * them) or by freeing them here. Note that this aligns with the "const"
247 249 * declarations below.
248 250 */
249 251 static
250 252 void
251 253 idmap_setqresults(
252 254 idmap_q_t *q,
253 255 char *san,
254 256 const char *dn,
255 257 const char *attr,
256 258 char *value,
257 259 char *sid,
258 260 rid_t rid,
259 261 int sid_type,
260 262 char *unixname,
261 263 posix_id_t pid)
262 264 {
263 265 char *domain;
264 266 int err1;
265 267
266 268 assert(dn != NULL);
267 269
268 270 if ((domain = adutils_dn2dns(dn)) == NULL)
269 271 goto out;
270 272
271 273 if (q->ecanonname != NULL && san != NULL) {
272 274 /* Check that this is the canonname that we were looking for */
273 275 if (u8_strcmp(q->ecanonname, san, 0,
274 276 U8_STRCMP_CI_LOWER, /* no normalization, for now */
275 277 U8_UNICODE_LATEST, &err1) != 0 || err1 != 0)
276 278 goto out;
277 279 }
278 280
279 281 if (q->edomain != NULL) {
280 282 /* Check that this is the domain that we were looking for */
281 283 if (!domain_eq(q->edomain, domain))
282 284 goto out;
283 285 }
284 286
285 287 /* Copy the DN and attr and value */
286 288 if (q->dn != NULL)
287 289 *q->dn = strdup(dn);
288 290
289 291 if (q->attr != NULL && attr != NULL)
290 292 *q->attr = strdup(attr);
291 293
292 294 if (q->value != NULL && value != NULL) {
293 295 *q->value = value;
294 296 value = NULL;
295 297 }
296 298
297 299 /* Set results */
298 300 if (q->sid) {
299 301 *q->sid = sid;
300 302 sid = NULL;
301 303 }
302 304 if (q->rid)
303 305 *q->rid = rid;
304 306 if (q->sid_type)
305 307 *q->sid_type = sid_type;
306 308 if (q->unixname) {
307 309 *q->unixname = unixname;
308 310 unixname = NULL;
309 311 }
310 312 if (q->domain != NULL) {
311 313 *q->domain = domain;
312 314 domain = NULL;
313 315 }
314 316 if (q->canonname != NULL) {
315 317 /*
316 318 * The caller may be replacing the given winname by its
317 319 * canonical name and therefore free any old name before
318 320 * overwriting the field by the canonical name.
319 321 */
320 322 free(*q->canonname);
321 323 *q->canonname = san;
322 324 san = NULL;
323 325 }
324 326
325 327 if (q->pid != NULL && pid != IDMAP_SENTINEL_PID) {
326 328 *q->pid = pid;
327 329 }
328 330
329 331 q->ad_rc = ADUTILS_SUCCESS;
330 332
331 333 out:
332 334 /* Free unused attribute values */
333 335 free(san);
334 336 free(sid);
335 337 free(domain);
336 338 free(unixname);
337 339 free(value);
338 340 }
339 341
340 342 #define BVAL_CASEEQ(bv, str) \
341 343 (((*(bv))->bv_len == (sizeof (str) - 1)) && \
342 344 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
343 345
344 346 /*
345 347 * Extract the class of the result entry. Returns 1 on success, 0 on
346 348 * failure.
347 349 */
348 350 static
349 351 int
350 352 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
351 353 {
352 354 BerValue **cbval;
353 355
354 356 *sid_type = IDMAP_SID;
355 357 if (bvalues == NULL)
356 358 return (0);
357 359
358 360 /*
359 361 * We consider Computer to be a subclass of User, so we can just
360 362 * ignore Computer entries and pay attention to the accompanying
361 363 * User entries.
362 364 */
363 365 for (cbval = bvalues; *cbval != NULL; cbval++) {
364 366 if (BVAL_CASEEQ(cbval, "group")) {
365 367 *sid_type = IDMAP_GSID;
366 368 break;
367 369 } else if (BVAL_CASEEQ(cbval, "user")) {
368 370 *sid_type = IDMAP_USID;
369 371 break;
370 372 }
371 373 /*
372 374 * "else if (*sid_type = IDMAP_USID)" then this is a
373 375 * new sub-class of user -- what to do with it??
374 376 */
375 377 }
376 378
377 379 return (1);
378 380 }
379 381
380 382 /*
381 383 * Handle a given search result entry
382 384 */
383 385 static
384 386 void
385 387 idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
386 388 LDAPMessage *res, LDAP *ld)
387 389 {
388 390 BerValue **bvalues;
389 391 const char *attr = NULL;
390 392 char *value = NULL;
391 393 char *unix_name = NULL;
392 394 char *dn;
393 395 char *san = NULL;
394 396 char *sid = NULL;
395 397 rid_t rid = 0;
396 398 int sid_type;
397 399 int ok;
398 400 posix_id_t pid = IDMAP_SENTINEL_PID;
399 401
400 402 assert(q->rc != NULL);
401 403 assert(q->domain == NULL || *q->domain == NULL);
402 404
403 405 if ((dn = ldap_get_dn(ld, res)) == NULL)
404 406 return;
405 407
406 408 bvalues = ldap_get_values_len(ld, res, OBJCLASS);
407 409 if (bvalues == NULL) {
408 410 /*
409 411 * Didn't find objectclass. Something's wrong with our
410 412 * AD data.
411 413 */
412 414 idmapdlog(LOG_ERR, "%s has no %s", dn, OBJCLASS);
413 415 goto out;
414 416 }
415 417 ok = idmap_bv_objclass2sidtype(bvalues, &sid_type);
416 418 ldap_value_free_len(bvalues);
417 419 if (!ok) {
418 420 /*
419 421 * Didn't understand objectclass. Something's wrong with our
420 422 * AD data.
421 423 */
422 424 idmapdlog(LOG_ERR, "%s has unexpected %s", dn, OBJCLASS);
423 425 goto out;
424 426 }
425 427
426 428 if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU &&
427 429 q->pid != NULL) {
428 430 if (sid_type == IDMAP_USID)
429 431 attr = UIDNUMBER;
430 432 else if (sid_type == IDMAP_GSID)
431 433 attr = GIDNUMBER;
432 434 if (attr != NULL) {
433 435 bvalues = ldap_get_values_len(ld, res, attr);
434 436 if (bvalues != NULL) {
435 437 value = adutils_bv_str(bvalues[0]);
436 438 if (!adutils_bv_uint(bvalues[0], &pid)) {
437 439 idmapdlog(LOG_ERR,
438 440 "%s has Invalid %s value \"%s\"",
439 441 dn, attr, value);
440 442 }
441 443 ldap_value_free_len(bvalues);
442 444 }
443 445 }
444 446 }
445 447
446 448 if (state->directory_based_mapping == DIRECTORY_MAPPING_NAME &&
447 449 q->unixname != NULL) {
448 450 /*
449 451 * If the caller has requested unixname then determine the
450 452 * AD attribute name that will have the unixname, and retrieve
451 453 * its value.
452 454 */
453 455 idmap_id_type esidtype;
454 456 /*
455 457 * Determine the target type.
456 458 *
457 459 * If the caller specified one, use that. Otherwise, give the
458 460 * same type that as we found for the Windows user.
459 461 */
460 462 esidtype = q->esidtype;
461 463 if (esidtype == IDMAP_SID)
462 464 esidtype = sid_type;
463 465
464 466 if (esidtype == IDMAP_USID)
465 467 attr = state->ad_unixuser_attr;
466 468 else if (esidtype == IDMAP_GSID)
467 469 attr = state->ad_unixgroup_attr;
468 470
469 471 if (attr != NULL) {
470 472 bvalues = ldap_get_values_len(ld, res, attr);
471 473 if (bvalues != NULL) {
472 474 unix_name = adutils_bv_str(bvalues[0]);
473 475 ldap_value_free_len(bvalues);
474 476 value = strdup(unix_name);
475 477 }
476 478 }
477 479 }
478 480
479 481 bvalues = ldap_get_values_len(ld, res, SAN);
480 482 if (bvalues != NULL) {
481 483 san = adutils_bv_str(bvalues[0]);
482 484 ldap_value_free_len(bvalues);
483 485 }
484 486
485 487 if (q->sid != NULL) {
486 488 bvalues = ldap_get_values_len(ld, res, OBJSID);
487 489 if (bvalues != NULL) {
488 490 sid = adutils_bv_objsid2sidstr(bvalues[0], &rid);
489 491 ldap_value_free_len(bvalues);
490 492 }
491 493 }
492 494
493 495 idmap_setqresults(q, san, dn,
494 496 attr, value,
495 497 sid, rid, sid_type,
496 498 unix_name, pid);
497 499
498 500 out:
499 501 ldap_memfree(dn);
500 502 }
501 503
502 504 void
503 505 idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid,
504 506 void *argp)
505 507 {
506 508 idmap_query_state_t *state = (idmap_query_state_t *)argp;
507 509 idmap_q_t *q = &(state->queries[qid]);
508 510
509 511 switch (rc) {
510 512 case LDAP_RES_SEARCH_RESULT:
511 513 if (q->search_res != NULL) {
512 514 idmap_extract_object(state, q, q->search_res, ld);
513 515 (void) ldap_msgfree(q->search_res);
514 516 q->search_res = NULL;
515 517 } else
516 518 q->ad_rc = ADUTILS_ERR_NOTFOUND;
517 519 break;
518 520 case LDAP_RES_SEARCH_ENTRY:
519 521 if (q->search_res == NULL) {
520 522 q->search_res = *res;
521 523 *res = NULL;
522 524 }
523 525 break;
524 526 default:
525 527 break;
526 528 }
527 529 }
528 530
529 531 static
530 532 void
531 533 idmap_cleanup_batch(idmap_query_state_t *batch)
532 534 {
533 535 int i;
534 536
535 537 for (i = 0; i < batch->qcount; i++) {
536 538 if (batch->queries[i].ecanonname != NULL)
537 539 free(batch->queries[i].ecanonname);
538 540 batch->queries[i].ecanonname = NULL;
539 541 if (batch->queries[i].edomain != NULL)
540 542 free(batch->queries[i].edomain);
541 543 batch->queries[i].edomain = NULL;
542 544 }
543 545 }
544 546
545 547 /*
546 548 * This routine frees the idmap_query_state_t structure
547 549 */
548 550 void
549 551 idmap_lookup_release_batch(idmap_query_state_t **state)
550 552 {
551 553 if (state == NULL || *state == NULL)
552 554 return;
553 555 adutils_lookup_batch_release(&(*state)->qs);
554 556 idmap_cleanup_batch(*state);
555 557 free((*state)->default_domain);
556 558 free(*state);
557 559 *state = NULL;
558 560 }
559 561
560 562 idmap_retcode
561 563 idmap_lookup_batch_end(idmap_query_state_t **state)
562 564 {
563 565 adutils_rc ad_rc;
564 566 int i;
565 567 idmap_query_state_t *id_qs = *state;
566 568
567 569 ad_rc = adutils_lookup_batch_end(&id_qs->qs);
568 570
569 571 /*
570 572 * Map adutils rc to idmap_retcode in each
571 573 * query because consumers in dbutils.c
572 574 * expects idmap_retcode.
573 575 */
574 576 for (i = 0; i < id_qs->qcount; i++) {
575 577 *id_qs->queries[i].rc =
576 578 map_adrc2idmaprc(id_qs->queries[i].ad_rc);
577 579 }
578 580 idmap_lookup_release_batch(state);
579 581 return (map_adrc2idmaprc(ad_rc));
580 582 }
581 583
582 584 /*
583 585 * Send one prepared search, queue up msgid, process what results are
584 586 * available
585 587 */
586 588 static
587 589 idmap_retcode
588 590 idmap_batch_add1(idmap_query_state_t *state, const char *filter,
589 591 char *ecanonname, char *edomain, idmap_id_type esidtype,
590 592 char **dn, char **attr, char **value,
591 593 char **canonname, char **dname,
592 594 char **sid, rid_t *rid, idmap_id_type *sid_type, char **unixname,
593 595 posix_id_t *pid,
594 596 idmap_retcode *rc)
595 597 {
596 598 adutils_rc ad_rc;
597 599 int qid, i;
598 600 idmap_q_t *q;
599 601 char *attrs[20]; /* Plenty */
600 602
601 603 qid = atomic_inc_32_nv(&state->qcount) - 1;
602 604 q = &(state->queries[qid]);
603 605
604 606 assert(qid < state->qsize);
605 607
606 608 /*
607 609 * Remember the expected canonname, domainname and unix type
608 610 * so we can check the results * against it
609 611 */
610 612 q->ecanonname = ecanonname;
611 613 q->edomain = edomain;
612 614 q->esidtype = esidtype;
613 615
614 616 /* Remember where to put the results */
615 617 q->canonname = canonname;
616 618 q->sid = sid;
617 619 q->domain = dname;
618 620 q->rid = rid;
619 621 q->sid_type = sid_type;
620 622 q->rc = rc;
621 623 q->unixname = unixname;
622 624 q->dn = dn;
623 625 q->attr = attr;
624 626 q->value = value;
625 627 q->pid = pid;
626 628
627 629 /* Add attributes that are not always needed */
628 630 i = 0;
629 631 attrs[i++] = SAN;
630 632 attrs[i++] = OBJSID;
631 633 attrs[i++] = OBJCLASS;
632 634
633 635 if (unixname != NULL) {
634 636 /* Add unixuser/unixgroup attribute names to the attrs list */
635 637 if (esidtype != IDMAP_GSID &&
636 638 state->ad_unixuser_attr != NULL)
637 639 attrs[i++] = (char *)state->ad_unixuser_attr;
638 640 if (esidtype != IDMAP_USID &&
639 641 state->ad_unixgroup_attr != NULL)
640 642 attrs[i++] = (char *)state->ad_unixgroup_attr;
641 643 }
642 644
643 645 if (pid != NULL) {
644 646 if (esidtype != IDMAP_GSID)
645 647 attrs[i++] = UIDNUMBER;
646 648 if (esidtype != IDMAP_USID)
647 649 attrs[i++] = GIDNUMBER;
648 650 }
649 651
650 652 attrs[i] = NULL;
651 653
652 654 /*
653 655 * Provide sane defaults for the results in case we never hear
654 656 * back from the DS before closing the connection.
655 657 *
656 658 * In particular we default the result to indicate a retriable
657 659 * error. The first complete matching result entry will cause
658 660 * this to be set to IDMAP_SUCCESS, and the end of the results
659 661 * for this search will cause this to indicate "not found" if no
660 662 * result entries arrived or no complete ones matched the lookup
661 663 * we were doing.
662 664 */
663 665 *rc = IDMAP_ERR_RETRIABLE_NET_ERR;
664 666 if (sid_type != NULL)
665 667 *sid_type = IDMAP_SID;
666 668 if (sid != NULL)
667 669 *sid = NULL;
668 670 if (dname != NULL)
669 671 *dname = NULL;
670 672 if (rid != NULL)
671 673 *rid = 0;
672 674 if (dn != NULL)
673 675 *dn = NULL;
674 676 if (attr != NULL)
675 677 *attr = NULL;
676 678 if (value != NULL)
677 679 *value = NULL;
678 680
679 681 /*
680 682 * Don't set *canonname to NULL because it may be pointing to the
681 683 * given winname. Later on if we get a canonical name from AD the
682 684 * old name if any will be freed before assigning the new name.
683 685 */
684 686
685 687 /*
686 688 * Invoke the mother of all APIs i.e. the adutils API
687 689 */
688 690 ad_rc = adutils_lookup_batch_add(state->qs, filter,
689 691 (const char **)attrs,
690 692 edomain, &q->result, &q->ad_rc);
691 693 return (map_adrc2idmaprc(ad_rc));
692 694 }
693 695
694 696 idmap_retcode
695 697 idmap_name2sid_batch_add1(idmap_query_state_t *state,
696 698 const char *name, const char *dname, idmap_id_type esidtype,
697 699 char **dn, char **attr, char **value,
698 700 char **canonname, char **sid, rid_t *rid,
699 701 idmap_id_type *sid_type, char **unixname,
700 702 posix_id_t *pid, idmap_retcode *rc)
701 703 {
702 704 idmap_retcode retcode;
703 705 char *filter, *s_name;
704 706 char *ecanonname, *edomain; /* expected canonname */
705 707
706 708 /*
707 709 * Strategy: search the global catalog for user/group by
708 710 * sAMAccountName = user/groupname with "" as the base DN and by
709 711 * userPrincipalName = user/groupname@domain. The result
710 712 * entries will be checked to conform to the name and domain
711 713 * name given here. The DN, sAMAccountName, userPrincipalName,
712 714 * objectSid and objectClass of the result entries are all we
713 715 * need to figure out which entries match the lookup, the SID of
714 716 * the user/group and whether it is a user or a group.
715 717 */
716 718
717 719 if ((ecanonname = strdup(name)) == NULL)
718 720 return (IDMAP_ERR_MEMORY);
719 721
720 722 if (dname == NULL || *dname == '\0') {
721 723 /* 'name' not qualified and dname not given */
722 724 dname = state->default_domain;
723 725 edomain = strdup(dname);
724 726 if (edomain == NULL) {
725 727 free(ecanonname);
726 728 return (IDMAP_ERR_MEMORY);
727 729 }
728 730 } else {
729 731 if ((edomain = strdup(dname)) == NULL) {
730 732 free(ecanonname);
731 733 return (IDMAP_ERR_MEMORY);
732 734 }
733 735 }
734 736
735 737 if (!adutils_lookup_check_domain(state->qs, dname)) {
736 738 free(ecanonname);
737 739 free(edomain);
738 740 return (IDMAP_ERR_DOMAIN_NOTFOUND);
739 741 }
740 742
741 743 s_name = sanitize_for_ldap_filter(name);
742 744 if (s_name == NULL) {
743 745 free(ecanonname);
744 746 free(edomain);
745 747 return (IDMAP_ERR_MEMORY);
746 748 }
747 749
748 750 /* Assemble filter */
749 751 (void) asprintf(&filter, SANFILTER, s_name);
750 752 if (s_name != name)
751 753 free(s_name);
752 754 if (filter == NULL) {
753 755 free(ecanonname);
754 756 free(edomain);
755 757 return (IDMAP_ERR_MEMORY);
756 758 }
757 759
758 760 retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
759 761 esidtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
760 762 unixname, pid, rc);
761 763
762 764 free(filter);
763 765
764 766 return (retcode);
765 767 }
766 768
767 769 idmap_retcode
768 770 idmap_sid2name_batch_add1(idmap_query_state_t *state,
769 771 const char *sid, const rid_t *rid, idmap_id_type esidtype,
770 772 char **dn, char **attr, char **value,
771 773 char **name, char **dname, idmap_id_type *sid_type,
772 774 char **unixname, posix_id_t *pid, idmap_retcode *rc)
773 775 {
774 776 idmap_retcode retcode;
775 777 int ret;
776 778 char *filter;
777 779 char cbinsid[ADUTILS_MAXHEXBINSID + 1];
778 780
779 781 /*
780 782 * Strategy: search [the global catalog] for user/group by
781 783 * objectSid = SID with empty base DN. The DN, sAMAccountName
782 784 * and objectClass of the result are all we need to figure out
783 785 * the name of the SID and whether it is a user, a group or a
784 786 * computer.
|
↓ open down ↓ |
712 lines elided |
↑ open up ↑ |
785 787 */
786 788
787 789 if (!adutils_lookup_check_sid_prefix(state->qs, sid))
788 790 return (IDMAP_ERR_DOMAIN_NOTFOUND);
789 791
790 792 ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
791 793 if (ret != 0)
792 794 return (IDMAP_ERR_SID);
793 795
794 796 /* Assemble filter */
795 - (void) asprintf(&filter, OBJSIDFILTER, cbinsid);
797 + (void) asprintf(&filter, OBJSIDFILTER, cbinsid, cbinsid);
796 798 if (filter == NULL)
797 799 return (IDMAP_ERR_MEMORY);
798 800
799 801 retcode = idmap_batch_add1(state, filter, NULL, NULL, esidtype,
800 802 dn, attr, value, name, dname, NULL, NULL, sid_type, unixname,
801 803 pid, rc);
802 804
803 805 free(filter);
804 806
805 807 return (retcode);
806 808 }
807 809
808 810 idmap_retcode
809 811 idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
810 812 const char *unixname, int is_user, int is_wuser,
811 813 char **dn, char **attr, char **value,
812 814 char **sid, rid_t *rid, char **name,
813 815 char **dname, idmap_id_type *sid_type, idmap_retcode *rc)
814 816 {
815 817 idmap_retcode retcode;
816 818 char *filter, *s_unixname;
817 819 const char *attrname;
818 820
819 821 /* Get unixuser or unixgroup AD attribute name */
820 822 attrname = (is_user) ?
821 823 state->ad_unixuser_attr : state->ad_unixgroup_attr;
822 824 if (attrname == NULL)
823 825 return (IDMAP_ERR_NOTFOUND);
824 826
825 827 s_unixname = sanitize_for_ldap_filter(unixname);
826 828 if (s_unixname == NULL)
827 829 return (IDMAP_ERR_MEMORY);
828 830
829 831 /* Assemble filter */
830 832 (void) asprintf(&filter, "(&(objectclass=%s)(%s=%s))",
831 833 is_wuser ? "user" : "group", attrname, s_unixname);
832 834 if (s_unixname != unixname)
833 835 free(s_unixname);
834 836 if (filter == NULL) {
835 837 return (IDMAP_ERR_MEMORY);
836 838 }
837 839
838 840 retcode = idmap_batch_add1(state, filter, NULL, NULL,
839 841 IDMAP_POSIXID, dn, NULL, NULL, name, dname, sid, rid, sid_type,
840 842 NULL, NULL, rc);
841 843
842 844 if (retcode == IDMAP_SUCCESS && attr != NULL) {
843 845 if ((*attr = strdup(attrname)) == NULL)
844 846 retcode = IDMAP_ERR_MEMORY;
845 847 }
846 848
847 849 if (retcode == IDMAP_SUCCESS && value != NULL) {
848 850 if ((*value = strdup(unixname)) == NULL)
849 851 retcode = IDMAP_ERR_MEMORY;
850 852 }
851 853
852 854 free(filter);
853 855
854 856 return (retcode);
855 857 }
856 858
857 859 idmap_retcode
858 860 idmap_pid2sid_batch_add1(idmap_query_state_t *state,
859 861 posix_id_t pid, int is_user,
860 862 char **dn, char **attr, char **value,
861 863 char **sid, rid_t *rid, char **name,
862 864 char **dname, idmap_id_type *sid_type, idmap_retcode *rc)
863 865 {
864 866 idmap_retcode retcode;
865 867 char *filter;
866 868 const char *attrname;
867 869
868 870 /* Assemble filter */
869 871 if (is_user) {
870 872 (void) asprintf(&filter, UIDNUMBERFILTER, pid);
871 873 attrname = UIDNUMBER;
872 874 } else {
873 875 (void) asprintf(&filter, GIDNUMBERFILTER, pid);
874 876 attrname = GIDNUMBER;
875 877 }
876 878 if (filter == NULL)
877 879 return (IDMAP_ERR_MEMORY);
878 880
879 881 retcode = idmap_batch_add1(state, filter, NULL, NULL,
880 882 IDMAP_POSIXID, dn, NULL, NULL, name, dname, sid, rid, sid_type,
881 883 NULL, NULL, rc);
882 884
883 885 if (retcode == IDMAP_SUCCESS && attr != NULL) {
884 886 if ((*attr = strdup(attrname)) == NULL)
885 887 retcode = IDMAP_ERR_MEMORY;
886 888 }
887 889
888 890 if (retcode == IDMAP_SUCCESS && value != NULL) {
889 891 (void) asprintf(value, "%u", pid);
890 892 if (*value == NULL)
891 893 retcode = IDMAP_ERR_MEMORY;
892 894 }
893 895
894 896 free(filter);
895 897
896 898 return (retcode);
897 899 }
|
↓ open down ↓ |
92 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX