2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Some helper routines for directory lookup. These offer functions that
2N/A * you could implement yourself on top of the generic routines, but since
2N/A * they're a common request we implement them here. (Well, OK, we cheat a bit
2N/A * and call an internal routine to do the dirty work to reduce code
2N/A * duplication, but you could still implement them using the generic routines.)
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#include <libuutil.h>
2N/A#include <rpcsvc/idmap_prot.h>
2N/A#include "directory.h"
2N/A#include "directory_private.h"
2N/A#include "directory_library_impl.h"
2N/A#include "sidutil.h"
2N/A
2N/A/*
2N/A * Given a username, return a text-form SID.
2N/A *
2N/A * The SID must be free()ed by the caller.
2N/A *
2N/A * d, if non-NULL, specifies an existing directory-search context.
2N/A * If NULL, a temporary one will be created.
2N/A */
2N/Adirectory_error_t
2N/Adirectory_sid_from_name_common(
2N/A directory_t d,
2N/A char *name,
2N/A char *type,
2N/A char **sid,
2N/A uint64_t *classes)
2N/A{
2N/A directory_t d1 = NULL;
2N/A static char *attrs[] = {
2N/A "objectSid",
2N/A "objectClass",
2N/A NULL,
2N/A };
2N/A directory_entry_t *ret_list = NULL;
2N/A directory_error_t de;
2N/A struct ret_sid {
2N/A sid_t **objectSid;
2N/A char **objectClass;
2N/A } *ret_sid;
2N/A
2N/A /* Prep for error cases. */
2N/A *sid = NULL;
2N/A if (classes != NULL)
2N/A *classes = 0;
2N/A
2N/A if (d == NULL) {
2N/A de = directory_open(&d1);
2N/A if (de != NULL)
2N/A goto out;
2N/A } else {
2N/A d1 = d;
2N/A }
2N/A
2N/A de = directory_get_v(d1, &ret_list, &name, 1, type, attrs);
2N/A if (de != NULL)
2N/A goto out;
2N/A if (ret_list[0].err != NULL) {
2N/A de = ret_list[0].err;
2N/A ret_list[0].err = NULL;
2N/A goto out;
2N/A }
2N/A
2N/A ret_sid = (struct ret_sid *)ret_list[0].attrs;
2N/A if (ret_sid == NULL)
2N/A goto out;
2N/A
2N/A if (ret_sid->objectSid != NULL &&
2N/A ret_sid->objectSid[0] != NULL) {
2N/A char text_sid[SID_STRSZ+1];
2N/A sid_from_le(ret_sid->objectSid[0]);
2N/A sid_tostr(ret_sid->objectSid[0], text_sid);
2N/A *sid = strdup(text_sid);
2N/A if (*sid == NULL)
2N/A goto nomem;
2N/A }
2N/A
2N/A if (ret_sid->objectClass != NULL &&
2N/A classes != NULL)
2N/A *classes = class_bitmap(ret_sid->objectClass);
2N/A
2N/A goto out;
2N/A
2N/Anomem:
2N/A de = directory_error("ENOMEM.directory_sid_from_name_common",
2N/A "Insufficient memory retrieving data about SID", NULL);
2N/A
2N/Aout:
2N/A directory_free(ret_list);
2N/A if (d == NULL)
2N/A directory_close(d1);
2N/A return (de);
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_sid_from_name(
2N/A directory_t d,
2N/A char *name,
2N/A char **sid,
2N/A uint64_t *classes)
2N/A{
2N/A return (directory_sid_from_name_common(d, name, DIRECTORY_ID_NAME, sid,
2N/A classes));
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_sid_from_user_name(directory_t d, char *name, char **sid)
2N/A{
2N/A return (directory_sid_from_name_common(d, name, DIRECTORY_ID_USER, sid,
2N/A NULL));
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_sid_from_group_name(directory_t d, char *name, char **sid)
2N/A{
2N/A return (directory_sid_from_name_common(d, name, DIRECTORY_ID_GROUP, sid,
2N/A NULL));
2N/A}
2N/A
2N/A/*
2N/A * Given a name or text-format SID, return a user@domain.
2N/A *
2N/A * The user@domain returned must be free()ed by the caller.
2N/A *
2N/A * Returns NULL and sets *name to NULL if no error occurred but the specified
2N/A * entity does not exist.
2N/A *
2N/A * d, if non-NULL, specifies an existing directory-search context.
2N/A * If NULL, a temporary one will be created.
2N/A */
2N/Astatic
2N/Adirectory_error_t
2N/Adirectory_canon_common(
2N/A directory_t d,
2N/A char *id,
2N/A char *id_type,
2N/A char **canon,
2N/A uint64_t *classes)
2N/A{
2N/A directory_t d1 = NULL;
2N/A directory_entry_t *ret_list = NULL;
2N/A directory_error_t de;
2N/A /*
2N/A * Attributes required to generate a canonical name, in named-list and
2N/A * structure form.
2N/A */
2N/A static char *attrs[] = {
2N/A "x-sun-canonicalName",
2N/A "objectClass",
2N/A NULL,
2N/A };
2N/A
2N/A struct canon_name_ret {
2N/A char **x_sun_canonicalName;
2N/A char **objectClass;
2N/A } *ret_name;
2N/A
2N/A /* Prep for error cases. */
2N/A *canon = NULL;
2N/A if (classes != NULL)
2N/A *classes = 0;
2N/A
2N/A if (d == NULL) {
2N/A de = directory_open(&d1);
2N/A if (de != NULL)
2N/A goto out;
2N/A } else {
2N/A d1 = d;
2N/A }
2N/A
2N/A de = directory_get_v(d1, &ret_list, &id, 1, id_type, attrs);
2N/A if (de != NULL)
2N/A goto out;
2N/A if (ret_list[0].err != NULL) {
2N/A de = ret_list[0].err;
2N/A ret_list[0].err = NULL;
2N/A goto out;
2N/A }
2N/A
2N/A ret_name = (struct canon_name_ret *)ret_list[0].attrs;
2N/A if (ret_name == NULL)
2N/A goto out;
2N/A
2N/A if (ret_name->x_sun_canonicalName != NULL &&
2N/A ret_name->x_sun_canonicalName[0] != NULL) {
2N/A *canon = strdup(ret_name->x_sun_canonicalName[0]);
2N/A if (*canon == NULL)
2N/A goto nomem;
2N/A }
2N/A
2N/A if (ret_name->objectClass != NULL &&
2N/A classes != NULL)
2N/A *classes = class_bitmap(ret_name->objectClass);
2N/A
2N/A goto out;
2N/A
2N/Anomem:
2N/A de = directory_error("ENOMEM.directory_canon_common",
2N/A "Insufficient memory retrieving data about name", NULL);
2N/A
2N/Aout:
2N/A directory_free(ret_list);
2N/A if (d == NULL)
2N/A directory_close(d1);
2N/A return (de);
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_name_from_sid(
2N/A directory_t d,
2N/A char *sid,
2N/A char **canon,
2N/A uint64_t *classes)
2N/A{
2N/A return (directory_canon_common(d, sid, DIRECTORY_ID_SID, canon,
2N/A classes));
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_canon_from_name(
2N/A directory_t d,
2N/A char *name,
2N/A char **canon,
2N/A uint64_t *classes)
2N/A{
2N/A return (directory_canon_common(d, name, DIRECTORY_ID_NAME, canon,
2N/A classes));
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_canon_from_user_name(directory_t d, char *name, char **canon)
2N/A{
2N/A return (
2N/A directory_canon_common(d, name, DIRECTORY_ID_USER, canon, NULL));
2N/A}
2N/A
2N/Adirectory_error_t
2N/Adirectory_canon_from_group_name(directory_t d, char *name, char **canon)
2N/A{
2N/A return (
2N/A directory_canon_common(d, name, DIRECTORY_ID_GROUP, canon, NULL));
2N/A}
2N/A
2N/Aboolean_t
2N/Ais_in_list(char **list, char *val)
2N/A{
2N/A for (; *list != NULL; list++) {
2N/A if (uu_strcaseeq(*list, val))
2N/A return (B_TRUE);
2N/A }
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Auint64_t
2N/Aclass_bitmap(char **objectClass)
2N/A{
2N/A uint64_t ret = 0;
2N/A
2N/A for (; *objectClass != NULL; objectClass++) {
2N/A if (uu_strcaseeq(*objectClass, "user") ||
2N/A uu_strcaseeq(*objectClass, "posixAccount"))
2N/A ret |= DIRECTORY_CLASS_USER;
2N/A
2N/A if (uu_strcaseeq(*objectClass, "group") ||
2N/A uu_strcaseeq(*objectClass, "posixGroup"))
2N/A ret |= DIRECTORY_CLASS_GROUP;
2N/A }
2N/A
2N/A return (ret);
2N/A}