4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
28 * native LDAP related utility routines
32 #include "idmap_priv.h"
34 #include "nldaputils.h"
38 * The following are format strings used to construct LDAP search filters
39 * when looking up Native LDAP directory service. The _F_XXX_SSD format
40 * is used by the libsldap API if a corresponding SSD is defined in
41 * Native LDAP configuration. The SSD contains a string that replaces
42 * the first %s in _F_XXX_SSD. If no SSD is defined then the regular
43 * _F_XXX format is used.
45 * Note that '\\' needs to be represented as "\\5c" in LDAP filters.
48 /* Native LDAP lookup using UNIX username */
49 #define _F_GETPWNAM "(&(objectClass=posixAccount)(uid=%s))"
50 #define _F_GETPWNAM_SSD "(&(%%s)(uid=%s))"
53 * Native LDAP user lookup using names of well-known SIDs
54 * Note the use of 1$, 2$ in the format string which basically
55 * allows snprintf to re-use its first two arguments.
57 #define _F_GETPWWNAMWK \
58 "(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
59 #define _F_GETPWWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
61 /* Native LDAP user lookup using winname@windomain OR windomain\winname */
62 #define _F_GETPWWNAMDOM \
63 "(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
64 #define _F_GETPWWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
66 /* Native LDAP lookup using UID */
67 #define _F_GETPWUID "(&(objectClass=posixAccount)(uidNumber=%u))"
68 #define _F_GETPWUID_SSD "(&(%%s)(uidNumber=%u))"
70 /* Native LDAP lookup using UNIX groupname */
71 #define _F_GETGRNAM "(&(objectClass=posixGroup)(cn=%s))"
72 #define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))"
74 /* Native LDAP group lookup using names of well-known SIDs */
75 #define _F_GETGRWNAMWK \
76 "(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
77 #define _F_GETGRWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))"
79 /* Native LDAP group lookup using winname@windomain OR windomain\winname */
80 #define _F_GETGRWNAMDOM \
81 "(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
82 #define _F_GETGRWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))"
84 /* Native LDAP lookup using GID */
85 #define _F_GETGRGID "(&(objectClass=posixGroup)(gidNumber=%u))"
86 #define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))"
88 /* Native LDAP attribute names */
91 #define UIDNUMBER "uidnumber"
92 #define GIDNUMBER "gidnumber"
95 #define IS_NLDAP_RC_FATAL(x) ((x == NS_LDAP_MEMORY) ? 1 : 0)
97 typedef struct idmap_nldap_q
{
108 ns_ldap_result_t
*result
;
109 ns_ldap_error_t
*errorp
;
114 typedef struct idmap_nldap_query_state
{
115 const char *nldap_winname_attr
;
120 ns_ldap_list_batch_t
*batch
;
121 idmap_nldap_q_t queries
[1];
122 } idmap_nldap_query_state_t
;
125 * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c
126 * after removing the debug statements.
128 * This is a generic filter callback function for merging the filter
129 * from service search descriptor with an existing search filter. This
130 * routine expects userdata to contain a format string with a single %s
131 * in it, and will use the format string with sprintf() to insert the
134 * This routine and userdata are passed to the __ns_ldap_list_batch_add()
137 * Consider an example that uses __ns_ldap_list_batch_add() to lookup
138 * native LDAP directory using a given userid 'xy12345'. In this
139 * example the userdata will contain the filter "(&(%s)(cn=xy1234))".
140 * If a SSD is defined to replace the rfc2307bis specified filter
141 * i.e. (objectClass=posixAccount) by a site-specific filter
142 * say (department=sds) then this routine when called will produce
143 * "(&(department=sds)(uid=xy1234))" as the real search filter.
147 merge_SSD_filter(const ns_ldap_search_desc_t
*desc
,
148 char **realfilter
, const void *userdata
)
153 if (realfilter
== NULL
)
154 return (NS_LDAP_INVALID_PARAM
);
156 if (desc
== NULL
|| desc
->filter
== NULL
|| userdata
== NULL
)
157 return (NS_LDAP_INVALID_PARAM
);
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
;
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. */
170 return (NS_LDAP_INVALID_PARAM
);
171 } while (checker
!= NULL
);
173 len
= strlen(userdata
) + strlen(desc
->filter
) + 1;
174 *realfilter
= (char *)malloc(len
);
175 if (*realfilter
== NULL
)
176 return (NS_LDAP_MEMORY
);
177 (void) sprintf(*realfilter
, (char *)userdata
, desc
->filter
);
178 return (NS_LDAP_SUCCESS
);
185 return ("0123456789abcdef"[n
& 0xf]);
189 * If the input string contains special characters that needs to be
190 * escaped before the string can be used in a LDAP filter then this
191 * function will return a new sanitized string. Otherwise this function
192 * returns the input string (This saves us un-necessary memory allocations
193 * especially when processing a batch of requests). The caller must free
194 * the returned string if it isn't the input string.
196 * The escape mechanism for LDAP filter is described in RFC2254 basically
197 * it's \hh where hh are the two hexadecimal digits representing the ASCII
198 * value of the encoded character (case of hh is not significant).
199 * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c,
201 * outstring = sanitize_for_ldap_filter(instring);
202 * if (outstring == NULL)
206 * if (outstring != instring)
211 sanitize_for_ldap_filter(const char *str
)
214 char *q
, *s_str
= NULL
;
217 /* Get a count of special characters */
218 for (p
= str
, n
= 0; *p
; p
++)
219 if (*p
== '*' || *p
== '(' || *p
== ')' ||
220 *p
== '\\' || *p
== '%')
222 /* If count is zero then no need to sanitize */
224 return ((char *)str
);
225 /* Create output buffer that will contain the sanitized value */
226 s_str
= calloc(1, n
* 2 + strlen(str
) + 1);
229 for (p
= str
, q
= s_str
; *p
; p
++) {
230 if (*p
== '*' || *p
== '(' || *p
== ')' ||
231 *p
== '\\' || *p
== '%') {
233 *q
++ = hex_char(*p
>> 4);
234 *q
++ = hex_char(*p
& 0xf);
242 * Map libsldap status to idmap status
246 nldaprc2retcode(int rc
)
249 case NS_LDAP_SUCCESS
:
250 case NS_LDAP_SUCCESS_WITH_INFO
:
251 return (IDMAP_SUCCESS
);
252 case NS_LDAP_NOTFOUND
:
253 return (IDMAP_ERR_NOTFOUND
);
255 return (IDMAP_ERR_MEMORY
);
257 return (IDMAP_ERR_NS_LDAP_CFG
);
258 case NS_LDAP_OP_FAILED
:
259 return (IDMAP_ERR_NS_LDAP_OP_FAILED
);
260 case NS_LDAP_PARTIAL
:
261 return (IDMAP_ERR_NS_LDAP_PARTIAL
);
262 case NS_LDAP_INTERNAL
:
263 return (IDMAP_ERR_INTERNAL
);
264 case NS_LDAP_INVALID_PARAM
:
265 return (IDMAP_ERR_ARG
);
267 return (IDMAP_ERR_OTHER
);
273 * Create a batch for native LDAP lookup.
277 idmap_nldap_lookup_batch_start(int nqueries
, idmap_nldap_query_state_t
**qs
)
279 idmap_nldap_query_state_t
*s
;
281 s
= calloc(1, sizeof (*s
) +
282 (nqueries
- 1) * sizeof (idmap_nldap_q_t
));
284 return (IDMAP_ERR_MEMORY
);
285 if (__ns_ldap_list_batch_start(&s
->batch
) != NS_LDAP_SUCCESS
) {
287 return (IDMAP_ERR_MEMORY
);
289 s
->nqueries
= nqueries
;
290 s
->flag
= NS_LDAP_KEEP_CONN
;
292 return (IDMAP_SUCCESS
);
296 * Add a lookup by winname request to the batch.
300 idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t
*qs
,
301 const char *winname
, const char *windomain
, int is_user
,
302 char **dn
, char **attr
, char **value
,
303 char **unixname
, uid_t
*pid
, idmap_retcode
*rc
)
306 const char *db
, *filter
, *udata
;
307 int flen
, ulen
, wksid
= 0;
308 char *s_winname
, *s_windomain
;
310 const char *pwd_attrs
[] = {UID
, UIDNUMBER
, NULL
, NULL
};
311 const char *grp_attrs
[] = {CN
, GIDNUMBER
, NULL
, NULL
};
313 s_winname
= s_windomain
= NULL
;
314 q
= &(qs
->queries
[qs
->qid
++]);
315 q
->unixname
= unixname
;
318 q
->is_user
= is_user
;
325 if (lookup_wksids_name2sid(winname
, NULL
, NULL
, NULL
, NULL
,
326 NULL
, NULL
) == IDMAP_SUCCESS
) {
327 filter
= _F_GETPWWNAMWK
;
328 udata
= _F_GETPWWNAMWK_SSD
;
330 } else if (windomain
!= NULL
) {
331 filter
= _F_GETPWWNAMDOM
;
332 udata
= _F_GETPWWNAMDOM_SSD
;
334 *q
->rc
= IDMAP_ERR_DOMAIN_NOTFOUND
;
337 pwd_attrs
[2] = qs
->nldap_winname_attr
;
341 if (lookup_wksids_name2sid(winname
, NULL
, NULL
, NULL
, NULL
,
342 NULL
, NULL
) == IDMAP_SUCCESS
) {
343 filter
= _F_GETGRWNAMWK
;
344 udata
= _F_GETGRWNAMWK_SSD
;
346 } else if (windomain
!= NULL
) {
347 filter
= _F_GETGRWNAMDOM
;
348 udata
= _F_GETGRWNAMDOM_SSD
;
350 *q
->rc
= IDMAP_ERR_DOMAIN_NOTFOUND
;
353 grp_attrs
[2] = qs
->nldap_winname_attr
;
358 * Sanitize names. No need to sanitize qs->nldap_winname_attr
359 * because if it contained any of the special characters then
360 * it would have been rejected by the function that reads it
361 * from the SMF config. LDAP attribute names can only contain
362 * letters, digits or hyphens.
364 s_winname
= sanitize_for_ldap_filter(winname
);
365 if (s_winname
== NULL
) {
366 *q
->rc
= IDMAP_ERR_MEMORY
;
369 /* windomain could be NULL for names of well-known SIDs */
370 if (windomain
!= NULL
) {
371 s_windomain
= sanitize_for_ldap_filter(windomain
);
372 if (s_windomain
== NULL
) {
373 *q
->rc
= IDMAP_ERR_MEMORY
;
378 /* Construct the filter and udata using snprintf. */
380 flen
= snprintf(NULL
, 0, filter
, qs
->nldap_winname_attr
,
382 ulen
= snprintf(NULL
, 0, udata
, qs
->nldap_winname_attr
,
385 flen
= snprintf(NULL
, 0, filter
, qs
->nldap_winname_attr
,
386 s_winname
, s_windomain
) + 1;
387 ulen
= snprintf(NULL
, 0, udata
, qs
->nldap_winname_attr
,
388 s_winname
, s_windomain
) + 1;
391 q
->filter
= malloc(flen
);
392 if (q
->filter
== NULL
) {
393 *q
->rc
= IDMAP_ERR_MEMORY
;
396 q
->udata
= malloc(ulen
);
397 if (q
->udata
== NULL
) {
398 *q
->rc
= IDMAP_ERR_MEMORY
;
403 (void) snprintf(q
->filter
, flen
, filter
,
404 qs
->nldap_winname_attr
, s_winname
);
405 (void) snprintf(q
->udata
, ulen
, udata
,
406 qs
->nldap_winname_attr
, s_winname
);
408 (void) snprintf(q
->filter
, flen
, filter
,
409 qs
->nldap_winname_attr
, s_winname
, s_windomain
);
410 (void) snprintf(q
->udata
, ulen
, udata
,
411 qs
->nldap_winname_attr
, s_winname
, s_windomain
);
414 if (s_winname
!= winname
)
416 if (s_windomain
!= windomain
)
419 q
->lrc
= __ns_ldap_list_batch_add(qs
->batch
, db
, q
->filter
,
420 merge_SSD_filter
, attrs
, NULL
, qs
->flag
, &q
->result
,
421 &q
->errorp
, &q
->lrc
, NULL
, q
->udata
);
423 if (IS_NLDAP_RC_FATAL(q
->lrc
))
424 return (nldaprc2retcode(q
->lrc
));
425 return (IDMAP_SUCCESS
);
428 /* query q and its content will be freed by batch_release */
429 if (s_winname
!= winname
)
431 if (s_windomain
!= windomain
)
437 * Add a lookup by uid/gid request to the batch.
441 idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t
*qs
,
442 uid_t pid
, int is_user
, char **dn
, char **attr
, char **value
,
443 char **winname
, char **windomain
,
444 char **unixname
, idmap_retcode
*rc
)
447 const char *db
, *filter
, *udata
;
450 const char *pwd_attrs
[] = {UID
, NULL
, NULL
};
451 const char *grp_attrs
[] = {CN
, NULL
, NULL
};
453 q
= &(qs
->queries
[qs
->qid
++]);
454 q
->winname
= winname
;
455 q
->windomain
= windomain
;
456 q
->unixname
= unixname
;
458 q
->is_user
= is_user
;
465 filter
= _F_GETPWUID
;
466 udata
= _F_GETPWUID_SSD
;
467 pwd_attrs
[1] = qs
->nldap_winname_attr
;
471 filter
= _F_GETGRGID
;
472 udata
= _F_GETGRGID_SSD
;
473 grp_attrs
[1] = qs
->nldap_winname_attr
;
477 len
= snprintf(NULL
, 0, filter
, pid
) + 1;
478 q
->filter
= malloc(len
);
479 if (q
->filter
== NULL
) {
480 *q
->rc
= IDMAP_ERR_MEMORY
;
481 return (IDMAP_ERR_MEMORY
);
483 (void) snprintf(q
->filter
, len
, filter
, pid
);
485 len
= snprintf(NULL
, 0, udata
, pid
) + 1;
486 q
->udata
= malloc(len
);
487 if (q
->udata
== NULL
) {
488 *q
->rc
= IDMAP_ERR_MEMORY
;
489 return (IDMAP_ERR_MEMORY
);
491 (void) snprintf(q
->udata
, len
, udata
, pid
);
493 q
->lrc
= __ns_ldap_list_batch_add(qs
->batch
, db
, q
->filter
,
494 merge_SSD_filter
, attrs
, NULL
, qs
->flag
, &q
->result
,
495 &q
->errorp
, &q
->lrc
, NULL
, q
->udata
);
497 if (IS_NLDAP_RC_FATAL(q
->lrc
))
498 return (nldaprc2retcode(q
->lrc
));
499 return (IDMAP_SUCCESS
);
503 * Add a lookup by user/group name request to the batch.
507 idmap_nldap_byunixname_batch_add(idmap_nldap_query_state_t
*qs
,
508 const char *unixname
, int is_user
,
509 char **dn
, char **attr
, char **value
,
510 char **winname
, char **windomain
, uid_t
*pid
, idmap_retcode
*rc
)
513 const char *db
, *filter
, *udata
;
515 char *s_unixname
= NULL
;
517 const char *pwd_attrs
[] = {UIDNUMBER
, NULL
, NULL
};
518 const char *grp_attrs
[] = {GIDNUMBER
, NULL
, NULL
};
520 q
= &(qs
->queries
[qs
->qid
++]);
521 q
->winname
= winname
;
522 q
->windomain
= windomain
;
525 q
->is_user
= is_user
;
532 filter
= _F_GETPWNAM
;
533 udata
= _F_GETPWNAM_SSD
;
534 pwd_attrs
[1] = qs
->nldap_winname_attr
;
538 filter
= _F_GETGRNAM
;
539 udata
= _F_GETGRNAM_SSD
;
540 grp_attrs
[1] = qs
->nldap_winname_attr
;
544 s_unixname
= sanitize_for_ldap_filter(unixname
);
545 if (s_unixname
== NULL
) {
546 *q
->rc
= IDMAP_ERR_MEMORY
;
547 return (IDMAP_ERR_MEMORY
);
550 len
= snprintf(NULL
, 0, filter
, s_unixname
) + 1;
551 q
->filter
= malloc(len
);
552 if (q
->filter
== NULL
) {
553 if (s_unixname
!= unixname
)
555 *q
->rc
= IDMAP_ERR_MEMORY
;
556 return (IDMAP_ERR_MEMORY
);
558 (void) snprintf(q
->filter
, len
, filter
, s_unixname
);
560 len
= snprintf(NULL
, 0, udata
, s_unixname
) + 1;
561 q
->udata
= malloc(len
);
562 if (q
->udata
== NULL
) {
563 if (s_unixname
!= unixname
)
565 *q
->rc
= IDMAP_ERR_MEMORY
;
566 return (IDMAP_ERR_MEMORY
);
568 (void) snprintf(q
->udata
, len
, udata
, s_unixname
);
570 if (s_unixname
!= unixname
)
573 q
->lrc
= __ns_ldap_list_batch_add(qs
->batch
, db
, q
->filter
,
574 merge_SSD_filter
, attrs
, NULL
, qs
->flag
, &q
->result
,
575 &q
->errorp
, &q
->lrc
, NULL
, q
->udata
);
577 if (IS_NLDAP_RC_FATAL(q
->lrc
))
578 return (nldaprc2retcode(q
->lrc
));
579 return (IDMAP_SUCCESS
);
587 idmap_nldap_lookup_batch_release(idmap_nldap_query_state_t
*qs
)
592 if (qs
->batch
!= NULL
)
593 (void) __ns_ldap_list_batch_release(qs
->batch
);
594 for (i
= 0; i
< qs
->qid
; i
++) {
595 q
= &(qs
->queries
[i
]);
598 if (q
->errorp
!= NULL
)
599 (void) __ns_ldap_freeError(&q
->errorp
);
600 if (q
->result
!= NULL
)
601 (void) __ns_ldap_freeResult(&q
->result
);
607 * Process all requests added to the batch and then free the batch.
608 * The results for individual requests will be accessible using the
609 * pointers passed during idmap_nldap_lookup_batch_end.
613 idmap_nldap_lookup_batch_end(idmap_nldap_query_state_t
*qs
)
617 ns_ldap_entry_t
*entry
;
618 char **val
, *end
, *str
, *name
, *dom
;
619 idmap_retcode rc
= IDMAP_SUCCESS
;
621 (void) __ns_ldap_list_batch_end(qs
->batch
);
623 for (i
= 0; i
< qs
->qid
; i
++) {
624 q
= &(qs
->queries
[i
]);
625 *q
->rc
= nldaprc2retcode(q
->lrc
);
626 if (*q
->rc
!= IDMAP_SUCCESS
)
628 if (q
->result
== NULL
||
629 !q
->result
->entries_count
||
630 (entry
= q
->result
->entry
) == NULL
||
631 !entry
->attr_count
) {
632 *q
->rc
= IDMAP_ERR_NOTFOUND
;
636 if (q
->pid
!= NULL
) {
637 val
= __ns_ldap_getAttr(entry
,
638 (q
->is_user
) ? UIDNUMBER
: GIDNUMBER
);
639 if (val
!= NULL
&& *val
!= NULL
)
640 *q
->pid
= strtoul(*val
, &end
, 10);
643 if (q
->unixname
!= NULL
) {
644 val
= __ns_ldap_getAttr(entry
,
645 (q
->is_user
) ? UID
: CN
);
646 if (val
!= NULL
&& *val
!= NULL
) {
647 *q
->unixname
= strdup(*val
);
648 if (*q
->unixname
== NULL
) {
649 rc
= *q
->rc
= IDMAP_ERR_MEMORY
;
654 /* Get DN for how info */
656 val
= __ns_ldap_getAttr(entry
, DN
);
657 if (val
!= NULL
&& *val
!= NULL
) {
658 *q
->dn
= strdup(*val
);
659 if (*q
->dn
== NULL
) {
660 rc
= *q
->rc
= IDMAP_ERR_MEMORY
;
665 /* Get nldap name mapping attr name for how info */
666 if (q
->attr
!= NULL
) {
667 *q
->attr
= strdup(qs
->nldap_winname_attr
);
668 if (*q
->attr
== NULL
) {
669 rc
= *q
->rc
= IDMAP_ERR_MEMORY
;
673 /* Get nldap name mapping attr value for how info */
674 val
= __ns_ldap_getAttr(entry
, qs
->nldap_winname_attr
);
675 if (val
== NULL
|| *val
== NULL
)
677 if (q
->value
!= NULL
) {
678 *q
->value
= strdup(*val
);
679 if (*q
->value
== NULL
) {
680 rc
= *q
->rc
= IDMAP_ERR_MEMORY
;
685 /* Get winname and windomain */
686 if (q
->winname
== NULL
&& q
->windomain
== NULL
)
689 * We need to split the value into winname and
690 * windomain. The value could be either in NT4
691 * style (i.e. dom\name) or AD-style (i.e. name@dom).
692 * We choose the first '\\' if it's in NT4 style and
693 * the last '@' if it's in AD-style for the split.
696 if (lookup_wksids_name2sid(*val
, NULL
, NULL
, NULL
, NULL
, NULL
,
697 NULL
) == IDMAP_SUCCESS
) {
700 } else if ((str
= strchr(*val
, '\\')) != NULL
) {
704 } else if ((str
= strrchr(*val
, '@')) != NULL
) {
709 idmapdlog(LOG_INFO
, "Domain-less "
710 "winname (%s) found in Native LDAP", *val
);
711 *q
->rc
= IDMAP_ERR_NS_LDAP_BAD_WINNAME
;
714 if (q
->winname
!= NULL
) {
715 *q
->winname
= strdup(name
);
716 if (*q
->winname
== NULL
) {
717 rc
= *q
->rc
= IDMAP_ERR_MEMORY
;
721 if (q
->windomain
!= NULL
&& dom
!= NULL
) {
722 *q
->windomain
= strdup(dom
);
723 if (*q
->windomain
== NULL
) {
724 rc
= *q
->rc
= IDMAP_ERR_MEMORY
;
731 (void) idmap_nldap_lookup_batch_release(qs
);
737 nldap_lookup_batch(lookup_state_t
*state
, idmap_mapping_batch
*batch
,
738 idmap_ids_res
*result
)
740 idmap_retcode retcode
, rc1
;
744 idmap_nldap_query_state_t
*qs
= NULL
;
747 if (state
->nldap_nqueries
== 0)
748 return (IDMAP_SUCCESS
);
750 /* Create nldap lookup batch */
751 retcode
= idmap_nldap_lookup_batch_start(state
->nldap_nqueries
, &qs
);
752 if (retcode
!= IDMAP_SUCCESS
) {
754 "Failed to create batch for native LDAP lookup");
758 qs
->nldap_winname_attr
= state
->nldap_winname_attr
;
759 qs
->defdom
= state
->defdom
;
761 /* Add requests to the batch */
762 for (i
= 0, add
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
763 req
= &batch
->idmap_mapping_batch_val
[i
];
764 res
= &result
->ids
.ids_val
[i
];
765 retcode
= IDMAP_SUCCESS
;
767 /* Skip if not marked for nldap lookup */
768 if (!(req
->direction
& _IDMAP_F_LOOKUP_NLDAP
))
771 if (IS_ID_SID(req
->id1
)) {
773 /* win2unix request: */
776 * When processing a win2unix request, nldap lookup
777 * is performed after AD lookup or a successful
778 * name-cache lookup. Therefore we should already
779 * have sid, winname and sidtype. Note that
780 * windomain could be NULL e.g. well-known SIDs.
782 assert(req
->id1name
!= NULL
&&
783 (res
->id
.idtype
== IDMAP_UID
||
784 res
->id
.idtype
== IDMAP_GID
));
786 /* Skip if we already have pid and unixname */
787 if (req
->id2name
!= NULL
&&
788 res
->id
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
) {
789 res
->retcode
= IDMAP_SUCCESS
;
793 /* Clear leftover value */
797 /* Lookup nldap by winname to get pid and unixname */
799 idmap_how_clear(&res
->info
.how
);
800 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
801 how
= &res
->info
.how
;
802 how
->map_type
= IDMAP_MAP_TYPE_DS_NLDAP
;
803 retcode
= idmap_nldap_bywinname_batch_add(
804 qs
, req
->id1name
, req
->id1domain
,
805 (res
->id
.idtype
== IDMAP_UID
) ? 1 : 0,
806 &how
->idmap_how_u
.nldap
.dn
,
807 &how
->idmap_how_u
.nldap
.attr
,
808 &how
->idmap_how_u
.nldap
.value
,
809 &req
->id2name
, &res
->id
.idmap_id_u
.uid
,
812 } else if (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
)) {
814 /* unix2win request: */
816 /* Skip if we already have winname */
817 if (req
->id2name
!= NULL
) {
818 res
->retcode
= IDMAP_SUCCESS
;
822 /* Clear old value */
823 free(req
->id2domain
);
824 req
->id2domain
= NULL
;
827 idmap_how_clear(&res
->info
.how
);
828 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
829 how
= &res
->info
.how
;
830 how
->map_type
= IDMAP_MAP_TYPE_DS_NLDAP
;
832 /* Lookup nldap by pid or unixname to get winname */
833 if (req
->id1
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
) {
835 retcode
= idmap_nldap_bypid_batch_add(
836 qs
, req
->id1
.idmap_id_u
.uid
,
837 (req
->id1
.idtype
== IDMAP_UID
) ? 1 : 0,
838 &how
->idmap_how_u
.nldap
.dn
,
839 &how
->idmap_how_u
.nldap
.attr
,
840 &how
->idmap_how_u
.nldap
.value
,
841 &req
->id2name
, &req
->id2domain
,
842 (req
->id1name
== NULL
) ?
843 &req
->id1name
: NULL
,
845 } else if (req
->id1name
!= NULL
) {
847 retcode
= idmap_nldap_byunixname_batch_add(
849 (req
->id1
.idtype
== IDMAP_UID
) ? 1 : 0,
850 &how
->idmap_how_u
.nldap
.dn
,
851 &how
->idmap_how_u
.nldap
.attr
,
852 &how
->idmap_how_u
.nldap
.value
,
853 &req
->id2name
, &req
->id2domain
,
854 &req
->id1
.idmap_id_u
.uid
, &res
->retcode
);
860 * nldap_batch_add API returns error only on fatal failures
861 * otherwise it returns success and the actual status
862 * is stored in the individual request (res->retcode).
863 * Stop adding requests to this batch on fatal failures
864 * (i.e. if retcode != success)
866 if (retcode
!= IDMAP_SUCCESS
)
871 idmap_nldap_lookup_batch_release(qs
);
872 else if (retcode
!= IDMAP_SUCCESS
)
873 idmap_nldap_lookup_batch_release(qs
);
875 retcode
= idmap_nldap_lookup_batch_end(qs
);
878 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
879 req
= &batch
->idmap_mapping_batch_val
[i
];
880 res
= &result
->ids
.ids_val
[i
];
881 if (!(req
->direction
& _IDMAP_F_LOOKUP_NLDAP
))
884 /* Reset nldap flag */
885 req
->direction
&= ~(_IDMAP_F_LOOKUP_NLDAP
);
888 * As noted earlier retcode != success if there were fatal
889 * errors during batch_start and batch_adds. If so then set
890 * the status of each nldap request to that error.
892 if (retcode
!= IDMAP_SUCCESS
) {
893 res
->retcode
= retcode
;
900 * If we successfully retrieved winname from nldap entry
901 * then lookup winname2sid locally. If not found locally
902 * then mark this request for AD lookup.
904 if (res
->retcode
== IDMAP_SUCCESS
&&
905 req
->id2name
!= NULL
&&
906 res
->id
.idmap_id_u
.sid
.prefix
== NULL
&&
907 (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
))) {
909 rc1
= lookup_name2sid(state
->cache
,
910 req
->id2name
, req
->id2domain
, -1,
912 &res
->id
.idmap_id_u
.sid
.prefix
,
913 &res
->id
.idmap_id_u
.sid
.rid
,
916 if (rc1
== IDMAP_ERR_NOTFOUND
) {
917 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
918 state
->ad_nqueries
++;
924 * Unset non-fatal errors in individual request. This allows
925 * the next pass to process other mapping mechanisms for
928 if (res
->retcode
!= IDMAP_SUCCESS
&&
929 res
->retcode
!= IDMAP_ERR_NS_LDAP_BAD_WINNAME
&&
930 !(IDMAP_FATAL_ERROR(res
->retcode
))) {
931 idmap_how_clear(&res
->info
.how
);
932 res
->retcode
= IDMAP_SUCCESS
;
936 state
->nldap_nqueries
= 0;