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