changeset 5043:667e437d66d0

6601949 nfsmapid should handle Windows users and groups in a heterogenous environment 6604089 nfsmapid uses incorrect size when allocating the return buffer
author baban
date Thu, 13 Sep 2007 13:50:11 -0700
parents 105442d80fa2
children 366fa13eb032
files usr/src/cmd/fs.d/nfs/nfsmapid/Makefile usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_test.c usr/src/cmd/fs.d/nfs/svc/mapid.xml usr/src/cmd/idmap/idmapd/dbutils.c usr/src/lib/libidmap/common/idmap.h usr/src/lib/libidmap/common/idmap_api.c usr/src/lib/libidmap/common/mapfile-vers
diffstat 8 files changed, 376 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fs.d/nfs/nfsmapid/Makefile	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/cmd/fs.d/nfs/nfsmapid/Makefile	Thu Sep 13 13:50:11 2007 -0700
@@ -33,7 +33,7 @@
 include		../../Makefile.fstype
 
 LDLIBS   +=	-L$(ROOT)/usr/lib/nfs -R/usr/lib/nfs
-LDLIBS   +=	-lnsl -lmapid -ldoor -ldtrace
+LDLIBS   +=	-lnsl -lmapid -ldoor -ldtrace -lidmap
 SRCS	  =	nfsmapid.c nfsmapid_server.c
 DSRC	  =	nfsmapid_dt.d
 DOBJ	  =	$(DSRC:%.d=%.o)
--- a/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c	Thu Sep 13 13:50:11 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,18 +52,8 @@
 #include <nfs/nfsid_map.h>
 #include <nfs/mapid.h>
 #include <sys/sdt.h>
-
-/*
- * We cannot use the backend nscd as it may make syscalls that may
- * cause further nfsmapid upcalls introducing deadlock.
- * Use the internal uncached versions of get*_r.
- */
-extern struct group *_uncached_getgrgid_r(gid_t, struct group *, char *, int);
-extern struct group *_uncached_getgrnam_r(const char *, struct group *,
-    char *, int);
-extern struct passwd *_uncached_getpwuid_r(uid_t, struct passwd *, char *, int);
-extern struct passwd *_uncached_getpwnam_r(const char *, struct passwd *,
-    char *, int);
+#include <sys/idmap.h>
+#include <idmap.h>
 
 #define		UID_MAX_STR_LEN		11	/* Digits in UID_MAX + 1 */
 #define		DIAG_FILE		"/var/run/nfs4_domain"
@@ -100,9 +90,12 @@
 {
 	struct mapid_res result;
 	struct passwd	 pwd;
+	struct passwd	*pwd_ptr;
+	int		 pwd_rc;
 	char		*pwd_buf;
 	char		*user;
 	char		*domain;
+	idmap_stat	 rc;
 
 	if (argp->u_arg.len <= 0 || arg_size < MAPID_ARG_LEN(argp->u_arg.len)) {
 		result.status = NFSMAPID_INVALID;
@@ -111,10 +104,10 @@
 	}
 
 	if (!extract_domain(argp->str, &user, &domain)) {
-		long id;
+		unsigned long id;
 
 		/*
-		 * Invalid "user@dns_domain" string. Still, the user
+		 * Invalid "user@domain" string. Still, the user
 		 * part might be an encoded uid, so do a final check.
 		 * Remember, domain part of string was not set since
 		 * not a valid string.
@@ -125,14 +118,13 @@
 			goto done;
 		}
 
+		errno = 0;
+		id = strtoul(user, (char **)NULL, 10);
+
 		/*
-		 * Since atoi() does not return proper errors for
-		 * invalid translation, use strtol() instead.
+		 * We don't accept ephemeral ids from the wire.
 		 */
-		errno = 0;
-		id = strtol(user, (char **)NULL, 10);
-
-		if (errno || id < 0 || id > UID_MAX) {
+		if (errno || id > UID_MAX) {
 			result.status = NFSMAPID_UNMAPPABLE;
 			result.u_res.uid = UID_NOBODY;
 			goto done;
@@ -145,19 +137,29 @@
 
 	/*
 	 * String properly constructed. Now we check for domain and
-	 * group validity. Note that we only look at the domain iff
-	 * the local domain is configured.
+	 * group validity.
 	 */
 	if (!cur_domain_null() && !valid_domain(domain)) {
-		result.status = NFSMAPID_BADDOMAIN;
-		result.u_res.uid = UID_NOBODY;
+		/*
+		 * If the domain part of the string does not
+		 * match the NFS domain, try to map it using
+		 * idmap service.
+		 */
+		rc = idmap_getuidbywinname(user, domain, &result.u_res.uid);
+		if (rc != IDMAP_SUCCESS) {
+			result.status = NFSMAPID_BADDOMAIN;
+			result.u_res.uid = UID_NOBODY;
+			goto done;
+		}
+		result.status = NFSMAPID_OK;
 		goto done;
 	}
 
 	if ((pwd_buf = malloc(pwd_buflen)) == NULL ||
-	    _uncached_getpwnam_r(user, &pwd, pwd_buf, pwd_buflen) == NULL) {
+	    (pwd_rc = getpwnam_r(user, &pwd, pwd_buf, pwd_buflen, &pwd_ptr))
+	    != 0 || pwd_ptr == NULL) {
 
-		if (pwd_buf == NULL)
+		if (pwd_buf == NULL || pwd_rc != 0)
 			result.status = NFSMAPID_INTERNAL;
 		else {
 			/*
@@ -187,8 +189,9 @@
 	struct mapid_res	 result;
 	struct mapid_res	*resp;
 	struct passwd		 pwd;
-	int			 pwd_len;
-	char			*pwd_buf;
+	struct passwd		 *pwd_ptr;
+	char			*pwd_buf = NULL;
+	char			*idmap_buf = NULL;
 	uid_t			 uid = argp->u_arg.uid;
 	size_t			 uid_str_len;
 	char			*pw_str;
@@ -197,10 +200,11 @@
 	size_t			 at_str_len;
 	char			 dom_str[DNAMEMAX];
 	size_t			 dom_str_len;
+	idmap_stat		 rc;
 
-	if (uid < 0 || uid > UID_MAX) {
+	if (uid == (uid_t)-1) {
 		/*
-		 * Negative uid or greater than UID_MAX
+		 * Sentinel uid is not a valid id
 		 */
 		resp = &result;
 		resp->status = NFSMAPID_BADID;
@@ -220,6 +224,35 @@
 	}
 
 	/*
+	 * If uid is ephemeral then resolve it using idmap service
+	 */
+	if (uid > UID_MAX) {
+		rc = idmap_getwinnamebyuid(uid, &idmap_buf, NULL);
+		if (rc != IDMAP_SUCCESS) {
+			/*
+			 * We don't put stringified ephemeral uids on
+			 * the wire.
+			 */
+			resp = &result;
+			resp->status = NFSMAPID_UNMAPPABLE;
+			resp->u_res.len = 0;
+			goto done;
+		}
+
+		/*
+		 * idmap_buf is already in the desired form i.e. name@domain
+		 */
+		pw_str = idmap_buf;
+		pw_str_len = strlen(pw_str);
+		at_str_len = dom_str_len = 0;
+		at_str = "";
+		dom_str[0] = '\0';
+		goto gen_result;
+	}
+
+	/*
+	 * Handling non-ephemeral uids
+	 *
 	 * We want to encode the uid into a literal string... :
 	 *
 	 *	- upon failure to allocate space from the heap
@@ -227,7 +260,8 @@
 	 *	- if there is no such uid in the passwd DB's
 	 */
 	if ((pwd_buf = malloc(pwd_buflen)) == NULL || dom_str_len == 0 ||
-	    _uncached_getpwuid_r(uid, &pwd, pwd_buf, pwd_buflen) == NULL) {
+	    getpwuid_r(uid, &pwd, pwd_buf, pwd_buflen, &pwd_ptr) != 0 ||
+	    pwd_ptr == NULL) {
 
 		/*
 		 * If we could not allocate from the heap, try
@@ -244,27 +278,34 @@
 		/*
 		 * Constructing literal string without '@' so that
 		 * we'll know that it's not a user, but rather a
-		 * uid encoded string. Can't overflow because we
-		 * already checked UID_MAX.
+		 * uid encoded string.
 		 */
 		pw_str = pwd_buf;
-		(void) sprintf(pw_str, "%d", (int)uid);
+		(void) sprintf(pw_str, "%u", uid);
 		pw_str_len = strlen(pw_str);
 		at_str_len = dom_str_len = 0;
 		at_str = "";
 		dom_str[0] = '\0';
 	} else {
 		/*
-		 * Otherwise, we construct the "user@domain" string
+		 * Otherwise, we construct the "user@domain" string if
+		 * it's not already in that form.
 		 */
 		pw_str = pwd.pw_name;
 		pw_str_len = strlen(pw_str);
-		at_str = "@";
-		at_str_len = 1;
+		if (strchr(pw_str, '@') == NULL) {
+			at_str = "@";
+			at_str_len = 1;
+		} else {
+			at_str_len = dom_str_len = 0;
+			at_str = "";
+			dom_str[0] = '\0';
+		}
 	}
 
+gen_result:
 	uid_str_len = pw_str_len + at_str_len + dom_str_len;
-	if ((resp = alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) {
+	if ((resp = alloca(MAPID_RES_LEN(uid_str_len))) == NULL) {
 		resp = &result;
 		resp->status = NFSMAPID_INTERNAL;
 		resp->u_res.len = 0;
@@ -273,7 +314,10 @@
 	/* LINTED format argument to sprintf */
 	(void) sprintf(resp->str, "%s%s%s", pw_str, at_str, dom_str);
 	resp->u_res.len = uid_str_len;
-	free(pwd_buf);
+	if (pwd_buf)
+		free(pwd_buf);
+	if (idmap_buf)
+		idmap_free(idmap_buf);
 	resp->status = NFSMAPID_OK;
 
 done:
@@ -286,7 +330,7 @@
 		resp->status = NFSMAPID_INTERNAL;
 		resp->u_res.len = 0;
 		(void) door_return((char *)&result, sizeof (struct mapid_res),
-							NULL, 0);
+		    NULL, 0);
 	}
 }
 
@@ -295,22 +339,25 @@
 {
 	struct mapid_res	result;
 	struct group		grp;
+	struct group		*grp_ptr;
+	int			grp_rc;
 	char			*grp_buf;
 	char			*group;
 	char			*domain;
+	idmap_stat		rc;
 
 	if (argp->u_arg.len <= 0 ||
-				arg_size < MAPID_ARG_LEN(argp->u_arg.len)) {
+	    arg_size < MAPID_ARG_LEN(argp->u_arg.len)) {
 		result.status = NFSMAPID_INVALID;
 		result.u_res.gid = GID_NOBODY;
 		goto done;
 	}
 
 	if (!extract_domain(argp->str, &group, &domain)) {
-		long id;
+		unsigned long id;
 
 		/*
-		 * Invalid "group@dns_domain" string. Still, the
+		 * Invalid "group@domain" string. Still, the
 		 * group part might be an encoded gid, so do a
 		 * final check. Remember, domain part of string
 		 * was not set since not a valid string.
@@ -321,14 +368,13 @@
 			goto done;
 		}
 
+		errno = 0;
+		id = strtoul(group, (char **)NULL, 10);
+
 		/*
-		 * Since atoi() does not return proper errors for
-		 * invalid translation, use strtol() instead.
+		 * We don't accept ephemeral ids from the wire.
 		 */
-		errno = 0;
-		id = strtol(group, (char **)NULL, 10);
-
-		if (errno || id < 0 || id > UID_MAX) {
+		if (errno || id > UID_MAX) {
 			result.status = NFSMAPID_UNMAPPABLE;
 			result.u_res.gid = GID_NOBODY;
 			goto done;
@@ -341,19 +387,29 @@
 
 	/*
 	 * String properly constructed. Now we check for domain and
-	 * group validity. Note that we only look at the domain iff
-	 * the local domain is configured.
+	 * group validity.
 	 */
 	if (!cur_domain_null() && !valid_domain(domain)) {
-		result.status = NFSMAPID_BADDOMAIN;
-		result.u_res.gid = GID_NOBODY;
+		/*
+		 * If the domain part of the string does not
+		 * match the NFS domain, try to map it using
+		 * idmap service.
+		 */
+		rc = idmap_getgidbywinname(group, domain, &result.u_res.gid);
+		if (rc != IDMAP_SUCCESS) {
+			result.status = NFSMAPID_BADDOMAIN;
+			result.u_res.gid = GID_NOBODY;
+			goto done;
+		}
+		result.status = NFSMAPID_OK;
 		goto done;
 	}
 
 	if ((grp_buf = malloc(grp_buflen)) == NULL ||
-	    _uncached_getgrnam_r(group, &grp, grp_buf, grp_buflen) == NULL) {
+	    (grp_rc = getgrnam_r(group, &grp, grp_buf, grp_buflen, &grp_ptr))
+	    != 0 || grp_ptr == NULL) {
 
-		if (grp_buf == NULL)
+		if (grp_buf == NULL || grp_rc != 0)
 			result.status = NFSMAPID_INTERNAL;
 		else {
 			/*
@@ -383,7 +439,10 @@
 	struct mapid_res	 result;
 	struct mapid_res	*resp;
 	struct group		 grp;
-	char			*grp_buf;
+	struct group		*grp_ptr;
+	char			*grp_buf = NULL;
+	char			*idmap_buf = NULL;
+	idmap_stat		 rc;
 	gid_t			 gid = argp->u_arg.gid;
 	size_t			 gid_str_len;
 	char			*gr_str;
@@ -393,9 +452,9 @@
 	char			 dom_str[DNAMEMAX];
 	size_t			 dom_str_len;
 
-	if (gid < 0 || gid > UID_MAX) {
+	if (gid == (gid_t)-1) {
 		/*
-		 * Negative gid or greater than UID_MAX
+		 * Sentinel gid is not a valid id
 		 */
 		resp = &result;
 		resp->status = NFSMAPID_BADID;
@@ -417,6 +476,35 @@
 	}
 
 	/*
+	 * If gid is ephemeral then resolve it using idmap service
+	 */
+	if (gid > UID_MAX) {
+		rc = idmap_getwinnamebygid(gid, &idmap_buf, NULL);
+		if (rc != IDMAP_SUCCESS) {
+			/*
+			 * We don't put stringified ephemeral gids on
+			 * the wire.
+			 */
+			resp = &result;
+			resp->status = NFSMAPID_UNMAPPABLE;
+			resp->u_res.len = 0;
+			goto done;
+		}
+
+		/*
+		 * idmap_buf is already in the desired form i.e. name@domain
+		 */
+		gr_str = idmap_buf;
+		gr_str_len = strlen(gr_str);
+		at_str_len = dom_str_len = 0;
+		at_str = "";
+		dom_str[0] = '\0';
+		goto gen_result;
+	}
+
+	/*
+	 * Handling non-ephemeral gids
+	 *
 	 * We want to encode the gid into a literal string... :
 	 *
 	 *	- upon failure to allocate space from the heap
@@ -424,7 +512,8 @@
 	 *	- if there is no such gid in the group DB's
 	 */
 	if ((grp_buf = malloc(grp_buflen)) == NULL || dom_str_len == 0 ||
-	    _uncached_getgrgid_r(gid, &grp, grp_buf, grp_buflen) == NULL) {
+	    getgrgid_r(gid, &grp, grp_buf, grp_buflen, &grp_ptr) != 0 ||
+	    grp_ptr == NULL) {
 
 		/*
 		 * If we could not allocate from the heap, try
@@ -441,27 +530,34 @@
 		/*
 		 * Constructing literal string without '@' so that
 		 * we'll know that it's not a group, but rather a
-		 * gid encoded string. Can't overflow because we
-		 * already checked UID_MAX.
+		 * gid encoded string.
 		 */
 		gr_str = grp_buf;
-		(void) sprintf(gr_str, "%d", (int)gid);
+		(void) sprintf(gr_str, "%u", gid);
 		gr_str_len = strlen(gr_str);
 		at_str_len = dom_str_len = 0;
 		at_str = "";
 		dom_str[0] = '\0';
 	} else {
 		/*
-		 * Otherwise, we construct the "group@domain" string
+		 * Otherwise, we construct the "group@domain" string if
+		 * it's not already in that form.
 		 */
 		gr_str = grp.gr_name;
 		gr_str_len = strlen(gr_str);
-		at_str = "@";
-		at_str_len = 1;
+		if (strchr(gr_str, '@') == NULL) {
+			at_str = "@";
+			at_str_len = 1;
+		} else {
+			at_str_len = dom_str_len = 0;
+			at_str = "";
+			dom_str[0] = '\0';
+		}
 	}
 
+gen_result:
 	gid_str_len = gr_str_len + at_str_len + dom_str_len;
-	if ((resp = alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) {
+	if ((resp = alloca(MAPID_RES_LEN(gid_str_len))) == NULL) {
 		resp = &result;
 		resp->status = NFSMAPID_INTERNAL;
 		resp->u_res.len = 0;
@@ -470,7 +566,10 @@
 	/* LINTED format argument to sprintf */
 	(void) sprintf(resp->str, "%s%s%s", gr_str, at_str, dom_str);
 	resp->u_res.len = gid_str_len;
-	free(grp_buf);
+	if (grp_buf)
+		free(grp_buf);
+	if (idmap_buf)
+		idmap_free(idmap_buf);
 	resp->status = NFSMAPID_OK;
 
 done:
@@ -483,7 +582,7 @@
 		resp->status = NFSMAPID_INTERNAL;
 		resp->u_res.len = 0;
 		(void) door_return((char *)&result, sizeof (struct mapid_res),
-							NULL, 0);
+		    NULL, 0);
 	}
 }
 
@@ -502,7 +601,7 @@
 		mapres.status = NFSMAPID_INVALID;
 		mapres.u_res.len = 0;
 		(void) door_return((char *)&mapres, sizeof (struct mapid_res),
-								NULL, 0);
+		    NULL, 0);
 		return;
 	}
 
@@ -566,7 +665,7 @@
 
 	if (!mapid_stdchk_domain(dom)) {
 		syslog(LOG_ERR, gettext("%s: Invalid inbound domain name %s."),
-			whoami, dom);
+		    whoami, dom);
 		return (0);
 	}
 
@@ -655,7 +754,7 @@
 		return;
 
 	syslog(LOG_ERR, "Failed to create %s. Enable syslog "
-			"daemon.debug for more info", DIAG_FILE);
+	    "daemon.debug for more info", DIAG_FILE);
 	msg_done = 1;
 }
 
@@ -678,7 +777,7 @@
 	n = write(n4_fd, buf, len);
 	if (n < 0 || n < len)
 		syslog(LOG_DEBUG, "Could not write %s to diag file", new);
-	fsync(n4_fd);
+	(void) fsync(n4_fd);
 
 	syslog(LOG_DEBUG, "nfsmapid domain = %s", new);
 }
--- a/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_test.c	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_test.c	Thu Sep 13 13:50:11 2007 -0700
@@ -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.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -60,12 +59,12 @@
 usage()
 {
 	fprintf(stderr, gettext(
-		"\nUsage:\tstr2uid string\n"
-		"\tstr2gid string\n"
-		"\tuid2str uid\n"
-		"\tgid2str gid\n"
-		"\techo string\n"
-		"\texit|quit\n"));
+	    "\nUsage:\tstr2uid string\n"
+	    "\tstr2gid string\n"
+	    "\tuid2str uid\n"
+	    "\tgid2str gid\n"
+	    "\techo string\n"
+	    "\texit|quit\n"));
 }
 
 static int read_line(char *buf, int size)
@@ -205,7 +204,7 @@
 		str.utf8string_val = argv[1];
 		str.utf8string_len = strlen(argv[1]);
 		stat = nfs_idmap_str_uid(&str, &uid);
-		printf(gettext("%d stat=%s \n"), uid, mapstat(stat));
+		printf(gettext("%u stat=%s \n"), uid, mapstat(stat));
 
 	} else if (strcmp(cmd, "str2gid") == 0) {
 		if (argc < 2) {
@@ -216,7 +215,7 @@
 		str.utf8string_val = argv[1];
 		str.utf8string_len = strlen(argv[1]);
 		stat = nfs_idmap_str_gid(&str, &gid);
-		printf(gettext("%d stat=%s \n"), gid, mapstat(stat));
+		printf(gettext("%u stat=%s \n"), gid, mapstat(stat));
 
 	} else if (strcmp(cmd, "uid2str") == 0) {
 		if (argc < 2) {
@@ -229,7 +228,7 @@
 		str.utf8string_val = str_buf;
 		stat = nfs_idmap_uid_str(uid, &str);
 		printf(gettext("%s stat=%s\n"), str.utf8string_val,
-					mapstat(stat));
+		    mapstat(stat));
 
 	} else if (strcmp(cmd, "gid2str") == 0) {
 		if (argc < 2) {
@@ -242,14 +241,14 @@
 		str.utf8string_val = str_buf;
 		stat = nfs_idmap_gid_str(gid, &str);
 		printf(gettext("%s stat=%s\n"), str.utf8string_val,
-					mapstat(stat));
+		    mapstat(stat));
 
 	} else if (strcmp(cmd, "echo") == 0) {
 		for (i = 1; i < argc; i++)
 			printf("%s ", argv[i]);
 		printf("\n");
 	} else if (strcmp(cmd, "exit") == 0 ||
-		    strcmp(cmd, "quit") == 0) {
+	    strcmp(cmd, "quit") == 0) {
 		printf(gettext("\n"));
 		free(argv_array);
 		return (1);
@@ -329,7 +328,7 @@
 	static int	msg_done = 0;
 
 	if (!u8s || !u8s->utf8string_val || !u8s->utf8string_len ||
-			(u8s->utf8string_val[0] == '\0')) {
+	    (u8s->utf8string_val[0] == '\0')) {
 		error = EINVAL;
 		goto s2u_done;
 	}
@@ -345,7 +344,7 @@
 
 	if ((mapargp = malloc(MAPID_ARG_LEN(u8s->utf8string_len))) == NULL) {
 		(void) fprintf(stderr, "Unable to malloc %d bytes\n",
-				MAPID_ARG_LEN(u8s->utf8string_len));
+		    MAPID_ARG_LEN(u8s->utf8string_len));
 		error = ENOMEM;
 		goto s2u_done;
 	}
@@ -367,7 +366,7 @@
 	if ((doorfd = nfs_idmap_doorget()) == -1) {
 		if (!msg_done) {
 			fprintf(stderr, "nfs_idmap_str_uid: Can't communicate"
-				" with mapping daemon nfsmapid\n");
+			    " with mapping daemon nfsmapid\n");
 			msg_done = 1;
 		}
 		error = ECOMM;
@@ -453,7 +452,7 @@
 	if ((doorfd = nfs_idmap_doorget()) == -1) {
 		if (!msg_done) {
 			fprintf(stderr, "nfs_idmap_uid_str: Can't "
-				"communicate with mapping daemon nfsmapid\n");
+			    "communicate with mapping daemon nfsmapid\n");
 			msg_done = 1;
 		}
 		error = ECOMM;
@@ -474,7 +473,7 @@
 
 	if (resp->u_res.len != strlen(resp->str)) {
 		(void) fprintf(stderr, "Incorrect length %d expected %d\n",
-			resp->u_res.len, strlen(resp->str));
+		    resp->u_res.len, strlen(resp->str));
 		error = NFSMAPID_INVALID;
 		goto u2s_done;
 	}
@@ -503,7 +502,7 @@
 	static int	msg_done = 0;
 
 	if (!u8s || !u8s->utf8string_val || !u8s->utf8string_len ||
-		(u8s->utf8string_val[0] == '\0')) {
+	    (u8s->utf8string_val[0] == '\0')) {
 		error = EINVAL;
 		goto s2g_done;
 	}
@@ -519,7 +518,7 @@
 
 	if ((mapargp = malloc(MAPID_ARG_LEN(u8s->utf8string_len))) == NULL) {
 		(void) fprintf(stderr, "Unable to malloc %d bytes\n",
-				MAPID_ARG_LEN(u8s->utf8string_len));
+		    MAPID_ARG_LEN(u8s->utf8string_len));
 		error = ENOMEM;
 		goto s2g_done;
 	}
@@ -541,7 +540,7 @@
 	if ((doorfd = nfs_idmap_doorget()) == -1) {
 		if (!msg_done) {
 			fprintf(stderr, "nfs_idmap_str_uid: Can't communicate"
-				" with mapping daemon nfsmapid\n");
+			    " with mapping daemon nfsmapid\n");
 			msg_done = 1;
 		}
 		error = ECOMM;
@@ -628,7 +627,7 @@
 	if ((doorfd = nfs_idmap_doorget()) == -1) {
 		if (!msg_done) {
 			fprintf(stderr, "nfs_idmap_uid_str: Can't "
-				"communicate with mapping daemon nfsmapid\n");
+			    "communicate with mapping daemon nfsmapid\n");
 			msg_done = 1;
 		}
 		error = ECOMM;
@@ -649,7 +648,7 @@
 
 	if (resp->u_res.len != strlen(resp->str)) {
 		(void) fprintf(stderr, "Incorrect length %d expected %d\n",
-			resp->u_res.len, strlen(resp->str));
+		    resp->u_res.len, strlen(resp->str));
 		error = NFSMAPID_INVALID;
 		goto g2s_done;
 	}
--- a/usr/src/cmd/fs.d/nfs/svc/mapid.xml	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/cmd/fs.d/nfs/svc/mapid.xml	Thu Sep 13 13:50:11 2007 -0700
@@ -1,15 +1,14 @@
 <?xml version="1.0"?>
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 <!--
- Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  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.
@@ -68,6 +67,13 @@
 		<service_fmri value='svc:/milestone/name-services' />
 	</dependency>
 
+	<dependency name='idmap'
+	    grouping='optional_all'
+	    restart_on='none'
+	    type='service'>
+		<service_fmri value='svc:/system/idmap' />
+	</dependency>
+
 	<dependency name='filesystem-minimal'
 	    grouping='require_all'
 	    restart_on='error'
--- a/usr/src/cmd/idmap/idmapd/dbutils.c	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c	Thu Sep 13 13:50:11 2007 -0700
@@ -2786,6 +2786,7 @@
 	idmap_id_res	idres;
 	lookup_state_t	state;
 	idmap_utf8str	*str;
+	char		*cp;
 	int		is_user;
 	idmap_retcode	retcode;
 	const char	*winname, *windomain;
@@ -2820,18 +2821,28 @@
 
 	if (winname != NULL && windomain == NULL) {
 		str = &mapping->id1domain;
-		RDLOCK_CONFIG();
-		if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
+
+		if ((cp = strchr(winname, '@')) != NULL) {
+			/*
+			 * if winname is qualified with a domain, use it.
+			 */
+			*cp = '\0';
+			retcode = idmap_str2utf8(&str, cp + 1, 0);
+		} else if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
+			/*
+			 * otherwise use the mapping domain
+			 */
+			RDLOCK_CONFIG();
 			retcode = idmap_str2utf8(&str,
 				_idmapdstate.cfg->pgcfg.mapping_domain, 0);
-			if (retcode != IDMAP_SUCCESS) {
-				UNLOCK_CONFIG();
-				idmapdlog(LOG_ERR, "Out of memory");
-				retcode = IDMAP_ERR_MEMORY;
-				goto out;
-			}
+			UNLOCK_CONFIG();
+		} else
+			retcode = IDMAP_SUCCESS;
+
+		if (retcode != IDMAP_SUCCESS) {
+			idmapdlog(LOG_ERR, "Out of memory");
+			goto out;
 		}
-		UNLOCK_CONFIG();
 		windomain = mapping->id1domain.idmap_utf8str_val;
 	}
 
--- a/usr/src/lib/libidmap/common/idmap.h	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/lib/libidmap/common/idmap.h	Thu Sep 13 13:50:11 2007 -0700
@@ -103,6 +103,23 @@
 /* Destroy the handle */
 extern void idmap_get_destroy(idmap_get_handle_t *);
 
+
+/*
+ * API to get Windows name by UID/GID and vice-versa
+ */
+/* Given UID, get Windows name */
+extern idmap_stat idmap_getwinnamebyuid(uid_t, char **, char **);
+
+/* Given GID, get Windows name */
+extern idmap_stat idmap_getwinnamebygid(gid_t, char **, char **);
+
+/* Given Windows name, get UID */
+extern idmap_stat idmap_getuidbywinname(const char *, const char *, uid_t *);
+
+/* Given Windows name, get GID */
+extern idmap_stat idmap_getgidbywinname(const char *, const char *, gid_t *);
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/libidmap/common/idmap_api.c	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/lib/libidmap/common/idmap_api.c	Thu Sep 13 13:50:11 2007 -0700
@@ -1639,3 +1639,131 @@
 	}
 	return (status);
 }
+
+
+/*
+ * Get uid given Windows name
+ */
+idmap_stat
+idmap_getuidbywinname(const char *name, const char *domain, uid_t *uid) {
+	idmap_handle_t	*ih;
+	idmap_retcode	rc;
+	int		is_user;
+
+	if (uid == NULL)
+		return (IDMAP_ERR_ARG);
+
+	/* Get mapping */
+	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
+		return (rc);
+	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, 0,
+	    &is_user, uid, NULL, NULL);
+	(void) idmap_fini(ih);
+
+	/*
+	 * XXX Until we have diagonal mapping support, check if
+	 * the given name belongs to a user
+	 */
+	if (rc == IDMAP_SUCCESS && !is_user)
+		return (IDMAP_ERR_NOTUSER);
+	return (rc);
+}
+
+
+/*
+ * Get gid given Windows name
+ */
+idmap_stat
+idmap_getgidbywinname(const char *name, const char *domain, gid_t *gid) {
+	idmap_handle_t	*ih;
+	idmap_retcode	rc;
+	int		is_user;
+
+	if (gid == NULL)
+		return (IDMAP_ERR_ARG);
+
+	/* Get mapping */
+	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
+		return (rc);
+	rc = idmap_get_w2u_mapping(ih, NULL, NULL, name, domain, 0,
+	    &is_user, gid, NULL, NULL);
+	(void) idmap_fini(ih);
+
+	/*
+	 * XXX Until we have diagonal mapping support, check if
+	 * the given name belongs to a group
+	 */
+	if (rc == IDMAP_SUCCESS && is_user)
+		return (IDMAP_ERR_NOTGROUP);
+	return (rc);
+}
+
+
+/*
+ * Get winname given pid
+ */
+static idmap_retcode
+idmap_getwinnamebypid(uid_t pid, int is_user, char **name, char **domain) {
+	idmap_handle_t	*ih;
+	idmap_retcode	rc;
+	int		len;
+	char		*winname, *windomain;
+
+	if (name == NULL)
+		return (IDMAP_ERR_ARG);
+
+	/* Get mapping */
+	if ((rc = idmap_init(&ih)) != IDMAP_SUCCESS)
+		return (rc);
+	rc = idmap_get_u2w_mapping(ih, &pid, NULL, 0, is_user, NULL,
+	    NULL, &winname, &windomain, NULL);
+	(void) idmap_fini(ih);
+
+	/* Return on error */
+	if (rc != IDMAP_SUCCESS)
+		return (rc);
+
+	/*
+	 * The given PID may have been mapped to a locally
+	 * generated SID in which case there isn't any
+	 * Windows name
+	 */
+	if (winname == NULL || windomain == NULL) {
+		idmap_free(winname);
+		idmap_free(windomain);
+		return (IDMAP_ERR_NORESULT);
+	}
+
+	if (domain != NULL) {
+		*name = winname;
+		*domain = windomain;
+	} else {
+		len = strlen(winname) + strlen(windomain) + 2;
+		if ((*name = malloc(len)) != NULL)
+			(void) snprintf(*name, len, "%s@%s", winname,
+			    windomain);
+		else
+			rc = IDMAP_ERR_MEMORY;
+		idmap_free(winname);
+		idmap_free(windomain);
+	}
+	return (rc);
+}
+
+
+/*
+ * Get winname given uid
+ */
+idmap_stat
+idmap_getwinnamebyuid(uid_t uid, char **name, char **domain) {
+	return (idmap_getwinnamebypid(uid, 1, name, domain));
+}
+
+
+/*
+ * Get winname given gid
+ */
+idmap_stat
+idmap_getwinnamebygid(gid_t gid, char **name, char **domain) {
+	return (idmap_getwinnamebypid(gid, 0, name, domain));
+}
--- a/usr/src/lib/libidmap/common/mapfile-vers	Thu Sep 13 12:08:31 2007 -0700
+++ b/usr/src/lib/libidmap/common/mapfile-vers	Thu Sep 13 13:50:11 2007 -0700
@@ -68,6 +68,10 @@
 	idmap_udt_commit;
 	idmap_udt_create;
 	idmap_udt_flush_namerules;
+	idmap_getwinnamebyuid;
+	idmap_getwinnamebygid;
+	idmap_getuidbywinname;
+	idmap_getgidbywinname;
     local:
 	*;
 };