Print this page
1668 CVE 2011-3508 (ldap format string issues)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/idmap/idmapd/nldaputils.c
+++ new/usr/src/cmd/idmap/idmapd/nldaputils.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 + * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * native LDAP related utility routines
28 29 */
29 30
30 31 #include "idmapd.h"
31 32 #include "idmap_priv.h"
32 33 #include "ns_sldap.h"
33 34 #include "nldaputils.h"
34 35 #include <assert.h>
35 36
36 37 /*
37 38 * The following are format strings used to construct LDAP search filters
38 39 * when looking up Native LDAP directory service. The _F_XXX_SSD format
39 40 * is used by the libsldap API if a corresponding SSD is defined in
40 41 * Native LDAP configuration. The SSD contains a string that replaces
41 42 * the first %s in _F_XXX_SSD. If no SSD is defined then the regular
42 43 * _F_XXX format is used.
43 44 *
44 45 * Note that '\\' needs to be represented as "\\5c" in LDAP filters.
45 46 */
46 47
47 48 /* Native LDAP lookup using UNIX username */
48 49 #define _F_GETPWNAM "(&(objectClass=posixAccount)(uid=%s))"
49 50 #define _F_GETPWNAM_SSD "(&(%%s)(uid=%s))"
50 51
51 52 /*
52 53 * Native LDAP user lookup using names of well-known SIDs
53 54 * Note the use of 1$, 2$ in the format string which basically
54 55 * allows snprintf to re-use its first two arguments.
55 56 */
56 57 #define _F_GETPWWNAMWK \
57 58 "(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
58 59 #define _F_GETPWWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
59 60
60 61 /* Native LDAP user lookup using winname@windomain OR windomain\winname */
61 62 #define _F_GETPWWNAMDOM \
62 63 "(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
63 64 #define _F_GETPWWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
64 65
65 66 /* Native LDAP lookup using UID */
66 67 #define _F_GETPWUID "(&(objectClass=posixAccount)(uidNumber=%u))"
67 68 #define _F_GETPWUID_SSD "(&(%%s)(uidNumber=%u))"
68 69
69 70 /* Native LDAP lookup using UNIX groupname */
70 71 #define _F_GETGRNAM "(&(objectClass=posixGroup)(cn=%s))"
71 72 #define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))"
72 73
73 74 /* Native LDAP group lookup using names of well-known SIDs */
74 75 #define _F_GETGRWNAMWK \
75 76 "(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
76 77 #define _F_GETGRWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
77 78
78 79 /* Native LDAP group lookup using winname@windomain OR windomain\winname */
79 80 #define _F_GETGRWNAMDOM \
80 81 "(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
81 82 #define _F_GETGRWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
82 83
83 84 /* Native LDAP lookup using GID */
84 85 #define _F_GETGRGID "(&(objectClass=posixGroup)(gidNumber=%u))"
85 86 #define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))"
86 87
87 88 /* Native LDAP attribute names */
88 89 #define UID "uid"
89 90 #define CN "cn"
90 91 #define UIDNUMBER "uidnumber"
91 92 #define GIDNUMBER "gidnumber"
92 93 #define DN "dn"
93 94
94 95 #define IS_NLDAP_RC_FATAL(x) ((x == NS_LDAP_MEMORY) ? 1 : 0)
95 96
96 97 typedef struct idmap_nldap_q {
97 98 char **winname;
98 99 char **windomain;
99 100 char **unixname;
100 101 uid_t *pid;
101 102 char **dn;
102 103 char **attr;
103 104 char **value;
104 105 int is_user;
105 106 idmap_retcode *rc;
106 107 int lrc;
107 108 ns_ldap_result_t *result;
108 109 ns_ldap_error_t *errorp;
109 110 char *filter;
110 111 char *udata;
111 112 } idmap_nldap_q_t;
112 113
113 114 typedef struct idmap_nldap_query_state {
114 115 const char *nldap_winname_attr;
115 116 const char *defdom;
116 117 int nqueries;
117 118 int qid;
118 119 int flag;
119 120 ns_ldap_list_batch_t *batch;
120 121 idmap_nldap_q_t queries[1];
121 122 } idmap_nldap_query_state_t;
122 123
123 124 /*
124 125 * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c
125 126 * after removing the debug statements.
126 127 *
127 128 * This is a generic filter callback function for merging the filter
128 129 * from service search descriptor with an existing search filter. This
129 130 * routine expects userdata to contain a format string with a single %s
130 131 * in it, and will use the format string with sprintf() to insert the
131 132 * SSD filter.
132 133 *
133 134 * This routine and userdata are passed to the __ns_ldap_list_batch_add()
134 135 * API.
135 136 *
136 137 * Consider an example that uses __ns_ldap_list_batch_add() to lookup
137 138 * native LDAP directory using a given userid 'xy12345'. In this
138 139 * example the userdata will contain the filter "(&(%s)(cn=xy1234))".
139 140 * If a SSD is defined to replace the rfc2307bis specified filter
|
↓ open down ↓ |
106 lines elided |
↑ open up ↑ |
140 141 * i.e. (objectClass=posixAccount) by a site-specific filter
141 142 * say (department=sds) then this routine when called will produce
142 143 * "(&(department=sds)(uid=xy1234))" as the real search filter.
143 144 */
144 145 static
145 146 int
146 147 merge_SSD_filter(const ns_ldap_search_desc_t *desc,
147 148 char **realfilter, const void *userdata)
148 149 {
149 150 int len;
151 + char *checker;
152 +
150 153 if (realfilter == NULL)
151 154 return (NS_LDAP_INVALID_PARAM);
152 155 *realfilter = NULL;
153 156 if (desc == NULL || desc->filter == NULL || userdata == NULL)
154 157 return (NS_LDAP_INVALID_PARAM);
158 +
159 + /* Parameter check. We only want one %s here, otherwise bail. */
160 + len = 0; /* Reuse 'len' as "Number of %s hits"... */
161 + checker = (char *)userdata;
162 + do {
163 + checker = strchr(checker, '%');
164 + if (checker != NULL) {
165 + if (len > 0 || *(checker + 1) != 's')
166 + return (NS_LDAP_INVALID_PARAM);
167 + len++; /* Got our %s. */
168 + checker += 2;
169 + } else if (len != 1)
170 + return (NS_LDAP_INVALID_PARAM);
171 + } while (checker != NULL);
172 +
155 173 len = strlen(userdata) + strlen(desc->filter) + 1;
156 174 *realfilter = (char *)malloc(len);
157 175 if (*realfilter == NULL)
158 176 return (NS_LDAP_MEMORY);
159 177 (void) sprintf(*realfilter, (char *)userdata, desc->filter);
160 178 return (NS_LDAP_SUCCESS);
161 179 }
162 180
163 181 static
164 182 char
165 183 hex_char(int n)
166 184 {
167 185 return ("0123456789abcdef"[n & 0xf]);
168 186 }
169 187
170 188 /*
171 189 * If the input string contains special characters that needs to be
172 190 * escaped before the string can be used in a LDAP filter then this
173 191 * function will return a new sanitized string. Otherwise this function
174 192 * returns the input string (This saves us un-necessary memory allocations
175 193 * especially when processing a batch of requests). The caller must free
176 194 * the returned string if it isn't the input string.
177 195 *
178 196 * The escape mechanism for LDAP filter is described in RFC2254 basically
179 197 * it's \hh where hh are the two hexadecimal digits representing the ASCII
180 198 * value of the encoded character (case of hh is not significant).
181 199 * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c,
182 200 *
183 201 * outstring = sanitize_for_ldap_filter(instring);
184 202 * if (outstring == NULL)
185 203 * Out of memory
186 204 * else
187 205 * Use outstring
188 206 * if (outstring != instring)
189 207 * free(outstring);
190 208 * done
191 209 */
192 210 char *
193 211 sanitize_for_ldap_filter(const char *str)
194 212 {
195 213 const char *p;
196 214 char *q, *s_str = NULL;
197 215 int n;
198 216
199 217 /* Get a count of special characters */
200 218 for (p = str, n = 0; *p; p++)
201 219 if (*p == '*' || *p == '(' || *p == ')' ||
202 220 *p == '\\' || *p == '%')
203 221 n++;
204 222 /* If count is zero then no need to sanitize */
205 223 if (n == 0)
206 224 return ((char *)str);
207 225 /* Create output buffer that will contain the sanitized value */
208 226 s_str = calloc(1, n * 2 + strlen(str) + 1);
209 227 if (s_str == NULL)
210 228 return (NULL);
211 229 for (p = str, q = s_str; *p; p++) {
212 230 if (*p == '*' || *p == '(' || *p == ')' ||
213 231 *p == '\\' || *p == '%') {
214 232 *q++ = '\\';
215 233 *q++ = hex_char(*p >> 4);
216 234 *q++ = hex_char(*p & 0xf);
217 235 } else
218 236 *q++ = *p;
219 237 }
220 238 return (s_str);
221 239 }
222 240
223 241 /*
224 242 * Map libsldap status to idmap status
225 243 */
226 244 static
227 245 idmap_retcode
228 246 nldaprc2retcode(int rc)
229 247 {
230 248 switch (rc) {
231 249 case NS_LDAP_SUCCESS:
232 250 case NS_LDAP_SUCCESS_WITH_INFO:
233 251 return (IDMAP_SUCCESS);
234 252 case NS_LDAP_NOTFOUND:
235 253 return (IDMAP_ERR_NOTFOUND);
236 254 case NS_LDAP_MEMORY:
237 255 return (IDMAP_ERR_MEMORY);
238 256 case NS_LDAP_CONFIG:
239 257 return (IDMAP_ERR_NS_LDAP_CFG);
240 258 case NS_LDAP_OP_FAILED:
241 259 return (IDMAP_ERR_NS_LDAP_OP_FAILED);
242 260 case NS_LDAP_PARTIAL:
243 261 return (IDMAP_ERR_NS_LDAP_PARTIAL);
244 262 case NS_LDAP_INTERNAL:
245 263 return (IDMAP_ERR_INTERNAL);
246 264 case NS_LDAP_INVALID_PARAM:
247 265 return (IDMAP_ERR_ARG);
248 266 default:
249 267 return (IDMAP_ERR_OTHER);
250 268 }
251 269 /*NOTREACHED*/
252 270 }
253 271
254 272 /*
255 273 * Create a batch for native LDAP lookup.
256 274 */
257 275 static
258 276 idmap_retcode
259 277 idmap_nldap_lookup_batch_start(int nqueries, idmap_nldap_query_state_t **qs)
260 278 {
261 279 idmap_nldap_query_state_t *s;
262 280
263 281 s = calloc(1, sizeof (*s) +
264 282 (nqueries - 1) * sizeof (idmap_nldap_q_t));
265 283 if (s == NULL)
266 284 return (IDMAP_ERR_MEMORY);
267 285 if (__ns_ldap_list_batch_start(&s->batch) != NS_LDAP_SUCCESS) {
268 286 free(s);
269 287 return (IDMAP_ERR_MEMORY);
270 288 }
271 289 s->nqueries = nqueries;
272 290 s->flag = NS_LDAP_KEEP_CONN;
273 291 *qs = s;
274 292 return (IDMAP_SUCCESS);
275 293 }
276 294
277 295 /*
278 296 * Add a lookup by winname request to the batch.
279 297 */
280 298 static
281 299 idmap_retcode
282 300 idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t *qs,
283 301 const char *winname, const char *windomain, int is_user,
284 302 char **dn, char **attr, char **value,
285 303 char **unixname, uid_t *pid, idmap_retcode *rc)
286 304 {
287 305 idmap_nldap_q_t *q;
288 306 const char *db, *filter, *udata;
289 307 int flen, ulen, wksid = 0;
290 308 char *s_winname, *s_windomain;
291 309 const char **attrs;
292 310 const char *pwd_attrs[] = {UID, UIDNUMBER, NULL, NULL};
293 311 const char *grp_attrs[] = {CN, GIDNUMBER, NULL, NULL};
294 312
295 313 s_winname = s_windomain = NULL;
296 314 q = &(qs->queries[qs->qid++]);
297 315 q->unixname = unixname;
298 316 q->pid = pid;
299 317 q->rc = rc;
300 318 q->is_user = is_user;
301 319 q->dn = dn;
302 320 q->attr = attr;
303 321 q->value = value;
304 322
305 323 if (is_user) {
306 324 db = "passwd";
307 325 if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL,
308 326 NULL, NULL) == IDMAP_SUCCESS) {
309 327 filter = _F_GETPWWNAMWK;
310 328 udata = _F_GETPWWNAMWK_SSD;
311 329 wksid = 1;
312 330 } else if (windomain != NULL) {
313 331 filter = _F_GETPWWNAMDOM;
314 332 udata = _F_GETPWWNAMDOM_SSD;
315 333 } else {
316 334 *q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
317 335 goto errout;
318 336 }
319 337 pwd_attrs[2] = qs->nldap_winname_attr;
320 338 attrs = pwd_attrs;
321 339 } else {
322 340 db = "group";
323 341 if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL,
324 342 NULL, NULL) == IDMAP_SUCCESS) {
325 343 filter = _F_GETGRWNAMWK;
326 344 udata = _F_GETGRWNAMWK_SSD;
327 345 wksid = 1;
328 346 } else if (windomain != NULL) {
329 347 filter = _F_GETGRWNAMDOM;
330 348 udata = _F_GETGRWNAMDOM_SSD;
331 349 } else {
332 350 *q->rc = IDMAP_ERR_DOMAIN_NOTFOUND;
333 351 goto errout;
334 352 }
335 353 grp_attrs[2] = qs->nldap_winname_attr;
336 354 attrs = grp_attrs;
337 355 }
338 356
339 357 /*
340 358 * Sanitize names. No need to sanitize qs->nldap_winname_attr
341 359 * because if it contained any of the special characters then
342 360 * it would have been rejected by the function that reads it
343 361 * from the SMF config. LDAP attribute names can only contain
344 362 * letters, digits or hyphens.
345 363 */
346 364 s_winname = sanitize_for_ldap_filter(winname);
347 365 if (s_winname == NULL) {
348 366 *q->rc = IDMAP_ERR_MEMORY;
349 367 goto errout;
350 368 }
351 369 /* windomain could be NULL for names of well-known SIDs */
352 370 if (windomain != NULL) {
353 371 s_windomain = sanitize_for_ldap_filter(windomain);
354 372 if (s_windomain == NULL) {
355 373 *q->rc = IDMAP_ERR_MEMORY;
356 374 goto errout;
357 375 }
358 376 }
359 377
360 378 /* Construct the filter and udata using snprintf. */
361 379 if (wksid) {
362 380 flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
363 381 s_winname) + 1;
364 382 ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
365 383 s_winname) + 1;
366 384 } else {
367 385 flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr,
368 386 s_winname, s_windomain) + 1;
369 387 ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr,
370 388 s_winname, s_windomain) + 1;
371 389 }
372 390
373 391 q->filter = malloc(flen);
374 392 if (q->filter == NULL) {
375 393 *q->rc = IDMAP_ERR_MEMORY;
376 394 goto errout;
377 395 }
378 396 q->udata = malloc(ulen);
379 397 if (q->udata == NULL) {
380 398 *q->rc = IDMAP_ERR_MEMORY;
381 399 goto errout;
382 400 }
383 401
384 402 if (wksid) {
385 403 (void) snprintf(q->filter, flen, filter,
386 404 qs->nldap_winname_attr, s_winname);
387 405 (void) snprintf(q->udata, ulen, udata,
388 406 qs->nldap_winname_attr, s_winname);
389 407 } else {
390 408 (void) snprintf(q->filter, flen, filter,
391 409 qs->nldap_winname_attr, s_winname, s_windomain);
392 410 (void) snprintf(q->udata, ulen, udata,
393 411 qs->nldap_winname_attr, s_winname, s_windomain);
394 412 }
395 413
396 414 if (s_winname != winname)
397 415 free(s_winname);
398 416 if (s_windomain != windomain)
399 417 free(s_windomain);
400 418
401 419 q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
402 420 merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
403 421 &q->errorp, &q->lrc, NULL, q->udata);
404 422
405 423 if (IS_NLDAP_RC_FATAL(q->lrc))
406 424 return (nldaprc2retcode(q->lrc));
407 425 return (IDMAP_SUCCESS);
408 426
409 427 errout:
410 428 /* query q and its content will be freed by batch_release */
411 429 if (s_winname != winname)
412 430 free(s_winname);
413 431 if (s_windomain != windomain)
414 432 free(s_windomain);
415 433 return (*q->rc);
416 434 }
417 435
418 436 /*
419 437 * Add a lookup by uid/gid request to the batch.
420 438 */
421 439 static
422 440 idmap_retcode
423 441 idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t *qs,
424 442 uid_t pid, int is_user, char **dn, char **attr, char **value,
425 443 char **winname, char **windomain,
426 444 char **unixname, idmap_retcode *rc)
427 445 {
428 446 idmap_nldap_q_t *q;
429 447 const char *db, *filter, *udata;
430 448 int len;
431 449 const char **attrs;
432 450 const char *pwd_attrs[] = {UID, NULL, NULL};
433 451 const char *grp_attrs[] = {CN, NULL, NULL};
434 452
435 453 q = &(qs->queries[qs->qid++]);
436 454 q->winname = winname;
437 455 q->windomain = windomain;
438 456 q->unixname = unixname;
439 457 q->rc = rc;
440 458 q->is_user = is_user;
441 459 q->dn = dn;
442 460 q->attr = attr;
443 461 q->value = value;
444 462
445 463 if (is_user) {
446 464 db = "passwd";
447 465 filter = _F_GETPWUID;
448 466 udata = _F_GETPWUID_SSD;
449 467 pwd_attrs[1] = qs->nldap_winname_attr;
450 468 attrs = pwd_attrs;
451 469 } else {
452 470 db = "group";
453 471 filter = _F_GETGRGID;
454 472 udata = _F_GETGRGID_SSD;
455 473 grp_attrs[1] = qs->nldap_winname_attr;
456 474 attrs = grp_attrs;
457 475 }
458 476
459 477 len = snprintf(NULL, 0, filter, pid) + 1;
460 478 q->filter = malloc(len);
461 479 if (q->filter == NULL) {
462 480 *q->rc = IDMAP_ERR_MEMORY;
463 481 return (IDMAP_ERR_MEMORY);
464 482 }
465 483 (void) snprintf(q->filter, len, filter, pid);
466 484
467 485 len = snprintf(NULL, 0, udata, pid) + 1;
468 486 q->udata = malloc(len);
469 487 if (q->udata == NULL) {
470 488 *q->rc = IDMAP_ERR_MEMORY;
471 489 return (IDMAP_ERR_MEMORY);
472 490 }
473 491 (void) snprintf(q->udata, len, udata, pid);
474 492
475 493 q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
476 494 merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
477 495 &q->errorp, &q->lrc, NULL, q->udata);
478 496
479 497 if (IS_NLDAP_RC_FATAL(q->lrc))
480 498 return (nldaprc2retcode(q->lrc));
481 499 return (IDMAP_SUCCESS);
482 500 }
483 501
484 502 /*
485 503 * Add a lookup by user/group name request to the batch.
486 504 */
487 505 static
488 506 idmap_retcode
489 507 idmap_nldap_byunixname_batch_add(idmap_nldap_query_state_t *qs,
490 508 const char *unixname, int is_user,
491 509 char **dn, char **attr, char **value,
492 510 char **winname, char **windomain, uid_t *pid, idmap_retcode *rc)
493 511 {
494 512 idmap_nldap_q_t *q;
495 513 const char *db, *filter, *udata;
496 514 int len;
497 515 char *s_unixname = NULL;
498 516 const char **attrs;
499 517 const char *pwd_attrs[] = {UIDNUMBER, NULL, NULL};
500 518 const char *grp_attrs[] = {GIDNUMBER, NULL, NULL};
501 519
502 520 q = &(qs->queries[qs->qid++]);
503 521 q->winname = winname;
504 522 q->windomain = windomain;
505 523 q->pid = pid;
506 524 q->rc = rc;
507 525 q->is_user = is_user;
508 526 q->dn = dn;
509 527 q->attr = attr;
510 528 q->value = value;
511 529
512 530 if (is_user) {
513 531 db = "passwd";
514 532 filter = _F_GETPWNAM;
515 533 udata = _F_GETPWNAM_SSD;
516 534 pwd_attrs[1] = qs->nldap_winname_attr;
517 535 attrs = pwd_attrs;
518 536 } else {
519 537 db = "group";
520 538 filter = _F_GETGRNAM;
521 539 udata = _F_GETGRNAM_SSD;
522 540 grp_attrs[1] = qs->nldap_winname_attr;
523 541 attrs = grp_attrs;
524 542 }
525 543
526 544 s_unixname = sanitize_for_ldap_filter(unixname);
527 545 if (s_unixname == NULL) {
528 546 *q->rc = IDMAP_ERR_MEMORY;
529 547 return (IDMAP_ERR_MEMORY);
530 548 }
531 549
532 550 len = snprintf(NULL, 0, filter, s_unixname) + 1;
533 551 q->filter = malloc(len);
534 552 if (q->filter == NULL) {
535 553 if (s_unixname != unixname)
536 554 free(s_unixname);
537 555 *q->rc = IDMAP_ERR_MEMORY;
538 556 return (IDMAP_ERR_MEMORY);
539 557 }
540 558 (void) snprintf(q->filter, len, filter, s_unixname);
541 559
542 560 len = snprintf(NULL, 0, udata, s_unixname) + 1;
543 561 q->udata = malloc(len);
544 562 if (q->udata == NULL) {
545 563 if (s_unixname != unixname)
546 564 free(s_unixname);
547 565 *q->rc = IDMAP_ERR_MEMORY;
548 566 return (IDMAP_ERR_MEMORY);
549 567 }
550 568 (void) snprintf(q->udata, len, udata, s_unixname);
551 569
552 570 if (s_unixname != unixname)
553 571 free(s_unixname);
554 572
555 573 q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter,
556 574 merge_SSD_filter, attrs, NULL, qs->flag, &q->result,
557 575 &q->errorp, &q->lrc, NULL, q->udata);
558 576
559 577 if (IS_NLDAP_RC_FATAL(q->lrc))
560 578 return (nldaprc2retcode(q->lrc));
561 579 return (IDMAP_SUCCESS);
562 580 }
563 581
564 582 /*
565 583 * Free the batch
566 584 */
567 585 static
568 586 void
569 587 idmap_nldap_lookup_batch_release(idmap_nldap_query_state_t *qs)
570 588 {
571 589 idmap_nldap_q_t *q;
572 590 int i;
573 591
574 592 if (qs->batch != NULL)
575 593 (void) __ns_ldap_list_batch_release(qs->batch);
576 594 for (i = 0; i < qs->qid; i++) {
577 595 q = &(qs->queries[i]);
578 596 free(q->filter);
579 597 free(q->udata);
580 598 if (q->errorp != NULL)
581 599 (void) __ns_ldap_freeError(&q->errorp);
582 600 if (q->result != NULL)
583 601 (void) __ns_ldap_freeResult(&q->result);
584 602 }
585 603 free(qs);
586 604 }
587 605
588 606 /*
589 607 * Process all requests added to the batch and then free the batch.
590 608 * The results for individual requests will be accessible using the
591 609 * pointers passed during idmap_nldap_lookup_batch_end.
592 610 */
593 611 static
594 612 idmap_retcode
595 613 idmap_nldap_lookup_batch_end(idmap_nldap_query_state_t *qs)
596 614 {
597 615 idmap_nldap_q_t *q;
598 616 int i;
599 617 ns_ldap_entry_t *entry;
600 618 char **val, *end, *str, *name, *dom;
601 619 idmap_retcode rc = IDMAP_SUCCESS;
602 620
603 621 (void) __ns_ldap_list_batch_end(qs->batch);
604 622 qs->batch = NULL;
605 623 for (i = 0; i < qs->qid; i++) {
606 624 q = &(qs->queries[i]);
607 625 *q->rc = nldaprc2retcode(q->lrc);
608 626 if (*q->rc != IDMAP_SUCCESS)
609 627 continue;
610 628 if (q->result == NULL ||
611 629 !q->result->entries_count ||
612 630 (entry = q->result->entry) == NULL ||
613 631 !entry->attr_count) {
614 632 *q->rc = IDMAP_ERR_NOTFOUND;
615 633 continue;
616 634 }
617 635 /* Get uid/gid */
618 636 if (q->pid != NULL) {
619 637 val = __ns_ldap_getAttr(entry,
620 638 (q->is_user) ? UIDNUMBER : GIDNUMBER);
621 639 if (val != NULL && *val != NULL)
622 640 *q->pid = strtoul(*val, &end, 10);
623 641 }
624 642 /* Get unixname */
625 643 if (q->unixname != NULL) {
626 644 val = __ns_ldap_getAttr(entry,
627 645 (q->is_user) ? UID : CN);
628 646 if (val != NULL && *val != NULL) {
629 647 *q->unixname = strdup(*val);
630 648 if (*q->unixname == NULL) {
631 649 rc = *q->rc = IDMAP_ERR_MEMORY;
632 650 goto out;
633 651 }
634 652 }
635 653 }
636 654 /* Get DN for how info */
637 655 if (q->dn != NULL) {
638 656 val = __ns_ldap_getAttr(entry, DN);
639 657 if (val != NULL && *val != NULL) {
640 658 *q->dn = strdup(*val);
641 659 if (*q->dn == NULL) {
642 660 rc = *q->rc = IDMAP_ERR_MEMORY;
643 661 goto out;
644 662 }
645 663 }
646 664 }
647 665 /* Get nldap name mapping attr name for how info */
648 666 if (q->attr != NULL) {
649 667 *q->attr = strdup(qs->nldap_winname_attr);
650 668 if (*q->attr == NULL) {
651 669 rc = *q->rc = IDMAP_ERR_MEMORY;
652 670 goto out;
653 671 }
654 672 }
655 673 /* Get nldap name mapping attr value for how info */
656 674 val = __ns_ldap_getAttr(entry, qs->nldap_winname_attr);
657 675 if (val == NULL || *val == NULL)
658 676 continue;
659 677 if (q->value != NULL) {
660 678 *q->value = strdup(*val);
661 679 if (*q->value == NULL) {
662 680 rc = *q->rc = IDMAP_ERR_MEMORY;
663 681 goto out;
664 682 }
665 683 }
666 684
667 685 /* Get winname and windomain */
668 686 if (q->winname == NULL && q->windomain == NULL)
669 687 continue;
670 688 /*
671 689 * We need to split the value into winname and
672 690 * windomain. The value could be either in NT4
673 691 * style (i.e. dom\name) or AD-style (i.e. name@dom).
674 692 * We choose the first '\\' if it's in NT4 style and
675 693 * the last '@' if it's in AD-style for the split.
676 694 */
677 695 name = dom = NULL;
678 696 if (lookup_wksids_name2sid(*val, NULL, NULL, NULL, NULL, NULL,
679 697 NULL) == IDMAP_SUCCESS) {
680 698 name = *val;
681 699 dom = NULL;
682 700 } else if ((str = strchr(*val, '\\')) != NULL) {
683 701 *str = '\0';
684 702 name = str + 1;
685 703 dom = *val;
686 704 } else if ((str = strrchr(*val, '@')) != NULL) {
687 705 *str = '\0';
688 706 name = *val;
689 707 dom = str + 1;
690 708 } else {
691 709 idmapdlog(LOG_INFO, "Domain-less "
692 710 "winname (%s) found in Native LDAP", *val);
693 711 *q->rc = IDMAP_ERR_NS_LDAP_BAD_WINNAME;
694 712 continue;
695 713 }
696 714 if (q->winname != NULL) {
697 715 *q->winname = strdup(name);
698 716 if (*q->winname == NULL) {
699 717 rc = *q->rc = IDMAP_ERR_MEMORY;
700 718 goto out;
701 719 }
702 720 }
703 721 if (q->windomain != NULL && dom != NULL) {
704 722 *q->windomain = strdup(dom);
705 723 if (*q->windomain == NULL) {
706 724 rc = *q->rc = IDMAP_ERR_MEMORY;
707 725 goto out;
708 726 }
709 727 }
710 728 }
711 729
712 730 out:
713 731 (void) idmap_nldap_lookup_batch_release(qs);
714 732 return (rc);
715 733 }
716 734
717 735 /* ARGSUSED */
718 736 idmap_retcode
719 737 nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
720 738 idmap_ids_res *result)
721 739 {
722 740 idmap_retcode retcode, rc1;
723 741 int i, add;
724 742 idmap_mapping *req;
725 743 idmap_id_res *res;
726 744 idmap_nldap_query_state_t *qs = NULL;
727 745 idmap_how *how;
728 746
729 747 if (state->nldap_nqueries == 0)
730 748 return (IDMAP_SUCCESS);
731 749
732 750 /* Create nldap lookup batch */
733 751 retcode = idmap_nldap_lookup_batch_start(state->nldap_nqueries, &qs);
734 752 if (retcode != IDMAP_SUCCESS) {
735 753 idmapdlog(LOG_ERR,
736 754 "Failed to create batch for native LDAP lookup");
737 755 goto out;
738 756 }
739 757
740 758 qs->nldap_winname_attr = state->nldap_winname_attr;
741 759 qs->defdom = state->defdom;
742 760
743 761 /* Add requests to the batch */
744 762 for (i = 0, add = 0; i < batch->idmap_mapping_batch_len; i++) {
745 763 req = &batch->idmap_mapping_batch_val[i];
746 764 res = &result->ids.ids_val[i];
747 765 retcode = IDMAP_SUCCESS;
748 766
749 767 /* Skip if not marked for nldap lookup */
750 768 if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP))
751 769 continue;
752 770
753 771 if (IS_ID_SID(req->id1)) {
754 772
755 773 /* win2unix request: */
756 774
757 775 /*
758 776 * When processing a win2unix request, nldap lookup
759 777 * is performed after AD lookup or a successful
760 778 * name-cache lookup. Therefore we should already
761 779 * have sid, winname and sidtype. Note that
762 780 * windomain could be NULL e.g. well-known SIDs.
763 781 */
764 782 assert(req->id1name != NULL &&
765 783 (res->id.idtype == IDMAP_UID ||
766 784 res->id.idtype == IDMAP_GID));
767 785
768 786 /* Skip if we already have pid and unixname */
769 787 if (req->id2name != NULL &&
770 788 res->id.idmap_id_u.uid != IDMAP_SENTINEL_PID) {
771 789 res->retcode = IDMAP_SUCCESS;
772 790 continue;
773 791 }
774 792
775 793 /* Clear leftover value */
776 794 free(req->id2name);
777 795 req->id2name = NULL;
778 796
779 797 /* Lookup nldap by winname to get pid and unixname */
780 798 add = 1;
781 799 idmap_how_clear(&res->info.how);
782 800 res->info.src = IDMAP_MAP_SRC_NEW;
783 801 how = &res->info.how;
784 802 how->map_type = IDMAP_MAP_TYPE_DS_NLDAP;
785 803 retcode = idmap_nldap_bywinname_batch_add(
786 804 qs, req->id1name, req->id1domain,
787 805 (res->id.idtype == IDMAP_UID) ? 1 : 0,
788 806 &how->idmap_how_u.nldap.dn,
789 807 &how->idmap_how_u.nldap.attr,
790 808 &how->idmap_how_u.nldap.value,
791 809 &req->id2name, &res->id.idmap_id_u.uid,
792 810 &res->retcode);
793 811
794 812 } else if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) {
795 813
796 814 /* unix2win request: */
797 815
798 816 /* Skip if we already have winname */
799 817 if (req->id2name != NULL) {
800 818 res->retcode = IDMAP_SUCCESS;
801 819 continue;
802 820 }
803 821
804 822 /* Clear old value */
805 823 free(req->id2domain);
806 824 req->id2domain = NULL;
807 825
808 826 /* Set how info */
809 827 idmap_how_clear(&res->info.how);
810 828 res->info.src = IDMAP_MAP_SRC_NEW;
811 829 how = &res->info.how;
812 830 how->map_type = IDMAP_MAP_TYPE_DS_NLDAP;
813 831
814 832 /* Lookup nldap by pid or unixname to get winname */
815 833 if (req->id1.idmap_id_u.uid != IDMAP_SENTINEL_PID) {
816 834 add = 1;
817 835 retcode = idmap_nldap_bypid_batch_add(
818 836 qs, req->id1.idmap_id_u.uid,
819 837 (req->id1.idtype == IDMAP_UID) ? 1 : 0,
820 838 &how->idmap_how_u.nldap.dn,
821 839 &how->idmap_how_u.nldap.attr,
822 840 &how->idmap_how_u.nldap.value,
823 841 &req->id2name, &req->id2domain,
824 842 (req->id1name == NULL) ?
825 843 &req->id1name : NULL,
826 844 &res->retcode);
827 845 } else if (req->id1name != NULL) {
828 846 add = 1;
829 847 retcode = idmap_nldap_byunixname_batch_add(
830 848 qs, req->id1name,
831 849 (req->id1.idtype == IDMAP_UID) ? 1 : 0,
832 850 &how->idmap_how_u.nldap.dn,
833 851 &how->idmap_how_u.nldap.attr,
834 852 &how->idmap_how_u.nldap.value,
835 853 &req->id2name, &req->id2domain,
836 854 &req->id1.idmap_id_u.uid, &res->retcode);
837 855 }
838 856
839 857 }
840 858
841 859 /*
842 860 * nldap_batch_add API returns error only on fatal failures
843 861 * otherwise it returns success and the actual status
844 862 * is stored in the individual request (res->retcode).
845 863 * Stop adding requests to this batch on fatal failures
846 864 * (i.e. if retcode != success)
847 865 */
848 866 if (retcode != IDMAP_SUCCESS)
849 867 break;
850 868 }
851 869
852 870 if (!add)
853 871 idmap_nldap_lookup_batch_release(qs);
854 872 else if (retcode != IDMAP_SUCCESS)
855 873 idmap_nldap_lookup_batch_release(qs);
856 874 else
857 875 retcode = idmap_nldap_lookup_batch_end(qs);
858 876
859 877 out:
860 878 for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
861 879 req = &batch->idmap_mapping_batch_val[i];
862 880 res = &result->ids.ids_val[i];
863 881 if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP))
864 882 continue;
865 883
866 884 /* Reset nldap flag */
867 885 req->direction &= ~(_IDMAP_F_LOOKUP_NLDAP);
868 886
869 887 /*
870 888 * As noted earlier retcode != success if there were fatal
871 889 * errors during batch_start and batch_adds. If so then set
872 890 * the status of each nldap request to that error.
873 891 */
874 892 if (retcode != IDMAP_SUCCESS) {
875 893 res->retcode = retcode;
876 894 continue;
877 895 }
878 896 if (!add)
879 897 continue;
880 898
881 899 /*
882 900 * If we successfully retrieved winname from nldap entry
883 901 * then lookup winname2sid locally. If not found locally
884 902 * then mark this request for AD lookup.
885 903 */
886 904 if (res->retcode == IDMAP_SUCCESS &&
887 905 req->id2name != NULL &&
888 906 res->id.idmap_id_u.sid.prefix == NULL &&
889 907 (IS_ID_UID(req->id1) || IS_ID_GID(req->id1))) {
890 908
891 909 rc1 = lookup_name2sid(state->cache,
892 910 req->id2name, req->id2domain, -1,
893 911 NULL, NULL,
894 912 &res->id.idmap_id_u.sid.prefix,
895 913 &res->id.idmap_id_u.sid.rid,
896 914 &res->id.idtype,
897 915 req, 1);
898 916 if (rc1 == IDMAP_ERR_NOTFOUND) {
899 917 req->direction |= _IDMAP_F_LOOKUP_AD;
900 918 state->ad_nqueries++;
901 919 } else
902 920 res->retcode = rc1;
903 921 }
904 922
905 923 /*
906 924 * Unset non-fatal errors in individual request. This allows
907 925 * the next pass to process other mapping mechanisms for
908 926 * this request.
909 927 */
910 928 if (res->retcode != IDMAP_SUCCESS &&
911 929 res->retcode != IDMAP_ERR_NS_LDAP_BAD_WINNAME &&
912 930 !(IDMAP_FATAL_ERROR(res->retcode))) {
913 931 idmap_how_clear(&res->info.how);
914 932 res->retcode = IDMAP_SUCCESS;
915 933 }
916 934 }
917 935
918 936 state->nldap_nqueries = 0;
919 937 return (retcode);
920 938 }
|
↓ open down ↓ |
756 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX