view usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_test.c @ 5043:667e437d66d0

6601949 nfsmapid should handle Windows users and groups in a heterogenous environment 6604089 nfsmapid uses incorrect size when allocating the return buffer
author baban
date Thu, 13 Sep 2007 13:50:11 -0700
parents 68f95e015346
children
line wrap: on
line source

/*
 * 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 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * Test nfsmapid. This program is not shipped on the binary release.
 */
#include <stdio.h>
#include <stdlib.h>
#include <stropts.h>
#include <strings.h>
#include <signal.h>
#include <fcntl.h>
#include <locale.h>
#include <unistd.h>
#include <netconfig.h>
#include <door.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <sys/systm.h>
#include <sys/kmem.h>
#include <sys/debug.h>
#include <rpcsvc/nfs4_prot.h>
#include <nfs/nfsid_map.h>

static char nobody_str[] = "nobody";
static int nfs_idmap_str_uid(utf8string *, uid_t *);
static int nfs_idmap_uid_str(uid_t, utf8string *);
static int nfs_idmap_str_gid(utf8string *, gid_t *);
static int nfs_idmap_gid_str(gid_t, utf8string *);

static void
usage()
{
	fprintf(stderr, gettext(
	    "\nUsage:\tstr2uid string\n"
	    "\tstr2gid string\n"
	    "\tuid2str uid\n"
	    "\tgid2str gid\n"
	    "\techo string\n"
	    "\texit|quit\n"));
}

static int read_line(char *buf, int size)
{
	int len;

	/* read the next line. If cntl-d, return with zero char count */
	printf(gettext("\n> "));

	if (fgets(buf, size, stdin) == NULL)
		return (0);

	len = strlen(buf);
	buf[--len] = '\0';
	return (len);
}

static int
parse_input_line(char *input_line, int *argc, char ***argv)
{
	const char nil = '\0';
	char *chptr;
	int chr_cnt;
	int arg_cnt = 0;
	int ch_was_space = 1;
	int ch_is_space;

	chr_cnt = strlen(input_line);

	/* Count the arguments in the input_line string */

	*argc = 1;

	for (chptr = &input_line[0]; *chptr != nil; chptr++) {
		ch_is_space = isspace(*chptr);
		if (ch_is_space && !ch_was_space) {
			(*argc)++;
		}
		ch_was_space = ch_is_space;
	}

	if (ch_was_space) {
		(*argc)--;
	}	/* minus trailing spaces */

	/* Now that we know how many args calloc the argv array */

	*argv = calloc((*argc)+1, sizeof (char *));
	chptr = (char *)(&input_line[0]);

	for (ch_was_space = 1; *chptr != nil; chptr++) {
		ch_is_space = isspace(*chptr);
		if (ch_is_space) {
			*chptr = nil;	/* replace each space with nil  */
		} else if (ch_was_space) {	/* begining of word? */
			(*argv)[arg_cnt++] = chptr;	/* new argument ? */
		}

		ch_was_space = ch_is_space;
	}

	return (chr_cnt);
}

char *
mapstat(int stat)
{
	switch (stat) {
	case NFSMAPID_OK:
		return ("NFSMAPID_OK");
	case NFSMAPID_NUMSTR:
		return ("NFSMAPID_NUMSTR");
	case NFSMAPID_UNMAPPABLE:
		return ("NFSMAPID_UNMAPPABLE");
	case NFSMAPID_INVALID:
		return ("NFSMAPID_INVALID");
	case NFSMAPID_INTERNAL:
		return ("NFSMAPID_INTERNAL");
	case NFSMAPID_BADDOMAIN:
		return ("NFSMAPID_BADDOMAIN");
	case NFSMAPID_BADID:
		return ("NFSMAPID_BADID");
	case NFSMAPID_NOTFOUND:
		return ("NFSMAPID_NOTFOUND");
	case EINVAL:
		return ("EINVAL");
	case ECOMM:
		return ("ECOMM");
	case ENOMEM:
		return ("ENOMEM");
	default:
		printf(" unknown error %d ", stat);
		return ("...");
	}
}

int
do_test(char *input_buf)
{
	int argc, seal_argc;
	char **argv, **argv_array;
	char *cmd;
	int i, bufsize = 512;
	char str_buf[512];
	utf8string str;
	uid_t uid;
	gid_t gid;
	int stat;

	argv = 0;

	if (parse_input_line(input_buf, &argc, &argv) == 0) {
		printf(gettext("\n"));
		return (1);
	}

	/*
	 * remember argv_array address, which is memory calloc'd by
	 * parse_input_line, so it can be free'd at the end of the loop.
	 */
	argv_array = argv;

	if (argc < 1) {
		usage();
		free(argv_array);
		return (0);
	}

	cmd = argv[0];

	if (strcmp(cmd, "str2uid") == 0) {
		if (argc < 2) {
			usage();
			free(argv_array);
			return (0);
		}
		str.utf8string_val = argv[1];
		str.utf8string_len = strlen(argv[1]);
		stat = nfs_idmap_str_uid(&str, &uid);
		printf(gettext("%u stat=%s \n"), uid, mapstat(stat));

	} else if (strcmp(cmd, "str2gid") == 0) {
		if (argc < 2) {
			usage();
			free(argv_array);
			return (0);
		}
		str.utf8string_val = argv[1];
		str.utf8string_len = strlen(argv[1]);
		stat = nfs_idmap_str_gid(&str, &gid);
		printf(gettext("%u stat=%s \n"), gid, mapstat(stat));

	} else if (strcmp(cmd, "uid2str") == 0) {
		if (argc < 2) {
			usage();
			free(argv_array);
			return (0);
		}
		uid = atoi(argv[1]);
		bzero(str_buf, bufsize);
		str.utf8string_val = str_buf;
		stat = nfs_idmap_uid_str(uid, &str);
		printf(gettext("%s stat=%s\n"), str.utf8string_val,
		    mapstat(stat));

	} else if (strcmp(cmd, "gid2str") == 0) {
		if (argc < 2) {
			usage();
			free(argv_array);
			return (0);
		}
		gid = atoi(argv[1]);
		bzero(str_buf, bufsize);
		str.utf8string_val = str_buf;
		stat = nfs_idmap_gid_str(gid, &str);
		printf(gettext("%s stat=%s\n"), str.utf8string_val,
		    mapstat(stat));

	} else if (strcmp(cmd, "echo") == 0) {
		for (i = 1; i < argc; i++)
			printf("%s ", argv[i]);
		printf("\n");
	} else if (strcmp(cmd, "exit") == 0 ||
	    strcmp(cmd, "quit") == 0) {
		printf(gettext("\n"));
		free(argv_array);
		return (1);

	} else
		usage();

	/* free argv array */
	free(argv_array);
	return (0);
}


int
main(int argc, char **argv)
{
	char buf[512];
	int len, ret;

	(void) setlocale(LC_ALL, "");
#ifndef TEXT_DOMAIN
#define	TEXT_DOMAIN	""
#endif
	(void) textdomain(TEXT_DOMAIN);

	usage();

	/*
	 * Loop, repeatedly calling parse_input_line() to get the
	 * next line and parse it into argc and argv. Act on the
	 * arguements found on the line.
	 */

	do {
		len = read_line(buf, 512);
		if (len)
			ret = do_test(buf);
	} while (!ret);

	return (0);
}

#define	NFSMAPID_DOOR	"/var/run/nfsmapid_door"

/*
 * Gen the door handle for connecting to the nfsmapid process.
 * Keep the door cached.  This call may be made quite often.
 */
int
nfs_idmap_doorget()
{
	static int doorfd = -1;

	if (doorfd != -1)
		return (doorfd);

	if ((doorfd = open(NFSMAPID_DOOR, O_RDWR)) == -1) {
		perror(NFSMAPID_DOOR);
		exit(1);
	}
	return (doorfd);
}

/*
 * Convert a user utf-8 string identifier into its local uid.
 */
int
nfs_idmap_str_uid(utf8string *u8s, uid_t *uid)
{
	struct mapid_arg *mapargp;
	struct mapid_res mapres;
	struct mapid_res *mapresp = &mapres;
	struct mapid_res *resp = mapresp;
	door_arg_t	door_args;
	int		doorfd;
	int		error = 0;
	static int	msg_done = 0;

	if (!u8s || !u8s->utf8string_val || !u8s->utf8string_len ||
	    (u8s->utf8string_val[0] == '\0')) {
		error = EINVAL;
		goto s2u_done;
	}

	if (bcmp(u8s->utf8string_val, "nobody", 6) == 0) {
		/*
		 * If "nobody", just short circuit and bail
		 */
		*uid = UID_NOBODY;
		goto s2u_done;

	}

	if ((mapargp = malloc(MAPID_ARG_LEN(u8s->utf8string_len))) == NULL) {
		(void) fprintf(stderr, "Unable to malloc %d bytes\n",
		    MAPID_ARG_LEN(u8s->utf8string_len));
		error = ENOMEM;
		goto s2u_done;
	}
	mapargp->cmd = NFSMAPID_STR_UID;
	mapargp->u_arg.len = u8s->utf8string_len;
	(void) bcopy(u8s->utf8string_val, mapargp->str, mapargp->u_arg.len);
	mapargp->str[mapargp->u_arg.len] = '\0';

	door_args.data_ptr = (char *)mapargp;
	door_args.data_size = MAPID_ARG_LEN(mapargp->u_arg.len);
	door_args.desc_ptr = NULL;
	door_args.desc_num = 0;
	door_args.rbuf = (char *)mapresp;
	door_args.rsize = sizeof (struct mapid_res);

	/*
	 * call to the nfsmapid daemon
	 */
	if ((doorfd = nfs_idmap_doorget()) == -1) {
		if (!msg_done) {
			fprintf(stderr, "nfs_idmap_str_uid: Can't communicate"
			    " with mapping daemon nfsmapid\n");
			msg_done = 1;
		}
		error = ECOMM;
		free(mapargp);
		goto s2u_done;
	}

	if (door_call(doorfd, &door_args) == -1) {
		perror("door_call failed");
		error = EINVAL;
		free(mapargp);
		goto s2u_done;
	}

	free(mapargp);

	resp = (struct mapid_res *)door_args.rbuf;
	switch (resp->status) {
	case NFSMAPID_OK:
		*uid = resp->u_res.uid;
		break;

	case NFSMAPID_NUMSTR:
		*uid = resp->u_res.uid;
		error = resp->status;
		goto out;

	default:
	case NFSMAPID_UNMAPPABLE:
	case NFSMAPID_INVALID:
	case NFSMAPID_INTERNAL:
	case NFSMAPID_BADDOMAIN:
	case NFSMAPID_BADID:
	case NFSMAPID_NOTFOUND:
		error = resp->status;
		goto s2u_done;
	}

s2u_done:
	if (error)
		*uid = UID_NOBODY;
out:
	if (resp != mapresp)
		munmap(door_args.rbuf, door_args.rsize);
	return (error);
}

/*
 * Convert a uid into its utf-8 string representation.
 */
int
nfs_idmap_uid_str(uid_t uid,		/* uid to map */
		utf8string *u8s)	/* resulting utf-8 string for uid */
{
	struct mapid_arg maparg;
	struct mapid_res mapres;
	struct mapid_res *mapresp = &mapres;
	struct mapid_res *resp = mapresp;
	door_arg_t	door_args;
	int		doorfd;
	int		error = 0;
	static int	msg_done = 0;

	if (uid == UID_NOBODY) {
		u8s->utf8string_len = strlen("nobody");
		u8s->utf8string_val = nobody_str;
		goto u2s_done;
	}

	/*
	 * Daemon call...
	 */
	maparg.cmd = NFSMAPID_UID_STR;
	maparg.u_arg.uid = uid;

	door_args.data_ptr = (char *)&maparg;
	door_args.data_size = sizeof (struct mapid_arg);
	door_args.desc_ptr = NULL;
	door_args.desc_num = 0;
	door_args.rbuf = (char *)mapresp;
	door_args.rsize = sizeof (struct mapid_res);

	if ((doorfd = nfs_idmap_doorget()) == -1) {
		if (!msg_done) {
			fprintf(stderr, "nfs_idmap_uid_str: Can't "
			    "communicate with mapping daemon nfsmapid\n");
			msg_done = 1;
		}
		error = ECOMM;
		goto u2s_done;
	}

	if (door_call(doorfd, &door_args) == -1) {
		perror("door_call failed");
		error = EINVAL;
		goto u2s_done;
	}

	resp = (struct mapid_res *)door_args.rbuf;
	if (resp->status != NFSMAPID_OK) {
		error = resp->status;
		goto u2s_done;
	}

	if (resp->u_res.len != strlen(resp->str)) {
		(void) fprintf(stderr, "Incorrect length %d expected %d\n",
		    resp->u_res.len, strlen(resp->str));
		error = NFSMAPID_INVALID;
		goto u2s_done;
	}
	u8s->utf8string_len = resp->u_res.len;
	bcopy(resp->str, u8s->utf8string_val, u8s->utf8string_len);

u2s_done:
	if (resp != mapresp)
		munmap(door_args.rbuf, door_args.rsize);
	return (error);
}

/*
 * Convert a group utf-8 string identifier into its local gid.
 */
int
nfs_idmap_str_gid(utf8string *u8s, gid_t *gid)
{
	struct mapid_arg *mapargp;
	struct mapid_res mapres;
	struct mapid_res *mapresp = &mapres;
	struct mapid_res *resp = mapresp;
	door_arg_t	door_args;
	int		doorfd;
	int		error = 0;
	static int	msg_done = 0;

	if (!u8s || !u8s->utf8string_val || !u8s->utf8string_len ||
	    (u8s->utf8string_val[0] == '\0')) {
		error = EINVAL;
		goto s2g_done;
	}

	if (bcmp(u8s->utf8string_val, "nobody", 6) == 0) {
		/*
		 * If "nobody", just short circuit and bail
		 */
		*gid = GID_NOBODY;
		goto s2g_done;

	}

	if ((mapargp = malloc(MAPID_ARG_LEN(u8s->utf8string_len))) == NULL) {
		(void) fprintf(stderr, "Unable to malloc %d bytes\n",
		    MAPID_ARG_LEN(u8s->utf8string_len));
		error = ENOMEM;
		goto s2g_done;
	}
	mapargp->cmd = NFSMAPID_STR_GID;
	mapargp->u_arg.len = u8s->utf8string_len;
	(void) bcopy(u8s->utf8string_val, mapargp->str, mapargp->u_arg.len);
	mapargp->str[mapargp->u_arg.len] = '\0';

	door_args.data_ptr = (char *)mapargp;
	door_args.data_size = MAPID_ARG_LEN(mapargp->u_arg.len);
	door_args.desc_ptr = NULL;
	door_args.desc_num = 0;
	door_args.rbuf = (char *)mapresp;
	door_args.rsize = sizeof (struct mapid_res);

	/*
	 * call to the nfsmapid daemon
	 */
	if ((doorfd = nfs_idmap_doorget()) == -1) {
		if (!msg_done) {
			fprintf(stderr, "nfs_idmap_str_uid: Can't communicate"
			    " with mapping daemon nfsmapid\n");
			msg_done = 1;
		}
		error = ECOMM;
		free(mapargp);
		goto s2g_done;
	}

	if (door_call(doorfd, &door_args) == -1) {
		perror("door_call failed");
		error = EINVAL;
		free(mapargp);
		goto s2g_done;
	}

	free(mapargp);

	resp = (struct mapid_res *)door_args.rbuf;
	switch (resp->status) {
	case NFSMAPID_OK:
		*gid = resp->u_res.gid;
		break;

	case NFSMAPID_NUMSTR:
		*gid = resp->u_res.gid;
		error = resp->status;
		goto out;

	default:
	case NFSMAPID_UNMAPPABLE:
	case NFSMAPID_INVALID:
	case NFSMAPID_INTERNAL:
	case NFSMAPID_BADDOMAIN:
	case NFSMAPID_BADID:
	case NFSMAPID_NOTFOUND:
		error = resp->status;
		goto s2g_done;
	}

s2g_done:
	if (error)
		*gid = GID_NOBODY;
out:
	if (resp != mapresp)
		munmap(door_args.rbuf, door_args.rsize);
	return (error);
}

/*
 * Convert a gid into its utf-8 string representation.
 */
int
nfs_idmap_gid_str(gid_t gid,		/* gid to map */
		utf8string *g8s)	/* resulting utf-8 string for gid */
{
	struct mapid_arg maparg;
	struct mapid_res mapres;
	struct mapid_res *mapresp = &mapres;
	struct mapid_res *resp = mapresp;
	door_arg_t	door_args;
	int		error = 0;
	int		doorfd;
	static int	msg_done = 0;

	if (gid == GID_NOBODY) {
		g8s->utf8string_len = strlen("nobody");
		g8s->utf8string_val = nobody_str;
		goto g2s_done;

	}

	/*
	 * Daemon call...
	 */
	maparg.cmd = NFSMAPID_GID_STR;
	maparg.u_arg.gid = gid;

	door_args.data_ptr = (char *)&maparg;
	door_args.data_size = sizeof (struct mapid_arg);
	door_args.desc_ptr = NULL;
	door_args.desc_num = 0;
	door_args.rbuf = (char *)mapresp;
	door_args.rsize = sizeof (struct mapid_res);

	if ((doorfd = nfs_idmap_doorget()) == -1) {
		if (!msg_done) {
			fprintf(stderr, "nfs_idmap_uid_str: Can't "
			    "communicate with mapping daemon nfsmapid\n");
			msg_done = 1;
		}
		error = ECOMM;
		goto g2s_done;
	}

	if (door_call(doorfd, &door_args) == -1) {
		perror("door_call failed");
		error = EINVAL;
		goto g2s_done;
	}

	resp = (struct mapid_res *)door_args.rbuf;
	if (resp->status != NFSMAPID_OK) {
		error = resp->status;
		goto g2s_done;
	}

	if (resp->u_res.len != strlen(resp->str)) {
		(void) fprintf(stderr, "Incorrect length %d expected %d\n",
		    resp->u_res.len, strlen(resp->str));
		error = NFSMAPID_INVALID;
		goto g2s_done;
	}
	g8s->utf8string_len = resp->u_res.len;
	bcopy(resp->str, g8s->utf8string_val, g8s->utf8string_len);

g2s_done:
	if (resp != mapresp)
		munmap(door_args.rbuf, door_args.rsize);
	return (error);
}