/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright Milan Jurik 2012. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright 2015 Joyent, Inc.
*/
/*
* libidmap API
*/
#include <stdlib.h>
#include <sys/varargs.h>
#include <inttypes.h>
#include <errno.h>
#include <strings.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <libintl.h>
#include <syslog.h>
#include <assert.h>
#include "idmap_impl.h"
#include "idmap_cache.h"
static struct timeval TIMEOUT = { 25, 0 };
static int idmap_stat2errno(idmap_stat);
static idmap_stat idmap_strdupnull(char **, const char *);
#define __ITER_CREATE(itera, argu, ityp)\
itera = calloc(1, sizeof (*itera));\
if (itera == NULL) {\
errno = ENOMEM;\
return (IDMAP_ERR_MEMORY);\
}\
argu = calloc(1, sizeof (*argu));\
if (argu == NULL) {\
free(itera);\
errno = ENOMEM;\
return (IDMAP_ERR_MEMORY);\
}\
itera->type = ityp;\
itera->retcode = IDMAP_NEXT;\
itera->limit = 1024;\
itera->arg = argu;
#define __ITER_CHECK(itera, ityp)\
if (itera == NULL) {\
errno = EINVAL;\
return (IDMAP_ERR_ARG);\
}\
if (itera->type != ityp) {\
errno = EINVAL;\
return (IDMAP_ERR_ARG);\
}
/*
* Free memory allocated by libidmap API
*
* Input:
* ptr - memory to be freed
*/
void
idmap_free(void *ptr)
{
free(ptr);
}
static idmap_stat
idmap_get_prop(idmap_prop_type pr, idmap_prop_res *res)
{
idmap_stat retcode;
(void) memset(res, 0, sizeof (*res));
retcode = _idmap_clnt_call(IDMAP_GET_PROP,
(xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr,
(xdrproc_t)xdr_idmap_prop_res, (caddr_t)res, TIMEOUT);
if (retcode != IDMAP_SUCCESS)
return (retcode);
return (res->retcode); /* This might not be IDMAP_SUCCESS! */
}
idmap_stat
idmap_get_prop_ds(idmap_prop_type pr, idmap_ad_disc_ds_t *dc)
{
idmap_prop_res res;
idmap_stat rc = IDMAP_SUCCESS;
rc = idmap_get_prop(pr, &res);
if (rc < 0)
return (rc);
dc->port = res.value.idmap_prop_val_u.dsval.port;
(void) strlcpy(dc->host, res.value.idmap_prop_val_u.dsval.host,
AD_DISC_MAXHOSTNAME);
/* xdr doesn't guarantee 0-termination of char[]: */
dc->host[AD_DISC_MAXHOSTNAME - 1] = '\0';
return (rc);
}
/*
* Sometimes the property is not set. In that case, str is set to NULL but
* otherwise IDMAP_SUCCESS is returned.
*/
idmap_stat
idmap_get_prop_str(idmap_prop_type pr, char **str)
{
idmap_prop_res res;
idmap_stat rc = IDMAP_SUCCESS;
rc = idmap_get_prop(pr, &res);
if (rc < 0)
return (rc);
rc = idmap_strdupnull(str, res.value.idmap_prop_val_u.utf8val);
return (rc);
}
/*
* Create/Initialize handle for updates
*
* Output:
* udthandle - update handle
*/
idmap_stat
idmap_udt_create(idmap_udt_handle_t **udthandle)
{
idmap_udt_handle_t *tmp;
if (udthandle == NULL) {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
errno = ENOMEM;
return (IDMAP_ERR_MEMORY);
}
*udthandle = tmp;
return (IDMAP_SUCCESS);
}
/*
* All the updates specified by the update handle are committed
* in a single transaction. i.e either all succeed or none.
*
* Input:
* udthandle - update handle with the update requests
*
* Return value:
* Status of the commit
*/
idmap_stat
idmap_udt_commit(idmap_udt_handle_t *udthandle)
{
idmap_update_res res;
idmap_stat retcode;
if (udthandle == NULL) {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
(void) memset(&res, 0, sizeof (res));
retcode = _idmap_clnt_call(IDMAP_UPDATE,
(xdrproc_t)xdr_idmap_update_batch, (caddr_t)&udthandle->batch,
(xdrproc_t)xdr_idmap_update_res, (caddr_t)&res,
TIMEOUT);
if (retcode != IDMAP_SUCCESS)
goto out;
retcode = udthandle->commit_stat = res.retcode;
udthandle->error_index = res.error_index;
if (retcode != IDMAP_SUCCESS) {
if (udthandle->error_index < 0)
goto out;
retcode = idmap_namerule_cpy(&udthandle->error_rule,
&res.error_rule);
if (retcode != IDMAP_SUCCESS) {
udthandle->error_index = -2;
goto out;
}
retcode = idmap_namerule_cpy(&udthandle->conflict_rule,
&res.conflict_rule);
if (retcode != IDMAP_SUCCESS) {
udthandle->error_index = -2;
goto out;
}
}
retcode = res.retcode;
out:
/* reset handle so that it can be used again */
if (retcode == IDMAP_SUCCESS) {
_IDMAP_RESET_UDT_HANDLE(udthandle);
}
(void) xdr_free(xdr_idmap_update_res, (caddr_t)&res);
errno = idmap_stat2errno(retcode);
return (retcode);
}
static void
idmap_namerule_parts_clear(char **windomain, char **winname,
char **unixname, boolean_t *is_user, boolean_t *is_wuser,
boolean_t *is_nt4, int *direction)
{
if (windomain)
*windomain = NULL;
if (winname)
*winname = NULL;
if (unixname)
*unixname = NULL;
if (is_nt4)
*is_nt4 = 0;
if (is_user)
*is_user = -1;
if (is_wuser)
*is_wuser = -1;
if (direction)
*direction = IDMAP_DIRECTION_UNDEF;
}
static idmap_stat
idmap_namerule2parts(idmap_namerule *rule,
char **windomain, char **winname,
char **unixname, boolean_t *is_user, boolean_t *is_wuser,
boolean_t *is_nt4, int *direction)
{
idmap_stat retcode;
if (EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
return (IDMAP_ERR_NORESULT);
retcode = idmap_strdupnull(windomain, rule->windomain);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(winname, rule->winname);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(unixname, rule->unixname);
if (retcode != IDMAP_SUCCESS)
goto errout;
if (is_user)
*is_user = rule->is_user;
if (is_wuser)
*is_wuser = rule->is_wuser;
if (is_nt4)
*is_nt4 = rule->is_nt4;
if (direction)
*direction = rule->direction;
return (IDMAP_SUCCESS);
errout:
if (windomain && *windomain)
free(*windomain);
if (winname && *winname)
free(*winname);
if (unixname && *unixname)
free(*unixname);
idmap_namerule_parts_clear(windomain, winname,
unixname, is_user, is_wuser, is_nt4, direction);
return (retcode);
}
/*
* Retrieve the index of the failed batch element. error_index == -1
* indicates failure at the beginning, -2 at the end.
*
* If idmap_udt_commit didn't return error, the returned value is undefined.
*
* Return value:
* IDMAP_SUCCESS
*/
idmap_stat
idmap_udt_get_error_index(idmap_udt_handle_t *udthandle,
int64_t *error_index)
{
if (error_index)
*error_index = udthandle->error_index;
return (IDMAP_SUCCESS);
}
/*
* Retrieve the rule which caused the batch to fail. If
* idmap_udt_commit didn't return error or if error_index is < 0, the
* retrieved rule is undefined.
*
* Return value:
* IDMAP_ERR_NORESULT if there is no error rule.
* IDMAP_SUCCESS if the rule was obtained OK.
* other error code (IDMAP_ERR_NOMEMORY etc)
*/
idmap_stat
idmap_udt_get_error_rule(idmap_udt_handle_t *udthandle,
char **windomain, char **winname,
char **unixname, boolean_t *is_user, boolean_t *is_wuser,
boolean_t *is_nt4, int *direction)
{
idmap_namerule_parts_clear(windomain, winname,
unixname, is_user, is_wuser, is_nt4, direction);
if (udthandle->commit_stat == IDMAP_SUCCESS ||
udthandle->error_index < 0)
return (IDMAP_ERR_NORESULT);
return (idmap_namerule2parts(
&udthandle->error_rule,
windomain,
winname,
unixname,
is_user,
is_wuser,
is_nt4,
direction));
}
/*
* Retrieve the rule with which there was a conflict. TODO: retrieve
* the value.
*
* Return value:
* IDMAP_ERR_NORESULT if there is no error rule.
* IDMAP_SUCCESS if the rule was obtained OK.
* other error code (IDMAP_ERR_NOMEMORY etc)
*/
idmap_stat
idmap_udt_get_conflict_rule(idmap_udt_handle_t *udthandle,
char **windomain, char **winname,
char **unixname, boolean_t *is_user, boolean_t *is_wuser,
boolean_t *is_nt4, int *direction)
{
idmap_namerule_parts_clear(windomain, winname,
unixname, is_user, is_wuser, is_nt4, direction);
if (udthandle->commit_stat != IDMAP_ERR_W2U_NAMERULE_CONFLICT &&
udthandle->commit_stat != IDMAP_ERR_U2W_NAMERULE_CONFLICT) {
return (IDMAP_ERR_NORESULT);
}
return (idmap_namerule2parts(
&udthandle->conflict_rule,
windomain,
winname,
unixname,
is_user,
is_wuser,
is_nt4,
direction));
}
/*
* Destroy the update handle
*/
void
idmap_udt_destroy(idmap_udt_handle_t *udthandle)
{
if (udthandle == NULL)
return;
(void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->error_rule);
(void) xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->conflict_rule);
free(udthandle);
}
idmap_stat
idmap_udt_add_namerule(idmap_udt_handle_t *udthandle, const char *windomain,
boolean_t is_user, boolean_t is_wuser, const char *winname,
const char *unixname, boolean_t is_nt4, int direction)
{
idmap_retcode retcode;
idmap_namerule *rule = NULL;
retcode = _udt_extend_batch(udthandle);
if (retcode != IDMAP_SUCCESS)
goto errout;
rule = &udthandle->batch.
idmap_update_batch_val[udthandle->next].
idmap_update_op_u.rule;
rule->is_user = is_user;
rule->is_wuser = is_wuser;
rule->direction = direction;
rule->is_nt4 = is_nt4;
retcode = idmap_strdupnull(&rule->windomain, windomain);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(&rule->winname, winname);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(&rule->unixname, unixname);
if (retcode != IDMAP_SUCCESS)
goto errout;
udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
OP_ADD_NAMERULE;
udthandle->next++;
return (IDMAP_SUCCESS);
errout:
/* The batch should still be usable */
if (rule)
(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
errno = idmap_stat2errno(retcode);
return (retcode);
}
/* ARGSUSED */
idmap_stat
idmap_udt_rm_namerule(idmap_udt_handle_t *udthandle, boolean_t is_user,
boolean_t is_wuser, const char *windomain, const char *winname,
const char *unixname, int direction)
{
idmap_retcode retcode;
idmap_namerule *rule = NULL;
retcode = _udt_extend_batch(udthandle);
if (retcode != IDMAP_SUCCESS)
goto errout;
rule = &udthandle->batch.
idmap_update_batch_val[udthandle->next].
idmap_update_op_u.rule;
rule->is_user = is_user;
rule->is_wuser = is_wuser;
rule->direction = direction;
retcode = idmap_strdupnull(&rule->windomain, windomain);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(&rule->winname, winname);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(&rule->unixname, unixname);
if (retcode != IDMAP_SUCCESS)
goto errout;
udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
OP_RM_NAMERULE;
udthandle->next++;
return (IDMAP_SUCCESS);
errout:
if (rule)
(void) xdr_free(xdr_idmap_namerule, (caddr_t)rule);
errno = idmap_stat2errno(retcode);
return (retcode);
}
/* ARGSUSED */
idmap_stat
idmap_udt_flush_namerules(idmap_udt_handle_t *udthandle)
{
idmap_retcode retcode;
retcode = _udt_extend_batch(udthandle);
if (retcode != IDMAP_SUCCESS)
goto errout;
udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
OP_FLUSH_NAMERULES;
udthandle->next++;
return (IDMAP_SUCCESS);
errout:
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Set the number of entries requested per batch by the iterator
*
* Input:
* iter - iterator
* limit - number of entries requested per batch
*/
idmap_stat
idmap_iter_set_limit(idmap_iter_t *iter, uint64_t limit)
{
if (iter == NULL) {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
iter->limit = limit;
return (IDMAP_SUCCESS);
}
/*
* Create iterator to get name-based mapping rules
*
* Input:
* windomain - Windows domain
* is_user - user or group rules
* winname - Windows user or group name
* unixname - Unix user or group name
*
* Output:
* iter - iterator
*/
idmap_stat
idmap_iter_namerules(const char *windomain,
boolean_t is_user, boolean_t is_wuser, const char *winname,
const char *unixname, idmap_iter_t **iter)
{
idmap_iter_t *tmpiter;
idmap_list_namerules_1_argument *arg = NULL;
idmap_namerule *rule;
idmap_retcode retcode;
__ITER_CREATE(tmpiter, arg, IDMAP_LIST_NAMERULES);
rule = &arg->rule;
rule->is_user = is_user;
rule->is_wuser = is_wuser;
rule->direction = IDMAP_DIRECTION_UNDEF;
retcode = idmap_strdupnull(&rule->windomain, windomain);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(&rule->winname, winname);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(&rule->unixname, unixname);
if (retcode != IDMAP_SUCCESS)
goto errout;
*iter = tmpiter;
return (IDMAP_SUCCESS);
errout:
if (arg) {
xdr_free(xdr_idmap_list_namerules_1_argument, (char *)arg);
free(arg);
}
if (tmpiter)
free(tmpiter);
return (retcode);
}
/*
* Iterate through the name-based mapping rules
*
* Input:
* iter - iterator
*
* Output:
* windomain - Windows domain
* winname - Windows user or group name
* unixname - Unix user or group name
* is_nt4 - NT4 or AD
* direction - bi(0), win2unix(1), unix2win(2)
*
* Return value:
* 0 - done
* 1 - more results available
* < 0 - error
*/
idmap_stat
idmap_iter_next_namerule(idmap_iter_t *iter, char **windomain,
char **winname, char **unixname, boolean_t *is_user,
boolean_t *is_wuser, boolean_t *is_nt4, int *direction)
{
idmap_namerules_res *namerules;
idmap_list_namerules_1_argument *arg;
idmap_retcode retcode;
idmap_namerule_parts_clear(windomain, winname,
unixname, is_user, is_wuser, is_nt4, direction);
__ITER_CHECK(iter, IDMAP_LIST_NAMERULES);
namerules = (idmap_namerules_res *)iter->retlist;
if (iter->retcode == IDMAP_NEXT && (namerules == NULL ||
iter->next >= namerules->rules.rules_len)) {
if ((arg = iter->arg) == NULL) {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
arg->limit = iter->limit;
retcode = _iter_get_next_list(IDMAP_LIST_NAMERULES,
iter, arg,
(uchar_t **)&namerules, sizeof (*namerules),
(xdrproc_t)xdr_idmap_list_namerules_1_argument,
(xdrproc_t)xdr_idmap_namerules_res);
if (retcode != IDMAP_SUCCESS)
return (retcode);
if (IDMAP_ERROR(namerules->retcode)) {
retcode = namerules->retcode;
xdr_free(xdr_idmap_namerules_res, (caddr_t)namerules);
free(namerules);
iter->retlist = NULL;
return (retcode);
}
iter->retcode = namerules->retcode;
arg->lastrowid = namerules->lastrowid;
}
if (namerules == NULL || namerules->rules.rules_len == 0)
return (IDMAP_SUCCESS);
if (iter->next >= namerules->rules.rules_len) {
return (IDMAP_ERR_ARG);
}
retcode = idmap_strdupnull(windomain,
namerules->rules.rules_val[iter->next].windomain);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(winname,
namerules->rules.rules_val[iter->next].winname);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(unixname,
namerules->rules.rules_val[iter->next].unixname);
if (retcode != IDMAP_SUCCESS)
goto errout;
if (is_nt4)
*is_nt4 = namerules->rules.rules_val[iter->next].is_nt4;
if (is_user)
*is_user = namerules->rules.rules_val[iter->next].is_user;
if (is_wuser)
*is_wuser = namerules->rules.rules_val[iter->next].is_wuser;
if (direction)
*direction = namerules->rules.rules_val[iter->next].direction;
iter->next++;
if (iter->next == namerules->rules.rules_len)
return (iter->retcode);
else
return (IDMAP_NEXT);
errout:
if (windomain && *windomain)
free(*windomain);
if (winname && *winname)
free(*winname);
if (unixname && *unixname)
free(*unixname);
return (retcode);
}
/*
* Create iterator to get SID to UID/GID mappings
*
* Output:
* iter - iterator
*/
idmap_stat
idmap_iter_mappings(idmap_iter_t **iter, int flag)
{
idmap_iter_t *tmpiter;
idmap_list_mappings_1_argument *arg = NULL;
__ITER_CREATE(tmpiter, arg, IDMAP_LIST_MAPPINGS);
arg->flag = flag;
*iter = tmpiter;
return (IDMAP_SUCCESS);
}
/*
* Iterate through the SID to UID/GID mappings
*
* Input:
* iter - iterator
*
* Output:
* sid - SID in canonical form
* pid - UID or GID
*
* Return value:
* 0 - done
* 1 - more results available
* < 0 - error
*/
idmap_stat
idmap_iter_next_mapping(idmap_iter_t *iter, char **sidprefix,
idmap_rid_t *rid, uid_t *pid, char **winname,
char **windomain, char **unixname, boolean_t *is_user,
boolean_t *is_wuser, int *direction, idmap_info *info)
{
idmap_mappings_res *mappings;
idmap_list_mappings_1_argument *arg;
idmap_retcode retcode;
char *str;
if (sidprefix)
*sidprefix = NULL;
if (rid)
*rid = UINT32_MAX;
if (winname)
*winname = NULL;
if (windomain)
*windomain = NULL;
if (unixname)
*unixname = NULL;
if (pid)
*pid = UINT32_MAX;
if (is_user)
*is_user = -1;
if (is_wuser)
*is_wuser = -1;
if (direction)
*direction = IDMAP_DIRECTION_UNDEF;
__ITER_CHECK(iter, IDMAP_LIST_MAPPINGS);
mappings = (idmap_mappings_res *)iter->retlist;
if (iter->retcode == IDMAP_NEXT && (mappings == NULL ||
iter->next >= mappings->mappings.mappings_len)) {
if ((arg = iter->arg) == NULL) {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
arg->limit = iter->limit;
retcode = _iter_get_next_list(IDMAP_LIST_MAPPINGS,
iter, arg,
(uchar_t **)&mappings, sizeof (*mappings),
(xdrproc_t)xdr_idmap_list_mappings_1_argument,
(xdrproc_t)xdr_idmap_mappings_res);
if (retcode != IDMAP_SUCCESS)
return (retcode);
if (IDMAP_ERROR(mappings->retcode)) {
retcode = mappings->retcode;
xdr_free(xdr_idmap_mappings_res, (caddr_t)mappings);
free(mappings);
iter->retlist = NULL;
return (retcode);
}
iter->retcode = mappings->retcode;
arg->lastrowid = mappings->lastrowid;
}
if (mappings == NULL || mappings->mappings.mappings_len == 0)
return (IDMAP_SUCCESS);
if (iter->next >= mappings->mappings.mappings_len) {
return (IDMAP_ERR_ARG);
}
if (sidprefix) {
str = mappings->mappings.mappings_val[iter->next].id1.
idmap_id_u.sid.prefix;
if (str && *str != '\0') {
*sidprefix = strdup(str);
if (*sidprefix == NULL) {
retcode = IDMAP_ERR_MEMORY;
goto errout;
}
}
}
if (rid)
*rid = mappings->mappings.mappings_val[iter->next].id1.
idmap_id_u.sid.rid;
retcode = idmap_strdupnull(windomain,
mappings->mappings.mappings_val[iter->next].id1domain);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(winname,
mappings->mappings.mappings_val[iter->next].id1name);
if (retcode != IDMAP_SUCCESS)
goto errout;
retcode = idmap_strdupnull(unixname,
mappings->mappings.mappings_val[iter->next].id2name);
if (retcode != IDMAP_SUCCESS)
goto errout;
if (pid)
*pid = mappings->mappings.mappings_val[iter->next].id2.
idmap_id_u.uid;
if (direction)
*direction = mappings->mappings.mappings_val[iter->next].
direction;
if (is_user)
*is_user = (mappings->mappings.mappings_val[iter->next].id2
.idtype == IDMAP_UID)?1:0;
if (is_wuser)
*is_wuser = (mappings->mappings.mappings_val[iter->next].id1
.idtype == IDMAP_USID)?1:0;
if (info) {
idmap_info_mov(info,
&mappings->mappings.mappings_val[iter->next].info);
}
iter->next++;
if (iter->next == mappings->mappings.mappings_len)
return (iter->retcode);
else
return (IDMAP_NEXT);
errout:
if (sidprefix && *sidprefix)
free(*sidprefix);
if (winname && *winname)
free(*winname);
if (windomain && *windomain)
free(*windomain);
if (unixname && *unixname)
free(*unixname);
return (retcode);
}
/*
* Destroy the iterator
*/
void
idmap_iter_destroy(idmap_iter_t *iter)
{
xdrproc_t _xdr_argument, _xdr_result;
if (iter == NULL)
return;
switch (iter->type) {
case IDMAP_LIST_NAMERULES:
_xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
_xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
break;
case IDMAP_LIST_MAPPINGS:
_xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
_xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
break;
default:
free(iter);
return;
};
if (iter->arg) {
xdr_free(_xdr_argument, (caddr_t)iter->arg);
free(iter->arg);
}
if (iter->retlist) {
xdr_free(_xdr_result, (caddr_t)iter->retlist);
free(iter->retlist);
}
free(iter);
}
/*
* Create handle to get SID to UID/GID mapping entries
*
* Input:
* gh - "get mapping" handle
*/
idmap_stat
idmap_get_create(idmap_get_handle_t **gh)
{
idmap_get_handle_t *tmp;
/* allocate the handle */
if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
errno = ENOMEM;
return (IDMAP_ERR_MEMORY);
}
*gh = tmp;
return (IDMAP_SUCCESS);
}
/*
* Given SID, get UID
*
* Input:
* sidprefix - SID prefix
* rid - RID
* flag - flag
*
* Output:
* stat - status of the get request
* uid - POSIX UID if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_get_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
int flag, uid_t *uid, idmap_stat *stat)
{
return (idmap_getext_uidbysid(gh, sidprefix, rid, flag, uid,
NULL, stat));
}
/*
* Given SID, get UID
*
* Input:
* sidprefix - SID prefix
* rid - RID
* flag - flag
*
* Output:
* stat - status of the get request
* uid - POSIX UID if stat = 0
* how - mapping type if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_getext_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
int flag, uid_t *uid, idmap_info *info, idmap_stat *stat)
{
idmap_retcode retcode;
idmap_mapping *mapping = NULL;
/* sanity checks */
if (gh == NULL)
return (IDMAP_ERR_ARG);
if (uid == NULL || sidprefix == NULL)
return (IDMAP_ERR_ARG);
if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
!(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
retcode = idmap_cache_lookup_uidbysid(sidprefix, rid, uid);
if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
*stat = retcode;
return (retcode);
}
}
/* Extend the request array and the return list */
if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
goto errout;
/* Setup the request */
mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
mapping->flag = flag;
mapping->id1.idtype = IDMAP_SID;
mapping->id1.idmap_id_u.sid.rid = rid;
if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
retcode = IDMAP_ERR_MEMORY;
goto errout;
}
mapping->id2.idtype = IDMAP_UID;
/* Setup pointers for the result */
gh->retlist[gh->next].idtype = IDMAP_UID;
gh->retlist[gh->next].uid = uid;
gh->retlist[gh->next].stat = stat;
gh->retlist[gh->next].info = info;
gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
gh->next++;
return (IDMAP_SUCCESS);
errout:
/* Batch created so far should still be usable */
if (mapping)
(void) memset(mapping, 0, sizeof (*mapping));
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Given SID, get GID
*
* Input:
* sidprefix - SID prefix
* rid - rid
* flag - flag
*
* Output:
* stat - status of the get request
* gid - POSIX GID if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_get_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
int flag, gid_t *gid, idmap_stat *stat)
{
return (idmap_getext_gidbysid(gh, sidprefix, rid, flag, gid,
NULL, stat));
}
/*
* Given SID, get GID
*
* Input:
* sidprefix - SID prefix
* rid - rid
* flag - flag
*
* Output:
* stat - status of the get request
* gid - POSIX GID if stat = 0
* how - mapping type if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_getext_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
int flag, gid_t *gid, idmap_info *info, idmap_stat *stat)
{
idmap_retcode retcode;
idmap_mapping *mapping = NULL;
/* sanity checks */
if (gh == NULL)
return (IDMAP_ERR_ARG);
if (gid == NULL || sidprefix == NULL)
return (IDMAP_ERR_ARG);
if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
!(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
retcode = idmap_cache_lookup_gidbysid(sidprefix, rid, gid);
if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
*stat = retcode;
return (retcode);
}
}
/* Extend the request array and the return list */
if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
goto errout;
/* Setup the request */
mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
mapping->flag = flag;
mapping->id1.idtype = IDMAP_SID;
mapping->id1.idmap_id_u.sid.rid = rid;
if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
retcode = IDMAP_ERR_MEMORY;
goto errout;
}
mapping->id2.idtype = IDMAP_GID;
/* Setup pointers for the result */
gh->retlist[gh->next].idtype = IDMAP_GID;
gh->retlist[gh->next].gid = gid;
gh->retlist[gh->next].stat = stat;
gh->retlist[gh->next].info = info;
gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
gh->next++;
return (IDMAP_SUCCESS);
errout:
if (mapping)
(void) memset(mapping, 0, sizeof (*mapping));
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Given SID, get POSIX ID i.e. UID/GID
*
* Input:
* sidprefix - SID prefix
* rid - rid
* flag - flag
*
* Output:
* stat - status of the get request
* is_user - user or group
* pid - POSIX UID if stat = 0 and is_user = 1
* POSIX GID if stat = 0 and is_user = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_get_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
int flag, uid_t *pid, int *is_user, idmap_stat *stat)
{
return (idmap_getext_pidbysid(gh, sidprefix, rid, flag, pid, is_user,
NULL, stat));
}
/*
* Given SID, get POSIX ID i.e. UID/GID
*
* Input:
* sidprefix - SID prefix
* rid - rid
* flag - flag
*
* Output:
* stat - status of the get request
* is_user - user or group
* pid - POSIX UID if stat = 0 and is_user = 1
* POSIX GID if stat = 0 and is_user = 0
* how - mapping type if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_getext_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
int flag, uid_t *pid, int *is_user, idmap_info *info, idmap_stat *stat)
{
idmap_retcode retcode;
idmap_mapping *mapping = NULL;
/* sanity checks */
if (gh == NULL)
return (IDMAP_ERR_ARG);
if (pid == NULL || sidprefix == NULL || is_user == NULL)
return (IDMAP_ERR_ARG);
if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
!(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
retcode = idmap_cache_lookup_pidbysid(sidprefix, rid, pid,
is_user);
if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
*stat = retcode;
return (retcode);
}
}
/* Extend the request array and the return list */
if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
goto errout;
/* Setup the request */
mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
mapping->flag = flag;
mapping->id1.idtype = IDMAP_SID;
mapping->id1.idmap_id_u.sid.rid = rid;
if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
retcode = IDMAP_ERR_MEMORY;
goto errout;
}
mapping->id2.idtype = IDMAP_POSIXID;
/* Setup pointers for the result */
gh->retlist[gh->next].idtype = IDMAP_POSIXID;
gh->retlist[gh->next].uid = pid;
gh->retlist[gh->next].gid = pid;
gh->retlist[gh->next].is_user = is_user;
gh->retlist[gh->next].stat = stat;
gh->retlist[gh->next].info = info;
gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
gh->next++;
return (IDMAP_SUCCESS);
errout:
if (mapping)
(void) memset(mapping, 0, sizeof (*mapping));
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Given UID, get SID
*
* Input:
* uid - POSIX UID
* flag - flag
*
* Output:
* stat - status of the get request
* sid - SID prefix (if stat == 0)
* rid - rid
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_get_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
{
return (idmap_getext_sidbyuid(gh, uid, flag, sidprefix, rid,
NULL, stat));
}
/*
* Given UID, get SID
*
* Input:
* uid - POSIX UID
* flag - flag
*
* Output:
* stat - status of the get request
* sid - SID prefix (if stat == 0)
* rid - rid
* how - mapping type if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_getext_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
{
idmap_retcode retcode;
idmap_mapping *mapping = NULL;
/* sanity checks */
if (gh == NULL)
return (IDMAP_ERR_ARG);
if (sidprefix == NULL)
return (IDMAP_ERR_ARG);
if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
!(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
retcode = idmap_cache_lookup_sidbyuid(sidprefix, rid, uid);
if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
*stat = retcode;
return (retcode);
}
}
/* Extend the request array and the return list */
if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
goto errout;
/* Setup the request */
mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
mapping->flag = flag;
mapping->id1.idtype = IDMAP_UID;
mapping->id1.idmap_id_u.uid = uid;
mapping->id2.idtype = IDMAP_SID;
/* Setup pointers for the result */
gh->retlist[gh->next].idtype = IDMAP_SID;
gh->retlist[gh->next].sidprefix = sidprefix;
gh->retlist[gh->next].rid = rid;
gh->retlist[gh->next].stat = stat;
gh->retlist[gh->next].info = info;
gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
gh->next++;
return (IDMAP_SUCCESS);
errout:
if (mapping)
(void) memset(mapping, 0, sizeof (*mapping));
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Given GID, get SID
*
* Input:
* gid - POSIX GID
* flag - flag
*
* Output:
* stat - status of the get request
* sidprefix - SID prefix (if stat == 0)
* rid - rid
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_get_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
{
return (idmap_getext_sidbygid(gh, gid, flag, sidprefix, rid,
NULL, stat));
}
/*
* Given GID, get SID
*
* Input:
* gid - POSIX GID
* flag - flag
*
* Output:
* stat - status of the get request
* sidprefix - SID prefix (if stat == 0)
* rid - rid
* how - mapping type if stat = 0
*
* Note: The output parameters will be set by idmap_get_mappings()
*/
idmap_stat
idmap_getext_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
{
idmap_retcode retcode;
idmap_mapping *mapping = NULL;
/* sanity checks */
if (gh == NULL)
return (IDMAP_ERR_ARG);
if (sidprefix == NULL)
return (IDMAP_ERR_ARG);
if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
!(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
retcode = idmap_cache_lookup_sidbygid(sidprefix, rid, gid);
if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
*stat = retcode;
return (retcode);
}
}
/* Extend the request array and the return list */
if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
goto errout;
/* Setup the request */
mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
mapping->flag = flag;
mapping->id1.idtype = IDMAP_GID;
mapping->id1.idmap_id_u.gid = gid;
mapping->id2.idtype = IDMAP_SID;
/* Setup pointers for the result */
gh->retlist[gh->next].idtype = IDMAP_SID;
gh->retlist[gh->next].sidprefix = sidprefix;
gh->retlist[gh->next].rid = rid;
gh->retlist[gh->next].stat = stat;
gh->retlist[gh->next].info = info;
gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
gh->next++;
return (IDMAP_SUCCESS);
errout:
if (mapping)
(void) memset(mapping, 0, sizeof (*mapping));
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Process the batched "get mapping" requests. The results (i.e.
* status and identity) will be available in the data areas
* provided by individual requests.
*/
idmap_stat
idmap_get_mappings(idmap_get_handle_t *gh)
{
idmap_retcode retcode;
idmap_ids_res res;
idmap_id *res_id;
int i;
idmap_id *req_id;
int direction;
if (gh == NULL) {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
(void) memset(&res, 0, sizeof (idmap_ids_res));
retcode = _idmap_clnt_call(IDMAP_GET_MAPPED_IDS,
(xdrproc_t)xdr_idmap_mapping_batch,
(caddr_t)&gh->batch,
(xdrproc_t)xdr_idmap_ids_res,
(caddr_t)&res,
TIMEOUT);
if (retcode != IDMAP_SUCCESS) {
goto out;
}
if (res.retcode != IDMAP_SUCCESS) {
retcode = res.retcode;
goto out;
}
for (i = 0; i < gh->next; i++) {
if (i >= res.ids.ids_len) {
*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
continue;
}
*gh->retlist[i].stat = res.ids.ids_val[i].retcode;
res_id = &res.ids.ids_val[i].id;
direction = res.ids.ids_val[i].direction;
req_id = &gh->batch.idmap_mapping_batch_val[i].id1;
switch (res_id->idtype) {
case IDMAP_UID:
if (gh->retlist[i].uid)
*gh->retlist[i].uid = res_id->idmap_id_u.uid;
if (gh->retlist[i].is_user)
*gh->retlist[i].is_user = 1;
if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
gh->retlist[i].cache_res) {
if (gh->retlist[i].is_user != NULL)
idmap_cache_add_sid2pid(
req_id->idmap_id_u.sid.prefix,
req_id->idmap_id_u.sid.rid,
res_id->idmap_id_u.uid, 1,
direction);
else
idmap_cache_add_sid2uid(
req_id->idmap_id_u.sid.prefix,
req_id->idmap_id_u.sid.rid,
res_id->idmap_id_u.uid,
direction);
}
break;
case IDMAP_GID:
if (gh->retlist[i].gid)
*gh->retlist[i].gid = res_id->idmap_id_u.gid;
if (gh->retlist[i].is_user)
*gh->retlist[i].is_user = 0;
if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
gh->retlist[i].cache_res) {
if (gh->retlist[i].is_user != NULL)
idmap_cache_add_sid2pid(
req_id->idmap_id_u.sid.prefix,
req_id->idmap_id_u.sid.rid,
res_id->idmap_id_u.gid, 0,
direction);
else
idmap_cache_add_sid2gid(
req_id->idmap_id_u.sid.prefix,
req_id->idmap_id_u.sid.rid,
res_id->idmap_id_u.gid,
direction);
}
break;
case IDMAP_POSIXID:
if (gh->retlist[i].uid)
*gh->retlist[i].uid = 60001;
if (gh->retlist[i].is_user)
*gh->retlist[i].is_user = -1;
break;
case IDMAP_SID:
case IDMAP_USID:
case IDMAP_GSID:
if (gh->retlist[i].rid)
*gh->retlist[i].rid =
res_id->idmap_id_u.sid.rid;
if (gh->retlist[i].sidprefix) {
if (res_id->idmap_id_u.sid.prefix == NULL ||
*res_id->idmap_id_u.sid.prefix == '\0') {
*gh->retlist[i].sidprefix = NULL;
break;
}
*gh->retlist[i].sidprefix =
strdup(res_id->idmap_id_u.sid.prefix);
if (*gh->retlist[i].sidprefix == NULL)
*gh->retlist[i].stat =
IDMAP_ERR_MEMORY;
}
if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
gh->retlist[i].cache_res) {
if (req_id->idtype == IDMAP_UID)
idmap_cache_add_sid2uid(
res_id->idmap_id_u.sid.prefix,
res_id->idmap_id_u.sid.rid,
req_id->idmap_id_u.uid,
direction);
else /* req_id->idtype == IDMAP_GID */
idmap_cache_add_sid2gid(
res_id->idmap_id_u.sid.prefix,
res_id->idmap_id_u.sid.rid,
req_id->idmap_id_u.gid,
direction);
}
break;
case IDMAP_NONE:
break;
default:
*gh->retlist[i].stat = IDMAP_ERR_NORESULT;
break;
}
if (gh->retlist[i].info != NULL) {
idmap_info_mov(gh->retlist[i].info,
&res.ids.ids_val[i].info);
}
}
retcode = IDMAP_SUCCESS;
out:
_IDMAP_RESET_GET_HANDLE(gh);
(void) xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Destroy the "get mapping" handle
*/
void
idmap_get_destroy(idmap_get_handle_t *gh)
{
if (gh == NULL)
return;
(void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
if (gh->retlist)
free(gh->retlist);
free(gh);
}
/*
* Get windows to unix mapping
*/
idmap_stat
idmap_get_w2u_mapping(
const char *sidprefix, idmap_rid_t *rid,
const char *winname, const char *windomain,
int flag, int *is_user, int *is_wuser,
uid_t *pid, char **unixname, int *direction, idmap_info *info)
{
idmap_mapping request, *mapping;
idmap_mappings_res result;
idmap_retcode retcode, rc;
(void) memset(&request, 0, sizeof (request));
(void) memset(&result, 0, sizeof (result));
if (pid)
*pid = UINT32_MAX;
if (unixname)
*unixname = NULL;
if (direction)
*direction = IDMAP_DIRECTION_UNDEF;
request.flag = flag;
request.id1.idtype = IDMAP_SID;
if (sidprefix && rid) {
request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
request.id1.idmap_id_u.sid.rid = *rid;
} else if (winname) {
retcode = idmap_strdupnull(&request.id1name, winname);
if (retcode != IDMAP_SUCCESS)
goto out;
retcode = idmap_strdupnull(&request.id1domain, windomain);
if (retcode != IDMAP_SUCCESS)
goto out;
request.id1.idmap_id_u.sid.prefix = NULL;
} else {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
if (*is_user == 1)
request.id2.idtype = IDMAP_UID;
else if (*is_user == 0)
request.id2.idtype = IDMAP_GID;
else
request.id2.idtype = IDMAP_POSIXID;
if (*is_wuser == 1)
request.id1.idtype = IDMAP_USID;
else if (*is_wuser == 0)
request.id1.idtype = IDMAP_GSID;
else
request.id1.idtype = IDMAP_SID;
retcode = _idmap_clnt_call(IDMAP_GET_MAPPED_ID_BY_NAME,
(xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
(xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
TIMEOUT);
if (retcode != IDMAP_SUCCESS)
goto out;
retcode = result.retcode;
if ((mapping = result.mappings.mappings_val) == NULL) {
if (retcode == IDMAP_SUCCESS)
retcode = IDMAP_ERR_NORESULT;
goto out;
}
if (info != NULL)
idmap_info_mov(info, &mapping->info);
if (mapping->id2.idtype == IDMAP_UID) {
*is_user = 1;
} else if (mapping->id2.idtype == IDMAP_GID) {
*is_user = 0;
} else {
goto out;
}
if (mapping->id1.idtype == IDMAP_USID) {
*is_wuser = 1;
} else if (mapping->id1.idtype == IDMAP_GSID) {
*is_wuser = 0;
} else {
goto out;
}
if (direction)
*direction = mapping->direction;
if (pid)
*pid = mapping->id2.idmap_id_u.uid;
rc = idmap_strdupnull(unixname, mapping->id2name);
if (rc != IDMAP_SUCCESS)
retcode = rc;
out:
if (request.id1name != NULL)
free(request.id1name);
if (request.id1domain != NULL)
free(request.id1domain);
xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
if (retcode != IDMAP_SUCCESS)
errno = idmap_stat2errno(retcode);
return (retcode);
}
/*
* Get unix to windows mapping
*/
idmap_stat
idmap_get_u2w_mapping(
uid_t *pid, const char *unixname,
int flag, int is_user, int *is_wuser,
char **sidprefix, idmap_rid_t *rid,
char **winname, char **windomain,
int *direction, idmap_info *info)
{
idmap_mapping request, *mapping;
idmap_mappings_res result;
idmap_retcode retcode, rc;
if (sidprefix)
*sidprefix = NULL;
if (winname)
*winname = NULL;
if (windomain)
*windomain = NULL;
if (rid)
*rid = UINT32_MAX;
if (direction)
*direction = IDMAP_DIRECTION_UNDEF;
(void) memset(&request, 0, sizeof (request));
(void) memset(&result, 0, sizeof (result));
request.flag = flag;
request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
if (pid && *pid != UINT32_MAX) {
request.id1.idmap_id_u.uid = *pid;
} else if (unixname) {
request.id1name = (char *)unixname;
request.id1.idmap_id_u.uid = UINT32_MAX;
} else {
errno = EINVAL;
return (IDMAP_ERR_ARG);
}
if (is_wuser == NULL)
request.id2.idtype = IDMAP_SID;
else if (*is_wuser == -1)
request.id2.idtype = IDMAP_SID;
else if (*is_wuser == 0)
request.id2.idtype = IDMAP_GSID;
else if (*is_wuser == 1)
request.id2.idtype = IDMAP_USID;
retcode = _idmap_clnt_call(IDMAP_GET_MAPPED_ID_BY_NAME,
(xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
(xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
TIMEOUT);
if (retcode != IDMAP_SUCCESS)
return (retcode);
retcode = result.retcode;
if ((mapping = result.mappings.mappings_val) == NULL) {
if (retcode == IDMAP_SUCCESS)
retcode = IDMAP_ERR_NORESULT;
goto out;
}
if (info != NULL)
idmap_info_mov(info, &mapping->info);
if (direction != NULL)
*direction = mapping->direction;
if (is_wuser != NULL) {
if (mapping->id2.idtype == IDMAP_USID)
*is_wuser = 1;
else if (mapping->id2.idtype == IDMAP_GSID)
*is_wuser = 0;
else
*is_wuser = -1;
}
if (sidprefix && mapping->id2.idmap_id_u.sid.prefix &&
*mapping->id2.idmap_id_u.sid.prefix != '\0') {
*sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
if (*sidprefix == NULL) {
retcode = IDMAP_ERR_MEMORY;
goto errout;
}
}
if (rid)
*rid = mapping->id2.idmap_id_u.sid.rid;
rc = idmap_strdupnull(winname, mapping->id2name);
if (rc != IDMAP_SUCCESS)
retcode = rc;
rc = idmap_strdupnull(windomain, mapping->id2domain);
if (rc != IDMAP_SUCCESS)
retcode = rc;
goto out;
errout:
if (sidprefix && *sidprefix) {
free(*sidprefix);
*sidprefix = NULL;
}
if (winname && *winname) {
free(*winname);
*winname = NULL;
}
if (windomain && *windomain) {
free(*windomain);
*windomain = NULL;
}
out:
xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
if (retcode != IDMAP_SUCCESS)
errno = idmap_stat2errno(retcode);
return (retcode);
}
#define gettext(s) s
static stat_table_t stattable[] = {
{IDMAP_SUCCESS, gettext("Success"), 0},
{IDMAP_NEXT, gettext("More results available"), 0},
{IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
{IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
{IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
{IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
{IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
{IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
{IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), ENOTSUP},
{IDMAP_ERR_W2U_NAMERULE,
gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
{IDMAP_ERR_U2W_NAMERULE,
gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
{IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
{IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
{IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
{IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
{IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
{IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EBADF},
{IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
{IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
{IDMAP_ERR_BUSY, gettext("Server is busy"), EBUSY},
{IDMAP_ERR_PERMISSION_DENIED, gettext("Permission denied"), EACCES},
{IDMAP_ERR_NOMAPPING,
gettext("Mapping not found or inhibited"), EINVAL},
{IDMAP_ERR_NEW_ID_ALLOC_REQD,
gettext("New mapping needs to be created"), EINVAL},
{IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
{IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
{IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
{IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
{IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
{IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
{IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
{IDMAP_ERR_NOTMAPPED_WELLKNOWN,
gettext("No mapping for well-known SID"), EINVAL},
{IDMAP_ERR_RETRIABLE_NET_ERR,
gettext("Windows lookup failed"), EINVAL},
{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
gettext("Duplicate rule or conflicts with an existing "
"Windows to UNIX name-based rule"), EINVAL},
{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
gettext("Duplicate rule or conflicts with an existing "
"Unix to Windows name-based rule"), EINVAL},
{IDMAP_ERR_BAD_UTF8,
gettext("Invalid or illegal UTF-8 sequence found in "
"a given Windows entity name or domain name"), EINVAL},
{IDMAP_ERR_NONE_GENERATED,
gettext("Mapping not found and none created (see -c option)"),
EINVAL},
{IDMAP_ERR_PROP_UNKNOWN,
gettext("Undefined property"),
EINVAL},
{IDMAP_ERR_NS_LDAP_CFG,
gettext("Native LDAP configuration error"), EINVAL},
{IDMAP_ERR_NS_LDAP_PARTIAL,
gettext("Partial result from Native LDAP"), EINVAL},
{IDMAP_ERR_NS_LDAP_OP_FAILED,
gettext("Native LDAP operation failed"), EINVAL},
{IDMAP_ERR_NS_LDAP_BAD_WINNAME,
gettext("Improper winname form found in Native LDAP"), EINVAL},
{IDMAP_ERR_NO_ACTIVEDIRECTORY,
gettext("No AD servers"),
EINVAL},
{-1, NULL, 0}
};
#undef gettext
/*
* Get description of status code
*
* Input:
* status - Status code returned by libidmap API call
*
* Return Value:
* human-readable localized description of idmap_stat
*/
const char *
idmap_stat2string(idmap_stat status)
{
int i;
for (i = 0; stattable[i].msg; i++) {
if (stattable[i].retcode == status)
return (dgettext(TEXT_DOMAIN, stattable[i].msg));
}
return (dgettext(TEXT_DOMAIN, "Unknown error"));
}
static int
idmap_stat2errno(idmap_stat stat)
{
int i;
for (i = 0; stattable[i].msg; i++) {
if (stattable[i].retcode == stat)
return (stattable[i].errnum);
}
return (EINVAL);
}
/*
* Get status code from string
*/
idmap_stat
idmap_string2stat(const char *str)
{
if (str == NULL)
return (IDMAP_ERR_INTERNAL);
#define return_cmp(a) \
if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
return (IDMAP_ERR_ ## a);
return_cmp(OTHER);
return_cmp(INTERNAL);
return_cmp(MEMORY);
return_cmp(NORESULT);
return_cmp(NOTUSER);
return_cmp(NOTGROUP);
return_cmp(NOTSUPPORTED);
return_cmp(W2U_NAMERULE);
return_cmp(U2W_NAMERULE);
return_cmp(CACHE);
return_cmp(DB);
return_cmp(ARG);
return_cmp(SID);
return_cmp(IDTYPE);
return_cmp(RPC_HANDLE);
return_cmp(RPC);
return_cmp(CLIENT_HANDLE);
return_cmp(BUSY);
return_cmp(PERMISSION_DENIED);
return_cmp(NOMAPPING);
return_cmp(NEW_ID_ALLOC_REQD);
return_cmp(DOMAIN);
return_cmp(SECURITY);
return_cmp(NOTFOUND);
return_cmp(DOMAIN_NOTFOUND);
return_cmp(MEMORY);
return_cmp(UPDATE_NOTALLOWED);
return_cmp(CFG);
return_cmp(CFG_CHANGE);
return_cmp(NOTMAPPED_WELLKNOWN);
return_cmp(RETRIABLE_NET_ERR);
return_cmp(W2U_NAMERULE_CONFLICT);
return_cmp(U2W_NAMERULE_CONFLICT);
return_cmp(BAD_UTF8);
return_cmp(NONE_GENERATED);
return_cmp(PROP_UNKNOWN);
return_cmp(NS_LDAP_CFG);
return_cmp(NS_LDAP_PARTIAL);
return_cmp(NS_LDAP_OP_FAILED);
return_cmp(NS_LDAP_BAD_WINNAME);
return_cmp(NO_ACTIVEDIRECTORY);
#undef return_cmp
return (IDMAP_ERR_OTHER);
}
/*
* Map the given status to one that can be returned by the protocol
*/
idmap_stat
idmap_stat4prot(idmap_stat status)
{
switch (status) {
case IDMAP_ERR_MEMORY:
case IDMAP_ERR_CACHE:
return (IDMAP_ERR_INTERNAL);
}
return (status);
}
/*
* This is a convenience routine which duplicates a string after
* checking for NULL pointers. This function will return success if
* either the 'to' OR 'from' pointers are NULL.
*/
static idmap_stat
idmap_strdupnull(char **to, const char *from)
{
if (to == NULL)
return (IDMAP_SUCCESS);
if (from == NULL || *from == '\0') {
*to = NULL;
return (IDMAP_SUCCESS);
}
*to = strdup(from);
if (*to == NULL)
return (IDMAP_ERR_MEMORY);
return (IDMAP_SUCCESS);
}
idmap_stat
idmap_namerule_cpy(idmap_namerule *to, idmap_namerule *from)
{
idmap_stat retval;
if (to == NULL)
return (IDMAP_SUCCESS);
(void) memcpy(to, from, sizeof (idmap_namerule));
to->windomain = NULL;
to->winname = NULL;
to->unixname = NULL;
retval = idmap_strdupnull(&to->windomain, from->windomain);
if (retval != IDMAP_SUCCESS)
return (retval);
retval = idmap_strdupnull(&to->winname, from->winname);
if (retval != IDMAP_SUCCESS) {
free(to->windomain);
to->windomain = NULL;
return (retval);
}
retval = idmap_strdupnull(&to->unixname, from->unixname);
if (retval != IDMAP_SUCCESS) {
free(to->windomain);
to->windomain = NULL;
free(to->winname);
to->winname = NULL;
return (retval);
}
return (retval);
}
/*
* Move the contents of the "info" structure from "from" to "to".
*/
void
idmap_info_mov(idmap_info *to, idmap_info *from)
{
(void) memcpy(to, from, sizeof (idmap_info));
(void) memset(from, 0, sizeof (idmap_info));
}
void
idmap_info_free(idmap_info *info)
{
if (info == NULL)
return;
xdr_free(xdr_idmap_info, (caddr_t)info);
(void) memset(info, 0, sizeof (idmap_info));
}
void
idmap_how_clear(idmap_how *how)
{
xdr_free(xdr_idmap_how, (caddr_t)how);
(void) memset(how, 0, sizeof (*how));
}
/*
* Get uid given Windows name
*/
idmap_stat
idmap_getuidbywinname(const char *name, const char *domain, int flag,
uid_t *uid)
{
idmap_retcode rc;
int is_user = 1;
int is_wuser = -1;
int direction;
if (uid == NULL)
return (IDMAP_ERR_ARG);
if (flag & IDMAP_REQ_FLG_USE_CACHE) {
rc = idmap_cache_lookup_uidbywinname(name, domain, uid);
if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
return (rc);
}
/* Get mapping */
rc = idmap_get_w2u_mapping(NULL, NULL, name, domain, flag,
&is_user, &is_wuser, uid, NULL, &direction, NULL);
if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
/* If we have not got the domain don't store UID to winname */
if (domain == NULL)
direction = IDMAP_DIRECTION_W2U;
idmap_cache_add_winname2uid(name, domain, *uid, direction);
}
return (rc);
}
/*
* Get gid given Windows name
*/
idmap_stat
idmap_getgidbywinname(const char *name, const char *domain, int flag,
gid_t *gid)
{
idmap_retcode rc;
int is_user = 0;
int is_wuser = -1;
int direction;
if (gid == NULL)
return (IDMAP_ERR_ARG);
if (flag & IDMAP_REQ_FLG_USE_CACHE) {
rc = idmap_cache_lookup_gidbywinname(name, domain, gid);
if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
return (rc);
}
/* Get mapping */
rc = idmap_get_w2u_mapping(NULL, NULL, name, domain, flag,
&is_user, &is_wuser, gid, NULL, &direction, NULL);
if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
/* If we have not got the domain don't store GID to winname */
if (domain == NULL)
direction = IDMAP_DIRECTION_W2U;
idmap_cache_add_winname2gid(name, domain, *gid, direction);
}
return (rc);
}
/*
* Get winname given pid
*/
idmap_stat
idmap_getwinnamebypid(uid_t pid, int is_user, int flag, char **name,
char **domain)
{
idmap_retcode rc;
int len;
char *winname, *windomain;
int direction;
if (name == NULL)
return (IDMAP_ERR_ARG);
if (flag & IDMAP_REQ_FLG_USE_CACHE) {
if (is_user)
rc = idmap_cache_lookup_winnamebyuid(&winname,
&windomain, pid);
else
rc = idmap_cache_lookup_winnamebygid(&winname,
&windomain, pid);
if (rc == IDMAP_SUCCESS)
goto out;
if (rc == IDMAP_ERR_MEMORY)
return (rc);
}
/* Get mapping */
rc = idmap_get_u2w_mapping(&pid, NULL, flag, is_user, NULL,
NULL, NULL, &winname, &windomain, &direction, NULL);
/* Return on error */
if (rc != IDMAP_SUCCESS)
return (rc);
/*
* The given PID may have been mapped to a locally
* generated SID in which case there isn't any
* Windows name
*/
if (winname == NULL) {
idmap_free(windomain);
return (IDMAP_ERR_NORESULT);
}
if (flag & IDMAP_REQ_FLG_USE_CACHE) {
if (is_user)
idmap_cache_add_winname2uid(winname, windomain,
pid, direction);
else
idmap_cache_add_winname2gid(winname, windomain,
pid, direction);
}
out:
if (domain != NULL) {
*name = winname;
*domain = windomain;
} else {
char *wd = windomain != NULL ? windomain : "";
len = snprintf(NULL, 0, "%s@%s", winname, wd) + 1;
if ((*name = malloc(len)) != NULL)
(void) snprintf(*name, len, "%s@%s", winname, wd);
else
rc = IDMAP_ERR_MEMORY;
idmap_free(winname);
idmap_free(windomain);
}
return (rc);
}
/*
* Get winname given uid
*/
idmap_stat
idmap_getwinnamebyuid(uid_t uid, int flag, char **name, char **domain)
{
return (idmap_getwinnamebypid(uid, 1, flag, name, domain));
}
/*
* Get winname given gid
*/
idmap_stat
idmap_getwinnamebygid(gid_t gid, int flag, char **name, char **domain)
{
return (idmap_getwinnamebypid(gid, 0, flag, name, domain));
}
idmap_stat
idmap_flush(idmap_flush_op op)
{
idmap_retcode rc1, rc2;
rc1 = _idmap_clnt_call(IDMAP_FLUSH,
(xdrproc_t)xdr_idmap_flush_op, (caddr_t)&op,
(xdrproc_t)xdr_idmap_retcode, (caddr_t)&rc2, TIMEOUT);
if (rc1 != IDMAP_SUCCESS)
return (rc1);
return (rc2);
}
/*
* syslog is the default logger.
* It can be overwritten by supplying a logger
* with idmap_set_logger()
*/
idmap_logger_t logger = syslog;
void
idmap_set_logger(idmap_logger_t funct)
{
logger = funct;
}
/*
* Helper functions that concatenate two parts of a name and then
* look up a value, so that the same set of functions can be used to
* process both "in" and "out" parameters.
*/
static
boolean_t
idmap_trace_get_str(nvlist_t *entry, char *n1, char *n2, char **ret)
{
char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is about 11 */
int err;
(void) strlcpy(name, n1, sizeof (name));
if (n2 != NULL)
(void) strlcat(name, n2, sizeof (name));
err = nvlist_lookup_string(entry, name, ret);
return (err == 0);
}
static
boolean_t
idmap_trace_get_int(nvlist_t *entry, char *n1, char *n2, int64_t *ret)
{
char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is about 11 */
int err;
(void) strlcpy(name, n1, sizeof (name));
if (n2 != NULL)
(void) strlcat(name, n2, sizeof (name));
err = nvlist_lookup_int64(entry, name, ret);
return (err == 0);
}
static
void
idmap_trace_print_id(FILE *out, nvlist_t *entry, char *fromto)
{
char *s;
int64_t i64;
if (idmap_trace_get_int(entry, fromto, IDMAP_TRACE_TYPE, &i64)) {
switch (i64) {
case IDMAP_POSIXID:
(void) fprintf(out, "unixname ");
break;
case IDMAP_UID:
(void) fprintf(out, "unixuser ");
break;
case IDMAP_GID:
(void) fprintf(out, "unixgroup ");
break;
case IDMAP_SID:
(void) fprintf(out, "winname ");
break;
case IDMAP_USID:
(void) fprintf(out, "winuser ");
break;
case IDMAP_GSID:
(void) fprintf(out, "wingroup ");
break;
case IDMAP_NONE:
(void) fprintf(out, gettext("unknown "));
break;
default:
(void) fprintf(out, gettext("bad %d "), (int)i64);
break;
}
}
if (idmap_trace_get_str(entry, fromto, IDMAP_TRACE_NAME, &s))
(void) fprintf(out, "%s ", s);
if (idmap_trace_get_str(entry, fromto, IDMAP_TRACE_SID, &s))
(void) fprintf(out, "%s ", s);
if (idmap_trace_get_int(entry, fromto, IDMAP_TRACE_UNIXID, &i64))
(void) fprintf(out, "%u ", (uid_t)i64);
}
void
idmap_trace_print_1(FILE *out, char *prefix, nvlist_t *entry)
{
char *s;
int64_t i64;
(void) fprintf(out, "%s", prefix);
idmap_trace_print_id(out, entry, "from");
(void) fprintf(out, "-> ");
idmap_trace_print_id(out, entry, "to");
if (idmap_trace_get_int(entry, IDMAP_TRACE_ERROR, NULL, &i64))
(void) fprintf(out, gettext("Error %d "), (int)i64);
(void) fprintf(out, "-");
if (idmap_trace_get_str(entry, IDMAP_TRACE_MESSAGE, NULL, &s))
(void) fprintf(out, " %s", s);
(void) fprintf(out, "\n");
}
void
idmap_trace_print(FILE *out, char *prefix, nvlist_t *trace)
{
nvpair_t *nvp;
for (nvp = nvlist_next_nvpair(trace, NULL);
nvp != NULL;
nvp = nvlist_next_nvpair(trace, nvp)) {
nvlist_t *entry;
int err;
err = nvpair_value_nvlist(nvp, &entry);
assert(err == 0);
idmap_trace_print_1(out, prefix, entry);
}
}