xref: /onnv-gate/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c (revision 12890:16985853e3aa)
110122SJordan.Brown@Sun.COM /*
210122SJordan.Brown@Sun.COM  * CDDL HEADER START
310122SJordan.Brown@Sun.COM  *
410122SJordan.Brown@Sun.COM  * The contents of this file are subject to the terms of the
510122SJordan.Brown@Sun.COM  * Common Development and Distribution License (the "License").
610122SJordan.Brown@Sun.COM  * You may not use this file except in compliance with the License.
710122SJordan.Brown@Sun.COM  *
810122SJordan.Brown@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910122SJordan.Brown@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010122SJordan.Brown@Sun.COM  * See the License for the specific language governing permissions
1110122SJordan.Brown@Sun.COM  * and limitations under the License.
1210122SJordan.Brown@Sun.COM  *
1310122SJordan.Brown@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410122SJordan.Brown@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510122SJordan.Brown@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610122SJordan.Brown@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710122SJordan.Brown@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810122SJordan.Brown@Sun.COM  *
1910122SJordan.Brown@Sun.COM  * CDDL HEADER END
2010122SJordan.Brown@Sun.COM  */
2110122SJordan.Brown@Sun.COM 
2210122SJordan.Brown@Sun.COM /*
23*12890SJoyce.McIntosh@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410122SJordan.Brown@Sun.COM  */
2510122SJordan.Brown@Sun.COM 
2610122SJordan.Brown@Sun.COM /*
2710122SJordan.Brown@Sun.COM  * Retrieve directory information for built-in users and groups
2810122SJordan.Brown@Sun.COM  */
2910122SJordan.Brown@Sun.COM 
3010122SJordan.Brown@Sun.COM #include <stdio.h>
3110122SJordan.Brown@Sun.COM #include <limits.h>
3210122SJordan.Brown@Sun.COM #include <sys/idmap.h>
3310122SJordan.Brown@Sun.COM #include <sys/param.h>
3410122SJordan.Brown@Sun.COM #include <string.h>
3510122SJordan.Brown@Sun.COM #include <stdlib.h>
3610122SJordan.Brown@Sun.COM #include <netdb.h>
37*12890SJoyce.McIntosh@Sun.COM #include <libuutil.h>
3810122SJordan.Brown@Sun.COM #include <note.h>
3910122SJordan.Brown@Sun.COM #include "idmapd.h"
4010122SJordan.Brown@Sun.COM #include "directory.h"
4110122SJordan.Brown@Sun.COM #include "directory_private.h"
4210122SJordan.Brown@Sun.COM #include <rpcsvc/idmap_prot.h>
4310122SJordan.Brown@Sun.COM #include "directory_server_impl.h"
4410122SJordan.Brown@Sun.COM #include "sidutil.h"
4510122SJordan.Brown@Sun.COM 
4610122SJordan.Brown@Sun.COM static directory_error_t sid_dav(directory_values_rpc *lvals,
4710122SJordan.Brown@Sun.COM     const wksids_table_t *wksid);
4810122SJordan.Brown@Sun.COM static directory_error_t directory_provider_builtin_populate(
4910122SJordan.Brown@Sun.COM     directory_entry_rpc *pent, const wksids_table_t *wksid,
5010122SJordan.Brown@Sun.COM     idmap_utf8str_list *attrs);
5110122SJordan.Brown@Sun.COM 
5210122SJordan.Brown@Sun.COM /*
5310122SJordan.Brown@Sun.COM  * Retrieve information by name.
5410122SJordan.Brown@Sun.COM  * Called indirectly through the directory_provider_static structure.
5510122SJordan.Brown@Sun.COM  */
5610122SJordan.Brown@Sun.COM static
5710122SJordan.Brown@Sun.COM directory_error_t
directory_provider_builtin_get(directory_entry_rpc * del,idmap_utf8str_list * ids,idmap_utf8str types,idmap_utf8str_list * attrs)5810122SJordan.Brown@Sun.COM directory_provider_builtin_get(
5910122SJordan.Brown@Sun.COM     directory_entry_rpc *del,
6010122SJordan.Brown@Sun.COM     idmap_utf8str_list *ids,
6110122SJordan.Brown@Sun.COM     idmap_utf8str types,
6210122SJordan.Brown@Sun.COM     idmap_utf8str_list *attrs)
6310122SJordan.Brown@Sun.COM {
6410122SJordan.Brown@Sun.COM 	int i;
6510122SJordan.Brown@Sun.COM 
6610122SJordan.Brown@Sun.COM 	for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
6710122SJordan.Brown@Sun.COM 		const wksids_table_t *wksid;
6810122SJordan.Brown@Sun.COM 		directory_error_t de;
6910122SJordan.Brown@Sun.COM 		int type;
7010122SJordan.Brown@Sun.COM 
7110122SJordan.Brown@Sun.COM 		/*
7210122SJordan.Brown@Sun.COM 		 * Extract the type for this particular ID.
7310122SJordan.Brown@Sun.COM 		 * Advance to the next type, if it's there, else keep
7410122SJordan.Brown@Sun.COM 		 * using this type until we run out of IDs.
7510122SJordan.Brown@Sun.COM 		 */
7610122SJordan.Brown@Sun.COM 		type = *types;
7710122SJordan.Brown@Sun.COM 		if (*(types+1) != '\0')
7810122SJordan.Brown@Sun.COM 			types++;
7910122SJordan.Brown@Sun.COM 
8010122SJordan.Brown@Sun.COM 		/*
8110122SJordan.Brown@Sun.COM 		 * If this entry has already been handled, one way or another,
8210122SJordan.Brown@Sun.COM 		 * skip it.
8310122SJordan.Brown@Sun.COM 		 */
8410122SJordan.Brown@Sun.COM 		if (del[i].status != DIRECTORY_NOT_FOUND)
8510122SJordan.Brown@Sun.COM 			continue;
8610122SJordan.Brown@Sun.COM 
8710122SJordan.Brown@Sun.COM 		char *id = ids->idmap_utf8str_list_val[i];
8810122SJordan.Brown@Sun.COM 
8910122SJordan.Brown@Sun.COM 		/*
9010122SJordan.Brown@Sun.COM 		 * End-to-end error injection point.
9110122SJordan.Brown@Sun.COM 		 * NEEDSWORK:  should probably eliminate this for production
9210122SJordan.Brown@Sun.COM 		 */
93*12890SJoyce.McIntosh@Sun.COM 		if (uu_streq(id, " DEBUG BUILTIN ERROR ")) {
9410122SJordan.Brown@Sun.COM 			directory_entry_set_error(&del[i],
9510122SJordan.Brown@Sun.COM 			    directory_error("Directory_provider_builtin.debug",
9610122SJordan.Brown@Sun.COM 			    "Directory_provider_builtin:  artificial error",
9710122SJordan.Brown@Sun.COM 			    NULL));
9810122SJordan.Brown@Sun.COM 			continue;
9910122SJordan.Brown@Sun.COM 		}
10010122SJordan.Brown@Sun.COM 
10110122SJordan.Brown@Sun.COM 		if (type == DIRECTORY_ID_SID[0])
10210122SJordan.Brown@Sun.COM 			wksid = find_wk_by_sid(id);
10310122SJordan.Brown@Sun.COM 		else {
10410122SJordan.Brown@Sun.COM 			int idmap_id_type;
10510122SJordan.Brown@Sun.COM 			if (type == DIRECTORY_ID_NAME[0])
10610122SJordan.Brown@Sun.COM 				idmap_id_type = IDMAP_POSIXID;
10710122SJordan.Brown@Sun.COM 			else if (type == DIRECTORY_ID_USER[0])
10810122SJordan.Brown@Sun.COM 				idmap_id_type = IDMAP_UID;
10910122SJordan.Brown@Sun.COM 			else if (type == DIRECTORY_ID_GROUP[0])
11010122SJordan.Brown@Sun.COM 				idmap_id_type = IDMAP_GID;
11110122SJordan.Brown@Sun.COM 			else {
11210122SJordan.Brown@Sun.COM 				directory_entry_set_error(&del[i],
11310122SJordan.Brown@Sun.COM 				    directory_error("invalid_arg.id_type",
11410122SJordan.Brown@Sun.COM 				    "Invalid ID type \"%1\"",
11510122SJordan.Brown@Sun.COM 				    types, NULL));
11610122SJordan.Brown@Sun.COM 				continue;
11710122SJordan.Brown@Sun.COM 			}
11810122SJordan.Brown@Sun.COM 
11910122SJordan.Brown@Sun.COM 			int id_len = strlen(id);
12010122SJordan.Brown@Sun.COM 			char name[id_len + 1];
12110122SJordan.Brown@Sun.COM 			char domain[id_len + 1];
12210122SJordan.Brown@Sun.COM 
12310122SJordan.Brown@Sun.COM 			split_name(name, domain, id);
12410122SJordan.Brown@Sun.COM 
12510122SJordan.Brown@Sun.COM 			wksid = find_wksid_by_name(name, domain, idmap_id_type);
12610122SJordan.Brown@Sun.COM 		}
12710122SJordan.Brown@Sun.COM 
12810122SJordan.Brown@Sun.COM 		if (wksid == NULL)
12910122SJordan.Brown@Sun.COM 			continue;
13010122SJordan.Brown@Sun.COM 
13110122SJordan.Brown@Sun.COM 		de = directory_provider_builtin_populate(&del[i], wksid, attrs);
13210122SJordan.Brown@Sun.COM 		if (de != NULL) {
13310122SJordan.Brown@Sun.COM 			directory_entry_set_error(&del[i], de);
13410122SJordan.Brown@Sun.COM 			de = NULL;
13510122SJordan.Brown@Sun.COM 		}
13610122SJordan.Brown@Sun.COM 	}
13710122SJordan.Brown@Sun.COM 
13810122SJordan.Brown@Sun.COM 	return (NULL);
13910122SJordan.Brown@Sun.COM }
14010122SJordan.Brown@Sun.COM 
14110122SJordan.Brown@Sun.COM /*
14210122SJordan.Brown@Sun.COM  * Given a well-known name entry and a list of attributes that were
14310122SJordan.Brown@Sun.COM  * requested, populate the structure to return to the caller.
14410122SJordan.Brown@Sun.COM  */
14510122SJordan.Brown@Sun.COM static
14610122SJordan.Brown@Sun.COM directory_error_t
directory_provider_builtin_populate(directory_entry_rpc * pent,const wksids_table_t * wksid,idmap_utf8str_list * attrs)14710122SJordan.Brown@Sun.COM directory_provider_builtin_populate(
14810122SJordan.Brown@Sun.COM     directory_entry_rpc *pent,
14910122SJordan.Brown@Sun.COM     const wksids_table_t *wksid,
15010122SJordan.Brown@Sun.COM     idmap_utf8str_list *attrs)
15110122SJordan.Brown@Sun.COM {
15210122SJordan.Brown@Sun.COM 	int j;
15310122SJordan.Brown@Sun.COM 	directory_values_rpc *llvals;
15410122SJordan.Brown@Sun.COM 	int nattrs;
15510122SJordan.Brown@Sun.COM 
15610122SJordan.Brown@Sun.COM 	nattrs = attrs->idmap_utf8str_list_len;
15710122SJordan.Brown@Sun.COM 
15810122SJordan.Brown@Sun.COM 	llvals = calloc(nattrs, sizeof (directory_values_rpc));
15910122SJordan.Brown@Sun.COM 	if (llvals == NULL)
16010122SJordan.Brown@Sun.COM 		goto nomem;
16110122SJordan.Brown@Sun.COM 
16210122SJordan.Brown@Sun.COM 	pent->status = DIRECTORY_FOUND;
16310122SJordan.Brown@Sun.COM 	pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
16410122SJordan.Brown@Sun.COM 	pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
16510122SJordan.Brown@Sun.COM 
16610122SJordan.Brown@Sun.COM 	for (j = 0; j < nattrs; j++) {
16710122SJordan.Brown@Sun.COM 		directory_values_rpc *val;
16810122SJordan.Brown@Sun.COM 		char *a;
16910122SJordan.Brown@Sun.COM 		directory_error_t de;
17010122SJordan.Brown@Sun.COM 
17110122SJordan.Brown@Sun.COM 		/*
17210122SJordan.Brown@Sun.COM 		 * We're going to refer to these a lot, so make a shorthand
17310122SJordan.Brown@Sun.COM 		 * copy.
17410122SJordan.Brown@Sun.COM 		 */
17510122SJordan.Brown@Sun.COM 		a = attrs->idmap_utf8str_list_val[j];
17610122SJordan.Brown@Sun.COM 		val = &llvals[j];
17710122SJordan.Brown@Sun.COM 
17810122SJordan.Brown@Sun.COM 		/*
17910122SJordan.Brown@Sun.COM 		 * Start by assuming no errors and that we don't have
18010122SJordan.Brown@Sun.COM 		 * the information.
18110122SJordan.Brown@Sun.COM 		 */
18210122SJordan.Brown@Sun.COM 		val->found = FALSE;
18310122SJordan.Brown@Sun.COM 		de = NULL;
18410122SJordan.Brown@Sun.COM 
185*12890SJoyce.McIntosh@Sun.COM 		if (uu_strcaseeq(a, "uid")) {
18610122SJordan.Brown@Sun.COM 			de = str_list_dav(val, &wksid->winname, 1);
187*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "uidNumber")) {
18811963SAfshin.Ardakani@Sun.COM 			if (wksid->pid != IDMAP_SENTINEL_PID &&
18911963SAfshin.Ardakani@Sun.COM 			    wksid->is_user) {
19010122SJordan.Brown@Sun.COM 				de = uint_list_dav(val, &wksid->pid, 1);
19110122SJordan.Brown@Sun.COM 			}
192*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "gidNumber")) {
19311963SAfshin.Ardakani@Sun.COM 			if (wksid->pid != IDMAP_SENTINEL_PID &&
19411963SAfshin.Ardakani@Sun.COM 			    !wksid->is_user) {
19510122SJordan.Brown@Sun.COM 				de = uint_list_dav(val, &wksid->pid, 1);
19610122SJordan.Brown@Sun.COM 			}
197*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "displayName") ||
198*12890SJoyce.McIntosh@Sun.COM 		    uu_strcaseeq(a, "cn")) {
19910122SJordan.Brown@Sun.COM 			de = str_list_dav(val, &wksid->winname, 1);
200*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "distinguishedName")) {
20110122SJordan.Brown@Sun.COM 			char *container;
20210122SJordan.Brown@Sun.COM 			if (wksid->domain == NULL) {
20310122SJordan.Brown@Sun.COM 				container = "Users";
20410122SJordan.Brown@Sun.COM 			} else {
20510122SJordan.Brown@Sun.COM 				container = "Builtin";
20610122SJordan.Brown@Sun.COM 			}
20710122SJordan.Brown@Sun.COM 			RDLOCK_CONFIG();
20810122SJordan.Brown@Sun.COM 			char *dn;
20910122SJordan.Brown@Sun.COM 			(void) asprintf(&dn,
21010122SJordan.Brown@Sun.COM 			    "CN=%s,CN=%s,DC=%s",
21110122SJordan.Brown@Sun.COM 			    wksid->winname, container, _idmapdstate.hostname);
21210122SJordan.Brown@Sun.COM 			UNLOCK_CONFIG();
21310122SJordan.Brown@Sun.COM 			const char *cdn = dn;
21410122SJordan.Brown@Sun.COM 			de = str_list_dav(val, &cdn, 1);
21510122SJordan.Brown@Sun.COM 			free(dn);
216*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "objectClass")) {
21710122SJordan.Brown@Sun.COM 			if (wksid->is_wuser) {
21810122SJordan.Brown@Sun.COM 				static const char *objectClasses[] = {
21910122SJordan.Brown@Sun.COM 					"top",
22010122SJordan.Brown@Sun.COM 					"person",
22110122SJordan.Brown@Sun.COM 					"organizationalPerson",
22210122SJordan.Brown@Sun.COM 					"user",
22310122SJordan.Brown@Sun.COM 				};
22410122SJordan.Brown@Sun.COM 				de = str_list_dav(val, objectClasses,
225*12890SJoyce.McIntosh@Sun.COM 				    UU_NELEM(objectClasses));
22610122SJordan.Brown@Sun.COM 			} else {
22710122SJordan.Brown@Sun.COM 				static const char *objectClasses[] = {
22810122SJordan.Brown@Sun.COM 					"top",
22910122SJordan.Brown@Sun.COM 					"group",
23010122SJordan.Brown@Sun.COM 				};
23110122SJordan.Brown@Sun.COM 				de = str_list_dav(val, objectClasses,
232*12890SJoyce.McIntosh@Sun.COM 				    UU_NELEM(objectClasses));
23310122SJordan.Brown@Sun.COM 			}
234*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "objectSid")) {
23510122SJordan.Brown@Sun.COM 			de = sid_dav(val, wksid);
236*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
23710122SJordan.Brown@Sun.COM 			char *canon;
23810122SJordan.Brown@Sun.COM 
23910122SJordan.Brown@Sun.COM 			if (wksid->domain == NULL) {
24010122SJordan.Brown@Sun.COM 				RDLOCK_CONFIG();
24110122SJordan.Brown@Sun.COM 				(void) asprintf(&canon, "%s@%s",
24210122SJordan.Brown@Sun.COM 				    wksid->winname, _idmapdstate.hostname);
24310122SJordan.Brown@Sun.COM 				UNLOCK_CONFIG();
244*12890SJoyce.McIntosh@Sun.COM 			} else if (uu_streq(wksid->domain, "")) {
24510122SJordan.Brown@Sun.COM 				canon = strdup(wksid->winname);
24610122SJordan.Brown@Sun.COM 			} else {
24710122SJordan.Brown@Sun.COM 				(void) asprintf(&canon, "%s@%s",
24810122SJordan.Brown@Sun.COM 				    wksid->winname, wksid->domain);
24910122SJordan.Brown@Sun.COM 			}
25010122SJordan.Brown@Sun.COM 
25110122SJordan.Brown@Sun.COM 			if (canon == NULL)
25210122SJordan.Brown@Sun.COM 				goto nomem;
25310122SJordan.Brown@Sun.COM 			const char *ccanon = canon;
25410122SJordan.Brown@Sun.COM 			de = str_list_dav(val, &ccanon, 1);
25510122SJordan.Brown@Sun.COM 			free(canon);
256*12890SJoyce.McIntosh@Sun.COM 		} else if (uu_strcaseeq(a, "x-sun-provider")) {
25710122SJordan.Brown@Sun.COM 			const char *provider = "Builtin";
25810122SJordan.Brown@Sun.COM 			de = str_list_dav(val, &provider, 1);
25910122SJordan.Brown@Sun.COM 		}
26010122SJordan.Brown@Sun.COM 		if (de != NULL)
26110122SJordan.Brown@Sun.COM 			return (de);
26210122SJordan.Brown@Sun.COM 	}
26310122SJordan.Brown@Sun.COM 
26410122SJordan.Brown@Sun.COM 	return (NULL);
26510122SJordan.Brown@Sun.COM 
26610122SJordan.Brown@Sun.COM nomem:
26710122SJordan.Brown@Sun.COM 	return (directory_error("ENOMEM.users",
26810122SJordan.Brown@Sun.COM 	    "No memory allocating return value for user lookup", NULL));
26910122SJordan.Brown@Sun.COM }
27010122SJordan.Brown@Sun.COM 
27110122SJordan.Brown@Sun.COM /*
27210122SJordan.Brown@Sun.COM  * Given a well-known name structure, generate a binary-format SID.
27310122SJordan.Brown@Sun.COM  * It's a bit perverse that we must take a text-format SID and turn it into
27410122SJordan.Brown@Sun.COM  * a binary-format SID, only to have the caller probably turn it back into
27510122SJordan.Brown@Sun.COM  * text format, but SIDs are carried across LDAP in binary format.
27610122SJordan.Brown@Sun.COM  */
27710122SJordan.Brown@Sun.COM static
27810122SJordan.Brown@Sun.COM directory_error_t
sid_dav(directory_values_rpc * lvals,const wksids_table_t * wksid)27910122SJordan.Brown@Sun.COM sid_dav(directory_values_rpc *lvals, const wksids_table_t *wksid)
28010122SJordan.Brown@Sun.COM {
28110122SJordan.Brown@Sun.COM 	char *text_sid;
28210122SJordan.Brown@Sun.COM 	sid_t *sid;
28310122SJordan.Brown@Sun.COM 	directory_error_t de;
28410122SJordan.Brown@Sun.COM 
28510122SJordan.Brown@Sun.COM 	if (wksid->sidprefix == NULL) {
28610122SJordan.Brown@Sun.COM 		RDLOCK_CONFIG();
28710122SJordan.Brown@Sun.COM 		(void) asprintf(&text_sid, "%s-%d",
28810122SJordan.Brown@Sun.COM 		    _idmapdstate.cfg->pgcfg.machine_sid,
28910122SJordan.Brown@Sun.COM 		    wksid->rid);
29010122SJordan.Brown@Sun.COM 		UNLOCK_CONFIG();
29110122SJordan.Brown@Sun.COM 	} else {
29210122SJordan.Brown@Sun.COM 		(void) asprintf(&text_sid, "%s-%d",
29310122SJordan.Brown@Sun.COM 		    wksid->sidprefix, wksid->rid);
29410122SJordan.Brown@Sun.COM 	}
29510122SJordan.Brown@Sun.COM 
29610122SJordan.Brown@Sun.COM 	if (text_sid == NULL)
29710122SJordan.Brown@Sun.COM 		goto nomem;
29810122SJordan.Brown@Sun.COM 
29910122SJordan.Brown@Sun.COM 	sid = sid_fromstr(text_sid);
30010122SJordan.Brown@Sun.COM 	free(text_sid);
30110122SJordan.Brown@Sun.COM 
30210122SJordan.Brown@Sun.COM 	if (sid == NULL)
30310122SJordan.Brown@Sun.COM 		goto nomem;
30410122SJordan.Brown@Sun.COM 
30510122SJordan.Brown@Sun.COM 	sid_to_le(sid);
30610122SJordan.Brown@Sun.COM 
30710122SJordan.Brown@Sun.COM 	de = bin_list_dav(lvals, sid, 1, sid_len(sid));
30810122SJordan.Brown@Sun.COM 
30910122SJordan.Brown@Sun.COM 	sid_free(sid);
31010122SJordan.Brown@Sun.COM 
31110122SJordan.Brown@Sun.COM 	return (de);
31210122SJordan.Brown@Sun.COM 
31310122SJordan.Brown@Sun.COM nomem:
31410122SJordan.Brown@Sun.COM 	return (directory_error("ENOMEM.sid_dav",
31510122SJordan.Brown@Sun.COM 	    "No memory allocating SID for user lookup", NULL));
31610122SJordan.Brown@Sun.COM }
31710122SJordan.Brown@Sun.COM 
31810122SJordan.Brown@Sun.COM struct directory_provider_static directory_provider_builtin = {
31910122SJordan.Brown@Sun.COM 	"builtin",
32010122SJordan.Brown@Sun.COM 	directory_provider_builtin_get,
32110122SJordan.Brown@Sun.COM };
322