11fcced4cSJordan Brown /*
21fcced4cSJordan Brown  * CDDL HEADER START
31fcced4cSJordan Brown  *
41fcced4cSJordan Brown  * The contents of this file are subject to the terms of the
51fcced4cSJordan Brown  * Common Development and Distribution License (the "License").
61fcced4cSJordan Brown  * You may not use this file except in compliance with the License.
71fcced4cSJordan Brown  *
81fcced4cSJordan Brown  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91fcced4cSJordan Brown  * or http://www.opensolaris.org/os/licensing.
101fcced4cSJordan Brown  * See the License for the specific language governing permissions
111fcced4cSJordan Brown  * and limitations under the License.
121fcced4cSJordan Brown  *
131fcced4cSJordan Brown  * When distributing Covered Code, include this CDDL HEADER in each
141fcced4cSJordan Brown  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151fcced4cSJordan Brown  * If applicable, add the following below this CDDL HEADER, with the
161fcced4cSJordan Brown  * fields enclosed by brackets "[]" replaced with your own identifying
171fcced4cSJordan Brown  * information: Portions Copyright [yyyy] [name of copyright owner]
181fcced4cSJordan Brown  *
191fcced4cSJordan Brown  * CDDL HEADER END
201fcced4cSJordan Brown  */
211fcced4cSJordan Brown 
221fcced4cSJordan Brown /*
23*cb174861Sjoyce mcintosh  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
241fcced4cSJordan Brown  */
251fcced4cSJordan Brown 
261fcced4cSJordan Brown /*
271fcced4cSJordan Brown  * Retrieve directory information for standard UNIX users/groups.
281fcced4cSJordan Brown  * (NB:  not just from files, but all nsswitch sources.)
291fcced4cSJordan Brown  */
301fcced4cSJordan Brown 
311fcced4cSJordan Brown #include <pwd.h>
321fcced4cSJordan Brown #include <grp.h>
331fcced4cSJordan Brown #include <malloc.h>
341fcced4cSJordan Brown #include <string.h>
351fcced4cSJordan Brown #include <stdlib.h>
361fcced4cSJordan Brown #include <netdb.h>
37*cb174861Sjoyce mcintosh #include <libuutil.h>
381fcced4cSJordan Brown #include <note.h>
391fcced4cSJordan Brown #include <errno.h>
401fcced4cSJordan Brown #include "idmapd.h"
411fcced4cSJordan Brown #include "directory.h"
421fcced4cSJordan Brown #include "directory_private.h"
431fcced4cSJordan Brown #include <rpcsvc/idmap_prot.h>
441fcced4cSJordan Brown #include "directory_server_impl.h"
451fcced4cSJordan Brown #include "sidutil.h"
461fcced4cSJordan Brown 
471fcced4cSJordan Brown static directory_error_t machine_sid_dav(directory_values_rpc *lvals,
481fcced4cSJordan Brown     unsigned int rid);
491fcced4cSJordan Brown static directory_error_t directory_provider_nsswitch_populate(
501fcced4cSJordan Brown     directory_entry_rpc *pent, struct passwd *pwd, struct group *grp,
511fcced4cSJordan Brown     idmap_utf8str_list *attrs);
521fcced4cSJordan Brown 
531fcced4cSJordan Brown /*
541fcced4cSJordan Brown  * Retrieve information by name.
551fcced4cSJordan Brown  * Called indirectly through the directory_provider_static structure.
561fcced4cSJordan Brown  */
571fcced4cSJordan Brown static
581fcced4cSJordan Brown directory_error_t
directory_provider_nsswitch_get(directory_entry_rpc * del,idmap_utf8str_list * ids,idmap_utf8str types,idmap_utf8str_list * attrs)591fcced4cSJordan Brown directory_provider_nsswitch_get(
601fcced4cSJordan Brown     directory_entry_rpc *del,
611fcced4cSJordan Brown     idmap_utf8str_list *ids,
621fcced4cSJordan Brown     idmap_utf8str types,
631fcced4cSJordan Brown     idmap_utf8str_list *attrs)
641fcced4cSJordan Brown {
651fcced4cSJordan Brown 	int i;
661fcced4cSJordan Brown 
671fcced4cSJordan Brown 	RDLOCK_CONFIG();
681fcced4cSJordan Brown 
691fcced4cSJordan Brown 	/* 6835280 spurious lint error if the strlen is in the declaration */
701fcced4cSJordan Brown 	int host_name_len = strlen(_idmapdstate.hostname);
711fcced4cSJordan Brown 	char my_host_name[host_name_len + 1];
721fcced4cSJordan Brown 	(void) strcpy(my_host_name, _idmapdstate.hostname);
731fcced4cSJordan Brown 
741fcced4cSJordan Brown 	/* We use len later, so this is not merely a workaround for 6835280 */
751fcced4cSJordan Brown 	int machine_sid_len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
761fcced4cSJordan Brown 	char my_machine_sid[machine_sid_len + 1];
771fcced4cSJordan Brown 	(void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
781fcced4cSJordan Brown 
791fcced4cSJordan Brown 	UNLOCK_CONFIG();
801fcced4cSJordan Brown 
811fcced4cSJordan Brown 	for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
821fcced4cSJordan Brown 		struct passwd *pwd = NULL;
831fcced4cSJordan Brown 		struct group *grp = NULL;
841fcced4cSJordan Brown 		directory_error_t de;
851fcced4cSJordan Brown 		int type;
861fcced4cSJordan Brown 
871fcced4cSJordan Brown 		/*
881fcced4cSJordan Brown 		 * Extract the type for this particular ID.
891fcced4cSJordan Brown 		 * Advance to the next type, if it's there, else keep
901fcced4cSJordan Brown 		 * using this type until we run out of IDs.
911fcced4cSJordan Brown 		 */
921fcced4cSJordan Brown 		type = *types;
931fcced4cSJordan Brown 		if (*(types+1) != '\0')
941fcced4cSJordan Brown 			types++;
951fcced4cSJordan Brown 
961fcced4cSJordan Brown 		/*
971fcced4cSJordan Brown 		 * If this entry has already been handled, one way or another,
981fcced4cSJordan Brown 		 * skip it.
991fcced4cSJordan Brown 		 */
1001fcced4cSJordan Brown 		if (del[i].status != DIRECTORY_NOT_FOUND)
1011fcced4cSJordan Brown 			continue;
1021fcced4cSJordan Brown 
1031fcced4cSJordan Brown 		char *id = ids->idmap_utf8str_list_val[i];
1041fcced4cSJordan Brown 
1051fcced4cSJordan Brown 		if (type == DIRECTORY_ID_SID[0]) {
1061fcced4cSJordan Brown 			/*
1071fcced4cSJordan Brown 			 * Is it our SID?
1081fcced4cSJordan Brown 			 * Check whether the first part matches, then a "-",
1091fcced4cSJordan Brown 			 * then a single RID.
1101fcced4cSJordan Brown 			 */
1111fcced4cSJordan Brown 			if (strncasecmp(id, my_machine_sid, machine_sid_len) !=
1121fcced4cSJordan Brown 			    0)
1131fcced4cSJordan Brown 				continue;
1141fcced4cSJordan Brown 			if (id[machine_sid_len] != '-')
1151fcced4cSJordan Brown 				continue;
1161fcced4cSJordan Brown 			char *p;
1171fcced4cSJordan Brown 			uint32_t rid =
1181fcced4cSJordan Brown 			    strtoul(id + machine_sid_len + 1, &p, 10);
1191fcced4cSJordan Brown 			if (*p != '\0')
1201fcced4cSJordan Brown 				continue;
1211fcced4cSJordan Brown 
1221fcced4cSJordan Brown 			if (rid < LOCALRID_UID_MIN) {
1231fcced4cSJordan Brown 				/* Builtin, not handled here */
1241fcced4cSJordan Brown 				continue;
1251fcced4cSJordan Brown 			}
1261fcced4cSJordan Brown 
1271fcced4cSJordan Brown 			if (rid <= LOCALRID_UID_MAX) {
1281fcced4cSJordan Brown 				/* User */
1291fcced4cSJordan Brown 				errno = 0;
1301fcced4cSJordan Brown 				pwd = getpwuid(rid - LOCALRID_UID_MIN);
1311fcced4cSJordan Brown 				if (pwd == NULL) {
1321fcced4cSJordan Brown 					if (errno == 0)		/* Not found */
1331fcced4cSJordan Brown 						continue;
1341fcced4cSJordan Brown 					char buf[40];
1351fcced4cSJordan Brown 					int err = errno;
1361fcced4cSJordan Brown 					(void) snprintf(buf, sizeof (buf),
1371fcced4cSJordan Brown 					    "%d", err);
1381fcced4cSJordan Brown 					directory_entry_set_error(&del[i],
1391fcced4cSJordan Brown 					    directory_error("errno.getpwuid",
1401fcced4cSJordan Brown 					    "getpwuid: %2 (%1)",
1411fcced4cSJordan Brown 					    buf, strerror(err), NULL));
1421fcced4cSJordan Brown 					continue;
1431fcced4cSJordan Brown 				}
1441fcced4cSJordan Brown 			} else if (rid >= LOCALRID_GID_MIN &&
1451fcced4cSJordan Brown 			    rid <= LOCALRID_GID_MAX) {
1461fcced4cSJordan Brown 				/* Group */
1471fcced4cSJordan Brown 				errno = 0;
1481fcced4cSJordan Brown 				grp = getgrgid(rid - LOCALRID_GID_MIN);
1491fcced4cSJordan Brown 				if (grp == NULL) {
1501fcced4cSJordan Brown 					if (errno == 0)		/* Not found */
1511fcced4cSJordan Brown 						continue;
1521fcced4cSJordan Brown 					char buf[40];
1531fcced4cSJordan Brown 					int err = errno;
1541fcced4cSJordan Brown 					(void) snprintf(buf, sizeof (buf),
1551fcced4cSJordan Brown 					    "%d", err);
1561fcced4cSJordan Brown 					directory_entry_set_error(&del[i],
1571fcced4cSJordan Brown 					    directory_error("errno.getgrgid",
1581fcced4cSJordan Brown 					    "getgrgid: %2 (%1)",
1591fcced4cSJordan Brown 					    buf, strerror(err), NULL));
1601fcced4cSJordan Brown 					continue;
1611fcced4cSJordan Brown 				}
1621fcced4cSJordan Brown 			} else
1631fcced4cSJordan Brown 				continue;
1641fcced4cSJordan Brown 
1651fcced4cSJordan Brown 		} else {
1661fcced4cSJordan Brown 			int id_len = strlen(id);
1671fcced4cSJordan Brown 			char name[id_len + 1];
1681fcced4cSJordan Brown 			char domain[id_len + 1];
1691fcced4cSJordan Brown 
1701fcced4cSJordan Brown 			split_name(name, domain, id);
1711fcced4cSJordan Brown 
1721fcced4cSJordan Brown 			if (domain[0] != '\0') {
1731fcced4cSJordan Brown 				if (!domain_eq(domain, my_host_name))
1741fcced4cSJordan Brown 					continue;
1751fcced4cSJordan Brown 			}
1761fcced4cSJordan Brown 
1771fcced4cSJordan Brown 			/*
1781fcced4cSJordan Brown 			 * If the caller has requested user or group
1791fcced4cSJordan Brown 			 * information specifically, we only set one of
1801fcced4cSJordan Brown 			 * pwd or grp.
1811fcced4cSJordan Brown 			 * If the caller has requested either type, we try
1821fcced4cSJordan Brown 			 * both in the hopes of getting one.
1831fcced4cSJordan Brown 			 * Note that directory_provider_nsswitch_populate
1841fcced4cSJordan Brown 			 * considers it to be an error if both are set.
1851fcced4cSJordan Brown 			 */
1861fcced4cSJordan Brown 			if (type != DIRECTORY_ID_GROUP[0]) {
1871fcced4cSJordan Brown 				/* prep for not found / error case */
1881fcced4cSJordan Brown 				errno = 0;
1891fcced4cSJordan Brown 
1901fcced4cSJordan Brown 				pwd = getpwnam(name);
1911fcced4cSJordan Brown 				if (pwd == NULL && errno != 0) {
1921fcced4cSJordan Brown 					char buf[40];
1931fcced4cSJordan Brown 					int err = errno;
1941fcced4cSJordan Brown 					(void) snprintf(buf, sizeof (buf),
1951fcced4cSJordan Brown 					    "%d", err);
1961fcced4cSJordan Brown 					directory_entry_set_error(&del[i],
1971fcced4cSJordan Brown 					    directory_error("errno.getpwnam",
1981fcced4cSJordan Brown 					    "getpwnam: %2 (%1)",
1991fcced4cSJordan Brown 					    buf, strerror(err), NULL));
2001fcced4cSJordan Brown 					continue;
2011fcced4cSJordan Brown 				}
2021fcced4cSJordan Brown 			}
2031fcced4cSJordan Brown 
2041fcced4cSJordan Brown 			if (type != DIRECTORY_ID_USER[0]) {
2051fcced4cSJordan Brown 				/* prep for not found / error case */
2061fcced4cSJordan Brown 				errno = 0;
2071fcced4cSJordan Brown 
2081fcced4cSJordan Brown 				grp = getgrnam(name);
2091fcced4cSJordan Brown 				if (grp == NULL && errno != 0) {
2101fcced4cSJordan Brown 					char buf[40];
2111fcced4cSJordan Brown 					int err = errno;
2121fcced4cSJordan Brown 					(void) snprintf(buf, sizeof (buf),
2131fcced4cSJordan Brown 					    "%d", err);
2141fcced4cSJordan Brown 					directory_entry_set_error(&del[i],
2151fcced4cSJordan Brown 					    directory_error("errno.getgrnam",
2161fcced4cSJordan Brown 					    "getgrnam: %2 (%1)",
2171fcced4cSJordan Brown 					    buf, strerror(err), NULL));
2181fcced4cSJordan Brown 					continue;
2191fcced4cSJordan Brown 				}
2201fcced4cSJordan Brown 			}
2211fcced4cSJordan Brown 		}
2221fcced4cSJordan Brown 
2231fcced4cSJordan Brown 		/*
2241fcced4cSJordan Brown 		 * Didn't find it, don't populate the structure.
2251fcced4cSJordan Brown 		 * Another provider might populate it.
2261fcced4cSJordan Brown 		 */
2271fcced4cSJordan Brown 		if (pwd == NULL && grp == NULL)
2281fcced4cSJordan Brown 			continue;
2291fcced4cSJordan Brown 
2301fcced4cSJordan Brown 		de = directory_provider_nsswitch_populate(&del[i], pwd, grp,
2311fcced4cSJordan Brown 		    attrs);
2321fcced4cSJordan Brown 		if (de != NULL) {
2331fcced4cSJordan Brown 			directory_entry_set_error(&del[i], de);
2341fcced4cSJordan Brown 			de = NULL;
2351fcced4cSJordan Brown 			continue;
2361fcced4cSJordan Brown 		}
2371fcced4cSJordan Brown 	}
2381fcced4cSJordan Brown 
2391fcced4cSJordan Brown 	return (NULL);
2401fcced4cSJordan Brown }
2411fcced4cSJordan Brown 
2421fcced4cSJordan Brown /*
2431fcced4cSJordan Brown  * Given a pwd structure or a grp structure, and a list of attributes that
2441fcced4cSJordan Brown  * were requested, populate the structure to return to the caller.
2451fcced4cSJordan Brown  */
2461fcced4cSJordan Brown static
2471fcced4cSJordan Brown directory_error_t
directory_provider_nsswitch_populate(directory_entry_rpc * pent,struct passwd * pwd,struct group * grp,idmap_utf8str_list * attrs)2481fcced4cSJordan Brown directory_provider_nsswitch_populate(
2491fcced4cSJordan Brown     directory_entry_rpc *pent,
2501fcced4cSJordan Brown     struct passwd *pwd,
2511fcced4cSJordan Brown     struct group *grp,
2521fcced4cSJordan Brown     idmap_utf8str_list *attrs)
2531fcced4cSJordan Brown {
2541fcced4cSJordan Brown 	int j;
2551fcced4cSJordan Brown 	directory_values_rpc *llvals;
2561fcced4cSJordan Brown 	int nattrs;
2571fcced4cSJordan Brown 
2581fcced4cSJordan Brown 	/*
2591fcced4cSJordan Brown 	 * If it wasn't for this case, everything would be a lot simpler.
2601fcced4cSJordan Brown 	 * UNIX allows users and groups with the same name.  Windows doesn't.
2611fcced4cSJordan Brown 	 */
2621fcced4cSJordan Brown 	if (pwd != NULL && grp != NULL) {
2631fcced4cSJordan Brown 		return directory_error("Ambiguous.Name",
2641fcced4cSJordan Brown 		    "Ambiguous name, is both a user and a group",
2651fcced4cSJordan Brown 		    NULL);
2661fcced4cSJordan Brown 	}
2671fcced4cSJordan Brown 
2681fcced4cSJordan Brown 	nattrs = attrs->idmap_utf8str_list_len;
2691fcced4cSJordan Brown 
2701fcced4cSJordan Brown 	llvals = calloc(nattrs, sizeof (directory_values_rpc));
2711fcced4cSJordan Brown 	if (llvals == NULL)
2721fcced4cSJordan Brown 		goto nomem;
2731fcced4cSJordan Brown 
2741fcced4cSJordan Brown 	pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
2751fcced4cSJordan Brown 	pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
2761fcced4cSJordan Brown 	pent->status = DIRECTORY_FOUND;
2771fcced4cSJordan Brown 
2781fcced4cSJordan Brown 	for (j = 0; j < nattrs; j++) {
2791fcced4cSJordan Brown 		directory_values_rpc *val;
2801fcced4cSJordan Brown 		char *a;
2811fcced4cSJordan Brown 		directory_error_t de;
2821fcced4cSJordan Brown 
2831fcced4cSJordan Brown 		/*
2841fcced4cSJordan Brown 		 * We're going to refer to these a lot, so make a shorthand
2851fcced4cSJordan Brown 		 * copy.
2861fcced4cSJordan Brown 		 */
2871fcced4cSJordan Brown 		a = attrs->idmap_utf8str_list_val[j];
2881fcced4cSJordan Brown 		val = &llvals[j];
2891fcced4cSJordan Brown 
2901fcced4cSJordan Brown 		/*
2911fcced4cSJordan Brown 		 * Start by assuming no errors and that we don't have
2921fcced4cSJordan Brown 		 * the information
2931fcced4cSJordan Brown 		 */
2941fcced4cSJordan Brown 		val->found = FALSE;
2951fcced4cSJordan Brown 		de = NULL;
2961fcced4cSJordan Brown 
2971fcced4cSJordan Brown 		if (pwd != NULL) {
2981fcced4cSJordan Brown 			/*
2991fcced4cSJordan Brown 			 * Handle attributes for user entries.
3001fcced4cSJordan Brown 			 */
301*cb174861Sjoyce mcintosh 			if (uu_strcaseeq(a, "cn")) {
3021fcced4cSJordan Brown 				const char *p = pwd->pw_name;
3031fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
304*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "objectClass")) {
3051fcced4cSJordan Brown 				static const char *objectClasses[] = {
3061fcced4cSJordan Brown 					"top",
3071fcced4cSJordan Brown 					"posixAccount",
3081fcced4cSJordan Brown 				};
3091fcced4cSJordan Brown 				de = str_list_dav(val, objectClasses,
310*cb174861Sjoyce mcintosh 				    UU_NELEM(objectClasses));
311*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "gidNumber")) {
3121fcced4cSJordan Brown 				de = uint_list_dav(val, &pwd->pw_gid, 1);
313*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "objectSid")) {
3141fcced4cSJordan Brown 				de = machine_sid_dav(val,
3151fcced4cSJordan Brown 				    pwd->pw_uid + LOCALRID_UID_MIN);
316*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "displayName")) {
3171fcced4cSJordan Brown 				const char *p = pwd->pw_gecos;
3181fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
319*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "distinguishedName")) {
3201fcced4cSJordan Brown 				char *dn;
3211fcced4cSJordan Brown 				RDLOCK_CONFIG();
3221fcced4cSJordan Brown 				(void) asprintf(&dn,
3231fcced4cSJordan Brown 				    "uid=%s,ou=people,dc=%s",
3241fcced4cSJordan Brown 				    pwd->pw_name, _idmapdstate.hostname);
3251fcced4cSJordan Brown 				UNLOCK_CONFIG();
3261fcced4cSJordan Brown 				if (dn == NULL)
3271fcced4cSJordan Brown 					goto nomem;
3281fcced4cSJordan Brown 				const char *cdn = dn;
3291fcced4cSJordan Brown 				de = str_list_dav(val, &cdn, 1);
3301fcced4cSJordan Brown 				free(dn);
331*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "uid")) {
3321fcced4cSJordan Brown 				const char *p = pwd->pw_name;
3331fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
334*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "uidNumber")) {
3351fcced4cSJordan Brown 				de = uint_list_dav(val, &pwd->pw_uid, 1);
336*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "gecos")) {
3371fcced4cSJordan Brown 				const char *p = pwd->pw_gecos;
3381fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
339*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "homeDirectory")) {
3401fcced4cSJordan Brown 				const char *p = pwd->pw_dir;
3411fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
342*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "loginShell")) {
3431fcced4cSJordan Brown 				const char *p = pwd->pw_shell;
3441fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
345*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
3461fcced4cSJordan Brown 				char *canon;
3471fcced4cSJordan Brown 				RDLOCK_CONFIG();
3481fcced4cSJordan Brown 				(void) asprintf(&canon, "%s@%s",
3491fcced4cSJordan Brown 				    pwd->pw_name, _idmapdstate.hostname);
3501fcced4cSJordan Brown 				UNLOCK_CONFIG();
3511fcced4cSJordan Brown 				if (canon == NULL)
3521fcced4cSJordan Brown 					goto nomem;
3531fcced4cSJordan Brown 				const char *ccanon = canon;
3541fcced4cSJordan Brown 				de = str_list_dav(val, &ccanon, 1);
3551fcced4cSJordan Brown 				free(canon);
356*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "x-sun-provider")) {
3571fcced4cSJordan Brown 				const char *provider = "UNIX-passwd";
3581fcced4cSJordan Brown 				de = str_list_dav(val, &provider, 1);
3591fcced4cSJordan Brown 			}
3601fcced4cSJordan Brown 		} else if (grp != NULL)  {
3611fcced4cSJordan Brown 			/*
3621fcced4cSJordan Brown 			 * Handle attributes for group entries.
3631fcced4cSJordan Brown 			 */
364*cb174861Sjoyce mcintosh 			if (uu_strcaseeq(a, "cn")) {
3651fcced4cSJordan Brown 				const char *p = grp->gr_name;
3661fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
367*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "objectClass")) {
3681fcced4cSJordan Brown 				static const char *objectClasses[] = {
3691fcced4cSJordan Brown 					"top",
3701fcced4cSJordan Brown 					"posixGroup",
3711fcced4cSJordan Brown 				};
3721fcced4cSJordan Brown 				de = str_list_dav(val, objectClasses,
373*cb174861Sjoyce mcintosh 				    UU_NELEM(objectClasses));
374*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "gidNumber")) {
3751fcced4cSJordan Brown 				de = uint_list_dav(val, &grp->gr_gid, 1);
376*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "objectSid")) {
3771fcced4cSJordan Brown 				de = machine_sid_dav(val,
3781fcced4cSJordan Brown 				    grp->gr_gid + LOCALRID_GID_MIN);
379*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "displayName")) {
3801fcced4cSJordan Brown 				const char *p = grp->gr_name;
3811fcced4cSJordan Brown 				de = str_list_dav(val, &p, 1);
382*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "distinguishedName")) {
3831fcced4cSJordan Brown 				char *dn;
3841fcced4cSJordan Brown 				RDLOCK_CONFIG();
3851fcced4cSJordan Brown 				(void) asprintf(&dn,
3861fcced4cSJordan Brown 				    "cn=%s,ou=group,dc=%s",
3871fcced4cSJordan Brown 				    grp->gr_name, _idmapdstate.hostname);
3881fcced4cSJordan Brown 				UNLOCK_CONFIG();
3891fcced4cSJordan Brown 				if (dn == NULL)
3901fcced4cSJordan Brown 					goto nomem;
3911fcced4cSJordan Brown 				const char *cdn = dn;
3921fcced4cSJordan Brown 				de = str_list_dav(val, &cdn, 1);
3931fcced4cSJordan Brown 				free(dn);
394*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "memberUid")) {
3951fcced4cSJordan Brown 				/*
3961fcced4cSJordan Brown 				 * NEEDSWORK:  There is probably a non-cast
3971fcced4cSJordan Brown 				 * way to do this, but I don't immediately
3981fcced4cSJordan Brown 				 * see it.
3991fcced4cSJordan Brown 				 */
4001fcced4cSJordan Brown 				const char * const *members =
4011fcced4cSJordan Brown 				    (const char * const *)grp->gr_mem;
4021fcced4cSJordan Brown 				de = str_list_dav(val, members, 0);
403*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
4041fcced4cSJordan Brown 				char *canon;
4051fcced4cSJordan Brown 				RDLOCK_CONFIG();
4061fcced4cSJordan Brown 				(void) asprintf(&canon, "%s@%s",
4071fcced4cSJordan Brown 				    grp->gr_name, _idmapdstate.hostname);
4081fcced4cSJordan Brown 				UNLOCK_CONFIG();
4091fcced4cSJordan Brown 				if (canon == NULL)
4101fcced4cSJordan Brown 					goto nomem;
4111fcced4cSJordan Brown 				const char *ccanon = canon;
4121fcced4cSJordan Brown 				de = str_list_dav(val, &ccanon, 1);
4131fcced4cSJordan Brown 				free(canon);
414*cb174861Sjoyce mcintosh 			} else if (uu_strcaseeq(a, "x-sun-provider")) {
4151fcced4cSJordan Brown 				const char *provider = "UNIX-group";
4161fcced4cSJordan Brown 				de = str_list_dav(val, &provider, 1);
4171fcced4cSJordan Brown 			}
4181fcced4cSJordan Brown 		}
4191fcced4cSJordan Brown 
4201fcced4cSJordan Brown 		if (de != NULL)
4211fcced4cSJordan Brown 			return (de);
4221fcced4cSJordan Brown 	}
4231fcced4cSJordan Brown 
4241fcced4cSJordan Brown 	return (NULL);
4251fcced4cSJordan Brown 
4261fcced4cSJordan Brown nomem:
4271fcced4cSJordan Brown 	return (directory_error("ENOMEM.users",
4281fcced4cSJordan Brown 	    "No memory allocating return value for user lookup", NULL));
4291fcced4cSJordan Brown }
4301fcced4cSJordan Brown 
4311fcced4cSJordan Brown /*
4321fcced4cSJordan Brown  * Populate a directory attribute value with a SID based on our machine SID
4331fcced4cSJordan Brown  * and the specified RID.
4341fcced4cSJordan Brown  *
4351fcced4cSJordan Brown  * It's a bit perverse that we must take a text-format SID and turn it into
4361fcced4cSJordan Brown  * a binary-format SID, only to have the caller probably turn it back into
4371fcced4cSJordan Brown  * text format, but SIDs are carried across LDAP in binary format.
4381fcced4cSJordan Brown  */
4391fcced4cSJordan Brown static
4401fcced4cSJordan Brown directory_error_t
machine_sid_dav(directory_values_rpc * lvals,unsigned int rid)4411fcced4cSJordan Brown machine_sid_dav(directory_values_rpc *lvals, unsigned int rid)
4421fcced4cSJordan Brown {
4431fcced4cSJordan Brown 	sid_t *sid;
4441fcced4cSJordan Brown 	directory_error_t de;
4451fcced4cSJordan Brown 
4461fcced4cSJordan Brown 	RDLOCK_CONFIG();
4471fcced4cSJordan Brown 	int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
4481fcced4cSJordan Brown 	char buf[len + 100];	/* 100 is enough space for any RID */
4491fcced4cSJordan Brown 	(void) snprintf(buf, sizeof (buf), "%s-%u",
4501fcced4cSJordan Brown 	    _idmapdstate.cfg->pgcfg.machine_sid, rid);
4511fcced4cSJordan Brown 	UNLOCK_CONFIG();
4521fcced4cSJordan Brown 
4531fcced4cSJordan Brown 	sid = sid_fromstr(buf);
4541fcced4cSJordan Brown 	if (sid == NULL)
4551fcced4cSJordan Brown 		goto nomem;
4561fcced4cSJordan Brown 
4571fcced4cSJordan Brown 	sid_to_le(sid);
4581fcced4cSJordan Brown 
4591fcced4cSJordan Brown 	de = bin_list_dav(lvals, sid, 1, sid_len(sid));
4601fcced4cSJordan Brown 	sid_free(sid);
4611fcced4cSJordan Brown 	return (de);
4621fcced4cSJordan Brown 
4631fcced4cSJordan Brown nomem:
4641fcced4cSJordan Brown 	return (directory_error("ENOMEM.machine_sid_dav",
4651fcced4cSJordan Brown 	    "Out of memory allocating return value for lookup", NULL));
4661fcced4cSJordan Brown }
4671fcced4cSJordan Brown 
4681fcced4cSJordan Brown struct directory_provider_static directory_provider_nsswitch = {
4691fcced4cSJordan Brown 	"files",
4701fcced4cSJordan Brown 	directory_provider_nsswitch_get,
4711fcced4cSJordan Brown };