summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorBaban Kenkre <Baban.Kenkre@Sun.COM>2008-11-07 12:09:53 -0800
committerBaban Kenkre <Baban.Kenkre@Sun.COM>2008-11-07 12:09:53 -0800
commit2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f (patch)
treeb9f0bc817d950cefb1af4653dad8de547a17e061 /usr/src
parent0a2b1d27cac02f57e17b310f8baeb1dda082c83a (diff)
downloadillumos-joyent-2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f.tar.gz
PSARC/2008/441 Active Directory name service module (nss_ad)
6722476 name service switch module for AD (nss_ad) needed
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/cmd/getent/dogetgr.c14
-rw-r--r--usr/src/cmd/getent/dogetpw.c6
-rw-r--r--usr/src/cmd/idmap/idmapd/Makefile7
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.c1422
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.h44
-rw-r--r--usr/src/cmd/idmap/idmapd/dbutils.c26
-rw-r--r--usr/src/cmd/idmap/idmapd/idmapd.h5
-rw-r--r--usr/src/cmd/idmap/idmapd/init.c16
-rw-r--r--usr/src/cmd/netfiles/Makefile12
-rw-r--r--usr/src/cmd/netfiles/nsswitch.ad77
-rw-r--r--usr/src/cmd/nscd/nscd_cfgdef.h3
-rw-r--r--usr/src/cmd/nscd/nscd_smfmonitor.c5
-rw-r--r--usr/src/head/rpcsvc/idmap_prot.x4
-rw-r--r--usr/src/lib/Makefile3
-rw-r--r--usr/src/lib/libadutils/Makefile49
-rw-r--r--usr/src/lib/libadutils/Makefile.com50
-rw-r--r--usr/src/lib/libadutils/amd64/Makefile29
-rw-r--r--usr/src/lib/libadutils/common/adutils.c1693
-rw-r--r--usr/src/lib/libadutils/common/adutils_impl.h146
-rw-r--r--usr/src/lib/libadutils/common/libadutils.h177
-rw-r--r--usr/src/lib/libadutils/common/llib-ladutils29
-rw-r--r--usr/src/lib/libadutils/common/mapfile-vers48
-rw-r--r--usr/src/lib/libadutils/i386/Makefile28
-rw-r--r--usr/src/lib/libadutils/sparc/Makefile28
-rw-r--r--usr/src/lib/libadutils/sparcv9/Makefile29
-rw-r--r--usr/src/lib/libc/port/gen/getgrnam_r.c12
-rw-r--r--usr/src/lib/libc/port/gen/getpwnam_r.c26
-rw-r--r--usr/src/lib/libc/port/gen/putpwent.c4
-rw-r--r--usr/src/lib/libidmap/common/idmap_api.c23
-rw-r--r--usr/src/lib/nsswitch/Makefile6
-rw-r--r--usr/src/lib/nsswitch/ad/Makefile46
-rw-r--r--usr/src/lib/nsswitch/ad/Makefile.com39
-rw-r--r--usr/src/lib/nsswitch/ad/amd64/Makefile32
-rw-r--r--usr/src/lib/nsswitch/ad/common/ad_common.c534
-rw-r--r--usr/src/lib/nsswitch/ad/common/ad_common.h132
-rw-r--r--usr/src/lib/nsswitch/ad/common/getgrent.c186
-rw-r--r--usr/src/lib/nsswitch/ad/common/getpwnam.c518
-rw-r--r--usr/src/lib/nsswitch/ad/common/getspent.c146
-rw-r--r--usr/src/lib/nsswitch/ad/common/mapfile-vers33
-rw-r--r--usr/src/lib/nsswitch/ad/i386/Makefile31
-rw-r--r--usr/src/lib/nsswitch/ad/sparc/Makefile31
-rw-r--r--usr/src/lib/nsswitch/ad/sparcv9/Makefile32
-rw-r--r--usr/src/lib/nsswitch/compat/common/compat_common.c55
-rw-r--r--usr/src/lib/nsswitch/compat/common/compat_common.h10
-rw-r--r--usr/src/lib/nsswitch/compat/common/getgrent.c53
-rw-r--r--usr/src/lib/nsswitch/compat/common/getpwent.c65
-rw-r--r--usr/src/lib/nsswitch/files/common/files_common.c50
-rw-r--r--usr/src/lib/nsswitch/files/common/files_common.h8
-rw-r--r--usr/src/lib/nsswitch/files/common/getgrent.c95
-rw-r--r--usr/src/lib/nsswitch/files/common/getpwnam.c100
-rw-r--r--usr/src/lib/nsswitch/ldap/common/getgrent.c14
-rw-r--r--usr/src/lib/nsswitch/ldap/common/getpwnam.c45
-rw-r--r--usr/src/lib/nsswitch/ldap/common/ldap_common.h14
-rw-r--r--usr/src/lib/nsswitch/nis/common/getgrent.c71
-rw-r--r--usr/src/lib/nsswitch/nis/common/getpwnam.c77
-rw-r--r--usr/src/lib/nsswitch/nis/common/nis_common.c13
-rw-r--r--usr/src/lib/nsswitch/nis/common/nis_common.h8
-rw-r--r--usr/src/lib/nsswitch/nisplus/common/getgrent.c17
-rw-r--r--usr/src/lib/nsswitch/nisplus/common/getpwnam.c26
-rw-r--r--usr/src/lib/nsswitch/nisplus/common/nisplus_common.h5
-rw-r--r--usr/src/lib/passwdutil/switch_utils.c40
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_i3863
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_sparc3
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_com3
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_i3863
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_sparc3
-rw-r--r--usr/src/pkgdefs/SUNWcsr/prototype_com1
69 files changed, 5028 insertions, 1540 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 6cffcc986f..0b6a7705aa 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -325,6 +325,7 @@ COMMON_SUBDIRS = \
lib/cfgadm_plugins/sdcard \
lib/crypt_modules \
lib/extendedFILE \
+ lib/libadutils \
lib/libadt_jni \
lib/libaio \
lib/libavl \
diff --git a/usr/src/cmd/getent/dogetgr.c b/usr/src/cmd/getent/dogetgr.c
index fcd7b64f43..740a46846e 100644
--- a/usr/src/cmd/getent/dogetgr.c
+++ b/usr/src/cmd/getent/dogetgr.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <grp.h>
#include <stdlib.h>
@@ -43,10 +41,10 @@ putgrent(const struct group *grp, FILE *fp)
return (1);
}
- if (fprintf(fp, "%s:%s:%d:",
- grp->gr_name != NULL ? grp->gr_name : "",
- grp->gr_passwd != NULL ? grp->gr_passwd : "",
- grp->gr_gid) == EOF)
+ if (fprintf(fp, "%s:%s:%u:",
+ grp->gr_name != NULL ? grp->gr_name : "",
+ grp->gr_passwd != NULL ? grp->gr_passwd : "",
+ grp->gr_gid) == EOF)
rc = 1;
mem = grp ->gr_mem;
@@ -89,7 +87,7 @@ dogetgr(const char **list)
* If the argument passed is not numeric, then
* we take it as the group name and proceed.
*/
- gid = strtol(*list, &ptr, 10);
+ gid = strtoul(*list, &ptr, 10);
if (!(*ptr == '\0' && errno == 0) ||
((grp = getgrgid(gid)) == NULL)) {
grp = getgrnam(*list);
diff --git a/usr/src/cmd/getent/dogetpw.c b/usr/src/cmd/getent/dogetpw.c
index 19257ad210..03a37bf134 100644
--- a/usr/src/cmd/getent/dogetpw.c
+++ b/usr/src/cmd/getent/dogetpw.c
@@ -19,10 +19,8 @@
* CDDL HEADER END
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,7 +58,7 @@ dogetpw(const char **list)
* If the argument passed is not numeric, then
* we take it as the user name and proceed.
*/
- uid = strtol(*list, &ptr, 10);
+ uid = strtoul(*list, &ptr, 10);
if (!(*ptr == '\0' && errno == 0) ||
((pwp = getpwuid(uid)) == NULL)) {
pwp = getpwnam(*list);
diff --git a/usr/src/cmd/idmap/idmapd/Makefile b/usr/src/cmd/idmap/idmapd/Makefile
index a1af3b3852..bb724b95db 100644
--- a/usr/src/cmd/idmap/idmapd/Makefile
+++ b/usr/src/cmd/idmap/idmapd/Makefile
@@ -22,8 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
PROG = idmapd
MANIFEST = idmap.xml
@@ -54,14 +52,15 @@ ROOTMANIFESTDIR = $(ROOTSVCSYSTEM)
$(ROOTMANIFEST) := FILEMODE= 444
INCS += -I. -I../../../lib/libidmap/common -I$(IDMAP_PROT_DIR)\
- -I../../../lib/libsldap/common
+ -I../../../lib/libsldap/common\
+ -I../../../lib/libadutils/common
$(OBJS) := CPPFLAGS += $(INCS) -D_REENTRANT
$(POFILE) := CPPFLAGS += $(INCS)
CLOBBERFILES += $(IDMAP_PROT_H)
CFLAGS += -v
-LDLIBS += -lsecdb -lsocket -lnsl -lidmap -lscf -lsldap -lldap -luuid
+LDLIBS += -lsecdb -lsocket -lnsl -lidmap -lscf -lsldap -lldap -luuid -ladutils
$(PROG) := MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB)
$(PROG) := LDFLAGS += $(MAPFILES:%=-M%)
diff --git a/usr/src/cmd/idmap/idmapd/adutils.c b/usr/src/cmd/idmap/idmapd/adutils.c
index d22ce169c9..f19706822e 100644
--- a/usr/src/cmd/idmap/idmapd/adutils.c
+++ b/usr/src/cmd/idmap/idmapd/adutils.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Processes name2sid & sid2name batched lookups for a given user or
* computer from an AD Directory server using GSSAPI authentication
@@ -47,14 +45,12 @@
#include <errno.h>
#include <assert.h>
#include <limits.h>
+#include <time.h>
#include <sys/u8_textprep.h>
+#include "libadutils.h"
#include "nldaputils.h"
#include "idmapd.h"
-/*
- * Internal data structures for this code
- */
-
/* Attribute names and filter format strings */
#define SAN "sAMAccountName"
#define OBJSID "objectSid"
@@ -62,58 +58,8 @@
#define SANFILTER "(sAMAccountName=%.*s)"
#define OBJSIDFILTER "(objectSid=%s)"
-/*
- * This should really be in some <sys/sid.h> file or so; we have a
- * private version of sid_t, and so must other components of ON until we
- * rationalize this.
- */
-typedef struct sid {
- uchar_t version;
- uchar_t sub_authority_count;
- uint64_t authority; /* really, 48-bits */
- rid_t sub_authorities[SID_MAX_SUB_AUTHORITIES];
-} sid_t;
-
-/* A single DS */
-typedef struct ad_host {
- struct ad_host *next;
- ad_t *owner; /* ad_t to which this belongs */
- pthread_mutex_t lock;
- LDAP *ld; /* LDAP connection */
- uint32_t ref; /* ref count */
- time_t idletime; /* time since last activity */
- int dead; /* error on LDAP connection */
- /*
- * Used to distinguish between different instances of LDAP
- * connections to this same DS. We need this so we never mix up
- * results for a given msgID from one connection with those of
- * another earlier connection where two batch state structures
- * share this ad_host object but used different LDAP connections
- * to send their LDAP searches.
- */
- uint64_t generation;
-
- /* LDAP DS info */
- char *host;
- int port;
-
- /* hardwired to SASL GSSAPI only for now */
- char *saslmech;
- unsigned saslflags;
-
- /* Number of outstanding search requests */
- uint32_t max_requests;
- uint32_t num_requests;
-} ad_host_t;
-
-/* A set of DSs for a given AD partition; ad_t typedef comes from adutil.h */
-struct ad {
- char *dflt_w2k_dom; /* used to qualify bare names */
- pthread_mutex_t lock;
- uint32_t ref;
- ad_host_t *last_adh;
- idmap_ad_partition_t partition; /* Data or global catalog? */
-};
+void idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
+ int qid, void *argp);
/*
* A place to put the results of a batched (async) query
@@ -140,9 +86,9 @@ typedef struct idmap_q {
char **attr; /* Attr for name mapping */
char **value; /* value for name mapping */
idmap_retcode *rc;
+ adutils_rc ad_rc;
+ adutils_result_t *result;
- /* lookup state */
- int msgid; /* LDAP message ID */
/*
* The LDAP search entry result is placed here to be processed
* when the search done result is received.
@@ -152,185 +98,21 @@ typedef struct idmap_q {
/* Batch context structure; typedef is in header file */
struct idmap_query_state {
- idmap_query_state_t *next;
+ adutils_query_state_t *qs;
int qcount; /* how many queries */
- int ref_cnt; /* reference count */
- pthread_cond_t cv; /* Condition wait variable */
uint32_t qlastsent;
- uint32_t qinflight; /* how many queries in flight */
- uint16_t qdead; /* oops, lost LDAP connection */
- ad_host_t *qadh; /* LDAP connection */
- uint64_t qadh_gen; /* same as qadh->generation */
const char *ad_unixuser_attr;
const char *ad_unixgroup_attr;
idmap_q_t queries[1]; /* array of query results */
};
-/*
- * List of query state structs -- needed so we can "route" LDAP results
- * to the right context if multiple threads should be using the same
- * connection concurrently
- */
-static idmap_query_state_t *qstatehead = NULL;
-static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER;
-
-/*
- * List of DSs, needed by the idle connection reaper thread
- */
-static ad_host_t *host_head = NULL;
static pthread_t reaperid = 0;
-static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER;
-
-
-static void
-idmap_lookup_unlock_batch(idmap_query_state_t **state);
-
-static void
-delete_ds(ad_t *ad, const char *host, int port);
-
-/*ARGSUSED*/
-static int
-idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
-{
- sasl_interact_t *interact;
-
- if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
- return (LDAP_PARAM_ERROR);
-
- /* There should be no extra arguemnts for SASL/GSSAPI authentication */
- for (interact = prompts; interact->id != SASL_CB_LIST_END;
- interact++) {
- interact->result = NULL;
- interact->len = 0;
- }
- return (LDAP_SUCCESS);
-}
-
-
-/*
- * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
- * attributes (CN, etc...). We don't need the reverse, for now.
- */
-static
-char *
-dn2dns(const char *dn)
-{
- char **rdns = NULL;
- char **attrs = NULL;
- char **labels = NULL;
- char *dns = NULL;
- char **rdn, **attr, **label;
- int maxlabels = 5;
- int nlabels = 0;
- int dnslen;
-
- /*
- * There is no reverse of ldap_dns_to_dn() in our libldap, so we
- * have to do the hard work here for now.
- */
-
- /*
- * This code is much too liberal: it looks for "dc" attributes
- * in all RDNs of the DN. In theory this could cause problems
- * if people were to use "dc" in nodes other than the root of
- * the tree, but in practice noone, least of all Active
- * Directory, does that.
- *
- * On the other hand, this code is much too conservative: it
- * does not make assumptions about ldap_explode_dn(), and _that_
- * is the true for looking at every attr of every RDN.
- *
- * Since we only ever look at dc and those must be DNS labels,
- * at least until we get around to supporting IDN here we
- * shouldn't see escaped labels from AD nor from libldap, though
- * the spec (RFC2253) does allow libldap to escape things that
- * don't need escaping -- if that should ever happen then
- * libldap will need a spanking, and we can take care of that.
- */
-
- /* Explode a DN into RDNs */
- if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
- return (NULL);
-
- labels = calloc(maxlabels + 1, sizeof (char *));
- label = labels;
-
- for (rdn = rdns; *rdn != NULL; rdn++) {
- if (attrs != NULL)
- ldap_value_free(attrs);
-
- /* Explode each RDN, look for DC attr, save val as DNS label */
- if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL)
- goto done;
-
- for (attr = attrs; *attr != NULL; attr++) {
- if (strncasecmp(*attr, "dc=", 3) != 0)
- continue;
-
- /* Found a DNS label */
- labels[nlabels++] = strdup((*attr) + 3);
-
- if (nlabels == maxlabels) {
- char **tmp;
- tmp = realloc(labels,
- sizeof (char *) * (maxlabels + 1));
-
- if (tmp == NULL)
- goto done;
-
- labels = tmp;
- labels[nlabels] = NULL;
- }
-
- /* There should be just one DC= attr per-RDN */
- break;
- }
- }
-
- /*
- * Got all the labels, now join with '.'
- *
- * We need room for nlabels - 1 periods ('.'), one nul
- * terminator, and the strlen() of each label.
- */
- dnslen = nlabels;
- for (label = labels; *label != NULL; label++)
- dnslen += strlen(*label);
-
- if ((dns = malloc(dnslen)) == NULL)
- goto done;
-
- *dns = '\0';
-
- for (label = labels; *label != NULL; label++) {
- (void) strlcat(dns, *label, dnslen);
- /*
- * NOTE: the last '.' won't be appended -- there's no room
- * for it!
- */
- (void) strlcat(dns, ".", dnslen);
- }
-
-done:
- if (labels != NULL) {
- for (label = labels; *label != NULL; label++)
- free(*label);
- free(labels);
- }
- if (attrs != NULL)
- ldap_value_free(attrs);
- if (rdns != NULL)
- ldap_value_free(rdns);
-
- return (dns);
-}
/*
* Keep connection management simple for now, extend or replace later
* with updated libsldap code.
*/
#define ADREAPERSLEEP 60
-#define ADCONN_TIME 300
/*
* Idle connection reaping side of connection management
@@ -343,8 +125,6 @@ static
void
adreaper(void *arg)
{
- ad_host_t *adh;
- time_t now;
timespec_t ts;
ts.tv_sec = ADREAPERSLEEP;
@@ -356,270 +136,8 @@ adreaper(void *arg)
* portable than usleep(3C)
*/
(void) nanosleep(&ts, NULL);
- (void) pthread_mutex_lock(&adhostlock);
- now = time(NULL);
- for (adh = host_head; adh != NULL; adh = adh->next) {
- (void) pthread_mutex_lock(&adh->lock);
- if (adh->ref == 0 && adh->idletime != 0 &&
- adh->idletime + ADCONN_TIME < now) {
- if (adh->ld) {
- (void) ldap_unbind(adh->ld);
- adh->ld = NULL;
- adh->idletime = 0;
- adh->ref = 0;
- }
- }
- (void) pthread_mutex_unlock(&adh->lock);
- }
- (void) pthread_mutex_unlock(&adhostlock);
- }
-}
-
-int
-idmap_ad_alloc(ad_t **new_ad, const char *default_domain,
- idmap_ad_partition_t part)
-{
- ad_t *ad;
-
- *new_ad = NULL;
-
- if ((default_domain == NULL || *default_domain == '\0') &&
- part != IDMAP_AD_GLOBAL_CATALOG)
- return (-1);
-
- if ((ad = calloc(1, sizeof (ad_t))) == NULL)
- return (-1);
-
- ad->ref = 1;
- ad->partition = part;
-
- if (default_domain == NULL)
- default_domain = "";
-
- if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL)
- goto err;
-
- if (pthread_mutex_init(&ad->lock, NULL) != 0)
- goto err;
-
- *new_ad = ad;
-
- return (0);
-err:
- if (ad->dflt_w2k_dom != NULL)
- free(ad->dflt_w2k_dom);
- free(ad);
- return (-1);
-}
-
-
-void
-idmap_ad_free(ad_t **ad)
-{
- ad_host_t *p;
- ad_host_t *prev;
-
- if (ad == NULL || *ad == NULL)
- return;
-
- (void) pthread_mutex_lock(&(*ad)->lock);
-
- if (atomic_dec_32_nv(&(*ad)->ref) > 0) {
- (void) pthread_mutex_unlock(&(*ad)->lock);
- *ad = NULL;
- return;
- }
-
- (void) pthread_mutex_lock(&adhostlock);
- prev = NULL;
- p = host_head;
- while (p != NULL) {
- if (p->owner != (*ad)) {
- prev = p;
- p = p->next;
- continue;
- } else {
- delete_ds((*ad), p->host, p->port);
- if (prev == NULL)
- p = host_head;
- else
- p = prev->next;
- }
- }
- (void) pthread_mutex_unlock(&adhostlock);
-
- (void) pthread_mutex_unlock(&(*ad)->lock);
- (void) pthread_mutex_destroy(&(*ad)->lock);
-
- free((*ad)->dflt_w2k_dom);
- free(*ad);
-
- *ad = NULL;
-}
-
-
-static
-int
-idmap_open_conn(ad_host_t *adh, int timeoutsecs)
-{
- int zero = 0;
- int ldversion, rc;
- int timeoutms = timeoutsecs * 1000;
-
- if (adh == NULL)
- return (0);
-
- (void) pthread_mutex_lock(&adh->lock);
-
- if (!adh->dead && adh->ld != NULL)
- /* done! */
- goto out;
-
- if (adh->ld != NULL) {
- (void) ldap_unbind(adh->ld);
- adh->ld = NULL;
- }
- adh->num_requests = 0;
-
- atomic_inc_64(&adh->generation);
-
- /* Open and bind an LDAP connection */
- adh->ld = ldap_init(adh->host, adh->port);
- if (adh->ld == NULL) {
- idmapdlog(LOG_INFO, "ldap_init() to server "
- "%s port %d failed. (%s)", adh->host,
- adh->port, strerror(errno));
- goto out;
- }
- ldversion = LDAP_VERSION3;
- (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
- (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
- (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
- (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
- (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
- (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
- rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */,
- adh->saslmech, NULL, NULL, adh->saslflags, &idmap_saslcallback,
- NULL);
-
- if (rc != LDAP_SUCCESS) {
- (void) ldap_unbind(adh->ld);
- adh->ld = NULL;
- idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
- "%s port %d failed. (%s)", adh->host, adh->port,
- ldap_err2string(rc));
+ adutils_reap_idle_connections();
}
-
- idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d",
- adh->host, adh->port);
-
-out:
- if (adh->ld != NULL) {
- atomic_inc_32(&adh->ref);
- adh->idletime = time(NULL);
- adh->dead = 0;
- (void) pthread_mutex_unlock(&adh->lock);
- return (1);
- }
-
- (void) pthread_mutex_unlock(&adh->lock);
- return (0);
-}
-
-
-/*
- * Connection management: find an open connection or open one
- */
-static
-ad_host_t *
-idmap_get_conn(ad_t *ad)
-{
- ad_host_t *adh = NULL;
- int tries;
- int dscount = 0;
- int timeoutsecs = IDMAPD_LDAP_OPEN_TIMEOUT;
-
-retry:
- (void) pthread_mutex_lock(&adhostlock);
-
- if (host_head == NULL) {
- (void) pthread_mutex_unlock(&adhostlock);
- goto out;
- }
-
- if (dscount == 0) {
- /*
- * First try: count the number of DSes.
- *
- * Integer overflow is not an issue -- we can't have so many
- * DSes because they won't fit even DNS over TCP, and SMF
- * shouldn't let you set so many.
- */
- for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) {
- if (adh->owner == ad)
- dscount++;
- }
-
- if (dscount == 0) {
- (void) pthread_mutex_unlock(&adhostlock);
- goto out;
- }
-
- tries = dscount * 3; /* three tries per-ds */
-
- /*
- * Begin round-robin at the next DS in the list after the last
- * one that we had a connection to, else start with the first
- * DS in the list.
- */
- adh = ad->last_adh;
- }
-
- /*
- * Round-robin -- pick the next one on the list; if the list
- * changes on us, no big deal, we'll just potentially go
- * around the wrong number of times.
- */
- for (;;) {
- if (adh != NULL && adh->ld != NULL && !adh->dead)
- break;
- if (adh == NULL || (adh = adh->next) == NULL)
- adh = host_head;
- if (adh->owner == ad)
- break;
- }
-
- ad->last_adh = adh;
- (void) pthread_mutex_unlock(&adhostlock);
-
-
- /* Found suitable DS, open it if not already opened */
- if (idmap_open_conn(adh, timeoutsecs))
- return (adh);
-
- tries--;
-
- if ((tries % dscount) == 0)
- timeoutsecs *= 2;
-
- if (tries > 0)
- goto retry;
-
-out:
- idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global "
- "catalog server!");
-
- return (NULL);
-}
-
-static
-void
-idmap_release_conn(ad_host_t *adh)
-{
- (void) pthread_mutex_lock(&adh->lock);
- if (atomic_dec_32_nv(&adh->ref) == 0)
- adh->idletime = time(NULL);
- (void) pthread_mutex_unlock(&adh->lock);
}
/*
@@ -628,415 +146,69 @@ idmap_release_conn(ad_host_t *adh)
*/
int
-idmap_add_ds(ad_t *ad, const char *host, int port)
+idmap_add_ds(adutils_ad_t *ad, const char *host, int port)
{
- ad_host_t *p;
- ad_host_t *new = NULL;
- int ret = -1;
-
- if (port == 0)
- port = (int)ad->partition;
-
- (void) pthread_mutex_lock(&adhostlock);
- for (p = host_head; p != NULL; p = p->next) {
- if (p->owner != ad)
- continue;
-
- if (strcmp(host, p->host) == 0 && p->port == port) {
- /* already added */
- ret = 0;
- goto err;
- }
- }
-
- /* add new entry */
- new = (ad_host_t *)calloc(1, sizeof (ad_host_t));
- if (new == NULL)
- goto err;
- new->owner = ad;
- new->port = port;
- new->dead = 0;
- new->max_requests = 80;
- new->num_requests = 0;
- if ((new->host = strdup(host)) == NULL)
- goto err;
-
- /* default to SASL GSSAPI only for now */
- new->saslflags = LDAP_SASL_INTERACTIVE;
- new->saslmech = "GSSAPI";
-
- if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
- free(new->host);
- new->host = NULL;
- errno = ret;
- ret = -1;
- goto err;
- }
+ int ret = -1;
- /* link in */
- new->next = host_head;
- host_head = new;
+ if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS)
+ ret = 0;
/* Start reaper if it doesn't exist */
- if (reaperid == 0)
+ if (ret == 0 && reaperid == 0)
(void) pthread_create(&reaperid, NULL,
(void *(*)(void *))adreaper, (void *)NULL);
-
-err:
- (void) pthread_mutex_unlock(&adhostlock);
-
- if (ret != 0 && new != NULL) {
- if (new->host != NULL) {
- (void) pthread_mutex_destroy(&new->lock);
- free(new->host);
- }
- free(new);
- }
-
return (ret);
}
-/*
- * Free a DS configuration.
- * Caller must lock the adhostlock mutex
- */
-static void
-delete_ds(ad_t *ad, const char *host, int port)
-{
- ad_host_t **p, *q;
-
- for (p = &host_head; *p != NULL; p = &((*p)->next)) {
- if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
- (*p)->port != port)
- continue;
- /* found */
- if ((*p)->ref > 0)
- break; /* still in use */
-
- q = *p;
- *p = (*p)->next;
-
- (void) pthread_mutex_destroy(&q->lock);
-
- if (q->ld)
- (void) ldap_unbind(q->ld);
- if (q->host)
- free(q->host);
- free(q);
- break;
- }
-
-}
-
-
-/*
- * Convert a binary SID in a BerValue to a sid_t
- */
-static
-int
-idmap_getsid(BerValue *bval, sid_t *sidp)
-{
- int i, j;
- uchar_t *v;
- uint32_t a;
-
- /*
- * The binary format of a SID is as follows:
- *
- * byte #0: version, always 0x01
- * byte #1: RID count, always <= 0x0f
- * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
- *
- * followed by RID count RIDs, each a little-endian, unsigned
- * 32-bit int.
- */
- /*
- * Sanity checks: must have at least one RID, version must be
- * 0x01, and the length must be 8 + rid count * 4
- */
- if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
- bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
- v = (uchar_t *)bval->bv_val;
- sidp->version = v[0];
- sidp->sub_authority_count = v[1];
- sidp->authority =
- /* big endian -- so start from the left */
- ((u_longlong_t)v[2] << 40) |
- ((u_longlong_t)v[3] << 32) |
- ((u_longlong_t)v[4] << 24) |
- ((u_longlong_t)v[5] << 16) |
- ((u_longlong_t)v[6] << 8) |
- (u_longlong_t)v[7];
- for (i = 0; i < sidp->sub_authority_count; i++) {
- j = 8 + (i * 4);
- /* little endian -- so start from the right */
- a = (v[j + 3] << 24) | (v[j + 2] << 16) |
- (v[j + 1] << 8) | (v[j]);
- sidp->sub_authorities[i] = a;
- }
- return (0);
- }
- return (-1);
-}
-
-/*
- * Convert a sid_t to S-1-...
- */
-static
-char *
-idmap_sid2txt(sid_t *sidp)
-{
- int rlen, i, len;
- char *str, *cp;
-
- if (sidp->version != 1)
- return (NULL);
-
- len = sizeof ("S-1-") - 1;
-
- /*
- * We could optimize like so, but, why?
- * if (sidp->authority < 10)
- * len += 2;
- * else if (sidp->authority < 100)
- * len += 3;
- * else
- * len += snprintf(NULL, 0"%llu", sidp->authority);
- */
- len += snprintf(NULL, 0, "%llu", sidp->authority);
-
- /* Max length of a uint32_t printed out in ASCII is 10 bytes */
- len += 1 + (sidp->sub_authority_count + 1) * 10;
-
- if ((cp = str = malloc(len)) == NULL)
- return (NULL);
-
- rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
-
- cp += rlen;
- len -= rlen;
-
- for (i = 0; i < sidp->sub_authority_count; i++) {
- assert(len > 0);
- rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
- cp += rlen;
- len -= rlen;
- assert(len >= 0);
- }
-
- return (str);
-}
-
-/*
- * Convert a sid_t to on-the-wire encoding
- */
static
-int
-idmap_sid2binsid(sid_t *sid, uchar_t *binsid, int binsidlen)
-{
- uchar_t *p;
- int i;
- uint64_t a;
- uint32_t r;
-
- if (sid->version != 1 ||
- binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
- return (-1);
-
- p = binsid;
- *p++ = 0x01; /* version */
- /* sub authority count */
- *p++ = sid->sub_authority_count;
- /* Authority */
- a = sid->authority;
- /* big-endian -- start from left */
- *p++ = (a >> 40) & 0xFF;
- *p++ = (a >> 32) & 0xFF;
- *p++ = (a >> 24) & 0xFF;
- *p++ = (a >> 16) & 0xFF;
- *p++ = (a >> 8) & 0xFF;
- *p++ = a & 0xFF;
-
- /* sub-authorities */
- for (i = 0; i < sid->sub_authority_count; i++) {
- r = sid->sub_authorities[i];
- /* little-endian -- start from right */
- *p++ = (r & 0x000000FF);
- *p++ = (r & 0x0000FF00) >> 8;
- *p++ = (r & 0x00FF0000) >> 16;
- *p++ = (r & 0xFF000000) >> 24;
- }
-
- return (0);
-}
-
-/*
- * Convert a stringified SID (S-1-...) into a hex-encoded version of the
- * on-the-wire encoding, but with each pair of hex digits pre-pended
- * with a '\', so we can pass this to libldap.
- */
-static
-int
-idmap_txtsid2hexbinsid(const char *txt, const rid_t *rid,
- char *hexbinsid, int hexbinsidlen)
+idmap_retcode
+map_adrc2idmaprc(adutils_rc adrc)
{
- sid_t sid = { 0 };
- int i, j;
- const char *cp;
- char *ecp;
- u_longlong_t a;
- unsigned long r;
- uchar_t *binsid, b, hb;
-
- /* Only version 1 SIDs please */
- if (strncmp(txt, "S-1-", strlen("S-1-")) != 0)
- return (-1);
-
- if (strlen(txt) < (strlen("S-1-") + 1))
- return (-1);
-
- /* count '-'s */
- for (j = 0, cp = strchr(txt, '-');
- cp != NULL && *cp != '\0';
- j++, cp = strchr(cp + 1, '-')) {
- /* can't end on a '-' */
- if (*(cp + 1) == '\0')
- return (-1);
- }
-
- /* Adjust count for version and authority */
- j -= 2;
-
- /* we know the version number and RID count */
- sid.version = 1;
- sid.sub_authority_count = (rid != NULL) ? j + 1 : j;
-
- /* must have at least one RID, but not too many */
- if (sid.sub_authority_count < 1 ||
- sid.sub_authority_count > SID_MAX_SUB_AUTHORITIES)
- return (-1);
-
- /* check that we only have digits and '-' */
- if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
- return (-1);
-
- cp = txt + strlen("S-1-");
-
- /* 64-bit safe parsing of unsigned 48-bit authority value */
- errno = 0;
- a = strtoull(cp, &ecp, 10);
-
- /* errors parsing the authority or too many bits */
- if (cp == ecp || (a == 0 && errno == EINVAL) ||
- (a == ULLONG_MAX && errno == ERANGE) ||
- (a & 0x0000ffffffffffffULL) != a)
- return (-1);
-
- cp = ecp;
-
- sid.authority = (uint64_t)a;
-
- for (i = 0; i < j; i++) {
- if (*cp++ != '-')
- return (-1);
- /* 64-bit safe parsing of unsigned 32-bit RID */
- errno = 0;
- r = strtoul(cp, &ecp, 10);
- /* errors parsing the RID or too many bits */
- if (cp == ecp || (r == 0 && errno == EINVAL) ||
- (r == ULONG_MAX && errno == ERANGE) ||
- (r & 0xffffffffUL) != r)
- return (-1);
- sid.sub_authorities[i] = (uint32_t)r;
- cp = ecp;
- }
-
- /* check that all of the string SID has been consumed */
- if (*cp != '\0')
- return (-1);
-
- if (rid != NULL)
- sid.sub_authorities[j] = *rid;
-
- j = 1 + 1 + 6 + sid.sub_authority_count * 4;
-
- if (hexbinsidlen < (j * 3))
- return (-2);
-
- /* binary encode the SID */
- binsid = (uchar_t *)alloca(j);
- (void) idmap_sid2binsid(&sid, binsid, j);
-
- /* hex encode, with a backslash before each byte */
- for (ecp = hexbinsid, i = 0; i < j; i++) {
- b = binsid[i];
- *ecp++ = '\\';
- hb = (b >> 4) & 0xF;
- *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
- hb = b & 0xF;
- *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
+ switch (adrc) {
+ case ADUTILS_SUCCESS:
+ return (IDMAP_SUCCESS);
+ case ADUTILS_ERR_NOTFOUND:
+ return (IDMAP_ERR_NOTFOUND);
+ case ADUTILS_ERR_MEMORY:
+ return (IDMAP_ERR_MEMORY);
+ case ADUTILS_ERR_DOMAIN:
+ return (IDMAP_ERR_DOMAIN);
+ case ADUTILS_ERR_OTHER:
+ return (IDMAP_ERR_OTHER);
+ case ADUTILS_ERR_RETRIABLE_NET_ERR:
+ return (IDMAP_ERR_RETRIABLE_NET_ERR);
+ default:
+ return (IDMAP_ERR_INTERNAL);
}
- *ecp = '\0';
-
- return (0);
+ /* NOTREACHED */
}
-static
-char *
-convert_bval2sid(BerValue *bval, rid_t *rid)
-{
- sid_t sid;
-
- if (idmap_getsid(bval, &sid) < 0)
- return (NULL);
-
- /*
- * If desired and if the SID is what should be a domain/computer
- * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
- * save the last RID and truncate the SID
- */
- if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
- *rid = sid.sub_authorities[--sid.sub_authority_count];
- return (idmap_sid2txt(&sid));
-}
-
-
idmap_retcode
-idmap_lookup_batch_start(ad_t *ad, int nqueries, idmap_query_state_t **state)
+idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
+ idmap_query_state_t **state)
{
- idmap_query_state_t *new_state;
- ad_host_t *adh = NULL;
+ idmap_query_state_t *new_state;
+ adutils_rc rc;
*state = NULL;
if (ad == NULL)
return (IDMAP_ERR_INTERNAL);
- adh = idmap_get_conn(ad);
- if (adh == NULL)
- return (IDMAP_ERR_RETRIABLE_NET_ERR);
-
new_state = calloc(1, sizeof (idmap_query_state_t) +
(nqueries - 1) * sizeof (idmap_q_t));
-
if (new_state == NULL)
return (IDMAP_ERR_MEMORY);
- new_state->ref_cnt = 1;
- new_state->qadh = adh;
- new_state->qcount = nqueries;
- new_state->qadh_gen = adh->generation;
- /* should be -1, but the atomic routines want unsigned */
- new_state->qlastsent = 0;
- (void) pthread_cond_init(&new_state->cv, NULL);
-
- (void) pthread_mutex_lock(&qstatelock);
- new_state->next = qstatehead;
- qstatehead = new_state;
- (void) pthread_mutex_unlock(&qstatelock);
+ if ((rc = adutils_lookup_batch_start(ad, nqueries,
+ idmap_ldap_res_search_cb, new_state, &new_state->qs))
+ != ADUTILS_SUCCESS) {
+ free(new_state);
+ return (map_adrc2idmaprc(rc));
+ }
+ new_state->qcount = nqueries;
*state = new_state;
-
return (IDMAP_SUCCESS);
}
@@ -1052,83 +224,6 @@ idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
}
/*
- * Find the idmap_query_state_t to which a given LDAP result msgid on a
- * given connection belongs. This routine increaments the reference count
- * so that the object can not be freed. idmap_lookup_unlock_batch()
- * must be called to decreament the reference count.
- */
-static
-int
-idmap_msgid2query(ad_host_t *adh, int msgid,
- idmap_query_state_t **state, int *qid)
-{
- idmap_query_state_t *p;
- int i;
- int ret;
-
- (void) pthread_mutex_lock(&qstatelock);
- for (p = qstatehead; p != NULL; p = p->next) {
- if (p->qadh != adh || adh->generation != p->qadh_gen)
- continue;
- for (i = 0; i < p->qcount; i++) {
- if ((p->queries[i]).msgid == msgid) {
- if (!p->qdead) {
- p->ref_cnt++;
- *state = p;
- *qid = i;
- ret = 1;
- } else
- ret = 0;
- (void) pthread_mutex_unlock(&qstatelock);
- return (ret);
- }
- }
- }
- (void) pthread_mutex_unlock(&qstatelock);
- return (0);
-}
-
-/*
- * Put the the search result onto the correct idmap_q_t given the LDAP result
- * msgid
- * Returns: 0 success
- * -1 already has a search result
- * -2 cant find message id
- */
-static
-int
-idmap_quesearchresbymsgid(ad_host_t *adh, int msgid, LDAPMessage *search_res)
-{
- idmap_query_state_t *p;
- int i;
- int res;
-
- (void) pthread_mutex_lock(&qstatelock);
- for (p = qstatehead; p != NULL; p = p->next) {
- if (p->qadh != adh || adh->generation != p->qadh_gen)
- continue;
- for (i = 0; i < p->qcount; i++) {
- if ((p->queries[i]).msgid == msgid) {
- if (p->queries[i].search_res == NULL) {
- if (!p->qdead) {
- p->queries[i].search_res =
- search_res;
- res = 0;
- } else
- res = -2;
- } else
- res = -1;
- (void) pthread_mutex_unlock(&qstatelock);
- return (res);
- }
- }
- }
- (void) pthread_mutex_unlock(&qstatelock);
- return (-2);
-}
-
-
-/*
* Take parsed attribute values from a search result entry and check if
* it is the result that was desired and, if so, set the result fields
* of the given idmap_q_t.
@@ -1145,7 +240,7 @@ idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
assert(dn != NULL);
- if ((domain = dn2dns(dn)) == NULL)
+ if ((domain = adutils_dn2dns(dn)) == NULL)
goto out;
if (q->ecanonname != NULL && san != NULL) {
@@ -1201,8 +296,7 @@ idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
san = NULL;
}
- /* Always have q->rc; idmap_extract_object() asserts this */
- *q->rc = IDMAP_SUCCESS;
+ q->ad_rc = ADUTILS_SUCCESS;
out:
/* Free unused attribute values */
@@ -1212,56 +306,6 @@ out:
free(unixname);
}
-/*
- * The following three functions extract objectSid, sAMAccountName and
- * objectClass attribute values and, in the case of objectSid and
- * objectClass, parse them.
- *
- * idmap_setqresults() takes care of dealing with the result entry's DN.
- */
-
-/*
- * Return a NUL-terminated stringified SID from the value of an
- * objectSid attribute and put the last RID in *rid.
- */
-static
-char *
-idmap_bv_objsid2sidstr(BerValue **bvalues, rid_t *rid)
-{
- char *sid;
-
- if (bvalues == NULL)
- return (NULL);
- /* objectSid is single valued */
- if ((sid = convert_bval2sid(bvalues[0], rid)) == NULL)
- return (NULL);
- return (sid);
-}
-
-/*
- * Return a NUL-terminated string from the value of a sAMAccountName
- * or unixname attribute.
- */
-static
-char *
-idmap_bv_name2str(BerValue **bvalues)
-{
- char *s;
-
- if (bvalues == NULL || bvalues[0] == NULL ||
- bvalues[0]->bv_val == NULL)
- return (NULL);
-
- if ((s = malloc(bvalues[0]->bv_len + 1)) == NULL)
- return (NULL);
-
- (void) snprintf(s, bvalues[0]->bv_len + 1, "%.*s", bvalues[0]->bv_len,
- bvalues[0]->bv_val);
-
- return (s);
-}
-
-
#define BVAL_CASEEQ(bv, str) \
(((*(bv))->bv_len == (sizeof (str) - 1)) && \
strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
@@ -1309,12 +353,11 @@ idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
*/
static
void
-idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
+idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
+ LDAPMessage *res, LDAP *ld)
{
BerElement *ber = NULL;
BerValue **bvalues;
- ad_host_t *adh;
- idmap_q_t *q;
char *attr;
const char *unixuser_attr = NULL;
const char *unixgroup_attr = NULL;
@@ -1327,24 +370,11 @@ idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
int sid_type = _IDMAP_T_UNDEF;
int has_class, has_san, has_sid;
int has_unixuser, has_unixgroup;
- int num;
-
- adh = state->qadh;
-
- (void) pthread_mutex_lock(&adh->lock);
-
- q = &(state->queries[qid]);
assert(q->rc != NULL);
- if (adh->dead || (dn = ldap_get_dn(adh->ld, res)) == NULL) {
- num = adh->num_requests;
- (void) pthread_mutex_unlock(&adh->lock);
- idmapdlog(LOG_DEBUG,
- "AD error decoding search result - %d queued requests",
- num);
+ if ((dn = ldap_get_dn(ld, res)) == NULL)
return;
- }
assert(q->domain == NULL || *q->domain == NULL);
@@ -1384,8 +414,8 @@ idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
}
has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0;
- for (attr = ldap_first_attribute(adh->ld, res, &ber); attr != NULL;
- attr = ldap_next_attribute(adh->ld, res, ber)) {
+ for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL;
+ attr = ldap_next_attribute(ld, res, ber)) {
bvalues = NULL; /* for memory management below */
/*
@@ -1394,15 +424,20 @@ idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
*/
if (q->sid != NULL && !has_sid &&
strcasecmp(attr, OBJSID) == 0) {
- bvalues = ldap_get_values_len(adh->ld, res, attr);
- sid = idmap_bv_objsid2sidstr(bvalues, &rid);
- has_sid = (sid != NULL);
+ bvalues = ldap_get_values_len(ld, res, attr);
+ if (bvalues != NULL) {
+ sid = adutils_bv_objsid2sidstr(
+ bvalues[0], &rid);
+ has_sid = (sid != NULL);
+ }
} else if (!has_san && strcasecmp(attr, SAN) == 0) {
- bvalues = ldap_get_values_len(adh->ld, res, attr);
- san = idmap_bv_name2str(bvalues);
- has_san = (san != NULL);
+ bvalues = ldap_get_values_len(ld, res, attr);
+ if (bvalues != NULL) {
+ san = adutils_bv_name2str(bvalues[0]);
+ has_san = (san != NULL);
+ }
} else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) {
- bvalues = ldap_get_values_len(adh->ld, res, attr);
+ bvalues = ldap_get_values_len(ld, res, attr);
has_class = idmap_bv_objclass2sidtype(bvalues,
&sid_type);
if (has_class && q->unixname != NULL &&
@@ -1431,15 +466,19 @@ idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
}
} else if (!has_unixuser && unixuser_attr != NULL &&
strcasecmp(attr, unixuser_attr) == 0) {
- bvalues = ldap_get_values_len(adh->ld, res, attr);
- unixuser = idmap_bv_name2str(bvalues);
- has_unixuser = (unixuser != NULL);
+ bvalues = ldap_get_values_len(ld, res, attr);
+ if (bvalues != NULL) {
+ unixuser = adutils_bv_name2str(bvalues[0]);
+ has_unixuser = (unixuser != NULL);
+ }
} else if (!has_unixgroup && unixgroup_attr != NULL &&
strcasecmp(attr, unixgroup_attr) == 0) {
- bvalues = ldap_get_values_len(adh->ld, res, attr);
- unixgroup = idmap_bv_name2str(bvalues);
- has_unixgroup = (unixgroup != NULL);
+ bvalues = ldap_get_values_len(ld, res, attr);
+ if (bvalues != NULL) {
+ unixgroup = adutils_bv_name2str(bvalues[0]);
+ has_unixgroup = (unixgroup != NULL);
+ }
}
if (bvalues != NULL)
@@ -1455,8 +494,6 @@ idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
}
}
- (void) pthread_mutex_unlock(&adh->lock);
-
if (!has_class) {
/*
* Didn't find objectclass. Something's wrong with our
@@ -1485,140 +522,31 @@ idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
ldap_memfree(dn);
}
-/*
- * Try to get a result; if there is one, find the corresponding
- * idmap_q_t and process the result.
- *
- * Returns: 0 success
- * -1 error
- * -2 queue empty
- */
-static
-int
-idmap_get_adobject_batch(ad_host_t *adh, struct timeval *timeout)
+void
+idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid,
+ void *argp)
{
- idmap_query_state_t *query_state;
- LDAPMessage *res = NULL;
- int rc, ret, msgid, qid;
- idmap_q_t *que;
- int num;
-
- (void) pthread_mutex_lock(&adh->lock);
- if (adh->dead || adh->num_requests == 0) {
- if (adh->dead)
- ret = -1;
- else
- ret = -2;
- (void) pthread_mutex_unlock(&adh->lock);
- return (ret);
- }
+ idmap_query_state_t *state = (idmap_query_state_t *)argp;
+ idmap_q_t *q = &(state->queries[qid]);
- /* Get one result */
- rc = ldap_result(adh->ld, LDAP_RES_ANY, 0,
- timeout, &res);
- if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) ||
- rc < 0)
- adh->dead = 1;
-
- if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0)
- adh->num_requests--;
-
- if (adh->dead) {
- num = adh->num_requests;
- (void) pthread_mutex_unlock(&adh->lock);
- idmapdlog(LOG_DEBUG,
- "AD ldap_result error - %d queued requests", num);
- return (-1);
- }
switch (rc) {
case LDAP_RES_SEARCH_RESULT:
- /* We should have the LDAP replies for some search... */
- msgid = ldap_msgid(res);
- if (idmap_msgid2query(adh, msgid, &query_state, &qid)) {
- (void) pthread_mutex_unlock(&adh->lock);
- que = &(query_state->queries[qid]);
- if (que->search_res != NULL) {
- idmap_extract_object(query_state, qid,
- que->search_res);
- (void) ldap_msgfree(que->search_res);
- que->search_res = NULL;
- } else
- *que->rc = IDMAP_ERR_NOTFOUND;
- /* ...so we can decrement qinflight */
- atomic_dec_32(&query_state->qinflight);
- idmap_lookup_unlock_batch(&query_state);
- } else {
- num = adh->num_requests;
- (void) pthread_mutex_unlock(&adh->lock);
- idmapdlog(LOG_DEBUG,
- "AD cannot find message ID - %d queued requests",
- num);
- }
- (void) ldap_msgfree(res);
- ret = 0;
+ if (q->search_res != NULL) {
+ idmap_extract_object(state, q, q->search_res, ld);
+ (void) ldap_msgfree(q->search_res);
+ q->search_res = NULL;
+ } else
+ q->ad_rc = ADUTILS_ERR_NOTFOUND;
break;
-
- case LDAP_RES_SEARCH_REFERENCE:
- /*
- * We have no need for these at the moment. Eventually,
- * when we query things that we can't expect to find in
- * the Global Catalog then we'll need to learn to follow
- * references.
- */
- (void) pthread_mutex_unlock(&adh->lock);
- (void) ldap_msgfree(res);
- ret = 0;
- break;
-
case LDAP_RES_SEARCH_ENTRY:
- /* Got a result - queue it */
- msgid = ldap_msgid(res);
- rc = idmap_quesearchresbymsgid(adh, msgid, res);
- num = adh->num_requests;
- (void) pthread_mutex_unlock(&adh->lock);
- if (rc == -1) {
- idmapdlog(LOG_DEBUG,
- "AD already has search result - %d queued requests",
- num);
- (void) ldap_msgfree(res);
- } else if (rc == -2) {
- idmapdlog(LOG_DEBUG,
- "AD cannot queue by message ID "
- "- %d queued requests", num);
- (void) ldap_msgfree(res);
+ if (q->search_res == NULL) {
+ q->search_res = *res;
+ *res = NULL;
}
- ret = 0;
break;
-
default:
- /* timeout or error; treat the same */
- (void) pthread_mutex_unlock(&adh->lock);
- ret = -1;
break;
}
-
- return (ret);
-}
-
-/*
- * This routine decreament the reference count of the
- * idmap_query_state_t
- */
-static void
-idmap_lookup_unlock_batch(idmap_query_state_t **state)
-{
- /*
- * Decrement reference count with qstatelock locked
- */
- (void) pthread_mutex_lock(&qstatelock);
- (*state)->ref_cnt--;
- /*
- * If there are no references wakup the allocating thread
- */
- if ((*state)->ref_cnt <= 1)
- (void) pthread_cond_signal(&(*state)->cv);
- (void) pthread_mutex_unlock(&qstatelock);
- *state = NULL;
}
static
@@ -1639,96 +567,38 @@ idmap_cleanup_batch(idmap_query_state_t *batch)
/*
* This routine frees the idmap_query_state_t structure
- * If the reference count is greater than 1 it waits
- * for the other threads to finish using it.
*/
void
idmap_lookup_release_batch(idmap_query_state_t **state)
{
- idmap_query_state_t **p;
-
- /*
- * Set state to dead to stop further operations.
- * Wait for reference count with qstatelock locked
- * to get to one.
- */
- (void) pthread_mutex_lock(&qstatelock);
- (*state)->qdead = 1;
- while ((*state)->ref_cnt > 1) {
- (void) pthread_cond_wait(&(*state)->cv, &qstatelock);
- }
-
- /* Remove this state struct from the list of state structs */
- for (p = &qstatehead; *p != NULL; p = &(*p)->next) {
- if (*p == (*state)) {
- *p = (*state)->next;
- break;
- }
- }
- (void) pthread_mutex_unlock(&qstatelock);
-
+ if (state == NULL || *state == NULL)
+ return;
+ adutils_lookup_batch_release(&(*state)->qs);
idmap_cleanup_batch(*state);
-
- (void) pthread_cond_destroy(&(*state)->cv);
-
- idmap_release_conn((*state)->qadh);
-
free(*state);
*state = NULL;
}
-
-/*
- * This routine waits for other threads using the
- * idmap_query_state_t structure to finish.
- * If the reference count is greater than 1 it waits
- * for the other threads to finish using it.
- */
-static
-void
-idmap_lookup_wait_batch(idmap_query_state_t *state)
-{
- /*
- * Set state to dead to stop further operation.
- * stating.
- * Wait for reference count to get to one
- * with qstatelock locked.
- */
- (void) pthread_mutex_lock(&qstatelock);
- state->qdead = 1;
- while (state->ref_cnt > 1) {
- (void) pthread_cond_wait(&state->cv, &qstatelock);
- }
- (void) pthread_mutex_unlock(&qstatelock);
-}
-
-
idmap_retcode
idmap_lookup_batch_end(idmap_query_state_t **state)
{
- int rc = LDAP_SUCCESS;
- idmap_retcode retcode = IDMAP_SUCCESS;
- struct timeval timeout;
+ adutils_rc ad_rc;
+ int i;
+ idmap_query_state_t *id_qs = *state;
- timeout.tv_sec = IDMAPD_SEARCH_TIMEOUT;
- timeout.tv_usec = 0;
+ ad_rc = adutils_lookup_batch_end(&id_qs->qs);
- /* Process results until done or until timeout, if given */
- while ((*state)->qinflight > 0) {
- if ((rc = idmap_get_adobject_batch((*state)->qadh,
- &timeout)) != 0)
- break;
+ /*
+ * Map adutils rc to idmap_retcode in each
+ * query because consumers in dbutils.c
+ * expects idmap_retcode.
+ */
+ for (i = 0; i < id_qs->qcount; i++) {
+ *id_qs->queries[i].rc =
+ map_adrc2idmaprc(id_qs->queries[i].ad_rc);
}
- (*state)->qdead = 1;
- /* Wait for other threads proceesing search result to finish */
- idmap_lookup_wait_batch(*state);
-
- if (rc == -1 || (*state)->qinflight != 0)
- retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
-
idmap_lookup_release_batch(state);
-
- return (retcode);
+ return (map_adrc2idmaprc(ad_rc));
}
/*
@@ -1744,11 +614,8 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
char **sid, rid_t *rid, int *sid_type, char **unixname,
idmap_retcode *rc)
{
- idmap_retcode retcode = IDMAP_SUCCESS;
- int lrc, qid, i;
- int num;
- int dead;
- struct timeval tv;
+ adutils_rc ad_rc;
+ int qid, i;
idmap_q_t *q;
static char *attrs[] = {
SAN,
@@ -1760,12 +627,11 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
};
qid = atomic_inc_32_nv(&state->qlastsent) - 1;
-
q = &(state->queries[qid]);
/*
- * Remember the expected canonname so we can check the results
- * agains it
+ * Remember the expected canonname, domainname and unix type
+ * so we can check the results * against it
*/
q->ecanonname = ecanonname;
q->edomain = edomain;
@@ -1821,69 +687,19 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
if (value != NULL)
*value = NULL;
- /* Check the number of queued requests first */
- tv.tv_sec = IDMAPD_SEARCH_TIMEOUT;
- tv.tv_usec = 0;
- while (!state->qadh->dead &&
- state->qadh->num_requests > state->qadh->max_requests) {
- if (idmap_get_adobject_batch(state->qadh, &tv) != 0)
- break;
- }
-
/*
* Don't set *canonname to NULL because it may be pointing to the
* given winname. Later on if we get a canonical name from AD the
* old name if any will be freed before assigning the new name.
*/
- /* Send this lookup, don't wait for a result here */
- lrc = LDAP_SUCCESS;
- (void) pthread_mutex_lock(&state->qadh->lock);
-
- if (!state->qadh->dead) {
- state->qadh->idletime = time(NULL);
- lrc = ldap_search_ext(state->qadh->ld, "",
- LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL,
- NULL, -1, &q->msgid);
-
- if (lrc == LDAP_SUCCESS) {
- state->qadh->num_requests++;
- } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE ||
- lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN ||
- lrc == LDAP_UNWILLING_TO_PERFORM) {
- retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
- state->qadh->dead = 1;
- } else {
- retcode = IDMAP_ERR_OTHER;
- state->qadh->dead = 1;
- }
- }
- dead = state->qadh->dead;
- num = state->qadh->num_requests;
- (void) pthread_mutex_unlock(&state->qadh->lock);
-
- if (dead) {
- if (lrc != LDAP_SUCCESS)
- idmapdlog(LOG_DEBUG,
- "AD ldap_search_ext error (%s) "
- "- %d queued requests",
- ldap_err2string(lrc), num);
- return (retcode);
- }
-
- atomic_inc_32(&state->qinflight);
-
/*
- * Reap as many requests as we can _without_ waiting
- *
- * We do this to prevent any possible TCP socket buffer
- * starvation deadlocks.
+ * Invoke the mother of all APIs i.e. the adutils API
*/
- (void) memset(&tv, 0, sizeof (tv));
- while (idmap_get_adobject_batch(state->qadh, &tv) == 0)
- ;
-
- return (IDMAP_SUCCESS);
+ ad_rc = adutils_lookup_batch_add(state->qs, filter,
+ (const char **)attrs,
+ edomain, &q->result, &q->ad_rc);
+ return (map_adrc2idmaprc(ad_rc));
}
idmap_retcode
@@ -1928,17 +744,15 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
}
*strchr(ecanonname, '@') = '\0';
} else {
- /*
- * 'name' not qualified and dname not given
- *
- * Note: ad->dflt_w2k_dom cannot be NULL - see
- * idmap_ad_alloc()
- */
- if (*state->qadh->owner->dflt_w2k_dom == '\0') {
+ /* 'name' not qualified and dname not given */
+ dname = adutils_lookup_batch_getdefdomain(
+ state->qs);
+ assert(dname != NULL);
+ if (*dname == '\0') {
free(ecanonname);
return (IDMAP_ERR_DOMAIN);
}
- edomain = strdup(state->qadh->owner->dflt_w2k_dom);
+ edomain = strdup(dname);
if (edomain == NULL) {
free(ecanonname);
return (IDMAP_ERR_MEMORY);
@@ -1990,7 +804,7 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state,
idmap_retcode retcode;
int flen, ret;
char *filter = NULL;
- char cbinsid[MAXHEXBINSID + 1];
+ char cbinsid[ADUTILS_MAXHEXBINSID + 1];
/*
* Strategy: search [the global catalog] for user/group by
@@ -2000,7 +814,7 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state,
* computer.
*/
- ret = idmap_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
+ ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
if (ret != 0)
return (IDMAP_ERR_SID);
diff --git a/usr/src/cmd/idmap/idmapd/adutils.h b/usr/src/cmd/idmap/idmapd/adutils.h
index c81c0a8dab..6b722749ac 100644
--- a/usr/src/cmd/idmap/idmapd/adutils.h
+++ b/usr/src/cmd/idmap/idmapd/adutils.h
@@ -27,8 +27,6 @@
#ifndef _ADUTILS_H
#define _ADUTILS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -51,6 +49,7 @@ extern "C" {
#include <thread.h>
#include <synch.h>
#include "idmap_prot.h"
+#include "libadutils.h"
#include <sys/idmap.h>
/*
@@ -68,49 +67,12 @@ extern "C" {
#define _IDMAP_T_DOMAIN -1006
#define _IDMAP_T_COMPUTER -1007
-#define SID_MAX_SUB_AUTHORITIES 15
-#define MAXBINSID (1 + 1 + 6 + (SID_MAX_SUB_AUTHORITIES * 4))
-#define MAXHEXBINSID (MAXBINSID * 3)
-
typedef uint32_t rid_t;
-/*
- * We use the port numbers for normal LDAP and global catalog LDAP as
- * the enum values for this enumeration. Clever? Silly? You decide.
- * Although we never actually use these enum values as port numbers and
- * never will, so this is just cute.
- */
-typedef enum idmap_ad_partition {
- IDMAP_AD_DATA = 389,
- IDMAP_AD_GLOBAL_CATALOG = 3268
-} idmap_ad_partition_t;
-
-typedef struct ad ad_t;
typedef struct idmap_query_state idmap_query_state_t;
-/*
- * Idmap interfaces:
- *
- * - an ad_t represents an AD partition
- * - a DS (hostname + port, if port != 0) can be added/removed from an ad_t
- * - and because libldap supports space-separated lists of servers, a
- * single hostname value can actually be a set of hostnames.
- * - an ad_t can be allocated, ref'ed and released; last release
- * releases resources
- *
- * - lookups are batched; see below.
- *
- * See below.
- */
-
-/* Allocate/release ad_t objects */
-int idmap_ad_alloc(ad_t **new_ad, const char *default_domain,
- idmap_ad_partition_t part);
-void idmap_ad_free(ad_t **ad);
+int idmap_add_ds(adutils_ad_t *ad, const char *host, int port);
-/* Add/remove a DS to/from an ad_t */
-int idmap_add_ds(ad_t *ad, const char *host, int port);
-void idmap_delete_ds(ad_t *ad, const char *host, int port);
/*
* Batch lookups
@@ -132,7 +94,7 @@ void idmap_delete_ds(ad_t *ad, const char *host, int port);
*/
/* Start a batch of lookups */
-idmap_retcode idmap_lookup_batch_start(ad_t *ad, int nqueries,
+idmap_retcode idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
idmap_query_state_t **state);
/* End a batch and release its idmap_query_state_t object */
diff --git a/usr/src/cmd/idmap/idmapd/dbutils.c b/usr/src/cmd/idmap/idmapd/dbutils.c
index 6420344b00..771eaf8250 100644
--- a/usr/src/cmd/idmap/idmapd/dbutils.c
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c
@@ -67,6 +67,9 @@ static idmap_retcode lookup_cache_name2sid(sqlite *, const char *,
#define AVOID_NAMESERVICE(req)\
(req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
+#define ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)\
+ (req->flag & IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY)
+
#define IS_EPHEMERAL(pid) (pid > INT32_MAX && pid != SENTINEL_PID)
#define LOCALRID_MIN 1000
@@ -1844,10 +1847,13 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
}
retry:
+ RDLOCK_CONFIG();
retcode = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries,
&qs);
+ UNLOCK_CONFIG();
if (retcode != IDMAP_SUCCESS) {
- if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
+ retries++ < ADUTILS_DEF_NUM_RETRIES)
goto retry;
degrade_svc(1, "failed to create batch for AD lookup");
goto out;
@@ -2019,7 +2025,8 @@ retry:
idmap_lookup_release_batch(&qs);
}
- if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
+ retries++ < ADUTILS_DEF_NUM_RETRIES)
goto retry;
else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
degrade_svc(1, "some AD lookups timed out repeatedly");
@@ -2224,11 +2231,16 @@ sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req,
if (retcode != IDMAP_ERR_NOTFOUND)
goto out;
- /* Check if this is a localsid */
if (!wksid) {
+ /* Check if this is a localsid */
retcode = lookup_localsid2pid(req, res);
if (retcode != IDMAP_ERR_NOTFOUND)
goto out;
+
+ if (ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)) {
+ retcode = IDMAP_ERR_NONEGENERATED;
+ goto out;
+ }
}
/* Lookup cache */
@@ -3581,9 +3593,12 @@ ad_lookup_by_winname(lookup_state_t *state,
idmap_retcode rc, retcode;
retry:
+ RDLOCK_CONFIG();
retcode = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
+ UNLOCK_CONFIG();
if (retcode != IDMAP_SUCCESS) {
- if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
+ retries++ < ADUTILS_DEF_NUM_RETRIES)
goto retry;
degrade_svc(1, "failed to create request for AD lookup "
"by winname");
@@ -3604,7 +3619,8 @@ retry:
else
retcode = idmap_lookup_batch_end(&qs);
- if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
+ retries++ < ADUTILS_DEF_NUM_RETRIES)
goto retry;
else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
degrade_svc(1, "some AD lookups timed out repeatedly");
diff --git a/usr/src/cmd/idmap/idmapd/idmapd.h b/usr/src/cmd/idmap/idmapd/idmapd.h
index 1fc0f696ed..b4cab338c4 100644
--- a/usr/src/cmd/idmap/idmapd/idmapd.h
+++ b/usr/src/cmd/idmap/idmapd/idmapd.h
@@ -26,8 +26,6 @@
#ifndef _IDMAPD_H
#define _IDMAPD_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -41,6 +39,7 @@
#include "idmap_prot.h"
#include "adutils.h"
#include "idmap_config.h"
+#include "libadutils.h"
#ifdef __cplusplus
extern "C" {
@@ -80,7 +79,7 @@ typedef struct idmapd_state {
gid_t limit_gid;
int new_eph_db; /* was the ephem ID db [re-]created? */
bool_t eph_map_unres_sids;
- ad_t *ad;
+ adutils_ad_t *ad;
} idmapd_state_t;
extern idmapd_state_t _idmapdstate;
diff --git a/usr/src/cmd/idmap/idmapd/init.c b/usr/src/cmd/idmap/idmapd/init.c
index 5ccb6553a3..f1eb9d9aaf 100644
--- a/usr/src/cmd/idmap/idmapd/init.c
+++ b/usr/src/cmd/idmap/idmapd/init.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Initialization routines
*/
@@ -105,9 +103,9 @@ load_config()
void
reload_ad()
{
- int i;
- ad_t *old;
- ad_t *new;
+ int i;
+ adutils_ad_t *old;
+ adutils_ad_t *new;
idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
@@ -126,8 +124,8 @@ reload_ad()
old = _idmapdstate.ad;
- if (idmap_ad_alloc(&new, pgcfg->default_domain,
- IDMAP_AD_GLOBAL_CATALOG) != 0) {
+ if (adutils_ad_alloc(&new, pgcfg->default_domain,
+ ADUTILS_AD_GLOBAL_CATALOG) != ADUTILS_SUCCESS) {
degrade_svc(0, "could not initialize AD context");
return;
}
@@ -136,7 +134,7 @@ reload_ad()
if (idmap_add_ds(new,
pgcfg->global_catalog[i].host,
pgcfg->global_catalog[i].port) != 0) {
- idmap_ad_free(&new);
+ adutils_ad_free(&new);
degrade_svc(0, "could not initialize AD GC context");
return;
}
@@ -145,7 +143,7 @@ reload_ad()
_idmapdstate.ad = new;
if (old != NULL)
- idmap_ad_free(&old);
+ adutils_ad_free(&old);
}
diff --git a/usr/src/cmd/netfiles/Makefile b/usr/src/cmd/netfiles/Makefile
index 6e7e66f805..4f21e795c8 100644
--- a/usr/src/cmd/netfiles/Makefile
+++ b/usr/src/cmd/netfiles/Makefile
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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.
@@ -19,10 +18,7 @@
#
# CDDL HEADER END
#
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -33,7 +29,7 @@ include ../Makefile.cmd
FILES= hosts services
ETCFILES= netconfig nsswitch.conf nsswitch.files nsswitch.nis nsswitch.nisplus \
- nsswitch.dns nsswitch.ldap
+ nsswitch.dns nsswitch.ldap nsswitch.ad
ROOTNET= $(ROOTETC)/net
TICLTS= $(ROOTNET)/ticlts
diff --git a/usr/src/cmd/netfiles/nsswitch.ad b/usr/src/cmd/netfiles/nsswitch.ad
new file mode 100644
index 0000000000..e869c6bd32
--- /dev/null
+++ b/usr/src/cmd/netfiles/nsswitch.ad
@@ -0,0 +1,77 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# /etc/nsswitch.ad:
+#
+# An example file that could be copied over to /etc/nsswitch.conf; it
+# uses Microsoft's Active Directory (AD) for passwd and group; DNS for
+# hosts lookups; and files for the remaining databases.
+#
+# AD name service currently only supports passwd(4) and group(4)
+# databases.
+#
+# Other name service databases such as audit_user(4) and user_attr(4)
+# that follow passwd entry in nsswitch.conf are not supported by AD.
+# If the AD backend is processed (based on the configuration) it will
+# return NOT FOUND for these databases.
+#
+# Since AD name service is not yet a complete Solaris solution, please
+# add other name service(s) as appropriate to the lines in this file.
+#
+# "hosts:" and "services:" in this file are used only if the
+# /etc/netconfig file has a "-" for nametoaddr_libs of "inet" transports.
+
+# DNS service expects that an instance of svc:/network/dns/client be
+# enabled and online.
+
+passwd: files ad
+group: files ad
+
+# Note that IPv4 addresses are searched for in all of the ipnodes databases
+# before searching the hosts databases.
+hosts: files dns
+ipnodes: files dns
+
+networks: files
+protocols: files
+rpc: files
+ethers: files
+netmasks: files
+bootparams: files
+publickey: files
+# At present there isn't a 'files' backend for netgroup; the system will
+# figure it out pretty quickly, and won't use netgroups at all.
+netgroup: files
+automount: files
+aliases: files
+services: files
+printers: user files
+
+auth_attr: files
+prof_attr: files
+project: files
+
+tnrhtp: files
+tnrhdb: files
diff --git a/usr/src/cmd/nscd/nscd_cfgdef.h b/usr/src/cmd/nscd/nscd_cfgdef.h
index f503dfbfea..6acdec9feb 100644
--- a/usr/src/cmd/nscd/nscd_cfgdef.h
+++ b/usr/src/cmd/nscd/nscd_cfgdef.h
@@ -26,8 +26,6 @@
#ifndef _NSCD_CFGDEF_H
#define _NSCD_CFGDEF_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -126,6 +124,7 @@ nscd_cfg_id_t _nscd_cfg_nsw_src[] = {
{ 5, "dns" },
{ 6, "compat" },
{ 7, "user" },
+ { 8, "ad" },
{ -1, NULL }
};
diff --git a/usr/src/cmd/nscd/nscd_smfmonitor.c b/usr/src/cmd/nscd/nscd_smfmonitor.c
index a0874e394d..bd2ff958ba 100644
--- a/usr/src/cmd/nscd/nscd_smfmonitor.c
+++ b/usr/src/cmd/nscd/nscd_smfmonitor.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <libscf.h>
#include <string.h>
@@ -164,9 +162,10 @@ _nscd_get_smf_state(int srci, int dbi, int recheck)
n = NSCD_NSW_SRC_NAME(srci);
/* the files, compat, and dns backends are always available */
- if ((*n == 'f' || *n == 'c' || *n == 'd') &&
+ if ((*n == 'f' || *n == 'c' || *n == 'd' || *n == 'a') &&
(strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 ||
strcmp(NSCD_NSW_SRC_NAME(srci), "compat") == 0 ||
+ strcmp(NSCD_NSW_SRC_NAME(srci), "ad") == 0 ||
strcmp(NSCD_NSW_SRC_NAME(srci), "dns") == 0)) {
return (SCF_STATE_ONLINE);
}
diff --git a/usr/src/head/rpcsvc/idmap_prot.x b/usr/src/head/rpcsvc/idmap_prot.x
index 23f62685cd..84893f290b 100644
--- a/usr/src/head/rpcsvc/idmap_prot.x
+++ b/usr/src/head/rpcsvc/idmap_prot.x
@@ -148,12 +148,16 @@ const IDMAP_REQ_FLG_NO_NAMESERVICE = 0x00000004;
/* Request how a mapping was formed */
const IDMAP_REQ_FLG_MAPPING_INFO = 0x00000008;
+
/*
* This libidmap only flag is defined in idmap.h
* It enables use of the libidmap cache
* const IDMAP_REQ_FLG_USE_CACHE = 0x00000010;
*/
+/* Request mapping for well-known or local SIDs only */
+const IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY = 0x00000020;
+
/*
* Mapping direction definitions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 94e5f1d7f3..7a22e5a065 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -243,6 +243,7 @@ SUBDIRS += \
libshare \
libsqlite \
libidmap \
+ libadutils \
libipmi \
libexacct/demo \
libvscan \
@@ -527,6 +528,8 @@ gss_mechs/mech_krb5: libgss libnsl libsocket libresolv pkcs11
libadt_jni: libbsm
$(CLOSED_BUILD)libc: $(CLOSED)/lib/libc_i18n
libast: libsocket
+libadutils: libldap5 libidmap
+nsswitch: libadutils
libbsm: libtsol
libcmd: libast libsocket libnsl
libcmdutils: libavl
diff --git a/usr/src/lib/libadutils/Makefile b/usr/src/lib/libadutils/Makefile
new file mode 100644
index 0000000000..cded41b662
--- /dev/null
+++ b/usr/src/lib/libadutils/Makefile
@@ -0,0 +1,49 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libadutils/Makefile.com b/usr/src/lib/libadutils/Makefile.com
new file mode 100644
index 0000000000..bdb5668bd8
--- /dev/null
+++ b/usr/src/lib/libadutils/Makefile.com
@@ -0,0 +1,50 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libadutils.a
+VERS = .1
+OBJECTS = adutils.o
+LINT_OBJECTS = adutils.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lldap -lidmap
+SRCDIR = ../common
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+IDMAP_PROT_DIR = $(SRC)/head/rpcsvc
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I$(SRCDIR) -I$(SRC)/lib/libidmap/common \
+ -I$(IDMAP_PROT_DIR)
+
+lint := OBJECTS = $(LINT_OBJECTS)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libadutils/amd64/Makefile b/usr/src/lib/libadutils/amd64/Makefile
new file mode 100644
index 0000000000..39ae44e24b
--- /dev/null
+++ b/usr/src/lib/libadutils/amd64/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libadutils/common/adutils.c b/usr/src/lib/libadutils/common/adutils.c
new file mode 100644
index 0000000000..d838858671
--- /dev/null
+++ b/usr/src/lib/libadutils/common/adutils.c
@@ -0,0 +1,1693 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <alloca.h>
+#include <string.h>
+#include <strings.h>
+#include <lber.h>
+#include <sasl/sasl.h>
+#include <string.h>
+#include <ctype.h>
+#include <synch.h>
+#include <atomic.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/u8_textprep.h>
+#include <sys/varargs.h>
+#include "libadutils.h"
+#include "adutils_impl.h"
+
+/* List of DSs, needed by the idle connection reaper thread */
+static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER;
+static adutils_host_t *host_head = NULL;
+
+/*
+ * List of query state structs -- needed so we can "route" LDAP results
+ * to the right context if multiple threads should be using the same
+ * connection concurrently
+ */
+static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER;
+static adutils_query_state_t *qstatehead = NULL;
+
+static char *adutils_sid_ber2str(BerValue *bvalues);
+static void adutils_lookup_batch_unlock(adutils_query_state_t **state);
+static void delete_ds(adutils_ad_t *ad, const char *host, int port);
+
+typedef struct binary_attrs {
+ const char *name;
+ char *(*ber2str)(BerValue *bvalues);
+} binary_attrs_t;
+
+static binary_attrs_t binattrs[] = {
+ {"objectSID", adutils_sid_ber2str},
+ {NULL, NULL}
+};
+
+void
+adutils_set_log(int pri, bool_t syslog, bool_t degraded)
+{
+ idmap_log_stderr(pri);
+ idmap_log_syslog(syslog);
+ idmap_log_degraded(degraded);
+}
+
+/*
+ * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com"
+ */
+static
+char *
+adutils_dns2dn(const char *dns)
+{
+ int nameparts;
+ return (ldap_dns_to_dn((char *)dns, &nameparts));
+}
+
+/*
+ * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
+ * attributes (CN, etc...).
+ */
+char *
+adutils_dn2dns(const char *dn)
+{
+ char **rdns = NULL;
+ char **attrs = NULL;
+ char **labels = NULL;
+ char *dns = NULL;
+ char **rdn, **attr, **label;
+ int maxlabels = 5;
+ int nlabels = 0;
+ int dnslen;
+
+ /*
+ * There is no reverse of ldap_dns_to_dn() in our libldap, so we
+ * have to do the hard work here for now.
+ */
+
+ /*
+ * This code is much too liberal: it looks for "dc" attributes
+ * in all RDNs of the DN. In theory this could cause problems
+ * if people were to use "dc" in nodes other than the root of
+ * the tree, but in practice noone, least of all Active
+ * Directory, does that.
+ *
+ * On the other hand, this code is much too conservative: it
+ * does not make assumptions about ldap_explode_dn(), and _that_
+ * is the true for looking at every attr of every RDN.
+ *
+ * Since we only ever look at dc and those must be DNS labels,
+ * at least until we get around to supporting IDN here we
+ * shouldn't see escaped labels from AD nor from libldap, though
+ * the spec (RFC2253) does allow libldap to escape things that
+ * don't need escaping -- if that should ever happen then
+ * libldap will need a spanking, and we can take care of that.
+ */
+
+ /* Explode a DN into RDNs */
+ if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
+ return (NULL);
+
+ labels = calloc(maxlabels + 1, sizeof (char *));
+ label = labels;
+
+ for (rdn = rdns; *rdn != NULL; rdn++) {
+ if (attrs != NULL)
+ ldap_value_free(attrs);
+
+ /* Explode each RDN, look for DC attr, save val as DNS label */
+ if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL)
+ goto done;
+
+ for (attr = attrs; *attr != NULL; attr++) {
+ if (strncasecmp(*attr, "dc=", 3) != 0)
+ continue;
+
+ /* Found a DNS label */
+ labels[nlabels++] = strdup((*attr) + 3);
+
+ if (nlabels == maxlabels) {
+ char **tmp;
+ tmp = realloc(labels,
+ sizeof (char *) * (maxlabels + 1));
+
+ if (tmp == NULL)
+ goto done;
+
+ labels = tmp;
+ labels[nlabels] = NULL;
+ }
+
+ /* There should be just one DC= attr per-RDN */
+ break;
+ }
+ }
+
+ /*
+ * Got all the labels, now join with '.'
+ *
+ * We need room for nlabels - 1 periods ('.'), one nul
+ * terminator, and the strlen() of each label.
+ */
+ dnslen = nlabels;
+ for (label = labels; *label != NULL; label++)
+ dnslen += strlen(*label);
+
+ if ((dns = malloc(dnslen)) == NULL)
+ goto done;
+
+ *dns = '\0';
+
+ for (label = labels; *label != NULL; label++) {
+ (void) strlcat(dns, *label, dnslen);
+ /*
+ * NOTE: the last '.' won't be appended -- there's no room
+ * for it!
+ */
+ (void) strlcat(dns, ".", dnslen);
+ }
+
+done:
+ if (labels != NULL) {
+ for (label = labels; *label != NULL; label++)
+ free(*label);
+ free(labels);
+ }
+ if (attrs != NULL)
+ ldap_value_free(attrs);
+ if (rdns != NULL)
+ ldap_value_free(rdns);
+
+ return (dns);
+}
+
+/*
+ * Convert a binary SID in a BerValue to a adutils_sid_t
+ */
+static
+int
+getsid(BerValue *bval, adutils_sid_t *sidp)
+{
+ int i, j;
+ uchar_t *v;
+ uint32_t a;
+
+ /*
+ * The binary format of a SID is as follows:
+ *
+ * byte #0: version, always 0x01
+ * byte #1: RID count, always <= 0x0f
+ * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
+ *
+ * followed by RID count RIDs, each a little-endian, unsigned
+ * 32-bit int.
+ */
+ /*
+ * Sanity checks: must have at least one RID, version must be
+ * 0x01, and the length must be 8 + rid count * 4
+ */
+ if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
+ bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
+ v = (uchar_t *)bval->bv_val;
+ sidp->version = v[0];
+ sidp->sub_authority_count = v[1];
+ sidp->authority =
+ /* big endian -- so start from the left */
+ ((u_longlong_t)v[2] << 40) |
+ ((u_longlong_t)v[3] << 32) |
+ ((u_longlong_t)v[4] << 24) |
+ ((u_longlong_t)v[5] << 16) |
+ ((u_longlong_t)v[6] << 8) |
+ (u_longlong_t)v[7];
+ for (i = 0; i < sidp->sub_authority_count; i++) {
+ j = 8 + (i * 4);
+ /* little endian -- so start from the right */
+ a = (v[j + 3] << 24) | (v[j + 2] << 16) |
+ (v[j + 1] << 8) | (v[j]);
+ sidp->sub_authorities[i] = a;
+ }
+ return (0);
+ }
+ return (-1);
+}
+
+/*
+ * Convert a adutils_sid_t to S-1-...
+ */
+static
+char *
+sid2txt(adutils_sid_t *sidp)
+{
+ int rlen, i, len;
+ char *str, *cp;
+
+ if (sidp->version != 1)
+ return (NULL);
+
+ len = sizeof ("S-1-") - 1;
+
+ /*
+ * We could optimize like so, but, why?
+ * if (sidp->authority < 10)
+ * len += 2;
+ * else if (sidp->authority < 100)
+ * len += 3;
+ * else
+ * len += snprintf(NULL, 0"%llu", sidp->authority);
+ */
+ len += snprintf(NULL, 0, "%llu", sidp->authority);
+
+ /* Max length of a uint32_t printed out in ASCII is 10 bytes */
+ len += 1 + (sidp->sub_authority_count + 1) * 10;
+
+ if ((cp = str = malloc(len)) == NULL)
+ return (NULL);
+
+ rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
+
+ cp += rlen;
+ len -= rlen;
+
+ for (i = 0; i < sidp->sub_authority_count; i++) {
+ assert(len > 0);
+ rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
+ cp += rlen;
+ len -= rlen;
+ assert(len >= 0);
+ }
+
+ return (str);
+}
+
+/*
+ * Convert a adutils_sid_t to on-the-wire encoding
+ */
+static
+int
+sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen)
+{
+ uchar_t *p;
+ int i;
+ uint64_t a;
+ uint32_t r;
+
+ if (sid->version != 1 ||
+ binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
+ return (-1);
+
+ p = binsid;
+ *p++ = 0x01; /* version */
+ /* sub authority count */
+ *p++ = sid->sub_authority_count;
+ /* Authority */
+ a = sid->authority;
+ /* big-endian -- start from left */
+ *p++ = (a >> 40) & 0xFF;
+ *p++ = (a >> 32) & 0xFF;
+ *p++ = (a >> 24) & 0xFF;
+ *p++ = (a >> 16) & 0xFF;
+ *p++ = (a >> 8) & 0xFF;
+ *p++ = a & 0xFF;
+
+ /* sub-authorities */
+ for (i = 0; i < sid->sub_authority_count; i++) {
+ r = sid->sub_authorities[i];
+ /* little-endian -- start from right */
+ *p++ = (r & 0x000000FF);
+ *p++ = (r & 0x0000FF00) >> 8;
+ *p++ = (r & 0x00FF0000) >> 16;
+ *p++ = (r & 0xFF000000) >> 24;
+ }
+
+ return (0);
+}
+
+/*
+ * Convert a stringified SID (S-1-...) into a hex-encoded version of the
+ * on-the-wire encoding, but with each pair of hex digits pre-pended
+ * with a '\', so we can pass this to libldap.
+ */
+int
+adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid,
+ char *hexbinsid, int hexbinsidlen)
+{
+ adutils_sid_t sid = { 0 };
+ int i, j;
+ const char *cp;
+ char *ecp;
+ u_longlong_t a;
+ unsigned long r;
+ uchar_t *binsid, b, hb;
+
+ /* Only version 1 SIDs please */
+ if (strncmp(txt, "S-1-", strlen("S-1-")) != 0)
+ return (-1);
+
+ if (strlen(txt) < (strlen("S-1-") + 1))
+ return (-1);
+
+ /* count '-'s */
+ for (j = 0, cp = strchr(txt, '-');
+ cp != NULL && *cp != '\0';
+ j++, cp = strchr(cp + 1, '-')) {
+ /* can't end on a '-' */
+ if (*(cp + 1) == '\0')
+ return (-1);
+ }
+
+ /* Adjust count for version and authority */
+ j -= 2;
+
+ /* we know the version number and RID count */
+ sid.version = 1;
+ sid.sub_authority_count = (rid != NULL) ? j + 1 : j;
+
+ /* must have at least one RID, but not too many */
+ if (sid.sub_authority_count < 1 ||
+ sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES)
+ return (-1);
+
+ /* check that we only have digits and '-' */
+ if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
+ return (-1);
+
+ cp = txt + strlen("S-1-");
+
+ /* 64-bit safe parsing of unsigned 48-bit authority value */
+ errno = 0;
+ a = strtoull(cp, &ecp, 10);
+
+ /* errors parsing the authority or too many bits */
+ if (cp == ecp || (a == 0 && errno == EINVAL) ||
+ (a == ULLONG_MAX && errno == ERANGE) ||
+ (a & 0x0000ffffffffffffULL) != a)
+ return (-1);
+
+ cp = ecp;
+
+ sid.authority = (uint64_t)a;
+
+ for (i = 0; i < j; i++) {
+ if (*cp++ != '-')
+ return (-1);
+ /* 64-bit safe parsing of unsigned 32-bit RID */
+ errno = 0;
+ r = strtoul(cp, &ecp, 10);
+ /* errors parsing the RID or too many bits */
+ if (cp == ecp || (r == 0 && errno == EINVAL) ||
+ (r == ULONG_MAX && errno == ERANGE) ||
+ (r & 0xffffffffUL) != r)
+ return (-1);
+ sid.sub_authorities[i] = (uint32_t)r;
+ cp = ecp;
+ }
+
+ /* check that all of the string SID has been consumed */
+ if (*cp != '\0')
+ return (-1);
+
+ if (rid != NULL)
+ sid.sub_authorities[j] = *rid;
+
+ j = 1 + 1 + 6 + sid.sub_authority_count * 4;
+
+ if (hexbinsidlen < (j * 3))
+ return (-2);
+
+ /* binary encode the SID */
+ binsid = (uchar_t *)alloca(j);
+ (void) sid2binsid(&sid, binsid, j);
+
+ /* hex encode, with a backslash before each byte */
+ for (ecp = hexbinsid, i = 0; i < j; i++) {
+ b = binsid[i];
+ *ecp++ = '\\';
+ hb = (b >> 4) & 0xF;
+ *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
+ hb = b & 0xF;
+ *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
+ }
+ *ecp = '\0';
+
+ return (0);
+}
+
+static
+char *
+convert_bval2sid(BerValue *bval, uint32_t *rid)
+{
+ adutils_sid_t sid;
+
+ if (getsid(bval, &sid) < 0)
+ return (NULL);
+
+ /*
+ * If desired and if the SID is what should be a domain/computer
+ * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
+ * save the last RID and truncate the SID
+ */
+ if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
+ *rid = sid.sub_authorities[--sid.sub_authority_count];
+ return (sid2txt(&sid));
+}
+
+
+/*
+ * Return a NUL-terminated stringified SID from the value of an
+ * objectSid attribute and put the last RID in *rid.
+ */
+char *
+adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid)
+{
+ char *sid;
+
+ if (bval == NULL)
+ return (NULL);
+ /* objectSid is single valued */
+ if ((sid = convert_bval2sid(bval, rid)) == NULL)
+ return (NULL);
+ return (sid);
+}
+
+static
+char *
+adutils_sid_ber2str(BerValue *bval)
+{
+ return (adutils_bv_objsid2sidstr(bval, NULL));
+}
+
+
+/* Return a NUL-terminated string from the Ber value */
+char *
+adutils_bv_name2str(BerValue *bval)
+{
+ char *s;
+
+ if (bval == NULL || bval->bv_val == NULL)
+ return (NULL);
+ if ((s = malloc(bval->bv_len + 1)) == NULL)
+ return (NULL);
+ (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len,
+ bval->bv_val);
+ return (s);
+}
+
+/*ARGSUSED*/
+static
+int
+saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
+{
+ sasl_interact_t *interact;
+
+ if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
+ return (LDAP_PARAM_ERROR);
+
+ /* There should be no extra arguemnts for SASL/GSSAPI authentication */
+ for (interact = prompts; interact->id != SASL_CB_LIST_END;
+ interact++) {
+ interact->result = NULL;
+ interact->len = 0;
+ }
+ return (LDAP_SUCCESS);
+}
+
+
+#define ADCONN_TIME 300
+
+/*
+ * Idle connection reaping side of connection management
+ */
+void
+adutils_reap_idle_connections()
+{
+ adutils_host_t *adh;
+ time_t now;
+
+ (void) pthread_mutex_lock(&adhostlock);
+ now = time(NULL);
+ for (adh = host_head; adh != NULL; adh = adh->next) {
+ (void) pthread_mutex_lock(&adh->lock);
+ if (adh->ref == 0 && adh->idletime != 0 &&
+ adh->idletime + ADCONN_TIME < now) {
+ if (adh->ld) {
+ (void) ldap_unbind(adh->ld);
+ adh->ld = NULL;
+ adh->idletime = 0;
+ adh->ref = 0;
+ }
+ }
+ (void) pthread_mutex_unlock(&adh->lock);
+ }
+ (void) pthread_mutex_unlock(&adhostlock);
+}
+
+
+adutils_rc
+adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain,
+ adutils_ad_partition_t part)
+{
+ adutils_ad_t *ad;
+
+ *new_ad = NULL;
+
+ if ((default_domain == NULL || *default_domain == '\0') &&
+ part != ADUTILS_AD_GLOBAL_CATALOG)
+ return (ADUTILS_ERR_DOMAIN);
+ if ((ad = calloc(1, sizeof (*ad))) == NULL)
+ return (ADUTILS_ERR_MEMORY);
+ ad->ref = 1;
+ ad->partition = part;
+ if (default_domain == NULL)
+ default_domain = "";
+ if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL)
+ goto err;
+ if (pthread_mutex_init(&ad->lock, NULL) != 0)
+ goto err;
+ *new_ad = ad;
+ return (ADUTILS_SUCCESS);
+
+err:
+ if (ad->dflt_w2k_dom != NULL)
+ free(ad->dflt_w2k_dom);
+ free(ad);
+ return (ADUTILS_ERR_MEMORY);
+}
+
+void
+adutils_ad_free(adutils_ad_t **ad)
+{
+ adutils_host_t *p;
+ adutils_host_t *prev;
+
+ if (ad == NULL || *ad == NULL)
+ return;
+
+ (void) pthread_mutex_lock(&(*ad)->lock);
+
+ if (atomic_dec_32_nv(&(*ad)->ref) > 0) {
+ (void) pthread_mutex_unlock(&(*ad)->lock);
+ *ad = NULL;
+ return;
+ }
+
+ (void) pthread_mutex_lock(&adhostlock);
+ prev = NULL;
+ p = host_head;
+ while (p != NULL) {
+ if (p->owner != (*ad)) {
+ prev = p;
+ p = p->next;
+ continue;
+ } else {
+ delete_ds((*ad), p->host, p->port);
+ if (prev == NULL)
+ p = host_head;
+ else
+ p = prev->next;
+ }
+ }
+ (void) pthread_mutex_unlock(&adhostlock);
+
+ (void) pthread_mutex_unlock(&(*ad)->lock);
+ (void) pthread_mutex_destroy(&(*ad)->lock);
+
+ free((*ad)->dflt_w2k_dom);
+ free(*ad);
+
+ *ad = NULL;
+}
+
+static
+int
+open_conn(adutils_host_t *adh, int timeoutsecs)
+{
+ int zero = 0;
+ int ldversion, rc;
+ int timeoutms = timeoutsecs * 1000;
+
+ if (adh == NULL)
+ return (0);
+
+ (void) pthread_mutex_lock(&adh->lock);
+
+ if (!adh->dead && adh->ld != NULL)
+ /* done! */
+ goto out;
+
+ if (adh->ld != NULL) {
+ (void) ldap_unbind(adh->ld);
+ adh->ld = NULL;
+ }
+ adh->num_requests = 0;
+
+ atomic_inc_64(&adh->generation);
+
+ /* Open and bind an LDAP connection */
+ adh->ld = ldap_init(adh->host, adh->port);
+ if (adh->ld == NULL) {
+ idmapdlog(LOG_INFO, "ldap_init() to server "
+ "%s port %d failed. (%s)", adh->host,
+ adh->port, strerror(errno));
+ goto out;
+ }
+ ldversion = LDAP_VERSION3;
+ (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
+ (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
+ rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */,
+ adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback,
+ NULL);
+
+ if (rc != LDAP_SUCCESS) {
+ (void) ldap_unbind(adh->ld);
+ adh->ld = NULL;
+ idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
+ "%s port %d failed. (%s)", adh->host, adh->port,
+ ldap_err2string(rc));
+ }
+
+ idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d",
+ adh->host, adh->port);
+
+out:
+ if (adh->ld != NULL) {
+ atomic_inc_32(&adh->ref);
+ adh->idletime = time(NULL);
+ adh->dead = 0;
+ (void) pthread_mutex_unlock(&adh->lock);
+ return (1);
+ }
+
+ (void) pthread_mutex_unlock(&adh->lock);
+ return (0);
+}
+
+
+/*
+ * Connection management: find an open connection or open one
+ */
+static
+adutils_host_t *
+get_conn(adutils_ad_t *ad)
+{
+ adutils_host_t *adh = NULL;
+ int tries;
+ int dscount = 0;
+ int timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT;
+
+retry:
+ (void) pthread_mutex_lock(&adhostlock);
+
+ if (host_head == NULL) {
+ (void) pthread_mutex_unlock(&adhostlock);
+ goto out;
+ }
+
+ if (dscount == 0) {
+ /*
+ * First try: count the number of DSes.
+ *
+ * Integer overflow is not an issue -- we can't have so many
+ * DSes because they won't fit even DNS over TCP, and SMF
+ * shouldn't let you set so many.
+ */
+ for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) {
+ if (adh->owner == ad)
+ dscount++;
+ }
+
+ if (dscount == 0) {
+ (void) pthread_mutex_unlock(&adhostlock);
+ goto out;
+ }
+
+ tries = dscount * 3; /* three tries per-ds */
+
+ /*
+ * Begin round-robin at the next DS in the list after the last
+ * one that we had a connection to, else start with the first
+ * DS in the list.
+ */
+ adh = ad->last_adh;
+ }
+
+ /*
+ * Round-robin -- pick the next one on the list; if the list
+ * changes on us, no big deal, we'll just potentially go
+ * around the wrong number of times.
+ */
+ for (;;) {
+ if (adh != NULL && adh->ld != NULL && !adh->dead)
+ break;
+ if (adh == NULL || (adh = adh->next) == NULL)
+ adh = host_head;
+ if (adh->owner == ad)
+ break;
+ }
+
+ ad->last_adh = adh;
+ (void) pthread_mutex_unlock(&adhostlock);
+
+ /* Found suitable DS, open it if not already opened */
+ if (open_conn(adh, timeoutsecs))
+ return (adh);
+
+ tries--;
+ if ((tries % dscount) == 0)
+ timeoutsecs *= 2;
+ if (tries > 0)
+ goto retry;
+
+out:
+ idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global "
+ "catalog server!");
+ return (NULL);
+}
+
+static
+void
+release_conn(adutils_host_t *adh)
+{
+ int delete = 0;
+
+ (void) pthread_mutex_lock(&adh->lock);
+ if (atomic_dec_32_nv(&adh->ref) == 0) {
+ if (adh->owner == NULL)
+ delete = 1;
+ adh->idletime = time(NULL);
+ }
+ (void) pthread_mutex_unlock(&adh->lock);
+
+ /* Free this host if its owner no longer exists. */
+ if (delete) {
+ (void) pthread_mutex_lock(&adhostlock);
+ delete_ds(NULL, adh->host, adh->port);
+ (void) pthread_mutex_unlock(&adhostlock);
+ }
+}
+
+/*
+ * Create a adutils_host_t, populate it and add it to the list of hosts.
+ */
+adutils_rc
+adutils_add_ds(adutils_ad_t *ad, const char *host, int port)
+{
+ adutils_host_t *p;
+ adutils_host_t *new = NULL;
+ int ret;
+ adutils_rc rc;
+
+ (void) pthread_mutex_lock(&adhostlock);
+ for (p = host_head; p != NULL; p = p->next) {
+ if (p->owner != ad)
+ continue;
+
+ if (strcmp(host, p->host) == 0 && p->port == port) {
+ /* already added */
+ rc = ADUTILS_SUCCESS;
+ goto err;
+ }
+ }
+
+ rc = ADUTILS_ERR_MEMORY;
+
+ /* add new entry */
+ new = (adutils_host_t *)calloc(1, sizeof (*new));
+ if (new == NULL)
+ goto err;
+ new->owner = ad;
+ new->port = port;
+ new->dead = 0;
+ new->max_requests = 80;
+ new->num_requests = 0;
+ if ((new->host = strdup(host)) == NULL)
+ goto err;
+ new->saslflags = LDAP_SASL_INTERACTIVE;
+ new->saslmech = "GSSAPI";
+
+ if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
+ free(new->host);
+ new->host = NULL;
+ errno = ret;
+ rc = ADUTILS_ERR_INTERNAL;
+ goto err;
+ }
+
+ /* link in */
+ rc = ADUTILS_SUCCESS;
+ new->next = host_head;
+ host_head = new;
+
+err:
+ (void) pthread_mutex_unlock(&adhostlock);
+
+ if (rc != 0 && new != NULL) {
+ if (new->host != NULL) {
+ (void) pthread_mutex_destroy(&new->lock);
+ free(new->host);
+ }
+ free(new);
+ }
+
+ return (rc);
+}
+
+/*
+ * Free a DS configuration.
+ * Caller must lock the adhostlock mutex
+ */
+static
+void
+delete_ds(adutils_ad_t *ad, const char *host, int port)
+{
+ adutils_host_t **p, *q;
+
+ for (p = &host_head; *p != NULL; p = &((*p)->next)) {
+ if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
+ (*p)->port != port)
+ continue;
+ /* found */
+
+ (void) pthread_mutex_lock(&((*p)->lock));
+ if ((*p)->ref > 0) {
+ /*
+ * Still in use. Set its owner to NULL so
+ * that it can be freed when its ref count
+ * becomes 0.
+ */
+ (*p)->owner = NULL;
+ (void) pthread_mutex_unlock(&((*p)->lock));
+ break;
+ }
+ (void) pthread_mutex_unlock(&((*p)->lock));
+
+ q = *p;
+ *p = (*p)->next;
+
+ (void) pthread_mutex_destroy(&q->lock);
+
+ if (q->ld)
+ (void) ldap_unbind(q->ld);
+ if (q->host)
+ free(q->host);
+ free(q);
+ break;
+ }
+
+}
+
+adutils_rc
+adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries,
+ adutils_ldap_res_search_cb ldap_res_search_cb,
+ void *ldap_res_search_argp,
+ adutils_query_state_t **state)
+{
+ adutils_query_state_t *new_state;
+ adutils_host_t *adh = NULL;
+
+ if (ad == NULL)
+ return (ADUTILS_ERR_INTERNAL);
+
+ *state = NULL;
+ adh = get_conn(ad);
+ if (adh == NULL)
+ return (ADUTILS_ERR_RETRIABLE_NET_ERR);
+
+ new_state = calloc(1, sizeof (adutils_query_state_t) +
+ (nqueries - 1) * sizeof (adutils_q_t));
+ if (new_state == NULL)
+ return (ADUTILS_ERR_MEMORY);
+
+ /*
+ * Save default domain from the ad object so that we don't
+ * have to access the 'ad' object later.
+ */
+ new_state->default_domain = strdup(adh->owner->dflt_w2k_dom);
+ if (new_state->default_domain == NULL) {
+ free(new_state);
+ return (ADUTILS_ERR_MEMORY);
+ }
+
+ if (ad->partition == ADUTILS_AD_DATA)
+ new_state->basedn = adutils_dns2dn(new_state->default_domain);
+ else
+ new_state->basedn = strdup("");
+ if (new_state->basedn == NULL) {
+ free(new_state->default_domain);
+ free(new_state);
+ return (ADUTILS_ERR_MEMORY);
+ }
+
+ new_state->ref_cnt = 1;
+ new_state->qadh = adh;
+ new_state->qcount = nqueries;
+ new_state->qadh_gen = adh->generation;
+ new_state->qlastsent = 0;
+ new_state->ldap_res_search_cb = ldap_res_search_cb;
+ new_state->ldap_res_search_argp = ldap_res_search_argp;
+ (void) pthread_cond_init(&new_state->cv, NULL);
+
+ (void) pthread_mutex_lock(&qstatelock);
+ new_state->next = qstatehead;
+ qstatehead = new_state;
+ (void) pthread_mutex_unlock(&qstatelock);
+ *state = new_state;
+
+ return (ADUTILS_SUCCESS);
+}
+
+/*
+ * Find the adutils_query_state_t to which a given LDAP result msgid on a
+ * given connection belongs. This routine increaments the reference count
+ * so that the object can not be freed. adutils_lookup_batch_unlock()
+ * must be called to decreament the reference count.
+ */
+static
+int
+msgid2query(adutils_host_t *adh, int msgid,
+ adutils_query_state_t **state, int *qid)
+{
+ adutils_query_state_t *p;
+ int i;
+ int ret;
+
+ (void) pthread_mutex_lock(&qstatelock);
+ for (p = qstatehead; p != NULL; p = p->next) {
+ if (p->qadh != adh || adh->generation != p->qadh_gen)
+ continue;
+ for (i = 0; i < p->qcount; i++) {
+ if ((p->queries[i]).msgid == msgid) {
+ if (!p->qdead) {
+ p->ref_cnt++;
+ *state = p;
+ *qid = i;
+ ret = 1;
+ } else
+ ret = 0;
+ (void) pthread_mutex_unlock(&qstatelock);
+ return (ret);
+ }
+ }
+ }
+ (void) pthread_mutex_unlock(&qstatelock);
+ return (0);
+}
+
+static
+int
+check_for_binary_attrs(const char *attr)
+{
+ int i;
+ for (i = 0; binattrs[i].name != NULL; i++) {
+ if (strcasecmp(binattrs[i].name, attr) == 0)
+ return (i);
+ }
+ return (-1);
+}
+
+static
+void
+free_entry(adutils_entry_t *entry)
+{
+ int i, j;
+ adutils_attr_t *ap;
+
+ if (entry == NULL)
+ return;
+ if (entry->attr_nvpairs == NULL) {
+ free(entry);
+ return;
+ }
+ for (i = 0; i < entry->num_nvpairs; i++) {
+ ap = &entry->attr_nvpairs[i];
+ if (ap->attr_name == NULL) {
+ ldap_value_free(ap->attr_values);
+ continue;
+ }
+ if (check_for_binary_attrs(ap->attr_name) >= 0) {
+ free(ap->attr_name);
+ if (ap->attr_values == NULL)
+ continue;
+ for (j = 0; j < ap->num_values; j++)
+ free(ap->attr_values[j]);
+ free(ap->attr_values);
+ } else if (strcasecmp(ap->attr_name, "dn") == 0) {
+ free(ap->attr_name);
+ ldap_memfree(ap->attr_values[0]);
+ free(ap->attr_values);
+ } else {
+ free(ap->attr_name);
+ ldap_value_free(ap->attr_values);
+ }
+ }
+ free(entry->attr_nvpairs);
+ free(entry);
+}
+
+void
+adutils_freeresult(adutils_result_t **result)
+{
+ adutils_entry_t *e, *next;
+
+ if (result == NULL || *result == NULL)
+ return;
+ if ((*result)->entries == NULL) {
+ free(*result);
+ *result = NULL;
+ return;
+ }
+ for (e = (*result)->entries; e != NULL; e = next) {
+ next = e->next;
+ free_entry(e);
+ }
+ free(*result);
+ *result = NULL;
+}
+
+const adutils_entry_t *
+adutils_getfirstentry(adutils_result_t *result)
+{
+ if (result != NULL)
+ return (result->entries);
+ return (NULL);
+}
+
+
+char **
+adutils_getattr(const adutils_entry_t *entry, const char *attrname)
+{
+ int i;
+ adutils_attr_t *ap;
+
+ if (entry == NULL || entry->attr_nvpairs == NULL)
+ return (NULL);
+ for (i = 0; i < entry->num_nvpairs; i++) {
+ ap = &entry->attr_nvpairs[i];
+ if (ap->attr_name != NULL &&
+ strcasecmp(ap->attr_name, attrname) == 0)
+ return (ap->attr_values);
+ }
+ return (NULL);
+}
+
+
+/*
+ * Queue LDAP result for the given query.
+ *
+ * Return values:
+ * 0 success
+ * -1 ignore result
+ * -2 error
+ */
+static
+int
+make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res,
+ adutils_entry_t **entry)
+{
+ BerElement *ber = NULL;
+ BerValue **bvalues = NULL;
+ char **strvalues;
+ char *attr = NULL, *dn = NULL, *domain = NULL;
+ adutils_entry_t *ep;
+ adutils_attr_t *ap;
+ int i, j, b, err = 0, ret = -2;
+
+ *entry = NULL;
+
+ /* Check that this is the domain that we were looking for */
+ if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL)
+ return (-2);
+ if ((domain = adutils_dn2dns(dn)) == NULL) {
+ ldap_memfree(dn);
+ return (-2);
+ }
+ if (q->edomain != NULL) {
+ if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
+ U8_UNICODE_LATEST, &err) != 0 || err != 0) {
+ ldap_memfree(dn);
+ free(domain);
+ return (-1);
+ }
+ }
+ free(domain);
+
+ /* Allocate memory for the entry */
+ if ((ep = calloc(1, sizeof (*ep))) == NULL)
+ goto out;
+
+ /* For 'dn' */
+ ep->num_nvpairs = 1;
+
+ /* Count the number of name-value pairs for this entry */
+ for (attr = ldap_first_attribute(adh->ld, search_res, &ber);
+ attr != NULL;
+ attr = ldap_next_attribute(adh->ld, search_res, ber)) {
+ ep->num_nvpairs++;
+ ldap_memfree(attr);
+ }
+ ber_free(ber, 0);
+ ber = NULL;
+
+ /* Allocate array for the attribute name-value pairs */
+ ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs));
+ if (ep->attr_nvpairs == NULL) {
+ ep->num_nvpairs = 0;
+ goto out;
+ }
+
+ /* For dn */
+ ap = &ep->attr_nvpairs[0];
+ if ((ap->attr_name = strdup("dn")) == NULL)
+ goto out;
+ ap->num_values = 1;
+ ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values));
+ if (ap->attr_values == NULL) {
+ ap->num_values = 0;
+ goto out;
+ }
+ ap->attr_values[0] = dn;
+ dn = NULL;
+
+ for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1;
+ attr != NULL;
+ ldap_memfree(attr), i++,
+ attr = ldap_next_attribute(adh->ld, search_res, ber)) {
+ ap = &ep->attr_nvpairs[i];
+ if ((ap->attr_name = strdup(attr)) == NULL)
+ goto out;
+
+ if ((b = check_for_binary_attrs(attr)) >= 0) {
+ bvalues =
+ ldap_get_values_len(adh->ld, search_res, attr);
+ if (bvalues == NULL)
+ continue;
+ ap->num_values = ldap_count_values_len(bvalues);
+ if (ap->num_values == 0) {
+ ldap_value_free_len(bvalues);
+ bvalues = NULL;
+ continue;
+ }
+ ap->attr_values = calloc(ap->num_values,
+ sizeof (*ap->attr_values));
+ if (ap->attr_values == NULL) {
+ ap->num_values = 0;
+ goto out;
+ }
+ for (j = 0; j < ap->num_values; j++) {
+ ap->attr_values[j] =
+ binattrs[b].ber2str(bvalues[j]);
+ if (ap->attr_values[j] == NULL)
+ goto out;
+ }
+ ldap_value_free_len(bvalues);
+ bvalues = NULL;
+ continue;
+ }
+
+ strvalues = ldap_get_values(adh->ld, search_res, attr);
+ if (strvalues == NULL)
+ continue;
+ ap->num_values = ldap_count_values(strvalues);
+ if (ap->num_values == 0) {
+ ldap_value_free(strvalues);
+ continue;
+ }
+ ap->attr_values = strvalues;
+ }
+
+ ret = 0;
+out:
+ ldap_memfree(attr);
+ ldap_memfree(dn);
+ ber_free(ber, 0);
+ ldap_value_free_len(bvalues);
+ if (ret < 0)
+ free_entry(ep);
+ else
+ *entry = ep;
+ return (ret);
+}
+
+/*
+ * Put the search result onto the given adutils_q_t.
+ * Returns: 0 success
+ * < 0 error
+ */
+static
+int
+add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res)
+{
+ int ret = -1;
+ adutils_entry_t *entry = NULL;
+ adutils_result_t *res;
+
+ ret = make_entry(q, adh, search_res, &entry);
+ if (ret < -1) {
+ *q->rc = ADUTILS_ERR_MEMORY;
+ goto out;
+ } else if (ret == -1) {
+ /* ignore result */
+ goto out;
+ }
+ if (*q->result == NULL) {
+ res = calloc(1, sizeof (*res));
+ if (res == NULL) {
+ *q->rc = ADUTILS_ERR_MEMORY;
+ goto out;
+ }
+ res->num_entries = 1;
+ res->entries = entry;
+ *q->result = res;
+ } else {
+ res = *q->result;
+ entry->next = res->entries;
+ res->entries = entry;
+ res->num_entries++;
+ }
+ *q->rc = ADUTILS_SUCCESS;
+ entry = NULL;
+ ret = 0;
+
+out:
+ free_entry(entry);
+ return (ret);
+}
+
+/*
+ * Try to get a result; if there is one, find the corresponding
+ * adutils_q_t and process the result.
+ *
+ * Returns: 0 success
+ * -1 error
+ */
+static
+int
+get_adobject_batch(adutils_host_t *adh, struct timeval *timeout)
+{
+ adutils_query_state_t *query_state;
+ LDAPMessage *res = NULL;
+ int rc, ret, msgid, qid;
+ adutils_q_t *que;
+ int num;
+
+ (void) pthread_mutex_lock(&adh->lock);
+ if (adh->dead || adh->num_requests == 0) {
+ ret = (adh->dead) ? -1 : -2;
+ (void) pthread_mutex_unlock(&adh->lock);
+ return (ret);
+ }
+
+ /* Get one result */
+ rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res);
+ if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) ||
+ rc < 0)
+ adh->dead = 1;
+
+ if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0)
+ adh->num_requests--;
+ if (adh->dead) {
+ num = adh->num_requests;
+ (void) pthread_mutex_unlock(&adh->lock);
+ idmapdlog(LOG_DEBUG,
+ "AD ldap_result error - %d queued requests", num);
+ return (-1);
+ }
+
+ switch (rc) {
+ case LDAP_RES_SEARCH_RESULT:
+ msgid = ldap_msgid(res);
+ if (msgid2query(adh, msgid, &query_state, &qid)) {
+ if (query_state->ldap_res_search_cb != NULL) {
+ /*
+ * We use the caller-provided callback
+ * to process the result.
+ */
+ query_state->ldap_res_search_cb(
+ adh->ld, &res, rc, qid,
+ query_state->ldap_res_search_argp);
+ (void) pthread_mutex_unlock(&adh->lock);
+ } else {
+ /*
+ * No callback. We fallback to our
+ * default behaviour. All the entries
+ * gotten from this search have been
+ * added to the result list during
+ * LDAP_RES_SEARCH_ENTRY (see below).
+ * Here we set the return status to
+ * notfound if the result is still empty.
+ */
+ (void) pthread_mutex_unlock(&adh->lock);
+ que = &(query_state->queries[qid]);
+ if (*que->result == NULL)
+ *que->rc = ADUTILS_ERR_NOTFOUND;
+ }
+ atomic_dec_32(&query_state->qinflight);
+ adutils_lookup_batch_unlock(&query_state);
+ } else {
+ num = adh->num_requests;
+ (void) pthread_mutex_unlock(&adh->lock);
+ idmapdlog(LOG_DEBUG,
+ "AD cannot find message ID (%d) "
+ "- %d queued requests",
+ msgid, num);
+ }
+ (void) ldap_msgfree(res);
+ ret = 0;
+ break;
+
+ case LDAP_RES_SEARCH_ENTRY:
+ msgid = ldap_msgid(res);
+ if (msgid2query(adh, msgid, &query_state, &qid)) {
+ if (query_state->ldap_res_search_cb != NULL) {
+ /*
+ * We use the caller-provided callback
+ * to process the entry.
+ */
+ query_state->ldap_res_search_cb(
+ adh->ld, &res, rc, qid,
+ query_state->ldap_res_search_argp);
+ (void) pthread_mutex_unlock(&adh->lock);
+ } else {
+ /*
+ * No callback. We fallback to our
+ * default behaviour. This entry
+ * will be added to the result list.
+ */
+ que = &(query_state->queries[qid]);
+ rc = add_entry(adh, que, res);
+ (void) pthread_mutex_unlock(&adh->lock);
+ if (rc < 0) {
+ idmapdlog(LOG_DEBUG,
+ "Failed to queue entry by "
+ "message ID (%d) "
+ "- %d queued requests",
+ msgid, num);
+ }
+ }
+ adutils_lookup_batch_unlock(&query_state);
+ } else {
+ num = adh->num_requests;
+ (void) pthread_mutex_unlock(&adh->lock);
+ idmapdlog(LOG_DEBUG,
+ "AD cannot find message ID (%d) "
+ "- %d queued requests",
+ msgid, num);
+ }
+ (void) ldap_msgfree(res);
+ ret = 0;
+ break;
+
+ case LDAP_RES_SEARCH_REFERENCE:
+ /*
+ * We have no need for these at the moment. Eventually,
+ * when we query things that we can't expect to find in
+ * the Global Catalog then we'll need to learn to follow
+ * references.
+ */
+ (void) pthread_mutex_unlock(&adh->lock);
+ (void) ldap_msgfree(res);
+ ret = 0;
+ break;
+
+ default:
+ /* timeout or error; treat the same */
+ (void) pthread_mutex_unlock(&adh->lock);
+ ret = -1;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * This routine decreament the reference count of the
+ * adutils_query_state_t
+ */
+static void
+adutils_lookup_batch_unlock(adutils_query_state_t **state)
+{
+ /*
+ * Decrement reference count with qstatelock locked
+ */
+ (void) pthread_mutex_lock(&qstatelock);
+ (*state)->ref_cnt--;
+ /*
+ * If there are no references wakup the allocating thread
+ */
+ if ((*state)->ref_cnt <= 1)
+ (void) pthread_cond_signal(&(*state)->cv);
+ (void) pthread_mutex_unlock(&qstatelock);
+ *state = NULL;
+}
+
+/*
+ * This routine frees the adutils_query_state_t structure
+ * If the reference count is greater than 1 it waits
+ * for the other threads to finish using it.
+ */
+void
+adutils_lookup_batch_release(adutils_query_state_t **state)
+{
+ adutils_query_state_t **p;
+ int i;
+
+ if (state == NULL || *state == NULL)
+ return;
+
+ /*
+ * Set state to dead to stop further operations.
+ * Wait for reference count with qstatelock locked
+ * to get to one.
+ */
+ (void) pthread_mutex_lock(&qstatelock);
+ (*state)->qdead = 1;
+ while ((*state)->ref_cnt > 1) {
+ (void) pthread_cond_wait(&(*state)->cv, &qstatelock);
+ }
+
+ /* Remove this state struct from the list of state structs */
+ for (p = &qstatehead; *p != NULL; p = &(*p)->next) {
+ if (*p == (*state)) {
+ *p = (*state)->next;
+ break;
+ }
+ }
+ (void) pthread_mutex_unlock(&qstatelock);
+ (void) pthread_cond_destroy(&(*state)->cv);
+ release_conn((*state)->qadh);
+
+ /* Clear results for queries that failed */
+ for (i = 0; i < (*state)->qcount; i++) {
+ if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) {
+ adutils_freeresult((*state)->queries[i].result);
+ }
+ }
+ free((*state)->default_domain);
+ free((*state)->basedn);
+ free(*state);
+ *state = NULL;
+}
+
+
+/*
+ * This routine waits for other threads using the
+ * adutils_query_state_t structure to finish.
+ * If the reference count is greater than 1 it waits
+ * for the other threads to finish using it.
+ */
+static
+void
+adutils_lookup_batch_wait(adutils_query_state_t *state)
+{
+ /*
+ * Set state to dead to stop further operation.
+ * stating.
+ * Wait for reference count to get to one
+ * with qstatelock locked.
+ */
+ (void) pthread_mutex_lock(&qstatelock);
+ state->qdead = 1;
+ while (state->ref_cnt > 1) {
+ (void) pthread_cond_wait(&state->cv, &qstatelock);
+ }
+ (void) pthread_mutex_unlock(&qstatelock);
+}
+
+/*
+ * Process active queries in the AD lookup batch and then finalize the
+ * result.
+ */
+adutils_rc
+adutils_lookup_batch_end(adutils_query_state_t **state)
+{
+ int rc = LDAP_SUCCESS;
+ adutils_rc ad_rc = ADUTILS_SUCCESS;
+ struct timeval tv;
+
+ tv.tv_sec = ADUTILS_SEARCH_TIMEOUT;
+ tv.tv_usec = 0;
+
+ /* Process results until done or until timeout, if given */
+ while ((*state)->qinflight > 0) {
+ if ((rc = get_adobject_batch((*state)->qadh,
+ &tv)) != 0)
+ break;
+ }
+ (*state)->qdead = 1;
+ /* Wait for other threads processing search result to finish */
+ adutils_lookup_batch_wait(*state);
+ if (rc == -1 || (*state)->qinflight != 0)
+ ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR;
+ adutils_lookup_batch_release(state);
+ return (ad_rc);
+}
+
+const char *
+adutils_lookup_batch_getdefdomain(adutils_query_state_t *state)
+{
+ return (state->default_domain);
+}
+
+/*
+ * Send one prepared search, queue up msgid, process what results are
+ * available
+ */
+adutils_rc
+adutils_lookup_batch_add(adutils_query_state_t *state,
+ const char *filter, const char **attrs, const char *edomain,
+ adutils_result_t **result, adutils_rc *rc)
+{
+ adutils_rc retcode = ADUTILS_SUCCESS;
+ int lrc, qid;
+ int num;
+ int dead;
+ struct timeval tv;
+ adutils_q_t *q;
+
+ qid = atomic_inc_32_nv(&state->qlastsent) - 1;
+ q = &(state->queries[qid]);
+
+ /*
+ * Remember the expected domain so we can check the results
+ * against it
+ */
+ q->edomain = edomain;
+
+ /* Remember where to put the results */
+ q->result = result;
+ q->rc = rc;
+
+ /*
+ * Provide sane defaults for the results in case we never hear
+ * back from the DS before closing the connection.
+ */
+ *rc = ADUTILS_ERR_RETRIABLE_NET_ERR;
+ if (result != NULL)
+ *result = NULL;
+
+ /* Check the number of queued requests first */
+ tv.tv_sec = ADUTILS_SEARCH_TIMEOUT;
+ tv.tv_usec = 0;
+ while (!state->qadh->dead &&
+ state->qadh->num_requests > state->qadh->max_requests) {
+ if (get_adobject_batch(state->qadh, &tv) != 0)
+ break;
+ }
+
+ /* Send this lookup, don't wait for a result here */
+ lrc = LDAP_SUCCESS;
+ (void) pthread_mutex_lock(&state->qadh->lock);
+
+ if (!state->qadh->dead) {
+ state->qadh->idletime = time(NULL);
+ lrc = ldap_search_ext(state->qadh->ld, state->basedn,
+ LDAP_SCOPE_SUBTREE, filter, (char **)attrs,
+ 0, NULL, NULL, NULL, -1, &q->msgid);
+
+ if (lrc == LDAP_SUCCESS) {
+ state->qadh->num_requests++;
+ } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE ||
+ lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN ||
+ lrc == LDAP_UNWILLING_TO_PERFORM) {
+ retcode = ADUTILS_ERR_RETRIABLE_NET_ERR;
+ state->qadh->dead = 1;
+ } else {
+ retcode = ADUTILS_ERR_OTHER;
+ state->qadh->dead = 1;
+ }
+ }
+ dead = state->qadh->dead;
+ num = state->qadh->num_requests;
+ (void) pthread_mutex_unlock(&state->qadh->lock);
+
+ if (dead) {
+ if (lrc != LDAP_SUCCESS)
+ idmapdlog(LOG_DEBUG,
+ "AD ldap_search_ext error (%s) "
+ "- %d queued requests",
+ ldap_err2string(lrc), num);
+ return (retcode);
+ }
+
+ atomic_inc_32(&state->qinflight);
+
+ /*
+ * Reap as many requests as we can _without_ waiting to prevent
+ * any possible TCP socket buffer starvation deadlocks.
+ */
+ (void) memset(&tv, 0, sizeof (tv));
+ while (get_adobject_batch(state->qadh, &tv) == 0)
+ ;
+
+ return (ADUTILS_SUCCESS);
+}
+
+/*
+ * Single AD lookup request implemented on top of the batch API.
+ */
+adutils_rc
+adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs,
+ const char *domain, adutils_result_t **result)
+{
+ adutils_rc rc, brc;
+ adutils_query_state_t *qs;
+
+ rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs);
+ if (rc != ADUTILS_SUCCESS)
+ return (rc);
+
+ rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
+ if (rc != ADUTILS_SUCCESS) {
+ adutils_lookup_batch_release(&qs);
+ return (rc);
+ }
+
+ rc = adutils_lookup_batch_end(&qs);
+ if (rc != ADUTILS_SUCCESS)
+ return (rc);
+ return (brc);
+}
diff --git a/usr/src/lib/libadutils/common/adutils_impl.h b/usr/src/lib/libadutils/common/adutils_impl.h
new file mode 100644
index 0000000000..847d5e384d
--- /dev/null
+++ b/usr/src/lib/libadutils/common/adutils_impl.h
@@ -0,0 +1,146 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ADUTILS_IMPL_H
+#define _ADUTILS_IMPL_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <ldap.h>
+#include <pthread.h>
+#include "addisc.h"
+#include "idmap_priv.h"
+#include "idmap_prot.h"
+#include "libadutils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ADUTILS_SEARCH_TIMEOUT 3
+#define ADUTILS_LDAP_OPEN_TIMEOUT 1
+
+typedef struct adutils_sid {
+ uchar_t version;
+ uchar_t sub_authority_count;
+ uint64_t authority; /* really, 48-bits */
+ uint32_t sub_authorities[ADUTILS_SID_MAX_SUB_AUTHORITIES];
+} adutils_sid_t;
+
+struct adutils_host;
+
+
+/* A set of DSs for a given AD partition */
+struct adutils_ad {
+ char *dflt_w2k_dom; /* used to qualify bare names */
+ pthread_mutex_t lock;
+ uint32_t ref;
+ struct adutils_host *last_adh;
+ adutils_ad_partition_t partition; /* Data or global catalog? */
+};
+
+typedef struct adutils_attr {
+ char *attr_name;
+ uint_t num_values;
+ char **attr_values;
+} adutils_attr_t;
+
+/* typedef in libadutils.h */
+struct adutils_entry {
+ uint_t num_nvpairs;
+ adutils_attr_t *attr_nvpairs;
+ struct adutils_entry *next;
+};
+
+/* typedef in libadutils.h */
+struct adutils_result {
+ uint_t num_entries;
+ adutils_entry_t *entries;
+};
+
+/* A single DS */
+typedef struct adutils_host {
+ struct adutils_host *next;
+ struct adutils_ad *owner; /* ad_t to which this belongs */
+ pthread_mutex_t lock;
+ LDAP *ld; /* LDAP connection */
+ uint32_t ref; /* ref count */
+ time_t idletime; /* time since last activity */
+ int dead; /* error on LDAP connection */
+ /*
+ * Used to distinguish between different instances of LDAP
+ * connections to this same DS. We need this so we never mix up
+ * results for a given msgID from one connection with those of
+ * another earlier connection where two batch state structures
+ * share this adutils_host object but used different LDAP connections
+ * to send their LDAP searches.
+ */
+ uint64_t generation;
+
+ /* LDAP DS info */
+ char *host;
+ int port;
+
+ /* hardwired to SASL GSSAPI only for now */
+ char *saslmech;
+ unsigned saslflags;
+
+ /* Number of outstanding search requests */
+ uint32_t max_requests;
+ uint32_t num_requests;
+} adutils_host_t;
+
+/* A place to put the results of a batched (async) query */
+typedef struct adutils_q {
+ const char *edomain; /* expected domain name */
+ struct adutils_result **result; /* The LDAP search result */
+ adutils_rc *rc;
+ int msgid; /* LDAP message ID */
+} adutils_q_t;
+
+/* Batch context structure */
+struct adutils_query_state {
+ struct adutils_query_state *next;
+ int qcount; /* how many queries */
+ int ref_cnt; /* reference count */
+ pthread_cond_t cv; /* Condition wait variable */
+ uint32_t qlastsent;
+ uint32_t qinflight; /* how many queries in flight */
+ uint16_t qdead; /* oops, lost LDAP connection */
+ adutils_host_t *qadh; /* LDAP connection */
+ uint64_t qadh_gen; /* same as qadh->generation */
+ adutils_ldap_res_search_cb ldap_res_search_cb;
+ void *ldap_res_search_argp;
+ char *default_domain;
+ char *basedn;
+ adutils_q_t queries[1]; /* array of query results */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ADUTILS_IMPL_H */
diff --git a/usr/src/lib/libadutils/common/libadutils.h b/usr/src/lib/libadutils/common/libadutils.h
new file mode 100644
index 0000000000..9a6d82a0b2
--- /dev/null
+++ b/usr/src/lib/libadutils/common/libadutils.h
@@ -0,0 +1,177 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBADUTILS_H
+#define _LIBADUTILS_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <ldap.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ADUTILS_DEF_NUM_RETRIES 2
+#define ADUTILS_SID_MAX_SUB_AUTHORITIES 15
+#define ADUTILS_MAXBINSID\
+ (1 + 1 + 6 + (ADUTILS_SID_MAX_SUB_AUTHORITIES * 4))
+#define ADUTILS_MAXHEXBINSID (ADUTILS_MAXBINSID * 3)
+
+typedef struct adutils_ad adutils_ad_t;
+typedef struct adutils_entry adutils_entry_t;
+typedef struct adutils_result adutils_result_t;
+typedef struct adutils_ctx adutils_ctx_t;
+typedef struct adutils_query_state adutils_query_state_t;
+
+/*
+ * Typedef for callback routine for adutils_lookup_batch_start.
+ * This callback routine is used to process the result of
+ * ldap_result(3LDAP).
+ * ld - LDAP handle used by ldap_result(3LDAP)
+ * res - Entry returned by ldap_result(3LDAP)
+ * rc - Return value of ldap_result(3LDAP)
+ * qid - Query ID that corresponds to the result.
+ * argp - Argument passed by the caller at the time
+ * of adutils_lookup_batch_start.
+ */
+typedef void (*adutils_ldap_res_search_cb)(LDAP *ld, LDAPMessage **res,
+ int rc, int qid, void *argp);
+
+typedef enum {
+ ADUTILS_SUCCESS = 0,
+ ADUTILS_ERR_INTERNAL = -10000,
+ ADUTILS_ERR_OTHER,
+ ADUTILS_ERR_NOTFOUND,
+ ADUTILS_ERR_RETRIABLE_NET_ERR,
+ ADUTILS_ERR_MEMORY,
+ ADUTILS_ERR_DOMAIN
+} adutils_rc;
+
+/*
+ * We use the port numbers for normal LDAP and global catalog LDAP as
+ * the enum values for this enumeration. Clever? Silly? You decide.
+ * Although we never actually use these enum values as port numbers and
+ * never will, so this is just cute.
+ */
+typedef enum adutils_ad_partition {
+ ADUTILS_AD_DATA = 389,
+ ADUTILS_AD_GLOBAL_CATALOG = 3268
+} adutils_ad_partition_t;
+
+
+/*
+ * adutils interfaces:
+ *
+ * - an adutils_ad_t represents an AD partition
+ * - a DS (hostname + port, if port != 0) can be added/removed from an
+ * adutils_ad_t
+ * - an adutils_ad_t can be allocated, ref'ed and released; last release
+ * releases resources
+ *
+ *
+ * adutils_lookup_batch_xxx interfaces:
+ *
+ * These interfaces allow the caller to batch AD lookup requests. The
+ * batched requests are processed asynchronously. The actual lookup
+ * is currently implement using libldap's ldap_search_ext(3LDAP) and
+ * ldap_result(3LDAP) APIs.
+ *
+ * Example:
+ * adutils_query_state_t *qs;
+ * adutils_lookup_batch_start(..., &qs);
+ * for each request {
+ * rc = adutils_lookup_batch_add(qs, ...);
+ * if (rc != success)
+ * break;
+ * }
+ * if (rc == success)
+ * adutils_lookup_batch_end(&qs);
+ * else
+ * adutils_lookup_batch_release(&qs);
+ *
+ * The adutils_lookup_batch_start interface allows the caller to pass
+ * in a callback function that's invoked when ldap_result() returns
+ * LDAP_RES_SEARCH_RESULT and LDAP_RES_SEARCH_ENTRY for each request.
+ *
+ * If no callback is provided then adutils batch API falls back to its
+ * default behaviour which is:
+ * For LDAP_RES_SEARCH_ENTRY, add the entry to the entry set.
+ * For LDAP_RES_SEARCH_RESULT, set return code to
+ * ADUTILS_ERR_NOTFOUND if the entry set is empty.
+ *
+ * See $SRC/cmd/idmap/idmapd/adutils.c for an example of
+ * non-default callback routine.
+ *
+ */
+
+extern adutils_rc adutils_ad_alloc(adutils_ad_t **new_ad,
+ const char *default_domain,
+ adutils_ad_partition_t part);
+extern void adutils_ad_free(adutils_ad_t **ad);
+extern adutils_rc adutils_add_ds(adutils_ad_t *ad,
+ const char *host, int port);
+extern void adutils_set_log(int pri, bool_t syslog,
+ bool_t degraded);
+extern void adutils_freeresult(adutils_result_t **result);
+extern adutils_rc adutils_lookup(adutils_ad_t *ad,
+ const char *searchfilter,
+ const char **attrs, const char *domain,
+ adutils_result_t **result);
+extern char **adutils_getattr(const adutils_entry_t *entry,
+ const char *attrname);
+extern const adutils_entry_t *adutils_getfirstentry(
+ adutils_result_t *result);
+extern int adutils_txtsid2hexbinsid(const char *txt,
+ const uint32_t *rid,
+ char *hexbinsid, int hexbinsidlen);
+extern char *adutils_bv_name2str(BerValue *bval);
+extern char *adutils_bv_objsid2sidstr(BerValue *bval,
+ uint32_t *rid);
+extern void adutils_reap_idle_connections(void);
+extern char *adutils_dn2dns(const char *dn);
+extern adutils_rc adutils_lookup_batch_start(adutils_ad_t *ad,
+ int nqueries,
+ adutils_ldap_res_search_cb ldap_res_search_cb,
+ void *ldap_res_search_argp,
+ adutils_query_state_t **state);
+extern adutils_rc adutils_lookup_batch_add(adutils_query_state_t *state,
+ const char *filter, const char **attrs,
+ const char *edomain, adutils_result_t **result,
+ adutils_rc *rc);
+extern adutils_rc adutils_lookup_batch_end(
+ adutils_query_state_t **state);
+extern void adutils_lookup_batch_release(
+ adutils_query_state_t **state);
+extern const char *adutils_lookup_batch_getdefdomain(
+ adutils_query_state_t *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBADUTILS_H */
diff --git a/usr/src/lib/libadutils/common/llib-ladutils b/usr/src/lib/libadutils/common/llib-ladutils
new file mode 100644
index 0000000000..e0f09dfe25
--- /dev/null
+++ b/usr/src/lib/libadutils/common/llib-ladutils
@@ -0,0 +1,29 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include "adutils_impl.h"
diff --git a/usr/src/lib/libadutils/common/mapfile-vers b/usr/src/lib/libadutils/common/mapfile-vers
new file mode 100644
index 0000000000..07d0065906
--- /dev/null
+++ b/usr/src/lib/libadutils/common/mapfile-vers
@@ -0,0 +1,48 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+SUNWprivate {
+ global:
+ adutils_txtsid2hexbinsid;
+ adutils_bv_name2str;
+ adutils_bv_objsid2sidstr;
+ adutils_getattr;
+ adutils_getfirstentry;
+ adutils_freeresult;
+ adutils_lookup;
+ adutils_lookup_batch_start;
+ adutils_lookup_batch_add;
+ adutils_lookup_batch_end;
+ adutils_lookup_batch_release;
+ adutils_lookup_batch_getdefdomain;
+ adutils_dn2dns;
+ adutils_reap_idle_connections;
+ adutils_ad_alloc;
+ adutils_ad_free;
+ adutils_add_ds;
+ adutils_set_log;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libadutils/i386/Makefile b/usr/src/lib/libadutils/i386/Makefile
new file mode 100644
index 0000000000..c7cca61bea
--- /dev/null
+++ b/usr/src/lib/libadutils/i386/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libadutils/sparc/Makefile b/usr/src/lib/libadutils/sparc/Makefile
new file mode 100644
index 0000000000..c7cca61bea
--- /dev/null
+++ b/usr/src/lib/libadutils/sparc/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libadutils/sparcv9/Makefile b/usr/src/lib/libadutils/sparcv9/Makefile
new file mode 100644
index 0000000000..39ae44e24b
--- /dev/null
+++ b/usr/src/lib/libadutils/sparcv9/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libc/port/gen/getgrnam_r.c b/usr/src/lib/libc/port/gen/getgrnam_r.c
index 52e1b6d0e7..7e610cd8f2 100644
--- a/usr/src/lib/libc/port/gen/getgrnam_r.c
+++ b/usr/src/lib/libc/port/gen/getgrnam_r.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "lint.h"
#include <mtlib.h>
#include <sys/types.h>
@@ -318,6 +316,7 @@ str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
char *p, *next;
int black_magic; /* "+" or "-" entry */
char **memlist, **limit;
+ ulong_t tmp;
if (lenstr + 1 > buflen)
return (NSS_STR_PARSE_ERANGE);
@@ -378,16 +377,15 @@ str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
return (NSS_STR_PARSE_PARSE);
}
if (!black_magic) {
- group->gr_gid = (gid_t)strtol(p, &next, 10);
+ tmp = strtoul(p, &next, 10);
if (next == p) {
/* gid field should be nonempty */
return (NSS_STR_PARSE_PARSE);
}
- /*
- * gids should be in the range 0 .. MAXUID
- */
- if (group->gr_gid > MAXUID)
+ if (group->gr_gid >= UINT32_MAX)
group->gr_gid = GID_NOBODY;
+ else
+ group->gr_gid = (gid_t)tmp;
}
if (*next++ != ':') {
/* Parse error, even for a '+' entry (which should have */
diff --git a/usr/src/lib/libc/port/gen/getpwnam_r.c b/usr/src/lib/libc/port/gen/getpwnam_r.c
index 7ff4d21f0d..7b7c417de5 100644
--- a/usr/src/lib/libc/port/gen/getpwnam_r.c
+++ b/usr/src/lib/libc/port/gen/getpwnam_r.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "lint.h"
#include <sys/types.h>
#include <pwd.h>
@@ -244,6 +242,7 @@ str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
struct passwd *passwd = (struct passwd *)ent;
char *p, *next;
int black_magic; /* "+" or "-" entry */
+ ulong_t tmp;
if (lenstr + 1 > buflen)
return (NSS_STR_PARSE_ERANGE);
@@ -310,7 +309,14 @@ str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
return (NSS_STR_PARSE_PARSE);
}
if (!black_magic) {
- passwd->pw_uid = (uid_t)strtol(p, &next, 10);
+ /*
+ * strtoul returns unsigned long which is
+ * 8 bytes on a 64-bit system. We don't want
+ * to assign it directly to passwd->pw_uid
+ * which is 4 bytes or else we will end up
+ * truncating the value.
+ */
+ tmp = strtoul(p, &next, 10);
if (next == p) {
/* uid field should be nonempty */
return (NSS_STR_PARSE_PARSE);
@@ -321,11 +327,13 @@ str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
* than 60001 (the rfs limit). If it met either of
* these conditions, the uid was translated to 60001.
*
- * Now we just check for negative uids; anything else
+ * Now we just check for -1 (UINT32_MAX); anything else
* is administrative policy
*/
- if (passwd->pw_uid > MAXUID)
+ if (tmp >= UINT32_MAX)
passwd->pw_uid = UID_NOBODY;
+ else
+ passwd->pw_uid = (uid_t)tmp;
}
if (*next++ != ':') {
if (black_magic)
@@ -341,17 +349,19 @@ str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
return (NSS_STR_PARSE_PARSE);
}
if (!black_magic) {
- passwd->pw_gid = (gid_t)strtol(p, &next, 10);
+ tmp = strtoul(p, &next, 10);
if (next == p) {
/* gid field should be nonempty */
return (NSS_STR_PARSE_PARSE);
}
/*
- * gid should be non-negative; anything else
+ * gid should not be -1; anything else
* is administrative policy.
*/
- if (passwd->pw_gid > MAXUID)
+ if (passwd->pw_gid >= UINT32_MAX)
passwd->pw_gid = GID_NOBODY;
+ else
+ passwd->pw_gid = (gid_t)tmp;
}
if (*next++ != ':') {
if (black_magic)
diff --git a/usr/src/lib/libc/port/gen/putpwent.c b/usr/src/lib/libc/port/gen/putpwent.c
index efc482c7f4..b4c1928902 100644
--- a/usr/src/lib/libc/port/gen/putpwent.c
+++ b/usr/src/lib/libc/port/gen/putpwent.c
@@ -27,8 +27,6 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* format a password file entry
*/
@@ -55,7 +53,7 @@ putpwent(const struct passwd *p, FILE *f)
p->pw_dir ? p->pw_dir : "",
p->pw_shell ? p->pw_shell : "");
} else { /* "normal case" */
- (void) fprintf(f, ":%d:%d:%s:%s:%s",
+ (void) fprintf(f, ":%u:%u:%s:%s:%s",
p->pw_uid,
p->pw_gid,
p->pw_gecos,
diff --git a/usr/src/lib/libidmap/common/idmap_api.c b/usr/src/lib/libidmap/common/idmap_api.c
index ef6079f0c0..69ed433d98 100644
--- a/usr/src/lib/libidmap/common/idmap_api.c
+++ b/usr/src/lib/libidmap/common/idmap_api.c
@@ -124,7 +124,7 @@ idmap_free(void *ptr)
}
-#define MIN_STACK_NEEDS 16384
+#define MIN_STACK_NEEDS 65536
/*
* Create and Initialize idmap client handle for rpc/doors
@@ -163,16 +163,19 @@ idmap_init(idmap_handle_t **handle)
/* stack grows down */
sendsz = ((char *)&sendsz - (char *)st.ss_sp);
- /*
- * Take much of the stack space left, divided by two,
- * but leave enough for our needs (just a guess!), and
- * if we can't, then roll the dice.
- */
- sendsz = RNDUP(sendsz / 2);
- if (sendsz < MIN_STACK_NEEDS)
+ if (sendsz <= MIN_STACK_NEEDS) {
sendsz = 0; /* RPC call may fail */
- else if (sendsz > IDMAP_MAX_DOOR_RPC)
- sendsz = IDMAP_MAX_DOOR_RPC;
+ } else {
+ /* Leave 64Kb (just a guess) for our needs */
+ sendsz -= MIN_STACK_NEEDS;
+
+ /* Divide the stack space left by two */
+ sendsz = RNDUP(sendsz / 2);
+
+ /* Limit sendsz to 256KB */
+ if (sendsz > IDMAP_MAX_DOOR_RPC)
+ sendsz = IDMAP_MAX_DOOR_RPC;
+ }
}
clnt = clnt_door_create(IDMAP_PROG, IDMAP_V1, sendsz);
diff --git a/usr/src/lib/nsswitch/Makefile b/usr/src/lib/nsswitch/Makefile
index dda261d132..76c882d0f9 100644
--- a/usr/src/lib/nsswitch/Makefile
+++ b/usr/src/lib/nsswitch/Makefile
@@ -19,9 +19,7 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# lib/nsswitch/Makefile
@@ -29,7 +27,7 @@
include $(SRC)/Makefile.master
-SUBDIRS= files nis nisplus compat dns ldap user mdns
+SUBDIRS= files nis nisplus compat dns ldap user mdns ad
all:= TARGET= all
clean:= TARGET= clean
diff --git a/usr/src/lib/nsswitch/ad/Makefile b/usr/src/lib/nsswitch/ad/Makefile
new file mode 100644
index 0000000000..284c347307
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/Makefile
@@ -0,0 +1,46 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# lib/nsswitch/ad/Makefile
+#
+
+include ../../../Makefile.master
+
+FILES_SUBDIRS= $(MACH) $(BUILD64) $(MACH64)
+
+all:= TARGET= all
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+install:= TARGET= install
+lint:= TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(FILES_SUBDIRS)
+
+$(MACH) $(MACH64): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/nsswitch/ad/Makefile.com b/usr/src/lib/nsswitch/ad/Makefile.com
new file mode 100644
index 0000000000..0b50f606ac
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/Makefile.com
@@ -0,0 +1,39 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# lib/nsswitch/ad/Makefile.com
+
+LIBRARY = libnss_ad.a
+VERS = .1
+OBJECTS = getpwnam.o getspent.o getgrent.o ad_common.o
+IDMAP_PROT_DIR = $(SRC)/head/rpcsvc
+
+# include common nsswitch library definitions.
+include ../../Makefile.com
+
+CPPFLAGS += -I../../../libadutils/common -I../../../libidmap/common \
+ -I$(IDMAP_PROT_DIR)
+LDLIBS += -ladutils -lidmap
+DYNLIB1 = nss_ad.so$(VERS)
diff --git a/usr/src/lib/nsswitch/ad/amd64/Makefile b/usr/src/lib/nsswitch/ad/amd64/Makefile
new file mode 100644
index 0000000000..6e71c56dcc
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+LIBS = $(DYNLIB1)
+
+include ../../Makefile.targ
+
+install: all $(ROOT64DYNLIB)
diff --git a/usr/src/lib/nsswitch/ad/common/ad_common.c b/usr/src/lib/nsswitch/ad/common/ad_common.c
new file mode 100644
index 0000000000..9265defe13
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/common/ad_common.c
@@ -0,0 +1,534 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <malloc.h>
+#include <synch.h>
+#include <syslog.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#include <pthread.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include "ad_common.h"
+
+static pthread_mutex_t statelock = PTHREAD_MUTEX_INITIALIZER;
+static nssad_state_t state = {0};
+
+static void
+nssad_cfg_free_props(nssad_prop_t *props)
+{
+ if (props->domain_name != NULL) {
+ free(props->domain_name);
+ props->domain_name = NULL;
+ }
+ if (props->domain_controller != NULL) {
+ free(props->domain_controller);
+ props->domain_controller = NULL;
+ }
+}
+
+static int
+nssad_cfg_discover_props(const char *domain, ad_disc_t ad_ctx,
+ nssad_prop_t *props)
+{
+ ad_disc_refresh(ad_ctx);
+ if (ad_disc_set_DomainName(ad_ctx, domain) != 0)
+ return (-1);
+ if (props->domain_controller == NULL)
+ props->domain_controller =
+ ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE);
+ return (0);
+}
+
+static int
+nssad_cfg_reload_ad(nssad_prop_t *props, adutils_ad_t **ad)
+{
+ int i;
+ adutils_ad_t *new;
+
+ if (props->domain_controller == NULL ||
+ props->domain_controller[0].host[0] == '\0')
+ return (0);
+ if (adutils_ad_alloc(&new, props->domain_name,
+ ADUTILS_AD_DATA) != ADUTILS_SUCCESS)
+ return (-1);
+ for (i = 0; props->domain_controller[i].host[0] != '\0'; i++) {
+ if (adutils_add_ds(new,
+ props->domain_controller[i].host,
+ props->domain_controller[i].port) != ADUTILS_SUCCESS) {
+ adutils_ad_free(&new);
+ return (-1);
+ }
+ }
+
+ if (*ad != NULL)
+ adutils_ad_free(ad);
+ *ad = new;
+ return (0);
+}
+
+static
+int
+update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new)
+{
+ if (*value == *new)
+ return (0);
+
+ if (*value != NULL && *new != NULL &&
+ ad_disc_compare_ds(*value, *new) == 0) {
+ free(*new);
+ *new = NULL;
+ return (0);
+ }
+
+ if (*value)
+ free(*value);
+ *value = *new;
+ *new = NULL;
+ return (1);
+}
+
+static
+int
+nssad_cfg_refresh(nssad_cfg_t *cp)
+{
+ nssad_prop_t props;
+
+ (void) ad_disc_SubnetChanged(cp->ad_ctx);
+ (void) memset(&props, 0, sizeof (props));
+ if (nssad_cfg_discover_props(cp->props.domain_name, cp->ad_ctx,
+ &props) < 0)
+ return (-1);
+ if (update_dirs(&cp->props.domain_controller,
+ &props.domain_controller)) {
+ if (cp->props.domain_controller != NULL &&
+ cp->props.domain_controller[0].host[0] != '\0')
+ (void) nssad_cfg_reload_ad(&cp->props, &cp->ad);
+ }
+ return (0);
+}
+
+static void
+nssad_cfg_destroy(nssad_cfg_t *cp)
+{
+ if (cp != NULL) {
+ (void) pthread_rwlock_destroy(&cp->lock);
+ ad_disc_fini(cp->ad_ctx);
+ nssad_cfg_free_props(&cp->props);
+ adutils_ad_free(&cp->ad);
+ free(cp);
+ }
+}
+
+static nssad_cfg_t *
+nssad_cfg_create(const char *domain)
+{
+ nssad_cfg_t *cp;
+
+ if ((cp = calloc(1, sizeof (*cp))) == NULL)
+ return (NULL);
+ if (pthread_rwlock_init(&cp->lock, NULL) != 0) {
+ free(cp);
+ return (NULL);
+ }
+ adutils_set_log(-1, TRUE, FALSE);
+ if ((cp->ad_ctx = ad_disc_init()) == NULL)
+ goto errout;
+ if ((cp->props.domain_name = strdup(domain)) == NULL)
+ goto errout;
+ if (nssad_cfg_discover_props(domain, cp->ad_ctx, &cp->props) < 0)
+ goto errout;
+ if (nssad_cfg_reload_ad(&cp->props, &cp->ad) < 0)
+ goto errout;
+ return (cp);
+errout:
+ nssad_cfg_destroy(cp);
+ return (NULL);
+}
+
+#define hex_char(n) "0123456789abcdef"[n & 0xf]
+
+int
+_ldap_filter_name(char *filter_name, const char *name, int filter_name_size)
+{
+ char *end = filter_name + filter_name_size;
+ char c;
+
+ for (; *name; name++) {
+ c = *name;
+ switch (c) {
+ case '*':
+ case '(':
+ case ')':
+ case '\\':
+ if (end <= filter_name + 3)
+ return (-1);
+ *filter_name++ = '\\';
+ *filter_name++ = hex_char(c >> 4);
+ *filter_name++ = hex_char(c & 0xf);
+ break;
+ default:
+ if (end <= filter_name + 1)
+ return (-1);
+ *filter_name++ = c;
+ break;
+ }
+ }
+ if (end <= filter_name)
+ return (-1);
+ *filter_name = '\0';
+ return (0);
+}
+
+static
+nss_status_t
+map_adrc2nssrc(adutils_rc adrc)
+{
+ if (adrc == ADUTILS_SUCCESS)
+ return ((nss_status_t)NSS_SUCCESS);
+ if (adrc == ADUTILS_ERR_NOTFOUND)
+ errno = 0;
+ return ((nss_status_t)NSS_NOTFOUND);
+}
+
+/* ARGSUSED */
+nss_status_t
+_nss_ad_marshall_data(ad_backend_ptr be, nss_XbyY_args_t *argp)
+{
+ int stat;
+
+ if (argp->buf.result == NULL) {
+ /*
+ * This suggests that the process (e.g. nscd) expects
+ * nssad to return the data in native file format in
+ * argp->buf.buffer i.e. no need to marshall the data.
+ */
+ argp->returnval = argp->buf.buffer;
+ argp->returnlen = strlen(argp->buf.buffer);
+ return ((nss_status_t)NSS_STR_PARSE_SUCCESS);
+ }
+
+ if (argp->str2ent == NULL)
+ return ((nss_status_t)NSS_STR_PARSE_PARSE);
+
+ stat = (*argp->str2ent)(be->buffer, be->buflen,
+ argp->buf.result, argp->buf.buffer, argp->buf.buflen);
+
+ if (stat == NSS_STR_PARSE_SUCCESS) {
+ argp->returnval = argp->buf.result;
+ argp->returnlen = 1; /* irrelevant */
+ }
+ return ((nss_status_t)stat);
+}
+
+nss_status_t
+_nss_ad_sanitize_status(ad_backend_ptr be, nss_XbyY_args_t *argp,
+ nss_status_t stat)
+{
+ if (be->buffer != NULL) {
+ free(be->buffer);
+ be->buffer = NULL;
+ be->buflen = 0;
+ be->db_type = NSS_AD_DB_NONE;
+ }
+
+ if (stat == NSS_STR_PARSE_SUCCESS) {
+ return ((nss_status_t)NSS_SUCCESS);
+ } else if (stat == NSS_STR_PARSE_PARSE) {
+ argp->returnval = 0;
+ return ((nss_status_t)NSS_NOTFOUND);
+ } else if (stat == NSS_STR_PARSE_ERANGE) {
+ argp->erange = 1;
+ return ((nss_status_t)NSS_NOTFOUND);
+ }
+ return ((nss_status_t)NSS_UNAVAIL);
+}
+
+/* ARGSUSED */
+static
+nssad_cfg_t *
+get_cfg(const char *domain)
+{
+ nssad_cfg_t *cp, *lru, *prev;
+
+ /*
+ * Note about the queue:
+ *
+ * The queue is used to hold our per domain
+ * configs. The queue is limited to CFG_QUEUE_MAX_SIZE.
+ * If the queue increases beyond that point we toss
+ * out the LRU entry. The entries are inserted into
+ * the queue at state.qtail and the LRU entry is
+ * removed from state.qhead. state.qnext points
+ * from the qtail to the qhead. Everytime a config
+ * is accessed it is moved to qtail.
+ */
+
+ (void) pthread_mutex_lock(&statelock);
+
+ for (cp = state.qtail, prev = NULL; cp != NULL;
+ prev = cp, cp = cp->qnext) {
+ if (cp->props.domain_name == NULL ||
+ strcasecmp(cp->props.domain_name, domain) != 0)
+ continue;
+
+ /* Found config for the given domain. */
+
+ if (state.qtail != cp) {
+ /*
+ * Move the entry to the tail of the queue.
+ * This way the LRU entry can be found at
+ * the head of the queue.
+ */
+ prev->qnext = cp->qnext;
+ if (state.qhead == cp)
+ state.qhead = prev;
+ cp->qnext = state.qtail;
+ state.qtail = cp;
+ }
+
+ if (ad_disc_get_TTL(cp->ad_ctx) == 0) {
+ /*
+ * If there are expired items in the
+ * config, grab the write lock and
+ * refresh the config.
+ */
+ (void) pthread_rwlock_wrlock(&cp->lock);
+ if (nssad_cfg_refresh(cp) < 0) {
+ (void) pthread_rwlock_unlock(&cp->lock);
+ (void) pthread_mutex_unlock(&statelock);
+ return (NULL);
+ }
+ (void) pthread_rwlock_unlock(&cp->lock);
+ }
+
+ /* Return the config found */
+ (void) pthread_rwlock_rdlock(&cp->lock);
+ (void) pthread_mutex_unlock(&statelock);
+ return (cp);
+ }
+
+ /* Create new config entry for the domain */
+ if ((cp = nssad_cfg_create(domain)) == NULL) {
+ (void) pthread_mutex_unlock(&statelock);
+ return (NULL);
+ }
+
+ /* Add it to the queue */
+ state.qcount++;
+ if (state.qtail == NULL) {
+ state.qtail = state.qhead = cp;
+ (void) pthread_rwlock_rdlock(&cp->lock);
+ (void) pthread_mutex_unlock(&statelock);
+ return (cp);
+ }
+ cp->qnext = state.qtail;
+ state.qtail = cp;
+
+ /* If the queue has exceeded its size, remove the LRU entry */
+ if (state.qcount >= CFG_QUEUE_MAX_SIZE) {
+ /* Detach the lru entry and destroy */
+ lru = state.qhead;
+ if (pthread_rwlock_trywrlock(&lru->lock) == 0) {
+ for (prev = state.qtail; prev != NULL;
+ prev = prev->qnext) {
+ if (prev->qnext != lru)
+ continue;
+ state.qhead = prev;
+ prev->qnext = NULL;
+ state.qcount--;
+ (void) pthread_rwlock_unlock(&lru->lock);
+ nssad_cfg_destroy(lru);
+ break;
+ }
+ (void) assert(prev != NULL);
+ }
+ }
+
+ (void) pthread_rwlock_rdlock(&cp->lock);
+ (void) pthread_mutex_unlock(&statelock);
+ return (cp);
+}
+
+
+/* ARGSUSED */
+static
+nss_status_t
+ad_lookup(const char *filter, const char **attrs,
+ const char *domain, adutils_result_t **result)
+{
+ int retries = 0;
+ adutils_rc rc, brc;
+ adutils_query_state_t *qs;
+ nssad_cfg_t *cp;
+
+retry:
+ if ((cp = get_cfg(domain)) == NULL)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ rc = adutils_lookup_batch_start(cp->ad, 1, NULL, NULL, &qs);
+ (void) pthread_rwlock_unlock(&cp->lock);
+ if (rc != ADUTILS_SUCCESS)
+ goto out;
+
+ rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
+ if (rc != ADUTILS_SUCCESS) {
+ adutils_lookup_batch_release(&qs);
+ goto out;
+ }
+
+ rc = adutils_lookup_batch_end(&qs);
+ if (rc != ADUTILS_SUCCESS)
+ goto out;
+ rc = brc;
+
+out:
+ if (rc == ADUTILS_ERR_RETRIABLE_NET_ERR &&
+ retries++ < ADUTILS_DEF_NUM_RETRIES)
+ goto retry;
+ return (map_adrc2nssrc(rc));
+}
+
+
+/* ARGSUSED */
+nss_status_t
+_nss_ad_lookup(ad_backend_ptr be, nss_XbyY_args_t *argp,
+ const char *database, const char *searchfilter,
+ const char *dname, int *try_idmap)
+{
+ nss_status_t stat;
+
+ *try_idmap = 0;
+
+ /* Clear up results if any */
+ (void) adutils_freeresult(&be->result);
+
+ /* Lookup AD */
+ stat = ad_lookup(searchfilter, be->attrs, dname, &be->result);
+ if (stat != NSS_SUCCESS) {
+ argp->returnval = 0;
+ *try_idmap = 1;
+ return (stat);
+ }
+
+ /* Map AD object(s) to string in native file format */
+ stat = be->adobj2str(be, argp);
+ if (stat == NSS_STR_PARSE_SUCCESS)
+ stat = _nss_ad_marshall_data(be, argp);
+ return (_nss_ad_sanitize_status(be, argp, stat));
+}
+
+static
+void
+clean_state()
+{
+ nssad_cfg_t *cp, *curr;
+
+ (void) pthread_mutex_lock(&statelock);
+ for (cp = state.qtail; cp != NULL; ) {
+ curr = cp;
+ cp = cp->qnext;
+ nssad_cfg_destroy(curr);
+ }
+ (void) memset(&state, 0, sizeof (state));
+ (void) pthread_mutex_unlock(&statelock);
+}
+
+static
+void
+_clean_ad_backend(ad_backend_ptr be)
+{
+ if (be->tablename != NULL)
+ free(be->tablename);
+ if (be->buffer != NULL) {
+ free(be->buffer);
+ be->buffer = NULL;
+ }
+ free(be);
+}
+
+
+/*
+ * _nss_ad_destr frees allocated memory before exiting this nsswitch shared
+ * backend library. This function is called before returning control back to
+ * nsswitch.
+ */
+/*ARGSUSED*/
+nss_status_t
+_nss_ad_destr(ad_backend_ptr be, void *a)
+{
+ (void) _clean_ad_backend(be);
+ clean_state();
+ return ((nss_status_t)NSS_SUCCESS);
+}
+
+
+/*ARGSUSED*/
+nss_status_t
+_nss_ad_setent(ad_backend_ptr be, void *a)
+{
+ return ((nss_status_t)NSS_UNAVAIL);
+}
+
+
+/*ARGSUSED*/
+nss_status_t
+_nss_ad_endent(ad_backend_ptr be, void *a)
+{
+ return ((nss_status_t)NSS_UNAVAIL);
+}
+
+
+/*ARGSUSED*/
+nss_status_t
+_nss_ad_getent(ad_backend_ptr be, void *a)
+{
+ return ((nss_status_t)NSS_UNAVAIL);
+}
+
+
+nss_backend_t *
+_nss_ad_constr(ad_backend_op_t ops[], int nops, char *tablename,
+ const char **attrs, fnf adobj2str)
+{
+ ad_backend_ptr be;
+
+ if ((be = (ad_backend_ptr) calloc(1, sizeof (*be))) == NULL)
+ return (NULL);
+ if ((be->tablename = (char *)strdup(tablename)) == NULL) {
+ free(be);
+ return (NULL);
+ }
+ be->ops = ops;
+ be->nops = (nss_dbop_t)nops;
+ be->attrs = attrs;
+ be->adobj2str = adobj2str;
+ (void) memset(&state, 0, sizeof (state));
+ return ((nss_backend_t *)be);
+}
diff --git a/usr/src/lib/nsswitch/ad/common/ad_common.h b/usr/src/lib/nsswitch/ad/common/ad_common.h
new file mode 100644
index 0000000000..a6c74fba02
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/common/ad_common.h
@@ -0,0 +1,132 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _AD_COMMON_H
+#define _AD_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ctype.h>
+#include <nss_dbdefs.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <signal.h>
+#include <idmap.h>
+#include <sys/idmap.h>
+#include <idmap_prot.h>
+#include <idmap_priv.h>
+#include "addisc.h"
+#include "libadutils.h"
+
+#define _GROUP "group"
+#define _PASSWD "passwd"
+#define _SHADOW "shadow"
+
+#define WK_DOMAIN "BUILTIN"
+#define CFG_QUEUE_MAX_SIZE 15
+
+#define SEARCHFILTERLEN 256
+#define RESET_ERRNO()\
+ if (errno == EINVAL)\
+ errno = 0;
+
+/*
+ * Superset the nss_backend_t abstract data type. This ADT has
+ * been extended to include AD associated data structures.
+ */
+
+typedef struct ad_backend *ad_backend_ptr;
+typedef nss_status_t (*ad_backend_op_t)(ad_backend_ptr, void *);
+typedef int (*fnf)(ad_backend_ptr be, nss_XbyY_args_t *argp);
+
+typedef enum {
+ NSS_AD_DB_NONE = 0,
+ NSS_AD_DB_PASSWD_BYNAME = 1,
+ NSS_AD_DB_PASSWD_BYUID = 2,
+ NSS_AD_DB_GROUP_BYNAME = 3,
+ NSS_AD_DB_GROUP_BYGID = 4,
+ NSS_AD_DB_SHADOW_BYNAME = 5
+} nss_ad_db_type_t;
+
+struct ad_backend {
+ ad_backend_op_t *ops;
+ nss_dbop_t nops;
+ char *tablename;
+ const char **attrs;
+ fnf adobj2str;
+ char *buffer;
+ int buflen;
+ idmap_handle_t *ih;
+ uid_t uid;
+ adutils_result_t *result;
+ nss_ad_db_type_t db_type;
+};
+
+typedef struct nssad_prop {
+ char *domain_name;
+ idmap_ad_disc_ds_t *domain_controller;
+} nssad_prop_t;
+
+typedef struct nssad_cfg {
+ pthread_rwlock_t lock;
+ nssad_prop_t props;
+ ad_disc_t ad_ctx;
+ adutils_ad_t *ad;
+ struct nssad_cfg *qnext;
+} nssad_cfg_t;
+
+typedef struct nssad_state {
+ nssad_cfg_t *qhead;
+ nssad_cfg_t *qtail;
+ uint32_t qcount;
+} nssad_state_t;
+
+extern nss_status_t _nss_ad_destr(ad_backend_ptr be, void *a);
+extern nss_status_t _nss_ad_endent(ad_backend_ptr be, void *a);
+extern nss_status_t _nss_ad_setent(ad_backend_ptr be, void *a);
+extern nss_status_t _nss_ad_getent(ad_backend_ptr be, void *a);
+nss_backend_t *_nss_ad_constr(ad_backend_op_t ops[], int nops,
+ char *tablename, const char **attrs, fnf ldapobj2str);
+extern nss_status_t _nss_ad_lookup(ad_backend_ptr be,
+ nss_XbyY_args_t *argp, const char *database,
+ const char *searchfilter, const char *dname,
+ int *try_idmap);
+extern nss_status_t _nss_ad_marshall_data(ad_backend_ptr be,
+ nss_XbyY_args_t *argp);
+extern nss_status_t _nss_ad_sanitize_status(ad_backend_ptr be,
+ nss_XbyY_args_t *argp, nss_status_t stat);
+extern int _ldap_filter_name(char *filter_name, const char *name,
+ int filter_name_size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AD_COMMON_H */
diff --git a/usr/src/lib/nsswitch/ad/common/getgrent.c b/usr/src/lib/nsswitch/ad/common/getgrent.c
new file mode 100644
index 0000000000..b5f70666ba
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/common/getgrent.c
@@ -0,0 +1,186 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <grp.h>
+#include <idmap.h>
+#include "ad_common.h"
+
+static int
+update_buffer(ad_backend_ptr be, nss_XbyY_args_t *argp,
+ const char *name, const char *domain, gid_t gid)
+{
+ int buflen;
+ char *buffer;
+
+ if (domain == NULL)
+ domain = WK_DOMAIN;
+
+ buflen = snprintf(NULL, 0, "%s@%s::%u:", name, domain, gid) + 1;
+
+ if (argp->buf.result != NULL) {
+ buffer = be->buffer = malloc(buflen);
+ if (be->buffer == NULL)
+ return (-1);
+ be->buflen = buflen;
+ } else {
+ if (buflen > argp->buf.buflen)
+ return (-1);
+ buflen = argp->buf.buflen;
+ buffer = argp->buf.buffer;
+ }
+
+ (void) snprintf(buffer, buflen, "%s@%s::%u:", name, domain, gid);
+ return (0);
+}
+
+/*
+ * getbynam gets a group entry by name. This function constructs an ldap
+ * search filter using the name invocation parameter and the getgrnam search
+ * filter defined. Once the filter is constructed, we search for a matching
+ * entry and marshal the data results into struct group for the frontend
+ * process. The function _nss_ad_group2ent performs the data marshaling.
+ */
+static nss_status_t
+getbynam(ad_backend_ptr be, void *a)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ char name[SEARCHFILTERLEN];
+ char *dname;
+ nss_status_t stat;
+ idmap_stat idmaprc;
+ gid_t gid;
+ int is_user, is_wuser;
+ idmap_handle_t *ih;
+
+ be->db_type = NSS_AD_DB_GROUP_BYNAME;
+
+ /* Sanitize name so that it can be used in our LDAP filter */
+ if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ if ((dname = strchr(name, '@')) == NULL)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ *dname = '\0';
+ dname++;
+
+ /*
+ * Map the name to gid using idmap service.
+ */
+ idmaprc = idmap_init(&ih);
+ if (idmaprc != IDMAP_SUCCESS)
+ return ((nss_status_t)NSS_NOTFOUND);
+ is_wuser = -1;
+ is_user = 0; /* Map name to gid */
+ idmaprc = idmap_get_w2u_mapping(ih, NULL, NULL, name, dname,
+ 0, &is_user, &is_wuser, &gid, NULL, NULL, NULL);
+ (void) idmap_fini(ih);
+ if (idmaprc != IDMAP_SUCCESS) {
+ RESET_ERRNO();
+ return ((nss_status_t)NSS_NOTFOUND);
+ }
+
+ /* Create group(4) style string */
+ if (update_buffer(be, argp, name, dname, gid) < 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ /* Marshall the data, sanitize the return status and return */
+ stat = _nss_ad_marshall_data(be, argp);
+ return (_nss_ad_sanitize_status(be, argp, stat));
+}
+
+/*
+ * getbygid gets a group entry by number. This function constructs an ldap
+ * search filter using the name invocation parameter and the getgrgid search
+ * filter defined. Once the filter is constructed, we searche for a matching
+ * entry and marshal the data results into struct group for the frontend
+ * process. The function _nss_ad_group2ent performs the data marshaling.
+ */
+static nss_status_t
+getbygid(ad_backend_ptr be, void *a)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ char *winname = NULL, *windomain = NULL;
+ nss_status_t stat;
+
+ be->db_type = NSS_AD_DB_GROUP_BYGID;
+
+ stat = (nss_status_t)NSS_NOTFOUND;
+
+ /* nss_ad does not support non ephemeral gids */
+ if (argp->key.gid <= MAXUID)
+ goto out;
+
+ /* Map the given GID to a SID using the idmap service */
+ if (idmap_init(&be->ih) != 0)
+ goto out;
+ if (idmap_get_u2w_mapping(be->ih, &argp->key.gid, NULL, 0,
+ 0, NULL, NULL, NULL, &winname, &windomain,
+ NULL, NULL) != 0) {
+ RESET_ERRNO();
+ goto out;
+ }
+
+ /*
+ * NULL winname implies a local SID or unresolvable SID both of
+ * which cannot be used to generated group(4) entry
+ */
+ if (winname == NULL)
+ goto out;
+
+ /* Create group(4) style string */
+ if (update_buffer(be, argp, winname, windomain, argp->key.gid) < 0)
+ goto out;
+
+ /* Marshall the data, sanitize the return status and return */
+ stat = _nss_ad_marshall_data(be, argp);
+ stat = _nss_ad_sanitize_status(be, argp, stat);
+
+out:
+ idmap_free(winname);
+ idmap_free(windomain);
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+ return (stat);
+}
+
+static ad_backend_op_t gr_ops[] = {
+ _nss_ad_destr,
+ _nss_ad_endent,
+ _nss_ad_setent,
+ _nss_ad_getent,
+ getbynam,
+ getbygid
+};
+
+/*ARGSUSED0*/
+nss_backend_t *
+_nss_ad_group_constr(const char *dummy1, const char *dummy2,
+ const char *dummy3)
+{
+
+ return ((nss_backend_t *)_nss_ad_constr(gr_ops,
+ sizeof (gr_ops)/sizeof (gr_ops[0]), _GROUP, NULL, NULL));
+}
diff --git a/usr/src/lib/nsswitch/ad/common/getpwnam.c b/usr/src/lib/nsswitch/ad/common/getpwnam.c
new file mode 100644
index 0000000000..ece50a54b0
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/common/getpwnam.c
@@ -0,0 +1,518 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <pwd.h>
+#include <idmap.h>
+#include <ctype.h>
+#include "ad_common.h"
+
+/* passwd attributes and filters */
+#define _PWD_DN "dn"
+#define _PWD_SAN "sAMAccountName"
+#define _PWD_OBJSID "objectSid"
+#define _PWD_PRIMARYGROUPID "primaryGroupID"
+#define _PWD_CN "cn"
+#define _PWD_HOMEDIRECTORY "homedirectory"
+#define _PWD_LOGINSHELL "loginshell"
+#define _PWD_OBJCLASS "objectClass"
+
+#define _F_GETPWNAM "(sAMAccountName=%.*s)"
+#define _F_GETPWUID "(objectSid=%s)"
+
+static const char *pwd_attrs[] = {
+ _PWD_SAN,
+ _PWD_OBJSID,
+ _PWD_PRIMARYGROUPID,
+ _PWD_CN,
+ _PWD_HOMEDIRECTORY,
+ _PWD_LOGINSHELL,
+ _PWD_OBJCLASS,
+ (char *)NULL
+};
+
+static int
+update_buffer(ad_backend_ptr be, nss_XbyY_args_t *argp,
+ const char *name, const char *domain,
+ uid_t uid, gid_t gid, const char *gecos,
+ const char *homedir, const char *shell)
+{
+ int buflen;
+ char *buffer;
+
+ if (be->db_type == NSS_AD_DB_PASSWD_BYNAME) {
+ /*
+ * The canonical name obtained from AD lookup may not match
+ * the case of the name (i.e. key) in the request. Therefore,
+ * use the name from the request to construct the result.
+ */
+ buflen = snprintf(NULL, 0, "%s:%s:%u:%u:%s:%s:%s",
+ argp->key.name, "x", uid, gid, gecos, homedir, shell) + 1;
+ } else {
+ if (domain == NULL)
+ domain = WK_DOMAIN;
+ buflen = snprintf(NULL, 0, "%s@%s:%s:%u:%u:%s:%s:%s",
+ name, domain, "x", uid, gid, gecos, homedir, shell) + 1;
+ }
+
+
+ if (argp->buf.result != NULL) {
+ buffer = be->buffer = malloc(buflen);
+ if (be->buffer == NULL)
+ return (-1);
+ be->buflen = buflen;
+ } else {
+ if (buflen > argp->buf.buflen)
+ return (-1);
+ buflen = argp->buf.buflen;
+ buffer = argp->buf.buffer;
+ }
+
+ if (be->db_type == NSS_AD_DB_PASSWD_BYNAME)
+ (void) snprintf(buffer, buflen, "%s:%s:%u:%u:%s:%s:%s",
+ argp->key.name, "x", uid, gid, gecos, homedir, shell);
+ else
+ (void) snprintf(buffer, buflen, "%s@%s:%s:%u:%u:%s:%s:%s",
+ name, domain, "x", uid, gid, gecos, homedir, shell);
+ return (0);
+}
+
+
+#define NET_SCHEME "/net"
+
+/*
+ * 1) If the homeDirectory string is in UNC format then convert it into
+ * a /net format. This needs to be revisited later but is fine for now
+ * because Solaris does not support -hosts automount map for CIFS yet.
+ *
+ * 2) If homeDirectory contains ':' then return NULL because ':' is the
+ * delimiter in passwd entries and may break apps that parse these entries.
+ *
+ * 3) For all other cases return the same string that was passed to
+ * this function.
+ */
+static
+char *
+process_homedir(char *homedir)
+{
+ size_t len, smb_len;
+ char *smb_homedir;
+ int i, slash = 0;
+
+ len = strlen(homedir);
+
+ if (strchr(homedir, ':') != NULL)
+ /*
+ * Ignore paths that have colon ':' because ':' is a
+ * delimiter for the passwd entry.
+ */
+ return (NULL);
+
+ if (!(len > 1 && homedir[0] == '\\' && homedir[1] == '\\'))
+ /* Keep homedir intact if not in UNC format */
+ return (homedir);
+
+ /*
+ * Convert UNC string into /net format
+ * Example: \\server\abc -> /net/server/abc
+ */
+ smb_len = len + 1 + sizeof (NET_SCHEME);
+ if ((smb_homedir = calloc(1, smb_len)) == NULL)
+ return (NULL);
+ (void) strlcpy(smb_homedir, NET_SCHEME, smb_len);
+ for (i = strlen(smb_homedir); *homedir != '\0'; homedir++) {
+ if (*homedir == '\\') {
+ /* Reduce double backslashes into one */
+ if (slash)
+ slash = 0;
+ else {
+ slash = 1;
+ smb_homedir[i++] = '/';
+ }
+ } else {
+ smb_homedir[i++] = *homedir;
+ slash = 0;
+ }
+ }
+ return (smb_homedir);
+}
+
+/*
+ * _nss_ad_passwd2str is the data marshaling method for the passwd getXbyY
+ * (e.g., getbyuid(), getbyname(), getpwent()) backend processes. This method is
+ * called after a successful AD search has been performed. This method will
+ * parse the AD search values into the file format.
+ * e.g.
+ *
+ * blue@whale:x:123456:10:Blue Whale:/:
+ *
+ */
+static int
+_nss_ad_passwd2str(ad_backend_ptr be, nss_XbyY_args_t *argp)
+{
+ int nss_result;
+ adutils_result_t *result = be->result;
+ const adutils_entry_t *entry;
+ char **sid_v, *ptr, **pgid_v, *end;
+ ulong_t tmp;
+ uint32_t urid, grid;
+ uid_t uid;
+ gid_t gid;
+ idmap_stat gstat;
+ idmap_get_handle_t *ig = NULL;
+ char **name_v, **dn_v, *domain = NULL;
+ char **gecos_v, **shell_v;
+ char **homedir_v = NULL, *homedir = NULL;
+ char *NULL_STR = "";
+
+ if (result == NULL)
+ return (NSS_STR_PARSE_PARSE);
+ entry = adutils_getfirstentry(result);
+ nss_result = NSS_STR_PARSE_PARSE;
+
+ /* Create handles for idmap service */
+ if (be->ih == NULL && idmap_init(&be->ih) != 0)
+ goto result_pwd2str;
+ if (idmap_get_create(be->ih, &ig) != 0)
+ goto result_pwd2str;
+
+ /* Get name */
+ name_v = adutils_getattr(entry, _PWD_SAN);
+ if (name_v == NULL || name_v[0] == NULL || *name_v[0] == '\0')
+ goto result_pwd2str;
+
+ /* Get domain */
+ dn_v = adutils_getattr(entry, _PWD_DN);
+ if (dn_v == NULL || dn_v[0] == NULL || *dn_v[0] == '\0')
+ goto result_pwd2str;
+ domain = adutils_dn2dns(dn_v[0]);
+
+ /* Get objectSID (in text format) */
+ sid_v = adutils_getattr(entry, _PWD_OBJSID);
+ if (sid_v == NULL || sid_v[0] == NULL || *sid_v[0] == '\0')
+ goto result_pwd2str;
+
+ /* Break SID into prefix and rid */
+ if ((ptr = strrchr(sid_v[0], '-')) == NULL)
+ goto result_pwd2str;
+ *ptr = '\0';
+ end = ++ptr;
+ tmp = strtoul(ptr, &end, 10);
+ if (end == ptr || tmp > UINT32_MAX)
+ goto result_pwd2str;
+ urid = (uint32_t)tmp;
+
+ /* We already have uid -- no need to call idmapd */
+ if (be->db_type == NSS_AD_DB_PASSWD_BYUID)
+ uid = argp->key.uid;
+ else
+ uid = be->uid;
+
+ /* Get primaryGroupID */
+ pgid_v = adutils_getattr(entry, _PWD_PRIMARYGROUPID);
+ if (pgid_v == NULL || pgid_v[0] == NULL || *pgid_v[0] == '\0')
+ /*
+ * If primaryGroupID is not found then we request
+ * a GID to be mapped to the given user's objectSID
+ * (diagonal mapping) and use this GID as the primary
+ * GID for the entry.
+ */
+ grid = urid;
+ else {
+ end = pgid_v[0];
+ tmp = strtoul(pgid_v[0], &end, 10);
+ if (end == pgid_v[0] || tmp > UINT32_MAX)
+ goto result_pwd2str;
+ grid = (uint32_t)tmp;
+ }
+
+ /* Map group SID to GID using idmap service */
+ if (idmap_get_gidbysid(ig, sid_v[0], grid, 0, &gid, &gstat) != 0)
+ goto result_pwd2str;
+ if (idmap_get_mappings(ig) != 0 || gstat != 0) {
+ RESET_ERRNO();
+ goto result_pwd2str;
+ }
+
+ /* Get gecos, homedirectory and shell information if available */
+ gecos_v = adutils_getattr(entry, _PWD_CN);
+ if (gecos_v == NULL || gecos_v[0] == NULL || *gecos_v[0] == '\0')
+ gecos_v = &NULL_STR;
+
+ homedir_v = adutils_getattr(entry, _PWD_HOMEDIRECTORY);
+ if (homedir_v == NULL || homedir_v[0] == NULL || *homedir_v[0] == '\0')
+ homedir = NULL_STR;
+ else if ((homedir = process_homedir(homedir_v[0])) == NULL)
+ homedir = NULL_STR;
+
+ shell_v = adutils_getattr(entry, _PWD_LOGINSHELL);
+ if (shell_v == NULL || shell_v[0] == NULL || *shell_v[0] == '\0')
+ shell_v = &NULL_STR;
+
+ if (update_buffer(be, argp, name_v[0], domain, uid, gid,
+ gecos_v[0], homedir, shell_v[0]) < 0)
+ nss_result = NSS_STR_PARSE_ERANGE;
+ else
+ nss_result = NSS_STR_PARSE_SUCCESS;
+
+result_pwd2str:
+ idmap_get_destroy(ig);
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+ (void) adutils_freeresult(&be->result);
+ free(domain);
+ if (homedir != NULL_STR && homedir_v != NULL &&
+ homedir != homedir_v[0])
+ free(homedir);
+ return ((int)nss_result);
+}
+
+/*
+ * getbyname gets a passwd entry by winname. This function constructs an ldap
+ * search filter using the name invocation parameter and the getpwnam search
+ * filter defined. Once the filter is constructed, we search for a matching
+ * entry and marshal the data results into struct passwd for the frontend
+ * process. The function _nss_ad_passwd2ent performs the data marshaling.
+ */
+
+static nss_status_t
+getbyname(ad_backend_ptr be, void *a)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ char *searchfilter;
+ char name[SEARCHFILTERLEN];
+ char *dname;
+ int filterlen, namelen;
+ int flag;
+ nss_status_t stat;
+ idmap_stat idmaprc;
+ uid_t uid;
+ gid_t gid;
+ int is_user, is_wuser, try_idmap;
+ idmap_handle_t *ih;
+
+ be->db_type = NSS_AD_DB_PASSWD_BYNAME;
+
+ /* Sanitize name so that it can be used in our LDAP filter */
+ if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ if ((dname = strchr(name, '@')) == NULL)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ *dname = '\0';
+ dname++;
+
+ /*
+ * Map the given name to UID using idmap service. If idmap
+ * call fails then this will save us doing AD discovery and
+ * AD lookup here.
+ */
+ if (idmap_init(&be->ih) != IDMAP_SUCCESS)
+ return ((nss_status_t)NSS_NOTFOUND);
+ flag = (strcasecmp(dname, WK_DOMAIN) == 0) ?
+ IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY : 0;
+ is_wuser = -1;
+ is_user = 1;
+ if (idmap_get_w2u_mapping(be->ih, NULL, NULL, name,
+ dname, flag, &is_user, &is_wuser, &be->uid, NULL,
+ NULL, NULL) != IDMAP_SUCCESS) {
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+ RESET_ERRNO();
+ return ((nss_status_t)NSS_NOTFOUND);
+ }
+
+ /* If this is not a Well-Known SID then try AD lookup. */
+ if (strcasecmp(dname, WK_DOMAIN) != 0) {
+ /* Assemble filter using the given name */
+ namelen = strlen(name);
+ filterlen = snprintf(NULL, 0, _F_GETPWNAM, namelen, name) + 1;
+ if ((searchfilter = (char *)malloc(filterlen)) == NULL)
+ return ((nss_status_t)NSS_NOTFOUND);
+ (void) snprintf(searchfilter, filterlen, _F_GETPWNAM,
+ namelen, name);
+ stat = _nss_ad_lookup(be, argp, _PASSWD, searchfilter,
+ dname, &try_idmap);
+ free(searchfilter);
+
+ if (!try_idmap) {
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+ return (stat);
+ }
+
+ }
+
+ /*
+ * Either this is a Well-Known SID or AD lookup failed. Map
+ * the given name to GID using idmap service and construct
+ * the passwd entry.
+ */
+ is_wuser = -1;
+ is_user = 0; /* Map name to primary gid */
+ idmaprc = idmap_get_w2u_mapping(be->ih, NULL, NULL, name, dname,
+ flag, &is_user, &is_wuser, &gid, NULL, NULL, NULL);
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+ if (idmaprc != IDMAP_SUCCESS) {
+ RESET_ERRNO();
+ return ((nss_status_t)NSS_NOTFOUND);
+ }
+
+ /* Create passwd(4) style string */
+ if (update_buffer(be, argp, name, dname,
+ be->uid, gid, "", "", "") < 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ /* Marshall the data, sanitize the return status and return */
+ stat = _nss_ad_marshall_data(be, argp);
+ return (_nss_ad_sanitize_status(be, argp, stat));
+}
+
+
+/*
+ * getbyuid gets a passwd entry by uid number. This function constructs an ldap
+ * search filter using the uid invocation parameter and the getpwuid search
+ * filter defined. Once the filter is constructed, we search for a matching
+ * entry and marshal the data results into struct passwd for the frontend
+ * process. The function _nss_ad_passwd2ent performs the data marshaling.
+ */
+
+static nss_status_t
+getbyuid(ad_backend_ptr be, void *a)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ char searchfilter[ADUTILS_MAXHEXBINSID + 14];
+ char *sidprefix = NULL;
+ idmap_rid_t rid;
+ char cbinsid[ADUTILS_MAXHEXBINSID + 1];
+ char *winname = NULL, *windomain = NULL;
+ int is_user, is_wuser;
+ gid_t gid;
+ idmap_stat idmaprc;
+ int ret, try_idmap;
+ nss_status_t stat;
+
+ be->db_type = NSS_AD_DB_PASSWD_BYUID;
+
+ stat = (nss_status_t)NSS_NOTFOUND;
+
+ /* nss_ad does not support non ephemeral uids */
+ if (argp->key.uid <= MAXUID)
+ goto out;
+
+ /* Map the given UID to a SID using the idmap service */
+ if (idmap_init(&be->ih) != 0)
+ goto out;
+ if (idmap_get_u2w_mapping(be->ih, &argp->key.uid, NULL, 0,
+ 1, NULL, &sidprefix, &rid, &winname, &windomain,
+ NULL, NULL) != 0) {
+ RESET_ERRNO();
+ goto out;
+ }
+
+ /*
+ * NULL winname implies a local SID or unresolvable SID both of
+ * which cannot be used to generated passwd(4) entry
+ */
+ if (winname == NULL)
+ goto out;
+
+ /* If this is not a Well-Known SID try AD lookup */
+ if (windomain != NULL && strcasecmp(windomain, WK_DOMAIN) != 0) {
+ if (adutils_txtsid2hexbinsid(sidprefix, &rid,
+ &cbinsid[0], sizeof (cbinsid)) != 0)
+ goto out;
+
+ ret = snprintf(searchfilter, sizeof (searchfilter),
+ _F_GETPWUID, cbinsid);
+ if (ret >= sizeof (searchfilter) || ret < 0)
+ goto out;
+
+ stat = _nss_ad_lookup(be, argp, _PASSWD, searchfilter,
+ windomain, &try_idmap);
+
+ if (!try_idmap)
+ goto out;
+ }
+
+ /* Map winname to primary gid using idmap service */
+ is_user = 0;
+ is_wuser = -1;
+ idmaprc = idmap_get_w2u_mapping(be->ih, NULL, NULL,
+ winname, windomain, 0, &is_user, &is_wuser, &gid,
+ NULL, NULL, NULL);
+
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+
+ if (idmaprc != IDMAP_SUCCESS) {
+ RESET_ERRNO();
+ goto out;
+ }
+
+ /* Create passwd(4) style string */
+ if (update_buffer(be, argp, winname, windomain,
+ argp->key.uid, gid, "", "", "") < 0)
+ goto out;
+
+ /* Marshall the data, sanitize the return status and return */
+ stat = _nss_ad_marshall_data(be, argp);
+ stat = _nss_ad_sanitize_status(be, argp, stat);
+
+out:
+ idmap_free(sidprefix);
+ idmap_free(winname);
+ idmap_free(windomain);
+ (void) idmap_fini(be->ih);
+ be->ih = NULL;
+ return (stat);
+}
+
+static ad_backend_op_t passwd_ops[] = {
+ _nss_ad_destr,
+ _nss_ad_endent,
+ _nss_ad_setent,
+ _nss_ad_getent,
+ getbyname,
+ getbyuid
+};
+
+/*
+ * _nss_ad_passwd_constr is where life begins. This function calls the
+ * generic AD constructor function to define and build the abstract
+ * data types required to support AD operations.
+ */
+
+/*ARGSUSED0*/
+nss_backend_t *
+_nss_ad_passwd_constr(const char *dummy1, const char *dummy2,
+ const char *dummy3)
+{
+
+ return ((nss_backend_t *)_nss_ad_constr(passwd_ops,
+ sizeof (passwd_ops)/sizeof (passwd_ops[0]),
+ _PASSWD, pwd_attrs, _nss_ad_passwd2str));
+}
diff --git a/usr/src/lib/nsswitch/ad/common/getspent.c b/usr/src/lib/nsswitch/ad/common/getspent.c
new file mode 100644
index 0000000000..257540c8db
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/common/getspent.c
@@ -0,0 +1,146 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <shadow.h>
+#include <stdlib.h>
+#include "ad_common.h"
+
+static int
+update_buffer(ad_backend_ptr be, nss_XbyY_args_t *argp,
+ const char *name, const char *domain)
+{
+ int buflen;
+ char *buffer;
+
+ /*
+ * The user password is not available in the AD object and therefore
+ * sp_pwdp will be "*NP*".
+ *
+ * nss_ad will leave aging fields empty (i.e. The front end
+ * marshaller will set sp_lstchgst, sp_min, sp_max, sp_warn,
+ * sp_inact, and sp_expire to -1 and sp_flag to 0) because shadow
+ * fields are irrevalent with AD and krb5.
+ */
+
+ buflen = snprintf(NULL, 0, "%s@%s:*NP*:::::::", name, domain) + 1;
+
+ if (argp->buf.result != NULL) {
+ buffer = be->buffer = malloc(buflen);
+ if (be->buffer == NULL)
+ return (-1);
+ be->buflen = buflen;
+ } else {
+ if (buflen > argp->buf.buflen)
+ return (-1);
+ buflen = argp->buf.buflen;
+ buffer = argp->buf.buffer;
+ }
+
+ buflen = snprintf(buffer, buflen, "%s@%s:*NP*:::::::",
+ name, domain) + 1;
+ return (0);
+}
+
+/*
+ * getbynam gets a shadow entry by winname. This function constructs an ldap
+ * search filter using the name invocation parameter and the getspnam search
+ * filter defined. Once the filter is constructed we search for a matching
+ * entry and marshal the data results into struct shadow for the frontend
+ * process. The function _nss_ad_shadow2ent performs the data marshaling.
+ */
+static nss_status_t
+getbynam(ad_backend_ptr be, void *a)
+{
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ char name[SEARCHFILTERLEN + 1];
+ char *dname;
+ nss_status_t stat;
+ idmap_stat idmaprc;
+ uid_t uid;
+ int is_user, is_wuser;
+ idmap_handle_t *ih;
+
+ be->db_type = NSS_AD_DB_SHADOW_BYNAME;
+
+ /* Sanitize name so that it can be used in our LDAP filter */
+ if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ if ((dname = strchr(name, '@')) == NULL)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ *dname = '\0';
+ dname++;
+
+ /*
+ * Use idmap service to verify that the given
+ * name is a valid Windows name.
+ */
+ idmaprc = idmap_init(&ih);
+ if (idmaprc != IDMAP_SUCCESS)
+ return ((nss_status_t)NSS_NOTFOUND);
+ is_wuser = -1;
+ is_user = 1;
+ idmaprc = idmap_get_w2u_mapping(ih, NULL, NULL, name, dname,
+ 0, &is_user, &is_wuser, &uid, NULL, NULL, NULL);
+ (void) idmap_fini(ih);
+ if (idmaprc != IDMAP_SUCCESS) {
+ RESET_ERRNO();
+ return ((nss_status_t)NSS_NOTFOUND);
+ }
+
+ /* Create shadow(4) style string */
+ if (update_buffer(be, argp, name, dname) < 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ /* Marshall the data, sanitize the return status and return */
+ stat = _nss_ad_marshall_data(be, argp);
+ return (_nss_ad_sanitize_status(be, argp, stat));
+}
+
+static ad_backend_op_t sp_ops[] = {
+ _nss_ad_destr,
+ _nss_ad_endent,
+ _nss_ad_setent,
+ _nss_ad_getent,
+ getbynam
+};
+
+
+/*
+ * _nss_ad_passwd_constr is where life begins. This function calls the
+ * generic ldap constructor function to define and build the abstract
+ * data types required to support ldap operations.
+ */
+/*ARGSUSED0*/
+nss_backend_t *
+_nss_ad_shadow_constr(const char *dummy1, const char *dummy2,
+ const char *dummy3)
+{
+
+ return ((nss_backend_t *)_nss_ad_constr(sp_ops,
+ sizeof (sp_ops)/sizeof (sp_ops[0]),
+ _SHADOW, NULL, NULL));
+}
diff --git a/usr/src/lib/nsswitch/ad/common/mapfile-vers b/usr/src/lib/nsswitch/ad/common/mapfile-vers
new file mode 100644
index 0000000000..a42ab674cb
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/common/mapfile-vers
@@ -0,0 +1,33 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+SUNWprivate {
+ global:
+ _nss_ad_passwd_constr;
+ _nss_ad_shadow_constr;
+ _nss_ad_group_constr;
+ local:
+ *;
+};
diff --git a/usr/src/lib/nsswitch/ad/i386/Makefile b/usr/src/lib/nsswitch/ad/i386/Makefile
new file mode 100644
index 0000000000..710f624b5c
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/i386/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+LIBS = $(DYNLIB1)
+
+include ../../Makefile.targ
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/nsswitch/ad/sparc/Makefile b/usr/src/lib/nsswitch/ad/sparc/Makefile
new file mode 100644
index 0000000000..710f624b5c
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/sparc/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+LIBS = $(DYNLIB1)
+
+include ../../Makefile.targ
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/nsswitch/ad/sparcv9/Makefile b/usr/src/lib/nsswitch/ad/sparcv9/Makefile
new file mode 100644
index 0000000000..6e71c56dcc
--- /dev/null
+++ b/usr/src/lib/nsswitch/ad/sparcv9/Makefile
@@ -0,0 +1,32 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+LIBS = $(DYNLIB1)
+
+include ../../Makefile.targ
+
+install: all $(ROOT64DYNLIB)
diff --git a/usr/src/lib/nsswitch/compat/common/compat_common.c b/usr/src/lib/nsswitch/compat/common/compat_common.c
index d696f80b3c..82975b3e37 100644
--- a/usr/src/lib/nsswitch/compat/common/compat_common.c
+++ b/usr/src/lib/nsswitch/compat/common/compat_common.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Common code and structures used by name-service-switch "compat" backends.
@@ -28,8 +28,6 @@
* the "files" backend; this file is no exception.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -692,6 +690,44 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num)
return (res);
}
+static int
+validate_ids(compat_backend_ptr_t be, nss_XbyY_args_t *argp,
+ char *line, int *linelenp, int buflen, int extra_chars)
+{
+ if (be->return_string_data != 1) {
+ struct passwd *p;
+ struct group *g;
+ /*
+ * The data is already marshalled into
+ * struct passwd or group.
+ */
+ if (strcmp(be->filename, PASSWD) == 0) {
+ p = (struct passwd *)argp->returnval;
+ if (p->pw_uid > MAXUID)
+ p->pw_uid = UID_NOBODY;
+ if (p->pw_gid > MAXUID)
+ p->pw_gid = GID_NOBODY;
+ } else if (strcmp(be->filename, GF_PATH) == 0) {
+ g = (struct group *)argp->returnval;
+ if (g->gr_gid > MAXUID)
+ g->gr_gid = GID_NOBODY;
+ }
+ return (NSS_STR_PARSE_SUCCESS);
+ }
+
+ /*
+ * The data needs to be returned in string format therefore
+ * validate the return string.
+ */
+ if (strcmp(be->filename, PASSWD) == 0)
+ return (validate_passwd_ids(line, linelenp, buflen,
+ extra_chars));
+ else if (strcmp(be->filename, GF_PATH) == 0)
+ return (validate_group_ids(line, linelenp, buflen,
+ extra_chars));
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
nss_status_t
_nss_compat_XY_all(be, args, check, op_num)
compat_backend_ptr_t be;
@@ -760,6 +796,19 @@ _nss_compat_XY_all(be, args, check, op_num)
args->returnval = args->buf.result;
if ((*check)(args) != 0) {
int len;
+
+ parsestat = validate_ids(be, args,
+ instr, &linelen, be->minbuf, 1);
+ if (parsestat ==
+ NSS_STR_PARSE_ERANGE) {
+ args->erange = 1;
+ res = NSS_NOTFOUND;
+ break;
+ } else if (parsestat !=
+ NSS_STR_PARSE_SUCCESS) {
+ continue;
+ }
+
if (be->return_string_data != 1) {
res = NSS_SUCCESS;
break;
diff --git a/usr/src/lib/nsswitch/compat/common/compat_common.h b/usr/src/lib/nsswitch/compat/common/compat_common.h
index 041dc0f322..5761651636 100644
--- a/usr/src/lib/nsswitch/compat/common/compat_common.h
+++ b/usr/src/lib/nsswitch/compat/common/compat_common.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
@@ -29,8 +29,6 @@
#ifndef _COMPAT_COMMON_H
#define _COMPAT_COMMON_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <nss_common.h>
#include <nss_dbdefs.h>
#include <stdio.h>
@@ -131,6 +129,12 @@ extern nss_status_t _nss_compat_XY_all();
extern nss_status_t _attrdb_compat_XY_all();
#endif
+/* functions to validate passwd and group ids */
+extern int validate_passwd_ids(char *line, int *linelenp, int buflen,
+ int extra_chars);
+extern int validate_group_ids(char *line, int *linelenp, int buflen,
+ int extra_chars);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/nsswitch/compat/common/getgrent.c b/usr/src/lib/nsswitch/compat/common/getgrent.c
index 0457392e59..6f9c81b1e0 100644
--- a/usr/src/lib/nsswitch/compat/common/getgrent.c
+++ b/usr/src/lib/nsswitch/compat/common/getgrent.c
@@ -21,7 +21,7 @@
/*
* getgrent.c
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* lib/nsswitch/compat/getgrent.c -- name-service-switch backend for getgrnam()
@@ -43,8 +43,6 @@
* - People who recursively specify "compat" deserve what they get.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <grp.h>
#include <stdlib.h>
#include <unistd.h> /* for GF_PATH */
@@ -62,6 +60,51 @@ _nss_initf_group_compat(p)
p->default_config = NSS_DEFCONF_GROUP_COMPAT;
}
+/*
+ * Validates group entry replacing gid > MAXUID by GID_NOBODY.
+ */
+int
+validate_group_ids(char *line, int *linelenp, int buflen, int extra_chars)
+{
+ char *linep, *limit, *gidp;
+ ulong_t gid;
+ int oldgidlen, idlen;
+ int linelen = *linelenp, newlinelen;
+
+ if (linelen == 0 || *line == '+' || *line == '-')
+ return (NSS_STR_PARSE_SUCCESS);
+
+ linep = line;
+ limit = line + linelen;
+
+ while (linep < limit && *linep++ != ':') /* skip groupname */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
+ if (linep == limit)
+ return (NSS_STR_PARSE_PARSE);
+
+ gidp = linep;
+ gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */
+ oldgidlen = linep - gidp;
+ if (linep >= limit || oldgidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ if (gid <= MAXUID)
+ return (NSS_STR_PARSE_SUCCESS);
+
+ idlen = snprintf(NULL, 0, "%u", GID_NOBODY);
+ newlinelen = linelen + idlen - oldgidlen;
+ if (newlinelen + extra_chars > buflen)
+ return (NSS_STR_PARSE_ERANGE);
+
+ (void) bcopy(linep, gidp + idlen, limit - linep + extra_chars);
+ (void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY);
+ *(gidp + idlen) = ':';
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
static const char *
get_grname(argp)
nss_XbyY_args_t *argp;
@@ -107,6 +150,8 @@ getbygid(be, a)
{
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ if (argp->key.gid > MAXUID)
+ return (NSS_NOTFOUND);
return (_nss_compat_XY_all(be, argp, check_grgid,
NSS_DBOP_GROUP_BYGID));
}
@@ -211,7 +256,7 @@ merge_grents(be, argp, fields)
/* Really "out of memory", but PARSE_PARSE will have to do */
}
s = buf;
- (void) snprintf(s, NSS_LINELEN_GROUP, "%s:%s:%d:",
+ (void) snprintf(s, NSS_LINELEN_GROUP, "%s:%s:%u:",
g->gr_name,
fields[1] != 0 ? fields[1] : g->gr_passwd,
g->gr_gid);
diff --git a/usr/src/lib/nsswitch/compat/common/getpwent.c b/usr/src/lib/nsswitch/compat/common/getpwent.c
index 1219dab7fa..f7e5961ebe 100644
--- a/usr/src/lib/nsswitch/compat/common/getpwent.c
+++ b/usr/src/lib/nsswitch/compat/common/getpwent.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* getpwent.c
@@ -49,8 +49,6 @@
* confusing.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <pwd.h>
#include <shadow.h> /* For PASSWD (pathname to passwd file) */
#include <stdlib.h>
@@ -68,6 +66,63 @@ _nss_initf_passwd_compat(p)
p->default_config = NSS_DEFCONF_PASSWD_COMPAT;
}
+/*
+ * Validates passwd entry replacing uid/gid > MAXUID by ID_NOBODY.
+ */
+int
+validate_passwd_ids(char *line, int *linelenp, int buflen, int extra_chars)
+{
+ char *linep, *limit, *uidp, *gidp;
+ uid_t uid;
+ gid_t gid;
+ ulong_t uidl, gidl;
+ int olduidlen, oldgidlen, idlen;
+ int linelen = *linelenp, newlinelen;
+
+ if (linelen == 0 || *line == '+' || *line == '-')
+ return (NSS_STR_PARSE_SUCCESS);
+
+ linep = line;
+ limit = line + linelen;
+
+ while (linep < limit && *linep++ != ':') /* skip username */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
+ if (linep == limit)
+ return (NSS_STR_PARSE_PARSE);
+
+ uidp = linep;
+ uidl = strtoul(uidp, (char **)&linep, 10); /* grab uid */
+ olduidlen = linep - uidp;
+ if (++linep >= limit || olduidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ gidp = linep;
+ gidl = strtoul(gidp, (char **)&linep, 10); /* grab gid */
+ oldgidlen = linep - gidp;
+ if (linep >= limit || oldgidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ if (uidl <= MAXUID && gidl <= MAXUID)
+ return (NSS_STR_PARSE_SUCCESS);
+ uid = (uidl > MAXUID) ? UID_NOBODY : (uid_t)uidl;
+ gid = (gidl > MAXUID) ? GID_NOBODY : (gid_t)gidl;
+
+ /* Check if we have enough space in the buffer */
+ idlen = snprintf(NULL, 0, "%u:%u", uid, gid);
+ newlinelen = linelen + idlen - olduidlen - oldgidlen - 1;
+ if (newlinelen + extra_chars > buflen)
+ return (NSS_STR_PARSE_ERANGE);
+
+ /* Replace ephemeral ids by ID_NOBODY */
+ (void) bcopy(linep, uidp + idlen, limit - linep + extra_chars);
+ (void) snprintf(uidp, idlen + 1, "%u:%u", uid, gid);
+ *(uidp + idlen) = ':'; /* restore : that was overwritten by snprintf */
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
static const char *
get_pwname(argp)
nss_XbyY_args_t *argp;
@@ -113,6 +168,8 @@ getbyuid(be, a)
{
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+ if (argp->key.uid > MAXUID)
+ return (NSS_NOTFOUND);
return (_nss_compat_XY_all(be, argp,
check_pwuid, NSS_DBOP_PASSWD_BYUID));
}
@@ -163,7 +220,7 @@ merge_pwents(be, argp, fields)
s += len;
buflen -= len;
- len = snprintf(s, buflen, ":%ld:%ld:%s:%s:%s",
+ len = snprintf(s, buflen, ":%u:%u:%s:%s:%s",
pw->pw_uid,
pw->pw_gid,
fields[4] != 0 ? fields[4] : pw->pw_gecos,
diff --git a/usr/src/lib/nsswitch/files/common/files_common.c b/usr/src/lib/nsswitch/files/common/files_common.c
index 74d47f7c8c..4b7b6753c1 100644
--- a/usr/src/lib/nsswitch/files/common/files_common.c
+++ b/usr/src/lib/nsswitch/files/common/files_common.c
@@ -25,8 +25,6 @@
* Common code and structures used by name-service-switch "files" backends.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* An implementation that used mmap() sensibly would be a wonderful thing,
* but this here is just yer standard fgets() thang.
@@ -299,9 +297,27 @@ _nss_files_XY_all(be, args, netdb, filter, check)
if (check != NULL && (*check)(args, instr, linelen) == 0)
continue;
- func = args->str2ent;
- parsestat = (*func)(instr, linelen, args->buf.result,
- args->buf.buffer, args->buf.buflen);
+ parsestat = NSS_STR_PARSE_SUCCESS;
+ if (be->filename != NULL) {
+ /*
+ * Special case for passwd and group wherein we
+ * replace uids/gids > MAXUID by ID_NOBODY
+ * because files backend does not support
+ * ephemeral ids.
+ */
+ if (strcmp(be->filename, PF_PATH) == 0)
+ parsestat = validate_passwd_ids(instr,
+ &linelen, be->minbuf, 2);
+ else if (strcmp(be->filename, GF_PATH) == 0)
+ parsestat = validate_group_ids(instr,
+ &linelen, be->minbuf, 2, check);
+ }
+
+ if (parsestat == NSS_STR_PARSE_SUCCESS) {
+ func = args->str2ent;
+ parsestat = (*func)(instr, linelen, args->buf.result,
+ args->buf.buffer, args->buf.buflen);
+ }
if (parsestat == NSS_STR_PARSE_SUCCESS) {
args->returnval = (args->buf.result != NULL)?
@@ -366,7 +382,7 @@ _nss_files_XY_hash(files_backend_ptr_t be, nss_XbyY_args_t *args,
int netdb, files_hash_t *fhp, int hashop, files_XY_check_func check)
{
/* LINTED E_FUNC_VAR_UNUSED */
- int fd, retries, ht;
+ int fd, retries, ht, stat;
/* LINTED E_FUNC_VAR_UNUSED */
uint_t hash, line, f;
/* LINTED E_FUNC_VAR_UNUSED */
@@ -412,6 +428,28 @@ retry:
if ((*check)(args, fhp->fh_line[line].l_start,
fhp->fh_line[line].l_len) == 0)
continue;
+
+ if (be->filename != NULL) {
+ stat = NSS_STR_PARSE_SUCCESS;
+ if (strcmp(be->filename, PF_PATH) == 0)
+ stat = validate_passwd_ids(
+ fhp->fh_line[line].l_start,
+ &fhp->fh_line[line].l_len,
+ fhp->fh_line[line].l_len + 1,
+ 1);
+ else if (strcmp(be->filename, GF_PATH) == 0)
+ stat = validate_group_ids(
+ fhp->fh_line[line].l_start,
+ &fhp->fh_line[line].l_len,
+ fhp->fh_line[line].l_len + 1,
+ 1, check);
+ if (stat != NSS_STR_PARSE_SUCCESS) {
+ if (stat == NSS_STR_PARSE_ERANGE)
+ args->erange = 1;
+ continue;
+ }
+ }
+
if ((*args->str2ent)(fhp->fh_line[line].l_start,
fhp->fh_line[line].l_len, args->buf.result,
args->buf.buffer, args->buf.buflen) ==
diff --git a/usr/src/lib/nsswitch/files/common/files_common.h b/usr/src/lib/nsswitch/files/common/files_common.h
index b526833022..2138d7180e 100644
--- a/usr/src/lib/nsswitch/files/common/files_common.h
+++ b/usr/src/lib/nsswitch/files/common/files_common.h
@@ -31,8 +31,6 @@
#ifndef _FILES_COMMON_H
#define _FILES_COMMON_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <nss_common.h>
#include <nss_dbdefs.h>
#include <stdio.h>
@@ -136,6 +134,12 @@ extern nss_status_t _nss_files_XY_hash();
int _nss_files_check_name_aliases(nss_XbyY_args_t *, const char *, int);
int _nss_files_check_name_colon(nss_XbyY_args_t *, const char *, int);
+/* passwd and group validation functions */
+extern int validate_group_ids(char *line, int *linelenp, int buflen,
+ int extra_chars, files_XY_check_func check);
+extern int validate_passwd_ids(char *line, int *linelenp, int buflen,
+ int extra_chars);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/nsswitch/files/common/getgrent.c b/usr/src/lib/nsswitch/files/common/getgrent.c
index 6f45136f16..455e070da4 100644
--- a/usr/src/lib/nsswitch/files/common/getgrent.c
+++ b/usr/src/lib/nsswitch/files/common/getgrent.c
@@ -19,14 +19,12 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* files/getgrent.c -- "files" backend for nsswitch "group" database
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <grp.h>
#include <unistd.h> /* for GF_PATH */
#include <stdlib.h> /* for GF_PATH */
@@ -69,16 +67,16 @@ hash_grgid(nss_XbyY_args_t *argp, int keyhash, const char *line,
if (keyhash)
return ((uint_t)argp->key.gid);
- /* skip groupname */
- while (linep < limit && *linep++ != ':');
- /* skip password */
- while (linep < limit && *linep++ != ':');
+ while (linep < limit && *linep++ != ':') /* skip groupname */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
if (linep == limit)
return (GID_NOBODY);
/* gid */
end = linep;
- id = (uint_t)strtol(linep, (char **)&end, 10);
+ id = (uint_t)strtoul(linep, (char **)&end, 10);
/* empty gid */
if (linep == end)
return (GID_NOBODY);
@@ -127,7 +125,7 @@ static int
check_grgid(nss_XbyY_args_t *argp, const char *line, int linelen)
{
const char *linep, *limit, *end;
- gid_t gr_gid;
+ ulong_t gr_gid;
linep = line;
limit = line + linelen;
@@ -136,22 +134,22 @@ check_grgid(nss_XbyY_args_t *argp, const char *line, int linelen)
if (linelen == 0 || *line == '+' || *line == '-')
return (0);
- /* skip username */
- while (linep < limit && *linep++ != ':');
- /* skip password */
- while (linep < limit && *linep++ != ':');
+ while (linep < limit && *linep++ != ':') /* skip groupname */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
if (linep == limit)
return (0);
- /* uid */
+ /* gid */
end = linep;
- gr_gid = (gid_t)strtol(linep, (char **)&end, 10);
+ gr_gid = strtoul(linep, (char **)&end, 10);
- /* empty gid is not valid */
- if (linep == end)
+ /* check if gid is empty or overflows */
+ if (linep == end || gr_gid > UINT32_MAX)
return (0);
- return (gr_gid == argp->key.gid);
+ return ((gid_t)gr_gid == argp->key.gid);
}
static nss_status_t
@@ -159,7 +157,66 @@ getbygid(be, a)
files_backend_ptr_t be;
void *a;
{
- return (_nss_files_XY_hash(be, a, 0, &hashinfo, 1, check_grgid));
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+
+ if (argp->key.gid > MAXUID)
+ return (NSS_NOTFOUND);
+ return (_nss_files_XY_hash(be, argp, 0, &hashinfo, 1, check_grgid));
+}
+
+/*
+ * Validates group entry replacing gid > MAXUID by GID_NOBODY.
+ */
+int
+validate_group_ids(char *line, int *linelenp, int buflen, int extra_chars,
+ files_XY_check_func check)
+{
+ char *linep, *limit, *gidp;
+ ulong_t gid;
+ int oldgidlen, idlen;
+ int linelen = *linelenp, newlinelen;
+
+ /*
+ * getbygid() rejects searching by ephemeral gid therefore
+ * no need to validate because the matched entry won't have
+ * an ephemeral gid.
+ */
+ if (check != NULL && check == check_grgid)
+ return (NSS_STR_PARSE_SUCCESS);
+
+ /* +/- entries valid for compat source only */
+ if (linelen == 0 || *line == '+' || *line == '-')
+ return (NSS_STR_PARSE_SUCCESS);
+
+ linep = line;
+ limit = line + linelen;
+
+ while (linep < limit && *linep++ != ':') /* skip groupname */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
+ if (linep == limit)
+ return (NSS_STR_PARSE_PARSE);
+
+ gidp = linep;
+ gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */
+ oldgidlen = linep - gidp;
+ if (linep >= limit || oldgidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ if (gid <= MAXUID)
+ return (NSS_STR_PARSE_SUCCESS);
+
+ idlen = snprintf(NULL, 0, "%u", GID_NOBODY);
+ newlinelen = linelen + idlen - oldgidlen;
+ if (newlinelen + extra_chars > buflen)
+ return (NSS_STR_PARSE_ERANGE);
+
+ (void) bcopy(linep, gidp + idlen, limit - linep + extra_chars);
+ (void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY);
+ *(gidp + idlen) = ':';
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
}
static nss_status_t
diff --git a/usr/src/lib/nsswitch/files/common/getpwnam.c b/usr/src/lib/nsswitch/files/common/getpwnam.c
index 8faa2014eb..570eec84ad 100644
--- a/usr/src/lib/nsswitch/files/common/getpwnam.c
+++ b/usr/src/lib/nsswitch/files/common/getpwnam.c
@@ -19,14 +19,12 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* files/getpwnam.c -- "files" backend for nsswitch "passwd" database
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <pwd.h>
#include <shadow.h>
#include <unistd.h> /* for PF_PATH */
@@ -70,16 +68,16 @@ hash_pwuid(nss_XbyY_args_t *argp, int keyhash, const char *line,
if (keyhash)
return ((uint_t)argp->key.uid);
- /* skip username */
- while (linep < limit && *linep++ != ':');
- /* skip password */
- while (linep < limit && *linep++ != ':');
+ while (linep < limit && *linep++ != ':') /* skip username */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
if (linep == limit)
return (UID_NOBODY);
/* uid */
end = linep;
- id = (uint_t)strtol(linep, (char **)&end, 10);
+ id = (uint_t)strtoul(linep, (char **)&end, 10);
/* empty uid */
if (linep == end)
@@ -129,7 +127,7 @@ static int
check_pwuid(nss_XbyY_args_t *argp, const char *line, int linelen)
{
const char *linep, *limit, *end;
- uid_t pw_uid;
+ ulong_t pw_uid;
linep = line;
limit = line + linelen;
@@ -138,22 +136,22 @@ check_pwuid(nss_XbyY_args_t *argp, const char *line, int linelen)
if (linelen == 0 || *line == '+' || *line == '-')
return (0);
- /* skip username */
- while (linep < limit && *linep++ != ':');
- /* skip password */
- while (linep < limit && *linep++ != ':');
+ while (linep < limit && *linep++ != ':') /* skip username */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
if (linep == limit)
return (0);
/* uid */
end = linep;
- pw_uid = (uid_t)strtol(linep, (char **)&end, 10);
+ pw_uid = strtoul(linep, (char **)&end, 10);
- /* empty uid is not valid */
- if (linep == end)
+ /* check if the uid is empty or overflows */
+ if (linep == end || pw_uid > UINT32_MAX)
return (0);
- return (pw_uid == argp->key.uid);
+ return ((uid_t)pw_uid == argp->key.uid);
}
static nss_status_t
@@ -161,7 +159,73 @@ getbyuid(be, a)
files_backend_ptr_t be;
void *a;
{
- return (_nss_files_XY_hash(be, a, 0, &hashinfo, 1, check_pwuid));
+ nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
+
+ if (argp->key.uid > MAXUID)
+ return (NSS_NOTFOUND);
+ return (_nss_files_XY_hash(be, argp, 0, &hashinfo, 1, check_pwuid));
+}
+
+/*
+ * Validates passwd entry replacing uid/gid > MAXUID by ID_NOBODY.
+ */
+int
+validate_passwd_ids(char *line, int *linelenp, int buflen, int extra_chars)
+{
+ char *linep, *limit, *uidp, *gidp;
+ uid_t uid;
+ gid_t gid;
+ ulong_t uidl, gidl;
+ int olduidlen, oldgidlen, idlen;
+ int linelen = *linelenp, newlinelen;
+
+ /*
+ * +name entries in passwd(4) do not override uid and gid
+ * values. Therefore no need to validate the ids in these
+ * entries.
+ */
+ if (linelen == 0 || *line == '+' || *line == '-')
+ return (NSS_STR_PARSE_SUCCESS);
+
+ linep = line;
+ limit = line + linelen;
+
+ while (linep < limit && *linep++ != ':') /* skip username */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
+ if (linep == limit)
+ return (NSS_STR_PARSE_PARSE);
+
+ uidp = linep;
+ uidl = strtoul(uidp, (char **)&linep, 10); /* grab uid */
+ olduidlen = linep - uidp;
+ if (++linep >= limit || olduidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ gidp = linep;
+ gidl = strtoul(gidp, (char **)&linep, 10); /* grab gid */
+ oldgidlen = linep - gidp;
+ if (linep >= limit || oldgidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ if (uidl <= MAXUID && gidl <= MAXUID)
+ return (NSS_STR_PARSE_SUCCESS);
+ uid = (uidl > MAXUID) ? UID_NOBODY : (uid_t)uidl;
+ gid = (gidl > MAXUID) ? GID_NOBODY : (gid_t)gidl;
+
+ /* Check if we have enough space in the buffer */
+ idlen = snprintf(NULL, 0, "%u:%u", uid, gid);
+ newlinelen = linelen + idlen - olduidlen - oldgidlen - 1;
+ if (newlinelen + extra_chars > buflen)
+ return (NSS_STR_PARSE_ERANGE);
+
+ /* Replace ephemeral ids by ID_NOBODY */
+ (void) bcopy(linep, uidp + idlen, limit - linep + extra_chars);
+ (void) snprintf(uidp, idlen + 1, "%u:%u", uid, gid);
+ *(uidp + idlen) = ':'; /* restore : that was overwritten by snprintf */
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
}
static files_backend_op_t passwd_ops[] = {
diff --git a/usr/src/lib/nsswitch/ldap/common/getgrent.c b/usr/src/lib/nsswitch/ldap/common/getgrent.c
index f9d92227dd..bfcec21fbb 100644
--- a/usr/src/lib/nsswitch/ldap/common/getgrent.c
+++ b/usr/src/lib/nsswitch/ldap/common/getgrent.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <grp.h>
#include "ldap_common.h"
@@ -74,9 +72,13 @@ _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
int firstime = 1;
char *buffer = NULL;
ns_ldap_result_t *result = be->result;
- char **gname, **passwd, **gid, *password;
+ char **gname, **passwd, **gid, *password, *end;
+ char gid_nobody[NOBODY_STR_LEN];
+ char *gid_nobody_v[1];
ns_ldap_attr_t *members;
+ (void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
+ gid_nobody_v[0] = gid_nobody;
if (result == NULL)
return (NSS_STR_PARSE_PARSE);
@@ -121,6 +123,9 @@ _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
nss_result = NSS_STR_PARSE_PARSE;
goto result_grp2str;
}
+ /* Validate GID */
+ if (strtoul(gid[0], &end, 10) > MAXUID)
+ gid = gid_nobody_v;
len = snprintf(buffer, buflen, "%s:%s:%s:", gname[0], password, gid[0]);
TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
@@ -206,6 +211,9 @@ getbygid(ldap_backend_ptr be, void *a)
char userdata[SEARCHFILTERLEN];
int ret;
+ if (argp->key.uid > MAXUID)
+ return ((nss_status_t)NSS_NOTFOUND);
+
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETGRGID, argp->key.uid);
if (ret >= sizeof (searchfilter) || ret < 0)
diff --git a/usr/src/lib/nsswitch/ldap/common/getpwnam.c b/usr/src/lib/nsswitch/ldap/common/getpwnam.c
index a2c9ff40c9..4b98ada4d5 100644
--- a/usr/src/lib/nsswitch/ldap/common/getpwnam.c
+++ b/usr/src/lib/nsswitch/ldap/common/getpwnam.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <pwd.h>
#include "ldap_common.h"
@@ -79,6 +77,14 @@ _nss_ldap_passwd2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
char **uid_v, **uidn_v, **gidn_v;
char **gecos_v, **homedir_v, **shell_v;
char *NULL_STR = "";
+ char uid_nobody[NOBODY_STR_LEN];
+ char gid_nobody[NOBODY_STR_LEN], *end;
+ char *uid_nobody_v[1], *gid_nobody_v[1];
+
+ (void) snprintf(uid_nobody, sizeof (uid_nobody), "%u", UID_NOBODY);
+ uid_nobody_v[0] = uid_nobody;
+ (void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
+ gid_nobody_v[0] = gid_nobody;
if (result == NULL)
return (NSS_STR_PARSE_PARSE);
@@ -98,10 +104,15 @@ _nss_ldap_passwd2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
uidn_v = __ns_ldap_getAttr(entry, _PWD_UIDNUMBER);
gidn_v = __ns_ldap_getAttr(entry, _PWD_GIDNUMBER);
if (uid_v == NULL || uidn_v == NULL || gidn_v == NULL ||
- uid_v[0] == NULL || uidn_v[0] == NULL || gidn_v[0] == NULL) {
+ uid_v[0] == NULL || uidn_v[0] == NULL || gidn_v[0] == NULL) {
nss_result = NSS_STR_PARSE_PARSE;
goto result_pwd2str;
}
+ /* Validate UID and GID */
+ if (strtoul(uidn_v[0], &end, 10) > MAXUID)
+ uidn_v = uid_nobody_v;
+ if (strtoul(gidn_v[0], &end, 10) > MAXUID)
+ gidn_v = gid_nobody_v;
str_len = strlen(uid_v[0]) + strlen(uidn_v[0]) + strlen(gidn_v[0]);
if (str_len > buflen) {
nss_result = NSS_STR_PARSE_ERANGE;
@@ -140,15 +151,14 @@ _nss_ldap_passwd2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
}
(void) snprintf(be->buffer, be->buflen,
- "%s:%s:%s:%s:%s:%s:%s",
- uid_v[0], "x", uidn_v[0], gidn_v[0],
- gecos_v[0], homedir_v[0], shell_v[0]);
+ "%s:%s:%s:%s:%s:%s:%s",
+ uid_v[0], "x", uidn_v[0], gidn_v[0],
+ gecos_v[0], homedir_v[0], shell_v[0]);
} else {
(void) snprintf(argp->buf.buffer, (str_len + 8),
- "%s:%s:%s:%s:%s:%s:%s",
- uid_v[0], "x", uidn_v[0], gidn_v[0],
- gecos_v[0], homedir_v[0], shell_v[0]);
-
+ "%s:%s:%s:%s:%s:%s:%s",
+ uid_v[0], "x", uidn_v[0], gidn_v[0],
+ gecos_v[0], homedir_v[0], shell_v[0]);
}
result_pwd2str:
@@ -186,8 +196,7 @@ getbyname(ldap_backend_ptr be, void *a)
return ((nss_status_t)NSS_NOTFOUND);
return ((nss_status_t)_nss_ldap_lookup(be, argp,
- _PASSWD, searchfilter, NULL,
- _merge_SSD_filter, userdata));
+ _PASSWD, searchfilter, NULL, _merge_SSD_filter, userdata));
}
@@ -207,6 +216,9 @@ getbyuid(ldap_backend_ptr be, void *a)
char userdata[SEARCHFILTERLEN];
int ret;
+ if (argp->key.uid > MAXUID)
+ return ((nss_status_t)NSS_NOTFOUND);
+
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETPWUID, (long)argp->key.uid);
if (ret >= sizeof (searchfilter) || ret < 0)
@@ -218,8 +230,7 @@ getbyuid(ldap_backend_ptr be, void *a)
return ((nss_status_t)NSS_NOTFOUND);
return ((nss_status_t)_nss_ldap_lookup(be, argp,
- _PASSWD, searchfilter, NULL,
- _merge_SSD_filter, userdata));
+ _PASSWD, searchfilter, NULL, _merge_SSD_filter, userdata));
}
static ldap_backend_op_t passwd_ops[] = {
@@ -245,6 +256,6 @@ _nss_ldap_passwd_constr(const char *dummy1, const char *dummy2,
{
return ((nss_backend_t *)_nss_ldap_constr(passwd_ops,
- sizeof (passwd_ops)/sizeof (passwd_ops[0]),
- _PASSWD, pwd_attrs, _nss_ldap_passwd2str));
+ sizeof (passwd_ops)/sizeof (passwd_ops[0]),
+ _PASSWD, pwd_attrs, _nss_ldap_passwd2str));
}
diff --git a/usr/src/lib/nsswitch/ldap/common/ldap_common.h b/usr/src/lib/nsswitch/ldap/common/ldap_common.h
index d6e08680c4..7d9b56613a 100644
--- a/usr/src/lib/nsswitch/ldap/common/ldap_common.h
+++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _LDAP_COMMON_H
#define _LDAP_COMMON_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -88,6 +86,16 @@ extern "C" {
buffer += len; \
buflen -= len;
+/*
+ * We need to use UID_NOBODY and GID_NOBODY as strings. Therefore we use
+ * snprintf to convert [U|G]ID_NOBODY into a string. The target buffer
+ * size was chosen as 21 to allow the largest 64-bit number to be stored
+ * as string in it. Right now uid_t and gid_t are 32-bit so we don't
+ * really need 21 characters but it does allow for future expansion
+ * without having to modify this code.
+ */
+#define NOBODY_STR_LEN 21
+
/*
* Superset the nss_backend_t abstract data type. This ADT has
diff --git a/usr/src/lib/nsswitch/nis/common/getgrent.c b/usr/src/lib/nsswitch/nis/common/getgrent.c
index f6447a9d4c..45fe104a9a 100644
--- a/usr/src/lib/nsswitch/nis/common/getgrent.c
+++ b/usr/src/lib/nsswitch/nis/common/getgrent.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,8 +27,6 @@
* nis/getgrent.c -- "nis" backend for nsswitch "group" database
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <grp.h>
#include <pwd.h>
#include "nis_common.h"
@@ -58,10 +56,70 @@ getbygid(be, a)
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
char gidstr[12]; /* More than enough */
+ if (argp->key.gid > MAXUID)
+ return (NSS_NOTFOUND);
(void) snprintf(gidstr, 12, "%d", argp->key.gid);
return (_nss_nis_lookup(be, argp, 0, "group.bygid", gidstr, 0));
}
+/*
+ * Validates group entry replacing gid > MAXUID by GID_NOBODY.
+ */
+int
+validate_group_ids(char **linepp, int *linelenp, int allocbuf)
+{
+ char *linep, *limit, *gidp, *newline;
+ ulong_t gid;
+ int oldgidlen, idlen;
+ int linelen = *linelenp, newlinelen;
+
+ linep = *linepp;
+ limit = linep + linelen;
+
+ /* +/- entries valid for compat source only */
+ if (linelen == 0 || *linep == '+' || *linep == '-')
+ return (NSS_STR_PARSE_SUCCESS);
+
+ while (linep < limit && *linep++ != ':') /* skip groupname */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
+ if (linep == limit)
+ return (NSS_STR_PARSE_PARSE);
+
+ gidp = linep;
+ gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */
+ oldgidlen = linep - gidp;
+ if (linep >= limit || oldgidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ if (gid <= MAXUID)
+ return (NSS_STR_PARSE_SUCCESS);
+
+ idlen = snprintf(NULL, 0, "%u", GID_NOBODY);
+ newlinelen = linelen + idlen - oldgidlen;
+ if (newlinelen > linelen) {
+ /* need a larger buffer */
+ if (!allocbuf || (newline = malloc(newlinelen + 1)) == NULL)
+ return (NSS_STR_PARSE_ERANGE);
+ /* Replace ephemeral ids by ID_NOBODY in the new buffer */
+ *(gidp - 1) = '\0';
+ (void) snprintf(newline, newlinelen + 1, "%s:%u%s",
+ *linepp, GID_NOBODY, linep);
+ free(*linepp);
+ *linepp = newline;
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
+ }
+
+ /* Replace ephemeral gid by GID_NOBODY in the same buffer */
+ (void) bcopy(linep, gidp + idlen, limit - linep + 1);
+ (void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY);
+ *(gidp + idlen) = ':';
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
static nss_status_t
getbymember(be, a)
nis_backend_ptr_t be;
@@ -225,16 +283,15 @@ netid_lookup(struct nss_groupsbymem *argp)
}
if ((res = _nss_nis_ypmatch(domain, "netid.byname", netname,
- &val, &vallen, 0)) != NSS_SUCCESS) {
+ &val, &vallen, 0)) != NSS_SUCCESS) {
return (res);
}
(void) strtok_r(val, "#", &lasts);
parse_res = parse_netid(val, argp->gid_array, argp->maxgids,
- &argp->numgids);
+ &argp->numgids);
free(val);
return ((parse_res == NSS_STR_PARSE_SUCCESS)
- ? NSS_SUCCESS
- : NSS_NOTFOUND);
+ ? NSS_SUCCESS : NSS_NOTFOUND);
}
diff --git a/usr/src/lib/nsswitch/nis/common/getpwnam.c b/usr/src/lib/nsswitch/nis/common/getpwnam.c
index a23ee8af5c..ad55f9e5ca 100644
--- a/usr/src/lib/nsswitch/nis/common/getpwnam.c
+++ b/usr/src/lib/nsswitch/nis/common/getpwnam.c
@@ -19,14 +19,12 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* nis/getpwnam.c -- "nis" backend for nsswitch "passwd" database
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <pwd.h>
#include "nis_common.h"
@@ -49,10 +47,81 @@ getbyuid(be, a)
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
char uidstr[12]; /* More than enough */
- (void) snprintf(uidstr, 12, "%ld", argp->key.uid);
+ if (argp->key.uid > MAXUID)
+ return (NSS_NOTFOUND);
+ (void) snprintf(uidstr, 12, "%u", argp->key.uid);
return (_nss_nis_lookup(be, argp, 0, "passwd.byuid", uidstr, 0));
}
+/*
+ * Validates passwd entry replacing uid/gid > MAXUID by ID_NOBODY.
+ */
+int
+validate_passwd_ids(char **linepp, int *linelenp, int allocbuf)
+{
+ char *linep, *limit, *uidp, *gidp, *newline;
+ uid_t uid;
+ gid_t gid;
+ ulong_t uidl, gidl;
+ int olduidlen, oldgidlen, idlen;
+ int linelen = *linelenp, newlinelen;
+
+ linep = *linepp;
+ limit = linep + linelen;
+
+ /* +/- entries valid for compat source only */
+ if (linelen == 0 || *linep == '+' || *linep == '-')
+ return (NSS_STR_PARSE_SUCCESS);
+
+ while (linep < limit && *linep++ != ':') /* skip username */
+ continue;
+ while (linep < limit && *linep++ != ':') /* skip password */
+ continue;
+ if (linep == limit)
+ return (NSS_STR_PARSE_PARSE);
+
+ uidp = linep;
+ uidl = strtoul(uidp, (char **)&linep, 10); /* grab uid */
+ olduidlen = linep - uidp;
+ if (++linep >= limit || olduidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ gidp = linep;
+ gidl = strtoul(gidp, (char **)&linep, 10); /* grab gid */
+ oldgidlen = linep - gidp;
+ if (linep >= limit || oldgidlen == 0)
+ return (NSS_STR_PARSE_PARSE);
+
+ if (uidl <= MAXUID && gidl <= MAXUID)
+ return (NSS_STR_PARSE_SUCCESS);
+ uid = (uidl > MAXUID) ? UID_NOBODY : (uid_t)uidl;
+ gid = (gidl > MAXUID) ? GID_NOBODY : (gid_t)gidl;
+
+ /* Check if we have enough space in the buffer */
+ idlen = snprintf(NULL, 0, "%u:%u", uid, gid);
+ newlinelen = linelen + idlen - olduidlen - oldgidlen - 1;
+ if (newlinelen > linelen) {
+ /* need a larger buffer */
+ if (!allocbuf || (newline = malloc(newlinelen + 1)) == NULL)
+ return (NSS_STR_PARSE_ERANGE);
+ /* Replace ephemeral ids by ID_NOBODY in the new buffer */
+ *(uidp - 1) = '\0';
+ (void) snprintf(newline, newlinelen + 1, "%s:%u:%u%s",
+ *linepp, uid, gid, linep);
+ free(*linepp);
+ *linepp = newline;
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
+ }
+
+ /* Replace ephemeral ids by ID_NOBODY in the same buffer */
+ (void) bcopy(linep, uidp + idlen, limit - linep + 1);
+ (void) snprintf(uidp, idlen + 1, "%u:%u", uid, gid);
+ *(uidp + idlen) = ':'; /* restore : that was overwritten by snprintf */
+ *linelenp = newlinelen;
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
static nis_backend_op_t passwd_ops[] = {
_nss_nis_destr,
_nss_nis_endent,
diff --git a/usr/src/lib/nsswitch/nis/common/nis_common.c b/usr/src/lib/nsswitch/nis/common/nis_common.c
index 6a4e6b4c13..a7294a85fb 100644
--- a/usr/src/lib/nsswitch/nis/common/nis_common.c
+++ b/usr/src/lib/nsswitch/nis/common/nis_common.c
@@ -30,8 +30,6 @@
* Common code and structures used by name-service-switch "nis" backends.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "nis_common.h"
#include <string.h>
#include <synch.h>
@@ -235,6 +233,17 @@ _nss_nis_lookup(be, args, netdb, map, key, ypstatusp)
return (res);
}
+ parsestat = NSS_STR_PARSE_SUCCESS;
+ if (strcmp(map, "passwd.byname") == 0 ||
+ strcmp(map, "passwd.byuid") == 0) {
+ parsestat = validate_passwd_ids(&val, &vallen, 1);
+ } else if (strcmp(map, "group.byname") == 0)
+ parsestat = validate_group_ids(&val, &vallen, 1);
+ if (parsestat != NSS_STR_PARSE_SUCCESS) {
+ free(val);
+ return (NSS_NOTFOUND);
+ }
+
free_ptr = val;
if (netdb) {
diff --git a/usr/src/lib/nsswitch/nis/common/nis_common.h b/usr/src/lib/nsswitch/nis/common/nis_common.h
index 7aaf6c4989..aabac9ab98 100644
--- a/usr/src/lib/nsswitch/nis/common/nis_common.h
+++ b/usr/src/lib/nsswitch/nis/common/nis_common.h
@@ -33,9 +33,9 @@
#ifndef _NIS_COMMON_H
#define _NIS_COMMON_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <nss_dbdefs.h>
+#include <stdlib.h>
+#include <strings.h>
#include <signal.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yp_prot.h>
@@ -131,6 +131,10 @@ extern int __yp_next_cflookup(char *, char *, char *, int, char **, int *,
extern int __yp_all_cflookup(char *, char *, struct ypall_callback *, int);
+/* functions to validate passwd and group ids */
+extern int validate_passwd_ids(char **linepp, int *linelenp, int allocbuf);
+extern int validate_group_ids(char **linepp, int *linelenp, int allocbuf);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/nsswitch/nisplus/common/getgrent.c b/usr/src/lib/nsswitch/nisplus/common/getgrent.c
index c5c76514b6..1c8cdeb349 100644
--- a/usr/src/lib/nsswitch/nisplus/common/getgrent.c
+++ b/usr/src/lib/nsswitch/nisplus/common/getgrent.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,8 +27,6 @@
* nisplus/getgrent.c -- NIS+ backend for nsswitch "group" database
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <grp.h>
#include <string.h>
#include <stdlib.h>
@@ -71,6 +69,9 @@ getbygid(be, a)
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
char gidstr[12]; /* More than enough */
+ if (argp->key.gid > MAXUID)
+ return (NSS_NOTFOUND);
+
(void) snprintf(gidstr, 12, "%u", argp->key.gid);
return (_nss_nisplus_lookup(be, argp, GR_TAG_GID, gidstr));
}
@@ -194,6 +195,8 @@ nis_object2str(nobj, obj, be, argp)
nss_XbyY_args_t *argp;
{
char *buffer, *name, *passwd, *gid, *members;
+ ulong_t gidl;
+ char gid_nobody[NOBODY_STR_LEN];
int buflen, namelen, passwdlen, gidlen, memberslen;
char *endnum;
struct entry_col *ecol;
@@ -224,9 +227,15 @@ nis_object2str(nobj, obj, be, argp)
/* gid: group id */
__NISPLUS_GETCOL_OR_RETURN(ecol, GR_NDX_GID, gidlen, gid);
- (void) strtol(gid, &endnum, 10);
+ gidl = strtoul(gid, &endnum, 10);
if (*endnum != 0 || gid == endnum)
return (NSS_STR_PARSE_PARSE);
+ if (gidl > MAXUID) {
+ (void) snprintf(gid_nobody, sizeof (gid_nobody),
+ "%u", GID_NOBODY);
+ gid = gid_nobody;
+ gidlen = strlen(gid);
+ }
/* members: gid list */
__NISPLUS_GETCOL_OR_EMPTY(ecol, GR_NDX_MEM, memberslen, members);
diff --git a/usr/src/lib/nsswitch/nisplus/common/getpwnam.c b/usr/src/lib/nsswitch/nisplus/common/getpwnam.c
index 19807456e5..c0d3d1bd4f 100644
--- a/usr/src/lib/nsswitch/nisplus/common/getpwnam.c
+++ b/usr/src/lib/nsswitch/nisplus/common/getpwnam.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,8 +27,6 @@
* nisplus/getpwnam.c -- NIS+ backend for nsswitch "passwd" database
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
@@ -54,6 +52,9 @@ getbyuid(be, a)
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
char uidstr[12]; /* More than enough */
+ if (argp->key.uid > MAXUID)
+ return (NSS_NOTFOUND);
+
(void) snprintf(uidstr, 12, "%ld", argp->key.uid);
return (_nss_nisplus_lookup(be, argp, PW_TAG_UID, uidstr));
}
@@ -73,6 +74,9 @@ nis_object2str(nobj, obj, be, argp)
nss_XbyY_args_t *argp;
{
char *buffer, *name, *uid, *gid, *gecos;
+ ulong_t uidl, gidl;
+ char uid_nobody[NOBODY_STR_LEN];
+ char gid_nobody[NOBODY_STR_LEN];
char *dir, *shell, *endnum;
int buflen, namelen, uidlen, gidlen, gecoslen;
int dirlen, shelllen;
@@ -100,15 +104,27 @@ nis_object2str(nobj, obj, be, argp)
/* uid: user id. Must be numeric */
__NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_UID, uidlen, uid);
- (void) strtol(uid, &endnum, 10);
+ uidl = strtoul(uid, &endnum, 10);
if (*endnum != 0 || uid == endnum)
return (NSS_STR_PARSE_PARSE);
+ if (uidl > MAXUID) {
+ (void) snprintf(uid_nobody, sizeof (uid_nobody),
+ "%u", UID_NOBODY);
+ uid = uid_nobody;
+ uidlen = strlen(uid);
+ }
/* gid: primary group id. Must be numeric */
__NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_GID, gidlen, gid);
- (void) strtol(gid, &endnum, 10);
+ gidl = strtoul(gid, &endnum, 10);
if (*endnum != 0 || gid == endnum)
return (NSS_STR_PARSE_PARSE);
+ if (gidl > MAXUID) {
+ (void) snprintf(gid_nobody, sizeof (gid_nobody),
+ "%u", GID_NOBODY);
+ gid = gid_nobody;
+ gidlen = strlen(gid);
+ }
/* gecos: user's real name */
__NISPLUS_GETCOL_OR_EMPTY(ecol, PW_NDX_GCOS, gecoslen, gecos);
diff --git a/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h b/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h
index b446c0b23a..2af5717262 100644
--- a/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h
+++ b/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h
@@ -28,8 +28,6 @@
* Common code used by name-service-switch "nisplus" backends
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef _NISPLUS_COMMON_H
#define _NISPLUS_COMMON_H
@@ -42,6 +40,9 @@
*/
#define NIS_LIST_COMMON (FOLLOW_LINKS | FOLLOW_PATH)
+/* See the comment in $SRC/lib/nsswitch/ldap/common/ldap_common.h */
+#define NOBODY_STR_LEN 21
+
typedef struct nisplus_backend *nisplus_backend_ptr_t;
typedef nss_status_t (*nisplus_backend_op_t)(nisplus_backend_ptr_t, void *);
diff --git a/usr/src/lib/passwdutil/switch_utils.c b/usr/src/lib/passwdutil/switch_utils.c
index 3b2221bff7..8145ed360e 100644
--- a/usr/src/lib/passwdutil/switch_utils.c
+++ b/usr/src/lib/passwdutil/switch_utils.c
@@ -23,7 +23,6 @@
* Use is subject to license terms.
*/
-
#include <sys/types.h>
#include <nsswitch.h>
#include <stdlib.h>
@@ -134,6 +133,8 @@ get_ns(pwu_repository_t *rep, int accesstype)
enum __nsw_parse_err pserr;
struct __nsw_lookup *lkp;
struct __nsw_lookup *lkp2;
+ struct __nsw_lookup *lkp3;
+ struct __nsw_lookup *lkpn;
int result = REP_NOREP;
if (rep != PWU_DEFAULT_REP) {
@@ -150,7 +151,7 @@ get_ns(pwu_repository_t *rep, int accesstype)
* find the name service switch entry. (Backward compat)
*/
syslog(LOG_ERR, "passwdutil.so: nameservice switch entry for "
- "passwd not found.");
+ "passwd not found.");
result = REP_FILES | REP_NIS;
return (result);
}
@@ -158,9 +159,13 @@ get_ns(pwu_repository_t *rep, int accesstype)
lkp = conf->lookups;
/*
- * Supported nsswitch.conf can have a maximum of 2 repositories.
+ * Supported nsswitch.conf can have a maximum of 3 repositories.
* If we encounter an unsupported nsswitch.conf, we return REP_NSS
* to fall back to the nsswitch backend.
+ *
+ * Note that specifying 'ad' in the configuration is acceptable
+ * though changing AD users' passwords through passwd(1) is not.
+ * Therefore "ad" will be silently ignored.
*/
if (conf->num_lookups == 1) {
/* files or compat */
@@ -185,6 +190,35 @@ get_ns(pwu_repository_t *rep, int accesstype)
result |= REP_NIS;
else if (strcmp(lkp2->service_name, "nisplus") == 0)
result |= REP_NISPLUS;
+ else if (strcmp(lkp2->service_name, "ad") != 0)
+ result = REP_NSS;
+ /* AD is ignored */
+ } else {
+ result = REP_NSS;
+ }
+ } else if (conf->num_lookups == 3) {
+ /*
+ * Valid configurations with 3 repositories are:
+ * files ad [nis | ldap | nisplus] OR
+ * files [nis | ldap | nisplus] ad
+ */
+ lkp2 = lkp->next;
+ lkp3 = lkp2->next;
+ if (strcmp(lkp2->service_name, "ad") == 0)
+ lkpn = lkp3;
+ else if (strcmp(lkp3->service_name, "ad") == 0)
+ lkpn = lkp2;
+ else
+ lkpn = NULL;
+ if (strcmp(lkp->service_name, "files") == 0 &&
+ lkpn != NULL) {
+ result = REP_FILES;
+ if (strcmp(lkpn->service_name, "ldap") == 0)
+ result |= REP_LDAP;
+ else if (strcmp(lkpn->service_name, "nis") == 0)
+ result |= REP_NIS;
+ else if (strcmp(lkpn->service_name, "nisplus") == 0)
+ result |= REP_NISPLUS;
else
result = REP_NSS;
} else {
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com
index 61f806d12c..293d707cca 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_com
+++ b/usr/src/pkgdefs/SUNWarc/prototype_com
@@ -23,8 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
#
# This required package information file contains a list of package contents.
@@ -72,6 +70,8 @@ s none usr/ccs/lib/values-Xt.o=../../lib/values-Xt.o
d none usr/lib 755 root bin
s none usr/lib/llib-ladm=../../lib/llib-ladm
s none usr/lib/llib-ladm.ln=../../lib/llib-ladm.ln
+f none usr/lib/llib-ladutils 644 root bin
+f none usr/lib/llib-ladutils.ln 644 root bin
s none usr/lib/llib-laio=../../lib/llib-laio
s none usr/lib/llib-laio.ln=../../lib/llib-laio.ln
s none usr/lib/llib-lpam=../../lib/llib-lpam
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386
index 924d200125..d08b072f5e 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386
@@ -23,8 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
#
# This required package information file contains a list of package contents.
@@ -68,6 +66,7 @@ f none usr/lib/amd64/values-Xt.o 644 root bin
f none usr/lib/amd64/values-xpg4.o 644 root bin
f none usr/lib/amd64/values-xpg6.o 644 root bin
s none usr/lib/amd64/llib-ladm.ln=../../../lib/amd64/llib-ladm.ln
+f none usr/lib/amd64/llib-ladutils.ln 644 root bin
s none usr/lib/amd64/llib-laio.ln=../../../lib/amd64/llib-laio.ln
f none usr/lib/amd64/llib-lbsdmalloc.ln 644 root bin
s none usr/lib/amd64/llib-lbsm.ln=../../../lib/amd64/llib-lbsm.ln
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc
index fe4b089836..23b7473759 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc
@@ -23,8 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
#
# This required package information file contains a list of package contents.
@@ -64,6 +62,7 @@ f none usr/lib/sparcv9/values-Xt.o 644 root bin
f none usr/lib/sparcv9/values-xpg4.o 644 root bin
f none usr/lib/sparcv9/values-xpg6.o 644 root bin
s none usr/lib/sparcv9/llib-ladm.ln=../../../lib/sparcv9/llib-ladm.ln
+f none usr/lib/sparcv9/llib-ladutils.ln 644 root bin
s none usr/lib/sparcv9/llib-laio.ln=../../../lib/sparcv9/llib-laio.ln
f none usr/lib/sparcv9/llib-lbsdmalloc.ln 644 root bin
s none usr/lib/sparcv9/llib-lbsm.ln=../../../lib/sparcv9/llib-lbsm.ln
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com
index 6c8a7e5e0e..cde1a248cf 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com
@@ -69,6 +69,8 @@ f none usr/lib/extendedFILE.so.1 755 root bin
f none usr/lib/lib.b 444 root bin
s none usr/lib/libadm.so=../../lib/libadm.so.1
s none usr/lib/libadm.so.1=../../lib/libadm.so.1
+f none usr/lib/libadutils.so.1 755 root bin
+s none usr/lib/libadutils.so=./libadutils.so.1
s none usr/lib/libaio.so=../../lib/libaio.so.1
s none usr/lib/libaio.so.1=../../lib/libaio.so.1
f none usr/lib/libast.so.1 755 root bin
@@ -298,6 +300,7 @@ s none usr/lib/nss_compat.so.1=../../lib/nss_compat.so.1
s none usr/lib/nss_dns.so.1=../../lib/nss_dns.so.1
s none usr/lib/nss_files.so.1=../../lib/nss_files.so.1
f none usr/lib/nss_ldap.so.1 755 root bin
+f none usr/lib/nss_ad.so.1 755 root bin
s none usr/lib/nss_nis.so.1=../../lib/nss_nis.so.1
s none usr/lib/nss_nisplus.so.1=../../lib/nss_nisplus.so.1
s none usr/lib/nss_user.so.1=../../lib/nss_user.so.1
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386
index 4b376fba9d..542bea8cdf 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386
@@ -156,6 +156,8 @@ f none usr/lib/security/amd64/pkcs11_softtoken.so.1 755 root bin
s none usr/lib/security/amd64/pkcs11_softtoken.so=./pkcs11_softtoken.so.1
s none usr/lib/64=amd64
d none usr/lib/amd64 755 root bin
+f none usr/lib/amd64/libadutils.so.1 755 root bin
+s none usr/lib/amd64/libadutils.so=./libadutils.so.1
f none usr/lib/amd64/libbsdmalloc.so.1 755 root bin
s none usr/lib/amd64/libbsdmalloc.so=libbsdmalloc.so.1
s none usr/lib/amd64/libbsm.so.1=../../../lib/amd64/libbsm.so.1
@@ -361,6 +363,7 @@ s none usr/lib/amd64/nss_compat.so.1=../../../lib/amd64/nss_compat.so.1
s none usr/lib/amd64/nss_dns.so.1=../../../lib/amd64/nss_dns.so.1
s none usr/lib/amd64/nss_files.so.1=../../../lib/amd64/nss_files.so.1
f none usr/lib/amd64/nss_ldap.so.1 755 root bin
+f none usr/lib/amd64/nss_ad.so.1 755 root bin
s none usr/lib/amd64/nss_nis.so.1=../../../lib/amd64/nss_nis.so.1
s none usr/lib/amd64/nss_nisplus.so.1=../../../lib/amd64/nss_nisplus.so.1
s none usr/lib/amd64/nss_user.so.1=../../../lib/amd64/nss_user.so.1
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
index e8117dff2c..407cbed963 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
@@ -149,6 +149,8 @@ f none usr/lib/security/sparcv9/pkcs11_softtoken.so.1 755 root bin
s none usr/lib/security/sparcv9/pkcs11_softtoken.so=./pkcs11_softtoken.so.1
s none usr/lib/64=sparcv9
d none usr/lib/sparcv9 755 root bin
+f none usr/lib/sparcv9/libadutils.so.1 755 root bin
+s none usr/lib/sparcv9/libadutils.so=./libadutils.so.1
f none usr/lib/sparcv9/libbsdmalloc.so.1 755 root bin
s none usr/lib/sparcv9/libbsdmalloc.so=libbsdmalloc.so.1
s none usr/lib/sparcv9/libbsm.so.1=../../../lib/sparcv9/libbsm.so.1
@@ -352,6 +354,7 @@ s none usr/lib/sparcv9/nss_compat.so.1=../../../lib/sparcv9/nss_compat.so.1
s none usr/lib/sparcv9/nss_dns.so.1=../../../lib/sparcv9/nss_dns.so.1
s none usr/lib/sparcv9/nss_files.so.1=../../../lib/sparcv9/nss_files.so.1
f none usr/lib/sparcv9/nss_ldap.so.1 755 root bin
+f none usr/lib/sparcv9/nss_ad.so.1 755 root bin
s none usr/lib/sparcv9/nss_nis.so.1=../../../lib/sparcv9/nss_nis.so.1
s none usr/lib/sparcv9/nss_nisplus.so.1=../../../lib/sparcv9/nss_nisplus.so.1
s none usr/lib/sparcv9/nss_user.so.1=../../../lib/sparcv9/nss_user.so.1
diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com
index 6682b68886..0938a05481 100644
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com
@@ -225,6 +225,7 @@ e nsswitch etc/nsswitch.conf 644 root sys
f none etc/nsswitch.files 644 root sys
f none etc/nsswitch.ldap 644 root sys
f none etc/nsswitch.dns 644 root sys
+f none etc/nsswitch.ad 644 root sys
d none etc/opt 755 root sys
e passwd etc/passwd 644 root sys
e etcprofile etc/profile 644 root sys