idmap.c revision 61b364a9162c5e321625fcd2f640da7e1dd2417e
/*
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <strings.h>
#include <errno.h>
#include <limits.h>
#include "idmap_engine.h"
#include "idmap_priv.h"
#include "idmap_impl.h"
/*
* used in do_show for the type of argument, which can be winname,
* unixname, uid, gid, sid or not given at all:
*/
/* Identity type strings */
#define ID_WINNAME "winname"
#define ID_UNIXUSER "unixuser"
#define ID_UNIXGROUP "unixgroup"
#define ID_WINUSER "winuser"
#define ID_WINGROUP "wingroup"
#define ID_USID "usid"
#define ID_GSID "gsid"
#define ID_SID "sid"
#define ID_UID "uid"
#define ID_GID "gid"
#define ID_UNKNOWN "unknown"
typedef struct {
char *identity;
int code;
} id_code_t;
id_code_t identity2code[] = {
{ID_WINNAME, TYPE_WN},
{ID_UNIXUSER, TYPE_UU},
{ID_UNIXGROUP, TYPE_UG},
{ID_WINUSER, TYPE_WU},
{ID_WINGROUP, TYPE_WG},
};
/* Flags */
#define f_FLAG 'f'
#define t_FLAG 't'
#define d_FLAG 'd'
#define D_FLAG 'D'
#define F_FLAG 'F'
#define a_FLAG 'a'
#define n_FLAG 'n'
#define c_FLAG 'c'
#define v_FLAG 'v'
#define j_FLAG 'j'
/* used in the function do_import */
#define MAX_INPUT_LINE_SZ 2047
typedef struct {
int is_user;
int is_wuser;
int direction;
char *unixname;
char *winname;
char *windomain;
char *sidprefix;
/*
* Formats of the output:
*
* name mappings in Samba username map format (smbusers), Netapp
* usermap.cfg.
*
* DEFAULT_FORMAT are in fact the idmap subcommands suitable for
* piping to idmap standart input. For example
* add -d winuser:bob@foo.com unixuser:fred
* add -d winuser:bob2bar.com unixuser:fred
*
* SMBUSERS is the format of Samba username map (smbusers). For full
* documentation, search for "username map" in smb.conf manpage.
* The format is for example
* fred = bob@foo.com bob2@bar.com
*
* USERMAP_CFG is the format of Netapp usermap.cfg file. Search
* http://www.netapp.com/ for more documentation. IP qualifiers are not
* supported.
* The format is for example
* bob@foo.com => fred
* "Bob With Spaces"@bar.com => fred #comment
*
* The previous formats were for name rules. MAPPING_NAME and
* commands. MAPPING_NAME prefers the string names of the user over
* their numerical identificators. MAPPING_ID prints just the
* identificators.
* Example of the MAPPING_NAME:
* winname:bob@foo.com -> unixname:fred
*
* Example of the MAPPING_ID:
* sid:S-1-2-3-4 -> uid:5678
*/
typedef enum {
UNDEFINED_FORMAT = -1,
DEFAULT_FORMAT = 0,
} format_t;
typedef struct {
/*
* idmap_api batch related variables:
*
* idmap can operate in two modes. It the batch mode, the idmap_api
* batch is committed at the end of a batch of several
* commands. At the end of input file, typically. This mode is used
* for processing input from a file.
* In the non-batch mode, each command is committed immediately. This
* mode is used for tty input.
*/
/* Are we in the batch mode? */
static int batch_mode = 0;
/* Self describing stricture for positions */
struct pos_sds {
int size;
int last;
};
/* Handles for idmap_api batch */
typedef struct {
char *user;
char *passwd;
char *auth;
char *windomain;
int direction;
} namemaps_t;
/* Do we need to commit the udt batch at the end? */
static int udt_used;
/* Command handlers */
/* Command names and their hanlers to be passed to idmap_engine */
{
"show",
"c(create)v(verbose)",
},
{
"dump",
"n(names)v(verbose)",
},
{
"import",
"F(flush)f:(file)",
},
{
"export",
"f:(file)",
},
{
"list",
"",
},
{
"add",
"d(directional)",
},
{
"remove",
"a(all)t(to)f(from)d(directional)",
},
{
"exit",
"",
},
{
"help",
"",
},
{
"set-namemap",
"a:(authentication)D:(bindDN)j:(passwd-file)",
},
{
"get-namemap",
"",
},
{
"unset-namemap",
"a:(authentication)D:(bindDN)j:(passwd-file):",
}
};
/* Print error message, possibly with a position */
/* printflike */
static void
{
/* Skip newlines etc at the end: */
length--;
gettext("Error at line %d: %.*s\n"),
}
}
/* Inits positions sds. 0 means everything went OK, -1 for errors */
static int
{
return (-1);
}
return (0);
}
/* Free the positions array */
static void
{
int i;
continue;
}
}
/*
* Add another position to the positions array. 0 means everything
* went OK, -1 for errors
*/
static int
{
sizeof (struct pos_sds) +
goto nomemory;
}
else {
sizeof (cmd_pos_t));
goto nomemory;
goto nomemory;
}
return (0);
return (-1);
}
/*
* Compare two strings just like strcmp, but stop before the end of
* the s2
*/
static int
{
}
/* Print help message */
static void
help()
{
"idmap\n"
"idmap -f command-file\n"
"idmap add [-d] name1 name2\n"
"idmap dump [-n] [-v]\n"
"idmap export [-f file] format\n"
"idmap get-namemap name\n"
"idmap help\n"
"idmap import [-F] [-f file] format\n"
"idmap list\n"
"idmap remove -a\n"
"idmap remove [-f|-t] name\n"
"idmap remove [-d] name1 name2\n"
"idmap set-namemap [-a authenticationMethod] [-D bindDN] "
"[-j passwdfile] name1 name2\n"
"idmap show [-c] [-v] identity [targettype]\n"
"idmap unset-namemap [-a authenticationMethod] [-D bindDN]"
"[-j passwdfile] name\n");
}
/* The handler for the "help" command. */
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
help();
return (0);
}
/* Initialization of the idmap api batch */
static int
{
if (stat != IDMAP_SUCCESS) {
gettext("Connection not established (%s)\n"),
return (-1);
}
return (0);
}
/* Initialization of the libidmap API (idmap help doesn't run that) */
static int
{
if (batch_mode)
return (0);
return (init_batch());
}
/* Finalization of the libidmap API */
static void
{
if (batch_mode)
return;
(void) idmap_fini(handle);
}
}
/* Initialization of the commands which perform write operations */
static int
{
if (init_batch())
return (-1);
if (stat != IDMAP_SUCCESS) {
gettext("Error initiating transaction (%s)"),
return (-1);
}
if (init_positions() < 0)
return (-1);
return (0);
}
/* Finalization of the write commands */
static int
{
udt_used = 1;
if (batch_mode)
return (0);
return (init_udt_batch());
}
/* If everythings is OK, send the udt batch to idmapd */
static int
{
int rc = 0;
if (batch_mode)
return (0);
gettext("Internal error: uninitiated batch.\n"));
return (-1);
}
if (stat == IDMAP_SUCCESS)
goto out;
rc = -1;
if (stat1 != IDMAP_SUCCESS) {
gettext("Error diagnosing transaction (%s)\n"),
goto out;
}
if (failpos < 0)
reported_pos = pos;
else
gettext("Error commiting transaction (%s)\n"),
}
out:
udt_used = 0;
return (rc);
}
/*
* Compare two possibly NULL strings
*/
static int
strcasecmp_null(char *a, char *b)
{
return (0);
if (a == NULL)
return (-1);
if (b == NULL)
return (1);
return (strcasecmp(a, b));
}
/*
* Compare two possibly NULL strings
*/
static int
strcmp_null(char *a, char *b)
{
return (0);
if (a == NULL)
return (-1);
if (b == NULL)
return (1);
return (strcmp(a, b));
}
static void
{
}
}
static
void
{
}
}
/* Initialization of the commands which perform write operations */
static
int
{
if (!batch_mode)
if (init_batch() < 0)
return (-1);
}
if (stat != IDMAP_SUCCESS) {
gettext("Error: could not perform directory-based "
"name mapping operation (%s)"),
return (-1);
}
return (-1);
}
}
return (0);
}
/* Cleanup after the xxx-namemaps commands */
static void
{
if (batch_mode)
return;
}
/* Convert numeric expression of the direction to it's string form */
static char *
{
switch (direction) {
case IDMAP_DIRECTION_BI:
return ("==");
case IDMAP_DIRECTION_W2U:
return ("=>");
case IDMAP_DIRECTION_U2W:
return ("<=");
default:
/* This can never happen: */
gettext("Internal error: invalid direction.\n"));
return ("");
}
/* never reached */
}
/*
* Returns 1 if c is a shell-meta-character requiring quoting, 0
* otherwise.
*
* We don't quote '*' and ':' because they cannot do any harm
* a) they have no meaning to idmap_engine b) even ifsomebody copy &
* paste idmap output to a shell commandline, there is the identity
* type string in front of them. On the other hand, '*' and ':' are
* everywhere.
*/
static int
is_shell_special(char c)
{
if (isspace(c))
return (1);
return (1);
return (0);
}
/*
* Returns 1 if c is a shell-meta-character requiring quoting even
* inside double quotes, 0 otherwise. It means \, " and $ .
*
* This set of characters is a subset of those in is_shell_special().
*/
static int
is_dq_special(char c)
{
return (1);
return (0);
}
/*
* Quote any shell meta-characters in the given string. If 'quote' is
* true then use double-quotes to quote the whole string, else use
* back-slash to quote each individual meta-character.
*
* The resulting string is placed in *res. Callers must free *res if the
* return value isn't 0 (even if the given string had no meta-chars).
* If there are any errors this returns -1, else 0.
*/
static int
{
int i, j;
char *out;
return (-1);
}
return (0);
}
/* First, let us count how many characters we need to quote: */
for (i = 0; i < len_orig; i++) {
if (is_shell_special(string[i])) {
noss++;
if (is_dq_special(string[i]))
noqb++;
}
}
/* Do we need to quote at all? */
if (noss == 0) {
return (-1);
}
return (0);
}
/* What is the length of the result? */
if (quote)
else
return (-1);
}
j = 0;
if (quote)
out[j++] = '"';
for (i = 0; i < len_orig; i++) {
/* Quote the dangerous chars by a backslash */
out[j++] = '\\';
}
}
if (quote)
out[j++] = '"';
out[j] = '\0';
return (0);
}
/* Assemble string form sid */
static char *
{
char *to;
char *typestring;
case IDMAP_YES:
break;
case IDMAP_NO:
break;
default:
typestring = ID_SID;
break;
}
/* 'usid:' + sidprefix + '-' + rid + '\0' */
return (NULL);
return (to);
}
/* Assemble string form uid or gid */
static char *
{
char *to;
/* ID_UID ":" + uid + '\0' */
return (NULL);
return (to);
}
/* Assemble winname, e.g. "winuser:bob@foo.sun.com", from name_mapping_t */
static int
{
char *out;
int is_domain = 1;
char *prefix;
/* Sometimes there are no text names. Return a sid, then. */
return (0);
}
case IDMAP_YES:
break;
case IDMAP_NO:
break;
case IDMAP_UNKNOWN:
break;
}
/* Windomain is not mandatory: */
is_domain = 0;
else
return (-1);
}
/* LINTED E_NOP_IF_STMT */
;
else if (!is_domain)
} else {
}
return (0);
}
/*
* Assemble a text unixname, e.g. unixuser:fred. Use only for
* mapping, not namerules - there an empty name means inhibited
* mappings, while here pid is printed if there is no name.
*/
static
int
{
/* Sometimes there is no name, just pid: */
return (-1);
return (0);
}
return (-1);
case IDMAP_YES:
break;
case IDMAP_NO:
break;
case IDMAP_UNKNOWN:
break;
}
return (-1);
}
return (0);
}
/* Allocate a new name_mapping_t and initialize the values. */
static name_mapping_t *
{
return (NULL);
}
return (nm);
}
/* Free name_mapping_t */
static void
{
}
static int
{
return (-1);
}
}
return (-1);
}
}
return (-1);
}
}
return (-1);
}
}
return (0);
}
static int
{
int maxlen;
return (-1);
return (-1);
}
return (-1);
}
/* 10 is strlen("add -d\t\t\n") + 1 */
} else {
}
return (0);
}
/* Initialize print_mapping variables. Must be called before print_mapping */
static print_handle_t *
{
return (NULL);
}
return (NULL);
return (out);
}
/* Finalize print_mapping. */
static int
{
int rc = 0;
case SMBUSERS:
}
break;
case DEFAULT_FORMAT:
break;
if (rc >= 0) {
}
break;
default:
;
}
return (rc);
}
static char *
usermap_cfg_string(char *in)
{
int len;
char *out;
return (strdup("\"\""));
return (NULL);
return (out);
}
/*
* This prints both name rules and ordinary mappings, based on the pnm_format
* set in print_mapping_init().
*/
static int
{
char *dirstring;
case MAPPING_NAME:
return (-1);
return (-1);
}
/* LINTED E_CASE_FALLTHRU */
case MAPPING_ID:
gettext("SID not given.\n"));
return (-1);
}
return (-1);
return (-1);
}
}
unixname);
break;
case SMBUSERS:
gettext("Group rule: "));
f = stderr;
gettext("Opposite direction of the mapping: "));
f = stderr;
f = stderr;
}
return (-1);
} else {
(void) fprintf(f, "\n");
}
}
}
break;
case USERMAP_CFG:
gettext("Group rule: "));
f = stderr;
}
return (-1);
}
(void) fprintf(f, "%s\t%s\t%s\n",
} else
"%s\\%s\t%s\t%s\n" :
"%2$s@%1$s\t%3$s\t%4$s\n",
break;
/* This is a format for namerules */
case DEFAULT_FORMAT:
/*
* If nm is the same as the last one except is_wuser, we combine
* winuser & wingroup to winname
*/
} else {
return (-1);
}
return (-1);
}
break;
default:
/* This can never happen: */
gettext("Internal error: invalid print format.\n"));
return (-1);
}
return (0);
}
static
void
{
char *rule_text;
case IDMAP_MAP_TYPE_DS_AD:
break;
case IDMAP_MAP_TYPE_DS_NLDAP:
break;
/*
* The name rules as specified by the user can have a
* "winname", "winuser" or "wingroup". "Winname" rules are
* decomposed to a "winuser" and "wingroup" rules by idmap.
* Currently is_wuser is a boolean. Due to these reasons
* the returned is_wuser does not represent the original rule.
* It is therefore better set is_wuser to unknown.
*/
}
break;
case IDMAP_MAP_TYPE_EPHEMERAL:
break;
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
case IDMAP_MAP_TYPE_KNOWN_SID:
break;
}
}
static
void
{
case IDMAP_MAP_SRC_NEW:
break;
case IDMAP_MAP_SRC_CACHE:
break;
case IDMAP_MAP_SRC_HARD_CODED:
break;
break;
}
}
}
static
void
{
char *rule_text;
case IDMAP_MAP_TYPE_DS_AD:
gettext("Failed Method:\tAD Directory\n"));
break;
case IDMAP_MAP_TYPE_DS_NLDAP:
gettext("Failed Method:\tNative LDAP Directory\n"));
break;
/*
* The name rules as specified by the user can have a
* "winname", "winuser" or "wingroup". "Winname" rules are
* decomposed to a "winuser" and "wingroup" rules by idmap.
* Currently is_wuser is a boolean. Due to these reasons
* the returned is_wuser does not represent the original rule.
* It is therefore better to set is_wuser to unknown.
*/
}
break;
case IDMAP_MAP_TYPE_EPHEMERAL:
break;
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
case IDMAP_MAP_TYPE_KNOWN_SID:
gettext("Failed Method:\tWell-Known mapping\n"));
break;
}
}
/* dump command handler */
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
int rc = 0;
int flag = 0;
if (init_command())
return (-1);
stdout);
return (-1);
if (stat < 0) {
gettext("Iteration handle not obtained (%s)\n"),
rc = -1;
goto cleanup;
}
do {
rc = -1;
goto cleanup;
}
if (stat >= 0) {
}
} while (stat > 0);
/* IDMAP_ERR_NOTFOUND indicates end of the list */
gettext("Error during iteration (%s)\n"),
rc = -1;
goto cleanup;
}
(void) print_mapping_fini(ph);
fini_command();
return (rc);
}
/*
* The same as strdup, but length chars is duplicated, no matter on
* '\0'. The caller must guarantee "length" chars in "from".
*/
static char *
{
return (NULL);
}
return (out);
}
/*
* Convert pid from string to it's numerical representation. If it is
* a valid string, i.e. number of a proper length, return 1. Otherwise
* print an error message and return 0.
*/
static int
{
int i;
long long ll;
char *type_string;
else
return (0);
for (i = 0; i < len; i++) {
gettext("\"%s\" is not a valid %s: the non-digit"
" character '%c' found.\n"), string,
type_string, string[i]);
return (0);
}
}
/* Isn't it too large? */
return (0);
}
return (1);
}
/*
* Convert SID from string to prefix and rid. If it has a valid
* format, i.e. S(\-\d+)+, return 1. Otherwise print an error
* message and return 0.
*/
static int
{
int i, j;
char *cp;
char *ecp;
char *prefix_end;
u_longlong_t a;
unsigned long r;
gettext("Invalid %s \"%s\": it doesn't start "
return (0);
}
gettext("Invalid %s \"%s\": the authority and RID parts are"
" missing.\n"),
return (0);
}
/* count '-'s */
/* can't end on a '-' */
gettext("Invalid %s \"%s\": '-' at the end.\n"),
return (0);
gettext("Invalid %s \"%s\": double '-'.\n"),
return (0);
}
}
/* check that we only have digits and '-' */
gettext("Invalid %s \"%s\": invalid character '%c'.\n"),
return (0);
}
/* 64-bit safe parsing of unsigned 48-bit authority value */
errno = 0;
/* errors parsing the authority or too many bits */
gettext("Invalid %s \"%s\": unable to parse the "
cp);
return (0);
}
(a & 0x0000ffffffffffffULL) != a) {
gettext("Invalid %s \"%s\": the authority "
return (0);
}
if (j < 3) {
gettext("Invalid %s \"%s\": must have at least one RID.\n"),
return (0);
}
for (i = 2; i < j; i++) {
if (*cp++ != '-') {
/* Should never happen */
gettext("Invalid %s \"%s\": internal error:"
" '-' missing.\n"),
return (0);
}
/* 32-bit safe parsing of unsigned 32-bit RID */
errno = 0;
/* errors parsing the RID */
/* should never happen */
gettext("Invalid %s \"%s\": internal error: "
"unable to parse the RID "
"after \"%.*s\".\n"), ID_SID,
return (0);
}
gettext("Invalid %s \"%s\": the RID \"%.*s\""
" is too large.\n"), ID_SID,
return (0);
}
prefix_end = cp;
}
/* check that all of the string SID has been consumed */
if (*cp != '\0') {
/* Should never happen */
gettext("Invalid %s \"%s\": internal error: "
"something is still left.\n"),
return (0);
}
*rid = (idmap_rid_t)r;
/* -1 for the '-' at the end: */
return (0);
}
return (1);
}
/* Does the line start with USERMAP_CFG IP qualifier? */
static int
ucp_is_IP_qualifier(char *line)
{
char *it;
}
/*
* returns interior of quotation marks in USERMAP_CFG. In this format,
* there cannot be a protected quotation mark inside.
*/
static char *
{
char *out;
gettext("Unclosed quotations\n"));
return (NULL);
}
return (out);
}
/*
* Grab next token from the line in USERMAP_CFG format. terminators,
* the 3rd parameter, contains all the characters which can terminate
* the token. line_num is the line number of input used for error
* reporting.
*/
static char *
{
char *token;
if (**line == '"')
else {
}
return (token);
}
/*
* Convert a line in usermap.cfg format to name_mapping.
*
* Return values: -1 for error, 0 for empty line, 1 for a mapping
* found.
*/
static int
{
char *it;
char *token;
char *token2;
char separator;
int is_direction = 0;
/* empty or comment lines are OK: */
return (0);
/* We do not support network qualifiers */
if (ucp_is_IP_qualifier(it)) {
gettext("Unable to handle network qualifier.\n"));
return (-1);
}
/* The windows name: */
return (-1);
/* Didn't we bump to the end of line? */
gettext("UNIX_name not found.\n"));
return (-1);
}
/* Do we have a domainname? */
it ++;
return (-1);
gettext("UNIX_name not found.\n"));
}
if (separator == '\\') {
} else {
}
} else {
}
/* Direction string is optional: */
is_direction = 1;
is_direction = 1;
is_direction = 1;
} else {
is_direction = 0;
}
if (is_direction) {
it += 2;
gettext("UNIX_name not found.\n"));
return (-1);
}
}
/* Now unixname: */
/* nm->winname to be freed by name_mapping_fini */
return (-1);
/* Neither here we support IP qualifiers */
if (ucp_is_IP_qualifier(token)) {
gettext("Unable to handle network qualifier.\n"));
return (-1);
}
/* Does something remain on the line */
return (-1);
}
return (1);
}
/*
* Parse SMBUSERS line to name_mapping_t. if line is NULL, then
* pasrsing of the previous line is continued. line_num is input line
* number used for error reporting.
* Return values:
* rc -1: error
* rc = 0: mapping found and the line is finished,
* rc = 1: mapping found and there remains other on the line
*/
static int
{
static size_t unixname_l = 0;
char *token;
return (0);
ll += unixname_l;
return (0);
}
return (0);
return (-1);
return (-1);
return (1);
}
/* Parse line to name_mapping_t. Basicaly just a format switch. */
static int
{
switch (f) {
case USERMAP_CFG:
return (0);
else
case SMBUSERS:
default:
/* This can never happen */
gettext("Internal error: invalid line format.\n"));
}
return (-1);
}
/* Examine -f flag and return the appropriate format_t */
static format_t
{
return (UNDEFINED_FORMAT);
}
return (DEFAULT_FORMAT);
return (USERMAP_CFG);
return (SMBUSERS);
"\"smbusers\".\n"));
return (UNDEFINED_FORMAT);
}
/* Delete all namerules of the given type */
static int
{
if (stat < 0) {
: gettext("Unable to flush groups (%s).\n"),
return (-1);
}
if (positions_add(pos) < 0)
return (-1);
return (0);
}
/* import command handler */
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
char line[MAX_INPUT_LINE_SZ];
int rc = 0;
if (batch_mode) {
gettext("Import is not allowed in the batch mode.\n"));
return (-1);
}
if (format == UNDEFINED_FORMAT)
return (-1);
if (init_udt_command())
return (-1);
/* We don't flush groups in the usermap.cfg nor smbusers format */
rc = -1;
goto cleanup;
}
/* Where we import from? */
else {
goto cleanup;
}
}
/*
* In SMBUSERS format there can be more mappings on
* each line. So we need the internal cycle for each line.
*/
do {
nm = name_mapping_init();
rc = -1;
goto cleanup;
}
if (rc < 1) {
break;
}
if (stat < 0) {
gettext("Transaction error (%s)\n"),
rc = -1;
}
if (rc >= 0)
} while (rc >= 0);
if (rc < 0) {
gettext("Import canceled.\n"));
break;
}
}
rc = -1;
return (rc);
}
/*
* List name mappings in the format specified. list_users /
* list_groups determine which type to list. The output goes to the
* file fi.
*/
static int
{
if (stat < 0) {
gettext("Iteration handle not obtained (%s)\n"),
return (-1);
}
return (-1);
do {
nm = name_mapping_init();
return (-1);
}
if (stat >= 0) {
}
} while (stat > 0);
(void) print_mapping_fini(ph);
gettext("Error during iteration (%s)\n"),
return (-1);
}
return (0);
}
/* Export command handler */
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
int rc;
if (format == UNDEFINED_FORMAT)
return (-1);
/* Where do we output to? */
else {
return (-1);
}
}
if (init_command() < 0) {
rc = -1;
goto cleanup;
}
/* List the requested types: */
fini_command();
return (rc);
}
/* List command handler */
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
int rc;
if (init_command()) {
return (-1);
}
/* List the requested types: */
fini_command();
return (rc);
}
/* This is just a debug function for dumping flags */
static void
print_flags(flag_t *f)
{
int c;
for (c = 0; c < FLAG_ALPHABET_SIZE; c++) {
if (f[c] == FLAG_SET)
(void) printf("FLAG: -%c, VALUE: %p\n", c,
(void *) f[c]);
else if (f[c])
(void) printf("FLAG: -%c, VALUE: %s\n", c, f[c]);
}
}
/* Convert string like sid or winname to the identity type code */
static int
int i;
int code = TYPE_INVALID;
for (i = 0; i < sizeof (identity2code) / sizeof (id_code_t); i++) {
break;
}
}
if (code == TYPE_INVALID) {
}
return (code);
}
/*
* Split argument to its identity code and a name part
* return values:
* TYPE_INVALID for unknown identity
* TYPE_AUTO for no identity (to be autodetected)
* <TYPE_XXX> for known identity
*/
static int
{
char *it;
int code = TYPE_INVALID;
return (TYPE_AUTO);
}
*it = '\0';
return (code);
}
/*
* This function splits name to the relevant pieces: is_user, winname,
* windomain unixname. E.g. for winname, it strdups nm->winname and possibly
* nm->windomain and return TYPE_WN.
*
* If there is already one of the text fields allocated, it is OK.
* Return values:
* -1 ... syntax error
* 0 ... it wasnt possible to determine
* <TYPE_XXX> otherwise
*/
static int
{
char *it;
int code;
switch (code) {
case TYPE_INVALID:
/* syntax error: */
return (-1);
case TYPE_AUTO:
/* autodetection: */
/* btw, nm->is_user can never be IDMAP_UNKNOWN here */
else
return (0);
/* If the code was guessed succesfully, we are OK. */
break;
default:
}
} else {
}
return (code);
} else
return (code);
}
return (code);
else
return (code);
}
return (-1);
else
return (code);
}
/*
* it is (!(code & TYPE_WIN) && !(code & TYPE_NAME)) here - the other
* possiblities are exhausted.
*/
return (-1);
else
return (code);
}
/*
* invalid.
*/
static
{
int code;
int i;
nm = name_mapping_init();
return (NULL);
switch (code) {
case -1:
goto fail;
case 0:
if (i > 0) {
gettext("Missing identity type"
" cannot be determined for %s.\n"),
argv[i % 2]);
goto fail;
}
break;
default:
gettext("%s is not a valid name\n"),
argv[i % 2]);
goto fail;
}
}
}
goto fail;
}
goto fail;
}
goto fail;
}
if (is_first_win != NULL)
return (nm);
fail:
return (NULL);
}
/* add command handler. */
static int
{
int rc = 0;
int is_first_win;
int is_wuser;
/* Exactly two arguments must be specified */
if (argc < 2) {
return (-1);
} else if (argc > 2) {
return (-1);
}
return (-1);
else
/* Now let us write it: */
if (init_udt_command()) {
return (-1);
}
/* nm->is_wuser can be IDMAP_YES, IDMAP_NO or IDMAP_UNKNOWN */
continue;
}
/* We echo the mapping */
rc = -1;
goto cleanup;
}
(void) print_mapping_fini(ph);
if (stat != IDMAP_SUCCESS) {
gettext("Mapping not created (%s)\n"),
rc = -1;
}
if (rc == 0)
rc = -1;
return (rc);
}
/* remove command handler */
static int
{
int rc = 0;
int is_first_win;
int is_wuser;
/* "-a" means we flush all of them */
if (argc) {
gettext("Too many arguments.\n"));
return (-1);
}
if (init_udt_command())
return (-1);
if (rc >= 0)
rc = -1;
return (rc);
}
/* Contrary to add_name_mapping, we can have only one argument */
if (argc < 1) {
return (-1);
} else if (argc > 2) {
return (-1);
} else if (
/* both -f and -t: */
/* -d with a single argument: */
/* -f or -t with two arguments: */
gettext("Direction ambiguous.\n"));
return (-1);
}
/*
* Similar to do_add_name_mapping - see the comments
* there. Except we may have only one argument here.
*/
return (-1);
/*
* If the direction is not specified by a -d/-f/-t flag, then it
* is IDMAP_DIRECTION_UNDEF, because in that case we want to
* remove any mapping. If it was IDMAP_DIRECTION_BI, idmap_api would
* delete a bidirectional one only.
*/
else
if (init_udt_command()) {
return (-1);
}
continue;
if (stat != IDMAP_SUCCESS) {
gettext("Mapping not deleted (%s)\n"),
rc = -1;
break;
}
}
if (rc == 0)
rc = -1;
return (rc);
}
/* exit command handler */
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
return (0);
}
/* debug command handler: just print the parameters */
static int
/* LINTED E_STATIC_UNUSED */
{
int i;
#if 0
#endif
print_flags(f);
for (i = 0; i < argc; i++) {
}
return (0);
}
/*
* From name_mapping_t, asseble a string containing identity of the
* given type.
*/
static int
{
switch (type) {
case TYPE_SID:
case TYPE_USID:
case TYPE_GSID:
return (-1);
return (0);
case TYPE_WN:
case TYPE_WU:
case TYPE_WG:
case TYPE_UID:
case TYPE_GID:
case TYPE_PID:
return (-1);
else
return (0);
case TYPE_UN:
case TYPE_UU:
case TYPE_UG:
default:
/* This can never happen: */
gettext("Internal error: invalid name type.\n"));
return (-1);
}
/* never reached */
}
/* show command handler */
static int
{
idmap_stat stat = 0;
int flag;
idmap_stat map_stat = 0;
int type_from;
int type_to;
char *fromname;
char *toname;
if (argc == 0) {
gettext("No identity given\n"));
return (-1);
} else if (argc > 2) {
gettext("Too many arguments.\n"));
return (-1);
}
if (init_command())
return (-1);
nm = name_mapping_init();
goto cleanup;
if (type_from <= 0) {
goto cleanup;
}
/* Second, determine type_to: */
if (argc < 2) {
} else {
if (type_to == TYPE_INVALID) {
goto cleanup;
}
}
else
} else {
}
/* Are both arguments the same OS side? */
gettext("Direction ambiguous.\n"));
goto cleanup;
}
/*
* We have two interfaces for retrieving the mappings:
* idmap_get_sidbyuid & comp (the batch interface) and
* idmap_get_w2u_mapping & comp. We want to use both of them, because
* the former mimicks kernel interface better and the later offers the
* string names. In the batch case, our batch has always size 1.
*
* Btw, type_from cannot be IDMAP_PID, because there is no type string
* for it.
*/
flag,
&info);
} else {
flag,
&info);
}
} else {
/* batch handle */
/* To be passed to idmap_get_uidbysid */
/* To be passed to idmap_get_gidbysid */
/* Create an in-memory structure for all the batch: */
if (stat != IDMAP_SUCCESS) {
gettext("Unable to create handle for communicating"
" with idmapd(1M) (%s)\n"),
goto cleanup;
}
/* Schedule the request: */
flag,
&uid,
&info,
&map_stat);
flag,
&gid,
&info,
&map_stat);
flag,
&info,
&map_stat);
flag,
&info,
&map_stat);
flag,
&info,
&map_stat);
} else {
/* This can never happen: */
gettext("Internal error in show.\n"));
exit(1);
}
if (stat < 0) {
gettext("Request for %.3s not sent (%s)\n"),
goto cleanup;
}
/* Send the batch to idmapd and obtain results: */
if (stat < 0) {
gettext("Mappings not obtained because of"
" RPC problem (%s)\n"),
goto cleanup;
}
/* Destroy the batch handle: */
}
/*
* If there was -c flag, we do output whatever we can even in
* the case of error:
*/
goto errormsg;
/*
* it uses special sentinel value i.e 4294967295 (or -1) to
* indicate that falbback pid is not available either. In such
* case idmap(1M) should not display the mapping because there
* is no fallback mapping.
*/
goto errormsg;
goto errormsg;
if (!(flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC))
(void) printf("%s -> %s:%u\n",
} else {
}
if (map_stat < 0) {
} else
print_info(&info);
fini_command();
}
static int
{
return (0); /* GSSAPI authentification => OK */
return (-1);
}
/* Password: */
char line[MAX_INPUT_LINE_SZ];
int i;
gettext("Failed to open password file \"%s\": (%s)"
goto fail;
}
/* The password is the fist line, we ignore the rest: */
gettext("The password file \"%s\" is empty.\n"),
f[j_FLAG]);
goto fail;
}
gettext("Unable to close the password file \"%s\""
goto fail;
}
/* Trim the eol: */
i--)
line[i] = '\0';
goto fail;
}
} else if (!batch_mode) {
/* If in the interactive mode, read the terminal input: */
gettext("Failed to get password (%s).\n"),
goto fail;
}
goto fail;
}
} else {
goto fail;
}
return (0);
fail:
}
return (-1);
}
static int
{
int is_first_win;
char *user;
char *passwd;
if (argc < 2) {
gettext("Not enough arguments: two names needed for a "
"namemap.\n"));
return (-1);
} else if (argc > 2) {
gettext("Too many arguments: two names needed for a "
"namemap.\n"));
return (-1);
}
return (-1);
return (-1);
return (-1);
if (stat != IDMAP_SUCCESS) {
gettext("Failed to set namemap (%s).\n"),
}
}
}
static int
{
int is_first_win;
char *user;
char *passwd;
if (argc < 1) {
gettext("Not enough arguments: a name needed to unset a "
"namemap.\n"));
return (-1);
} else if (argc > 2) {
gettext("Too many arguments: Only target name and type is "
"needed to unset namemap.\n"));
return (-1);
}
return (-1);
return (-1);
gettext("Target type \"%s\" is redundant.\n"),
argv[1]);
goto cleanup;
} else if (argc > 1) {
case TYPE_INVALID:
return (-1);
case TYPE_UU:
break;
case TYPE_UG:
break;
default:
gettext("Invalid target type \"%s\": here the "
"possible target type is unixuser or "
goto cleanup;
}
}
return (-1);
if (stat != IDMAP_SUCCESS) {
gettext("Failed to unset namemap (%s).\n"),
}
}
}
static int
/* LINTED E_FUNC_ARG_UNUSED */
{
int is_first_win;
int is_source_ad;
if (argc < 1) {
gettext("Not enough arguments: a name needed to get a "
"namemap.\n"));
return (-1);
} else if (argc > 1) {
gettext("Too many arguments: just one name needed to get "
"a namemap.\n"));
return (-1);
}
return (-1);
/* nm->is_user is IDMAP_UNKNOWN for IDMAP_DIRECTION_W2U */
goto cleanup;
}
goto cleanup;
}
}
return (-1);
if (stat != IDMAP_SUCCESS) {
gettext("Failed to get namemap info (%s).\n"),
goto cleanup;
}
goto cleanup;
switch (is_source_ad) {
case IDMAP_YES:
else {
}
break;
case IDMAP_NO:
goto cleanup;
"native LDAP.\n"));
else {
unixname);
}
break;
default:
/*
* This can never happen; the error must be recognized in
* args2nm
*/
gettext("Internal error: unknown source of namemaps.\n"));
}
}
/* main function. Returns 1 for error, 0 otherwise */
int
{
int rc;
/* set locale and domain for internationalization */
(void) textdomain(TEXT_DOMAIN);
/* idmap_engine determines the batch_mode: */
argc - 1,
argv + 1,
&batch_mode);
if (rc < 0) {
(void) engine_fini();
if (rc == IDMAP_ENG_ERROR_SILENT)
help();
return (1);
}
udt_used = 0;
if (batch_mode) {
if (init_udt_batch() < 0)
return (1);
}
if (batch_mode) {
batch_mode = 0;
rc = -1;
}
fini_command();
(void) engine_fini();
return (rc == 0 ? 0 : 1);
}