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 built-in users and groups
281fcced4cSJordan Brown  */
291fcced4cSJordan Brown 
301fcced4cSJordan Brown #include <stdio.h>
311fcced4cSJordan Brown #include <limits.h>
321fcced4cSJordan Brown #include <sys/idmap.h>
331fcced4cSJordan Brown #include <sys/param.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 "idmapd.h"
401fcced4cSJordan Brown #include "directory.h"
411fcced4cSJordan Brown #include "directory_private.h"
421fcced4cSJordan Brown #include <rpcsvc/idmap_prot.h>
431fcced4cSJordan Brown #include "directory_server_impl.h"
441fcced4cSJordan Brown #include "sidutil.h"
451fcced4cSJordan Brown 
461fcced4cSJordan Brown static directory_error_t sid_dav(directory_values_rpc *lvals,
471fcced4cSJordan Brown     const wksids_table_t *wksid);
481fcced4cSJordan Brown static directory_error_t directory_provider_builtin_populate(
491fcced4cSJordan Brown     directory_entry_rpc *pent, const wksids_table_t *wksid,
501fcced4cSJordan Brown     idmap_utf8str_list *attrs);
511fcced4cSJordan Brown 
521fcced4cSJordan Brown /*
531fcced4cSJordan Brown  * Retrieve information by name.
541fcced4cSJordan Brown  * Called indirectly through the directory_provider_static structure.
551fcced4cSJordan Brown  */
561fcced4cSJordan Brown static
571fcced4cSJordan Brown directory_error_t
directory_provider_builtin_get(directory_entry_rpc * del,idmap_utf8str_list * ids,idmap_utf8str types,idmap_utf8str_list * attrs)581fcced4cSJordan Brown directory_provider_builtin_get(
591fcced4cSJordan Brown     directory_entry_rpc *del,
601fcced4cSJordan Brown     idmap_utf8str_list *ids,
611fcced4cSJordan Brown     idmap_utf8str types,
621fcced4cSJordan Brown     idmap_utf8str_list *attrs)
631fcced4cSJordan Brown {
641fcced4cSJordan Brown 	int i;
651fcced4cSJordan Brown 
661fcced4cSJordan Brown 	for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
671fcced4cSJordan Brown 		const wksids_table_t *wksid;
681fcced4cSJordan Brown 		directory_error_t de;
691fcced4cSJordan Brown 		int type;
701fcced4cSJordan Brown 
711fcced4cSJordan Brown 		/*
721fcced4cSJordan Brown 		 * Extract the type for this particular ID.
731fcced4cSJordan Brown 		 * Advance to the next type, if it's there, else keep
741fcced4cSJordan Brown 		 * using this type until we run out of IDs.
751fcced4cSJordan Brown 		 */
761fcced4cSJordan Brown 		type = *types;
771fcced4cSJordan Brown 		if (*(types+1) != '\0')
781fcced4cSJordan Brown 			types++;
791fcced4cSJordan Brown 
801fcced4cSJordan Brown 		/*
811fcced4cSJordan Brown 		 * If this entry has already been handled, one way or another,
821fcced4cSJordan Brown 		 * skip it.
831fcced4cSJordan Brown 		 */
841fcced4cSJordan Brown 		if (del[i].status != DIRECTORY_NOT_FOUND)
851fcced4cSJordan Brown 			continue;
861fcced4cSJordan Brown 
871fcced4cSJordan Brown 		char *id = ids->idmap_utf8str_list_val[i];
881fcced4cSJordan Brown 
891fcced4cSJordan Brown 		/*
901fcced4cSJordan Brown 		 * End-to-end error injection point.
911fcced4cSJordan Brown 		 * NEEDSWORK:  should probably eliminate this for production
921fcced4cSJordan Brown 		 */
93*cb174861Sjoyce mcintosh 		if (uu_streq(id, " DEBUG BUILTIN ERROR ")) {
941fcced4cSJordan Brown 			directory_entry_set_error(&del[i],
951fcced4cSJordan Brown 			    directory_error("Directory_provider_builtin.debug",
961fcced4cSJordan Brown 			    "Directory_provider_builtin:  artificial error",
971fcced4cSJordan Brown 			    NULL));
981fcced4cSJordan Brown 			continue;
991fcced4cSJordan Brown 		}
1001fcced4cSJordan Brown 
1011fcced4cSJordan Brown 		if (type == DIRECTORY_ID_SID[0])
1021fcced4cSJordan Brown 			wksid = find_wk_by_sid(id);
1031fcced4cSJordan Brown 		else {
1041fcced4cSJordan Brown 			int idmap_id_type;
1051fcced4cSJordan Brown 			if (type == DIRECTORY_ID_NAME[0])
1061fcced4cSJordan Brown 				idmap_id_type = IDMAP_POSIXID;
1071fcced4cSJordan Brown 			else if (type == DIRECTORY_ID_USER[0])
1081fcced4cSJordan Brown 				idmap_id_type = IDMAP_UID;
1091fcced4cSJordan Brown 			else if (type == DIRECTORY_ID_GROUP[0])
1101fcced4cSJordan Brown 				idmap_id_type = IDMAP_GID;
1111fcced4cSJordan Brown 			else {
1121fcced4cSJordan Brown 				directory_entry_set_error(&del[i],
1131fcced4cSJordan Brown 				    directory_error("invalid_arg.id_type",
1141fcced4cSJordan Brown 				    "Invalid ID type \"%1\"",
1151fcced4cSJordan Brown 				    types, NULL));
1161fcced4cSJordan Brown 				continue;
1171fcced4cSJordan Brown 			}
1181fcced4cSJordan Brown 
1191fcced4cSJordan Brown 			int id_len = strlen(id);
1201fcced4cSJordan Brown 			char name[id_len + 1];
1211fcced4cSJordan Brown 			char domain[id_len + 1];
1221fcced4cSJordan Brown 
1231fcced4cSJordan Brown 			split_name(name, domain, id);
1241fcced4cSJordan Brown 
1251fcced4cSJordan Brown 			wksid = find_wksid_by_name(name, domain, idmap_id_type);
1261fcced4cSJordan Brown 		}
1271fcced4cSJordan Brown 
1281fcced4cSJordan Brown 		if (wksid == NULL)
1291fcced4cSJordan Brown 			continue;
1301fcced4cSJordan Brown 
1311fcced4cSJordan Brown 		de = directory_provider_builtin_populate(&del[i], wksid, attrs);
1321fcced4cSJordan Brown 		if (de != NULL) {
1331fcced4cSJordan Brown 			directory_entry_set_error(&del[i], de);
1341fcced4cSJordan Brown 			de = NULL;
1351fcced4cSJordan Brown 		}
1361fcced4cSJordan Brown 	}
1371fcced4cSJordan Brown 
1381fcced4cSJordan Brown 	return (NULL);
1391fcced4cSJordan Brown }
1401fcced4cSJordan Brown 
1411fcced4cSJordan Brown /*
1421fcced4cSJordan Brown  * Given a well-known name entry and a list of attributes that were
1431fcced4cSJordan Brown  * requested, populate the structure to return to the caller.
1441fcced4cSJordan Brown  */
1451fcced4cSJordan Brown static
1461fcced4cSJordan Brown directory_error_t
directory_provider_builtin_populate(directory_entry_rpc * pent,const wksids_table_t * wksid,idmap_utf8str_list * attrs)1471fcced4cSJordan Brown directory_provider_builtin_populate(
1481fcced4cSJordan Brown     directory_entry_rpc *pent,
1491fcced4cSJordan Brown     const wksids_table_t *wksid,
1501fcced4cSJordan Brown     idmap_utf8str_list *attrs)
1511fcced4cSJordan Brown {
1521fcced4cSJordan Brown 	int j;
1531fcced4cSJordan Brown 	directory_values_rpc *llvals;
1541fcced4cSJordan Brown 	int nattrs;
1551fcced4cSJordan Brown 
1561fcced4cSJordan Brown 	nattrs = attrs->idmap_utf8str_list_len;
1571fcced4cSJordan Brown 
1581fcced4cSJordan Brown 	llvals = calloc(nattrs, sizeof (directory_values_rpc));
1591fcced4cSJordan Brown 	if (llvals == NULL)
1601fcced4cSJordan Brown 		goto nomem;
1611fcced4cSJordan Brown 
1621fcced4cSJordan Brown 	pent->status = DIRECTORY_FOUND;
1631fcced4cSJordan Brown 	pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
1641fcced4cSJordan Brown 	pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
1651fcced4cSJordan Brown 
1661fcced4cSJordan Brown 	for (j = 0; j < nattrs; j++) {
1671fcced4cSJordan Brown 		directory_values_rpc *val;
1681fcced4cSJordan Brown 		char *a;
1691fcced4cSJordan Brown 		directory_error_t de;
1701fcced4cSJordan Brown 
1711fcced4cSJordan Brown 		/*
1721fcced4cSJordan Brown 		 * We're going to refer to these a lot, so make a shorthand
1731fcced4cSJordan Brown 		 * copy.
1741fcced4cSJordan Brown 		 */
1751fcced4cSJordan Brown 		a = attrs->idmap_utf8str_list_val[j];
1761fcced4cSJordan Brown 		val = &llvals[j];
1771fcced4cSJordan Brown 
1781fcced4cSJordan Brown 		/*
1791fcced4cSJordan Brown 		 * Start by assuming no errors and that we don't have
1801fcced4cSJordan Brown 		 * the information.
1811fcced4cSJordan Brown 		 */
1821fcced4cSJordan Brown 		val->found = FALSE;
1831fcced4cSJordan Brown 		de = NULL;
1841fcced4cSJordan Brown 
185*cb174861Sjoyce mcintosh 		if (uu_strcaseeq(a, "uid")) {
1861fcced4cSJordan Brown 			de = str_list_dav(val, &wksid->winname, 1);
187*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "uidNumber")) {
1889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			if (wksid->pid != IDMAP_SENTINEL_PID &&
1899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    wksid->is_user) {
1901fcced4cSJordan Brown 				de = uint_list_dav(val, &wksid->pid, 1);
1911fcced4cSJordan Brown 			}
192*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "gidNumber")) {
1939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			if (wksid->pid != IDMAP_SENTINEL_PID &&
1949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    !wksid->is_user) {
1951fcced4cSJordan Brown 				de = uint_list_dav(val, &wksid->pid, 1);
1961fcced4cSJordan Brown 			}
197*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "displayName") ||
198*cb174861Sjoyce mcintosh 		    uu_strcaseeq(a, "cn")) {
1991fcced4cSJordan Brown 			de = str_list_dav(val, &wksid->winname, 1);
200*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "distinguishedName")) {
2011fcced4cSJordan Brown 			char *container;
2021fcced4cSJordan Brown 			if (wksid->domain == NULL) {
2031fcced4cSJordan Brown 				container = "Users";
2041fcced4cSJordan Brown 			} else {
2051fcced4cSJordan Brown 				container = "Builtin";
2061fcced4cSJordan Brown 			}
2071fcced4cSJordan Brown 			RDLOCK_CONFIG();
2081fcced4cSJordan Brown 			char *dn;
2091fcced4cSJordan Brown 			(void) asprintf(&dn,
2101fcced4cSJordan Brown 			    "CN=%s,CN=%s,DC=%s",
2111fcced4cSJordan Brown 			    wksid->winname, container, _idmapdstate.hostname);
2121fcced4cSJordan Brown 			UNLOCK_CONFIG();
2131fcced4cSJordan Brown 			const char *cdn = dn;
2141fcced4cSJordan Brown 			de = str_list_dav(val, &cdn, 1);
2151fcced4cSJordan Brown 			free(dn);
216*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "objectClass")) {
2171fcced4cSJordan Brown 			if (wksid->is_wuser) {
2181fcced4cSJordan Brown 				static const char *objectClasses[] = {
2191fcced4cSJordan Brown 					"top",
2201fcced4cSJordan Brown 					"person",
2211fcced4cSJordan Brown 					"organizationalPerson",
2221fcced4cSJordan Brown 					"user",
2231fcced4cSJordan Brown 				};
2241fcced4cSJordan Brown 				de = str_list_dav(val, objectClasses,
225*cb174861Sjoyce mcintosh 				    UU_NELEM(objectClasses));
2261fcced4cSJordan Brown 			} else {
2271fcced4cSJordan Brown 				static const char *objectClasses[] = {
2281fcced4cSJordan Brown 					"top",
2291fcced4cSJordan Brown 					"group",
2301fcced4cSJordan Brown 				};
2311fcced4cSJordan Brown 				de = str_list_dav(val, objectClasses,
232*cb174861Sjoyce mcintosh 				    UU_NELEM(objectClasses));
2331fcced4cSJordan Brown 			}
234*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "objectSid")) {
2351fcced4cSJordan Brown 			de = sid_dav(val, wksid);
236*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
2371fcced4cSJordan Brown 			char *canon;
2381fcced4cSJordan Brown 
2391fcced4cSJordan Brown 			if (wksid->domain == NULL) {
2401fcced4cSJordan Brown 				RDLOCK_CONFIG();
2411fcced4cSJordan Brown 				(void) asprintf(&canon, "%s@%s",
2421fcced4cSJordan Brown 				    wksid->winname, _idmapdstate.hostname);
2431fcced4cSJordan Brown 				UNLOCK_CONFIG();
244*cb174861Sjoyce mcintosh 			} else if (uu_streq(wksid->domain, "")) {
2451fcced4cSJordan Brown 				canon = strdup(wksid->winname);
2461fcced4cSJordan Brown 			} else {
2471fcced4cSJordan Brown 				(void) asprintf(&canon, "%s@%s",
2481fcced4cSJordan Brown 				    wksid->winname, wksid->domain);
2491fcced4cSJordan Brown 			}
2501fcced4cSJordan Brown 
2511fcced4cSJordan Brown 			if (canon == NULL)
2521fcced4cSJordan Brown 				goto nomem;
2531fcced4cSJordan Brown 			const char *ccanon = canon;
2541fcced4cSJordan Brown 			de = str_list_dav(val, &ccanon, 1);
2551fcced4cSJordan Brown 			free(canon);
256*cb174861Sjoyce mcintosh 		} else if (uu_strcaseeq(a, "x-sun-provider")) {
2571fcced4cSJordan Brown 			const char *provider = "Builtin";
2581fcced4cSJordan Brown 			de = str_list_dav(val, &provider, 1);
2591fcced4cSJordan Brown 		}
2601fcced4cSJordan Brown 		if (de != NULL)
2611fcced4cSJordan Brown 			return (de);
2621fcced4cSJordan Brown 	}
2631fcced4cSJordan Brown 
2641fcced4cSJordan Brown 	return (NULL);
2651fcced4cSJordan Brown 
2661fcced4cSJordan Brown nomem:
2671fcced4cSJordan Brown 	return (directory_error("ENOMEM.users",
2681fcced4cSJordan Brown 	    "No memory allocating return value for user lookup", NULL));
2691fcced4cSJordan Brown }
2701fcced4cSJordan Brown 
2711fcced4cSJordan Brown /*
2721fcced4cSJordan Brown  * Given a well-known name structure, generate a binary-format SID.
2731fcced4cSJordan Brown  * It's a bit perverse that we must take a text-format SID and turn it into
2741fcced4cSJordan Brown  * a binary-format SID, only to have the caller probably turn it back into
2751fcced4cSJordan Brown  * text format, but SIDs are carried across LDAP in binary format.
2761fcced4cSJordan Brown  */
2771fcced4cSJordan Brown static
2781fcced4cSJordan Brown directory_error_t
sid_dav(directory_values_rpc * lvals,const wksids_table_t * wksid)2791fcced4cSJordan Brown sid_dav(directory_values_rpc *lvals, const wksids_table_t *wksid)
2801fcced4cSJordan Brown {
2811fcced4cSJordan Brown 	char *text_sid;
2821fcced4cSJordan Brown 	sid_t *sid;
2831fcced4cSJordan Brown 	directory_error_t de;
2841fcced4cSJordan Brown 
2851fcced4cSJordan Brown 	if (wksid->sidprefix == NULL) {
2861fcced4cSJordan Brown 		RDLOCK_CONFIG();
2871fcced4cSJordan Brown 		(void) asprintf(&text_sid, "%s-%d",
2881fcced4cSJordan Brown 		    _idmapdstate.cfg->pgcfg.machine_sid,
2891fcced4cSJordan Brown 		    wksid->rid);
2901fcced4cSJordan Brown 		UNLOCK_CONFIG();
2911fcced4cSJordan Brown 	} else {
2921fcced4cSJordan Brown 		(void) asprintf(&text_sid, "%s-%d",
2931fcced4cSJordan Brown 		    wksid->sidprefix, wksid->rid);
2941fcced4cSJordan Brown 	}
2951fcced4cSJordan Brown 
2961fcced4cSJordan Brown 	if (text_sid == NULL)
2971fcced4cSJordan Brown 		goto nomem;
2981fcced4cSJordan Brown 
2991fcced4cSJordan Brown 	sid = sid_fromstr(text_sid);
3001fcced4cSJordan Brown 	free(text_sid);
3011fcced4cSJordan Brown 
3021fcced4cSJordan Brown 	if (sid == NULL)
3031fcced4cSJordan Brown 		goto nomem;
3041fcced4cSJordan Brown 
3051fcced4cSJordan Brown 	sid_to_le(sid);
3061fcced4cSJordan Brown 
3071fcced4cSJordan Brown 	de = bin_list_dav(lvals, sid, 1, sid_len(sid));
3081fcced4cSJordan Brown 
3091fcced4cSJordan Brown 	sid_free(sid);
3101fcced4cSJordan Brown 
3111fcced4cSJordan Brown 	return (de);
3121fcced4cSJordan Brown 
3131fcced4cSJordan Brown nomem:
3141fcced4cSJordan Brown 	return (directory_error("ENOMEM.sid_dav",
3151fcced4cSJordan Brown 	    "No memory allocating SID for user lookup", NULL));
3161fcced4cSJordan Brown }
3171fcced4cSJordan Brown 
3181fcced4cSJordan Brown struct directory_provider_static directory_provider_builtin = {
3191fcced4cSJordan Brown 	"builtin",
3201fcced4cSJordan Brown 	directory_provider_builtin_get,
3211fcced4cSJordan Brown };
322