/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * native LDAP related utility routines */ #include "idmapd.h" #include "idmap_priv.h" #include "ns_sldap.h" #include "nldaputils.h" #include /* * The following are format strings used to construct LDAP search filters * when looking up Native LDAP directory service. The _F_XXX_SSD format * is used by the libsldap API if a corresponding SSD is defined in * Native LDAP configuration. The SSD contains a string that replaces * the first %s in _F_XXX_SSD. If no SSD is defined then the regular * _F_XXX format is used. * * Note that '\\' needs to be represented as "\\5c" in LDAP filters. */ /* Native LDAP lookup using UNIX username */ #define _F_GETPWNAM "(&(objectClass=posixAccount)(uid=%s))" #define _F_GETPWNAM_SSD "(&(%%s)(uid=%s))" /* * Native LDAP user lookup using names of well-known SIDs * Note the use of 1$, 2$ in the format string which basically * allows snprintf to re-use its first two arguments. */ #define _F_GETPWWNAMWK \ "(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" #define _F_GETPWWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" /* Native LDAP user lookup using winname@windomain OR windomain\winname */ #define _F_GETPWWNAMDOM \ "(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" #define _F_GETPWWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" /* Native LDAP lookup using UID */ #define _F_GETPWUID "(&(objectClass=posixAccount)(uidNumber=%u))" #define _F_GETPWUID_SSD "(&(%%s)(uidNumber=%u))" /* Native LDAP lookup using UNIX groupname */ #define _F_GETGRNAM "(&(objectClass=posixGroup)(cn=%s))" #define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))" /* Native LDAP group lookup using names of well-known SIDs */ #define _F_GETGRWNAMWK \ "(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" #define _F_GETGRWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" /* Native LDAP group lookup using winname@windomain OR windomain\winname */ #define _F_GETGRWNAMDOM \ "(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" #define _F_GETGRWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" /* Native LDAP lookup using GID */ #define _F_GETGRGID "(&(objectClass=posixGroup)(gidNumber=%u))" #define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))" /* Native LDAP attribute names */ #define UID "uid" #define CN "cn" #define UIDNUMBER "uidnumber" #define GIDNUMBER "gidnumber" #define DN "dn" #define IS_NLDAP_RC_FATAL(x) ((x == NS_LDAP_MEMORY) ? 1 : 0) typedef struct idmap_nldap_q { char **winname; char **windomain; char **unixname; uid_t *pid; char **dn; char **attr; char **value; int is_user; idmap_retcode *rc; int lrc; ns_ldap_result_t *result; ns_ldap_error_t *errorp; char *filter; char *udata; } idmap_nldap_q_t; typedef struct idmap_nldap_query_state { const char *nldap_winname_attr; const char *defdom; int nqueries; int qid; int flag; ns_ldap_list_batch_t *batch; idmap_nldap_q_t queries[1]; } idmap_nldap_query_state_t; /* * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c * after removing the debug statements. * * This is a generic filter callback function for merging the filter * from service search descriptor with an existing search filter. This * routine expects userdata to contain a format string with a single %s * in it, and will use the format string with sprintf() to insert the * SSD filter. * * This routine and userdata are passed to the __ns_ldap_list_batch_add() * API. * * Consider an example that uses __ns_ldap_list_batch_add() to lookup * native LDAP directory using a given userid 'xy12345'. In this * example the userdata will contain the filter "(&(%s)(cn=xy1234))". * If a SSD is defined to replace the rfc2307bis specified filter * i.e. (objectClass=posixAccount) by a site-specific filter * say (department=sds) then this routine when called will produce * "(&(department=sds)(uid=xy1234))" as the real search filter. */ static int merge_SSD_filter(const ns_ldap_search_desc_t *desc, char **realfilter, const void *userdata) { int len; if (realfilter == NULL) return (NS_LDAP_INVALID_PARAM); *realfilter = NULL; if (desc == NULL || desc->filter == NULL || userdata == NULL) return (NS_LDAP_INVALID_PARAM); len = strlen(userdata) + strlen(desc->filter) + 1; *realfilter = (char *)malloc(len); if (*realfilter == NULL) return (NS_LDAP_MEMORY); (void) sprintf(*realfilter, (char *)userdata, desc->filter); return (NS_LDAP_SUCCESS); } static char hex_char(int n) { return ("0123456789abcdef"[n & 0xf]); } /* * If the input string contains special characters that needs to be * escaped before the string can be used in a LDAP filter then this * function will return a new sanitized string. Otherwise this function * returns the input string (This saves us un-necessary memory allocations * especially when processing a batch of requests). The caller must free * the returned string if it isn't the input string. * * The escape mechanism for LDAP filter is described in RFC2254 basically * it's \hh where hh are the two hexadecimal digits representing the ASCII * value of the encoded character (case of hh is not significant). * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c, * * outstring = sanitize_for_ldap_filter(instring); * if (outstring == NULL) * Out of memory * else * Use outstring * if (outstring != instring) * free(outstring); * done */ char * sanitize_for_ldap_filter(const char *str) { const char *p; char *q, *s_str = NULL; int n; /* Get a count of special characters */ for (p = str, n = 0; *p; p++) if (*p == '*' || *p == '(' || *p == ')' || *p == '\\' || *p == '%') n++; /* If count is zero then no need to sanitize */ if (n == 0) return ((char *)str); /* Create output buffer that will contain the sanitized value */ s_str = calloc(1, n * 2 + strlen(str) + 1); if (s_str == NULL) return (NULL); for (p = str, q = s_str; *p; p++) { if (*p == '*' || *p == '(' || *p == ')' || *p == '\\' || *p == '%') { *q++ = '\\'; *q++ = hex_char(*p >> 4); *q++ = hex_char(*p & 0xf); } else *q++ = *p; } return (s_str); } /* * Map libsldap status to idmap status */ static idmap_retcode nldaprc2retcode(int rc) { switch (rc) { case NS_LDAP_SUCCESS: case NS_LDAP_SUCCESS_WITH_INFO: return (IDMAP_SUCCESS); case NS_LDAP_NOTFOUND: return (IDMAP_ERR_NOTFOUND); case NS_LDAP_MEMORY: return (IDMAP_ERR_MEMORY); case NS_LDAP_CONFIG: return (IDMAP_ERR_NS_LDAP_CFG); case NS_LDAP_OP_FAILED: return (IDMAP_ERR_NS_LDAP_OP_FAILED); case NS_LDAP_PARTIAL: return (IDMAP_ERR_NS_LDAP_PARTIAL); case NS_LDAP_INTERNAL: return (IDMAP_ERR_INTERNAL); case NS_LDAP_INVALID_PARAM: return (IDMAP_ERR_ARG); default: return (IDMAP_ERR_OTHER); } /*NOTREACHED*/ } /* * Create a batch for native LDAP lookup. */ static idmap_retcode idmap_nldap_lookup_batch_start(int nqueries, idmap_nldap_query_state_t **qs) { idmap_nldap_query_state_t *s; s = calloc(1, sizeof (*s) + (nqueries - 1) * sizeof (idmap_nldap_q_t)); if (s == NULL) return (IDMAP_ERR_MEMORY); if (__ns_ldap_list_batch_start(&s->batch) != NS_LDAP_SUCCESS) { free(s); return (IDMAP_ERR_MEMORY); } s->nqueries = nqueries; s->flag = NS_LDAP_KEEP_CONN; *qs = s; return (IDMAP_SUCCESS); } /* * Add a lookup by winname request to the batch. */ static idmap_retcode idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t *qs, const char *winname, const char *windomain, int is_user, char **dn, char **attr, char **value, char **unixname, uid_t *pid, idmap_retcode *rc) { idmap_nldap_q_t *q; const char *db, *filter, *udata; int flen, ulen, wksid = 0; char *s_winname, *s_windomain; const char **attrs; const char *pwd_attrs[] = {UID, UIDNUMBER, NULL, NULL}; const char *grp_attrs[] = {CN, GIDNUMBER, NULL, NULL}; s_winname = s_windomain = NULL; q = &(qs->queries[qs->qid++]); q->unixname = unixname; q->pid = pid; q->rc = rc; q->is_user = is_user; q->dn = dn; q->attr = attr; q->value = value; if (is_user) { db = "passwd"; if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL, NULL, NULL) == IDMAP_SUCCESS) { filter = _F_GETPWWNAMWK; udata = _F_GETPWWNAMWK_SSD; wksid = 1; } else if (windomain != NULL) { filter = _F_GETPWWNAMDOM; udata = _F_GETPWWNAMDOM_SSD; } else { *q->rc = IDMAP_ERR_DOMAIN_NOTFOUND; goto errout; } pwd_attrs[2] = qs->nldap_winname_attr; attrs = pwd_attrs; } else { db = "group"; if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL, NULL, NULL) == IDMAP_SUCCESS) { filter = _F_GETGRWNAMWK; udata = _F_GETGRWNAMWK_SSD; wksid = 1; } else if (windomain != NULL) { filter = _F_GETGRWNAMDOM; udata = _F_GETGRWNAMDOM_SSD; } else { *q->rc = IDMAP_ERR_DOMAIN_NOTFOUND; goto errout; } grp_attrs[2] = qs->nldap_winname_attr; attrs = grp_attrs; } /* * Sanitize names. No need to sanitize qs->nldap_winname_attr * because if it contained any of the special characters then * it would have been rejected by the function that reads it * from the SMF config. LDAP attribute names can only contain * letters, digits or hyphens. */ s_winname = sanitize_for_ldap_filter(winname); if (s_winname == NULL) { *q->rc = IDMAP_ERR_MEMORY; goto errout; } /* windomain could be NULL for names of well-known SIDs */ if (windomain != NULL) { s_windomain = sanitize_for_ldap_filter(windomain); if (s_windomain == NULL) { *q->rc = IDMAP_ERR_MEMORY; goto errout; } } /* Construct the filter and udata using snprintf. */ if (wksid) { flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr, s_winname) + 1; ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr, s_winname) + 1; } else { flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr, s_winname, s_windomain) + 1; ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr, s_winname, s_windomain) + 1; } q->filter = malloc(flen); if (q->filter == NULL) { *q->rc = IDMAP_ERR_MEMORY; goto errout; } q->udata = malloc(ulen); if (q->udata == NULL) { *q->rc = IDMAP_ERR_MEMORY; goto errout; } if (wksid) { (void) snprintf(q->filter, flen, filter, qs->nldap_winname_attr, s_winname); (void) snprintf(q->udata, ulen, udata, qs->nldap_winname_attr, s_winname); } else { (void) snprintf(q->filter, flen, filter, qs->nldap_winname_attr, s_winname, s_windomain); (void) snprintf(q->udata, ulen, udata, qs->nldap_winname_attr, s_winname, s_windomain); } if (s_winname != winname) free(s_winname); if (s_windomain != windomain) free(s_windomain); q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter, merge_SSD_filter, attrs, NULL, qs->flag, &q->result, &q->errorp, &q->lrc, NULL, q->udata); if (IS_NLDAP_RC_FATAL(q->lrc)) return (nldaprc2retcode(q->lrc)); return (IDMAP_SUCCESS); errout: /* query q and its content will be freed by batch_release */ if (s_winname != winname) free(s_winname); if (s_windomain != windomain) free(s_windomain); return (*q->rc); } /* * Add a lookup by uid/gid request to the batch. */ static idmap_retcode idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t *qs, uid_t pid, int is_user, char **dn, char **attr, char **value, char **winname, char **windomain, char **unixname, idmap_retcode *rc) { idmap_nldap_q_t *q; const char *db, *filter, *udata; int len; const char **attrs; const char *pwd_attrs[] = {UID, NULL, NULL}; const char *grp_attrs[] = {CN, NULL, NULL}; q = &(qs->queries[qs->qid++]); q->winname = winname; q->windomain = windomain; q->unixname = unixname; q->rc = rc; q->is_user = is_user; q->dn = dn; q->attr = attr; q->value = value; if (is_user) { db = "passwd"; filter = _F_GETPWUID; udata = _F_GETPWUID_SSD; pwd_attrs[1] = qs->nldap_winname_attr; attrs = pwd_attrs; } else { db = "group"; filter = _F_GETGRGID; udata = _F_GETGRGID_SSD; grp_attrs[1] = qs->nldap_winname_attr; attrs = grp_attrs; } len = snprintf(NULL, 0, filter, pid) + 1; q->filter = malloc(len); if (q->filter == NULL) { *q->rc = IDMAP_ERR_MEMORY; return (IDMAP_ERR_MEMORY); } (void) snprintf(q->filter, len, filter, pid); len = snprintf(NULL, 0, udata, pid) + 1; q->udata = malloc(len); if (q->udata == NULL) { *q->rc = IDMAP_ERR_MEMORY; return (IDMAP_ERR_MEMORY); } (void) snprintf(q->udata, len, udata, pid); q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter, merge_SSD_filter, attrs, NULL, qs->flag, &q->result, &q->errorp, &q->lrc, NULL, q->udata); if (IS_NLDAP_RC_FATAL(q->lrc)) return (nldaprc2retcode(q->lrc)); return (IDMAP_SUCCESS); } /* * Add a lookup by user/group name request to the batch. */ static idmap_retcode idmap_nldap_byunixname_batch_add(idmap_nldap_query_state_t *qs, const char *unixname, int is_user, char **dn, char **attr, char **value, char **winname, char **windomain, uid_t *pid, idmap_retcode *rc) { idmap_nldap_q_t *q; const char *db, *filter, *udata; int len; char *s_unixname = NULL; const char **attrs; const char *pwd_attrs[] = {UIDNUMBER, NULL, NULL}; const char *grp_attrs[] = {GIDNUMBER, NULL, NULL}; q = &(qs->queries[qs->qid++]); q->winname = winname; q->windomain = windomain; q->pid = pid; q->rc = rc; q->is_user = is_user; q->dn = dn; q->attr = attr; q->value = value; if (is_user) { db = "passwd"; filter = _F_GETPWNAM; udata = _F_GETPWNAM_SSD; pwd_attrs[1] = qs->nldap_winname_attr; attrs = pwd_attrs; } else { db = "group"; filter = _F_GETGRNAM; udata = _F_GETGRNAM_SSD; grp_attrs[1] = qs->nldap_winname_attr; attrs = grp_attrs; } s_unixname = sanitize_for_ldap_filter(unixname); if (s_unixname == NULL) { *q->rc = IDMAP_ERR_MEMORY; return (IDMAP_ERR_MEMORY); } len = snprintf(NULL, 0, filter, s_unixname) + 1; q->filter = malloc(len); if (q->filter == NULL) { if (s_unixname != unixname) free(s_unixname); *q->rc = IDMAP_ERR_MEMORY; return (IDMAP_ERR_MEMORY); } (void) snprintf(q->filter, len, filter, s_unixname); len = snprintf(NULL, 0, udata, s_unixname) + 1; q->udata = malloc(len); if (q->udata == NULL) { if (s_unixname != unixname) free(s_unixname); *q->rc = IDMAP_ERR_MEMORY; return (IDMAP_ERR_MEMORY); } (void) snprintf(q->udata, len, udata, s_unixname); if (s_unixname != unixname) free(s_unixname); q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter, merge_SSD_filter, attrs, NULL, qs->flag, &q->result, &q->errorp, &q->lrc, NULL, q->udata); if (IS_NLDAP_RC_FATAL(q->lrc)) return (nldaprc2retcode(q->lrc)); return (IDMAP_SUCCESS); } /* * Free the batch */ static void idmap_nldap_lookup_batch_release(idmap_nldap_query_state_t *qs) { idmap_nldap_q_t *q; int i; if (qs->batch != NULL) (void) __ns_ldap_list_batch_release(qs->batch); for (i = 0; i < qs->qid; i++) { q = &(qs->queries[i]); free(q->filter); free(q->udata); if (q->errorp != NULL) (void) __ns_ldap_freeError(&q->errorp); if (q->result != NULL) (void) __ns_ldap_freeResult(&q->result); } free(qs); } /* * Process all requests added to the batch and then free the batch. * The results for individual requests will be accessible using the * pointers passed during idmap_nldap_lookup_batch_end. */ static idmap_retcode idmap_nldap_lookup_batch_end(idmap_nldap_query_state_t *qs) { idmap_nldap_q_t *q; int i; ns_ldap_entry_t *entry; char **val, *end, *str, *name, *dom; idmap_retcode rc = IDMAP_SUCCESS; (void) __ns_ldap_list_batch_end(qs->batch); qs->batch = NULL; for (i = 0; i < qs->qid; i++) { q = &(qs->queries[i]); *q->rc = nldaprc2retcode(q->lrc); if (*q->rc != IDMAP_SUCCESS) continue; if (q->result == NULL || !q->result->entries_count || (entry = q->result->entry) == NULL || !entry->attr_count) { *q->rc = IDMAP_ERR_NOTFOUND; continue; } /* Get uid/gid */ if (q->pid != NULL) { val = __ns_ldap_getAttr(entry, (q->is_user) ? UIDNUMBER : GIDNUMBER); if (val != NULL && *val != NULL) *q->pid = strtoul(*val, &end, 10); } /* Get unixname */ if (q->unixname != NULL) { val = __ns_ldap_getAttr(entry, (q->is_user) ? UID : CN); if (val != NULL && *val != NULL) { *q->unixname = strdup(*val); if (*q->unixname == NULL) { rc = *q->rc = IDMAP_ERR_MEMORY; goto out; } } } /* Get DN for how info */ if (q->dn != NULL) { val = __ns_ldap_getAttr(entry, DN); if (val != NULL && *val != NULL) { *q->dn = strdup(*val); if (*q->dn == NULL) { rc = *q->rc = IDMAP_ERR_MEMORY; goto out; } } } /* Get nldap name mapping attr name for how info */ if (q->attr != NULL) { *q->attr = strdup(qs->nldap_winname_attr); if (*q->attr == NULL) { rc = *q->rc = IDMAP_ERR_MEMORY; goto out; } } /* Get nldap name mapping attr value for how info */ val = __ns_ldap_getAttr(entry, qs->nldap_winname_attr); if (val == NULL || *val == NULL) continue; if (q->value != NULL) { *q->value = strdup(*val); if (*q->value == NULL) { rc = *q->rc = IDMAP_ERR_MEMORY; goto out; } } /* Get winname and windomain */ if (q->winname == NULL && q->windomain == NULL) continue; /* * We need to split the value into winname and * windomain. The value could be either in NT4 * style (i.e. dom\name) or AD-style (i.e. name@dom). * We choose the first '\\' if it's in NT4 style and * the last '@' if it's in AD-style for the split. */ name = dom = NULL; if (lookup_wksids_name2sid(*val, NULL, NULL, NULL, NULL, NULL, NULL) == IDMAP_SUCCESS) { name = *val; dom = NULL; } else if ((str = strchr(*val, '\\')) != NULL) { *str = '\0'; name = str + 1; dom = *val; } else if ((str = strrchr(*val, '@')) != NULL) { *str = '\0'; name = *val; dom = str + 1; } else { idmapdlog(LOG_INFO, "Domain-less " "winname (%s) found in Native LDAP", *val); *q->rc = IDMAP_ERR_NS_LDAP_BAD_WINNAME; continue; } if (q->winname != NULL) { *q->winname = strdup(name); if (*q->winname == NULL) { rc = *q->rc = IDMAP_ERR_MEMORY; goto out; } } if (q->windomain != NULL && dom != NULL) { *q->windomain = strdup(dom); if (*q->windomain == NULL) { rc = *q->rc = IDMAP_ERR_MEMORY; goto out; } } } out: (void) idmap_nldap_lookup_batch_release(qs); return (rc); } /* ARGSUSED */ idmap_retcode nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, idmap_ids_res *result) { idmap_retcode retcode, rc1; int i, add, is_wuser; idmap_mapping *req; idmap_id_res *res; idmap_nldap_query_state_t *qs = NULL; idmap_how *how; if (state->nldap_nqueries == 0) return (IDMAP_SUCCESS); /* Create nldap lookup batch */ retcode = idmap_nldap_lookup_batch_start(state->nldap_nqueries, &qs); if (retcode != IDMAP_SUCCESS) { idmapdlog(LOG_ERR, "Failed to create batch for native LDAP lookup"); goto out; } qs->nldap_winname_attr = state->nldap_winname_attr; qs->defdom = state->defdom; /* Add requests to the batch */ for (i = 0, add = 0; i < batch->idmap_mapping_batch_len; i++) { req = &batch->idmap_mapping_batch_val[i]; res = &result->ids.ids_val[i]; retcode = IDMAP_SUCCESS; /* Skip if not marked for nldap lookup */ if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP)) continue; if (IS_REQUEST_SID(*req, 1)) { /* win2unix request: */ /* * When processing a win2unix request, nldap lookup * is performed after AD lookup or a successful * name-cache lookup. Therefore we should already * have sid, winname and sidtype. Note that * windomain could be NULL e.g. well-known SIDs. */ assert(req->id1name != NULL && (res->id.idtype == IDMAP_UID || res->id.idtype == IDMAP_GID)); /* Skip if we already have pid and unixname */ if (req->id2name != NULL && res->id.idmap_id_u.uid != SENTINEL_PID) { res->retcode = IDMAP_SUCCESS; continue; } /* Clear leftover value */ free(req->id2name); req->id2name = NULL; /* Lookup nldap by winname to get pid and unixname */ add = 1; idmap_info_free(&res->info); res->info.src = IDMAP_MAP_SRC_NEW; how = &res->info.how; how->map_type = IDMAP_MAP_TYPE_DS_NLDAP; retcode = idmap_nldap_bywinname_batch_add( qs, req->id1name, req->id1domain, (res->id.idtype == IDMAP_UID) ? 1 : 0, &how->idmap_how_u.nldap.dn, &how->idmap_how_u.nldap.attr, &how->idmap_how_u.nldap.value, &req->id2name, &res->id.idmap_id_u.uid, &res->retcode); } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { /* unix2win request: */ /* Skip if we already have winname */ if (req->id2name != NULL) { res->retcode = IDMAP_SUCCESS; continue; } /* Clear old value */ free(req->id2domain); req->id2domain = NULL; /* Set how info */ idmap_info_free(&res->info); res->info.src = IDMAP_MAP_SRC_NEW; how = &res->info.how; how->map_type = IDMAP_MAP_TYPE_DS_NLDAP; /* Lookup nldap by pid or unixname to get winname */ if (req->id1.idmap_id_u.uid != SENTINEL_PID) { add = 1; retcode = idmap_nldap_bypid_batch_add( qs, req->id1.idmap_id_u.uid, (req->id1.idtype == IDMAP_UID) ? 1 : 0, &how->idmap_how_u.nldap.dn, &how->idmap_how_u.nldap.attr, &how->idmap_how_u.nldap.value, &req->id2name, &req->id2domain, (req->id1name == NULL) ? &req->id1name : NULL, &res->retcode); } else if (req->id1name != NULL) { add = 1; retcode = idmap_nldap_byunixname_batch_add( qs, req->id1name, (req->id1.idtype == IDMAP_UID) ? 1 : 0, &how->idmap_how_u.nldap.dn, &how->idmap_how_u.nldap.attr, &how->idmap_how_u.nldap.value, &req->id2name, &req->id2domain, &req->id1.idmap_id_u.uid, &res->retcode); } } /* * nldap_batch_add API returns error only on fatal failures * otherwise it returns success and the actual status * is stored in the individual request (res->retcode). * Stop adding requests to this batch on fatal failures * (i.e. if retcode != success) */ if (retcode != IDMAP_SUCCESS) break; } if (!add) idmap_nldap_lookup_batch_release(qs); else if (retcode != IDMAP_SUCCESS) idmap_nldap_lookup_batch_release(qs); else retcode = idmap_nldap_lookup_batch_end(qs); out: for (i = 0; i < batch->idmap_mapping_batch_len; i++) { req = &batch->idmap_mapping_batch_val[i]; res = &result->ids.ids_val[i]; if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP)) continue; /* Reset nldap flag */ req->direction &= ~(_IDMAP_F_LOOKUP_NLDAP); /* * As noted earlier retcode != success if there were fatal * errors during batch_start and batch_adds. If so then set * the status of each nldap request to that error. */ if (retcode != IDMAP_SUCCESS) { res->retcode = retcode; continue; } if (!add) continue; /* * If we successfully retrieved winname from nldap entry * then lookup winname2sid locally. If not found locally * then mark this request for AD lookup. */ if (res->retcode == IDMAP_SUCCESS && req->id2name != NULL && res->id.idmap_id_u.sid.prefix == NULL && (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req))) { is_wuser = -1; rc1 = lookup_name2sid(state->cache, req->id2name, req->id2domain, &is_wuser, NULL, NULL, &res->id.idmap_id_u.sid.prefix, &res->id.idmap_id_u.sid.rid, req, 1); if (rc1 == IDMAP_SUCCESS) res->id.idtype = is_wuser ? IDMAP_USID : IDMAP_GSID; else if (rc1 == IDMAP_ERR_NOTFOUND) { req->direction |= _IDMAP_F_LOOKUP_AD; state->ad_nqueries++; } else res->retcode = rc1; } /* * Unset non-fatal errors in individual request. This allows * the next pass to process other mapping mechanisms for * this request. */ if (res->retcode != IDMAP_SUCCESS && res->retcode != IDMAP_ERR_NS_LDAP_BAD_WINNAME && !(IDMAP_FATAL_ERROR(res->retcode))) { idmap_info_free(&res->info); res->retcode = IDMAP_SUCCESS; } } state->nldap_nqueries = 0; return (retcode); }