Blame cifscreds.c

Packit 5f9837
/*
Packit 5f9837
 * Credentials stashing utility for Linux CIFS VFS (virtual filesystem) client
Packit 5f9837
 * Copyright (C) 2010 Jeff Layton (jlayton@samba.org)
Packit 5f9837
 * Copyright (C) 2010 Igor Druzhinin (jaxbrigs@gmail.com)
Packit 5f9837
 *
Packit 5f9837
 * This program is free software; you can redistribute it and/or modify
Packit 5f9837
 * it under the terms of the GNU General Public License as published by
Packit 5f9837
 * the Free Software Foundation; either version 3 of the License, or
Packit 5f9837
 * (at your option) any later version.
Packit 5f9837
 *
Packit 5f9837
 * This program is distributed in the hope that it will be useful,
Packit 5f9837
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5f9837
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 5f9837
 * GNU General Public License for more details.
Packit 5f9837
 *
Packit 5f9837
 * You should have received a copy of the GNU General Public License
Packit 5f9837
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 5f9837
 */
Packit 5f9837
Packit 5f9837
#ifdef HAVE_CONFIG_H
Packit 5f9837
#include "config.h"
Packit 5f9837
#endif /* HAVE_CONFIG_H */
Packit 5f9837
Packit 5f9837
#include <stdio.h>
Packit 5f9837
#include <stdlib.h>
Packit 5f9837
#include <unistd.h>
Packit 5f9837
#include <string.h>
Packit 5f9837
#include <ctype.h>
Packit 5f9837
#include <keyutils.h>
Packit 5f9837
#include <getopt.h>
Packit 5f9837
#include <errno.h>
Packit 5f9837
#include "cifskey.h"
Packit 5f9837
#include "mount.h"
Packit 5f9837
#include "resolve_host.h"
Packit 5f9837
#include "util.h"
Packit 5f9837
Packit 5f9837
#define THIS_PROGRAM_NAME "cifscreds"
Packit 5f9837
Packit 5f9837
/* max length of appropriate command */
Packit 5f9837
#define MAX_COMMAND_SIZE 32
Packit 5f9837
Packit 5f9837
struct cmdarg {
Packit 5f9837
	char		*host;
Packit 5f9837
	char		*user;
Packit 5f9837
	char		keytype;
Packit 5f9837
};
Packit 5f9837
Packit 5f9837
struct command {
Packit 5f9837
	int (*action)(struct cmdarg *arg);
Packit 5f9837
	const char	name[MAX_COMMAND_SIZE];
Packit 5f9837
	const char	*format;
Packit 5f9837
};
Packit 5f9837
Packit 5f9837
static int cifscreds_add(struct cmdarg *arg);
Packit 5f9837
static int cifscreds_clear(struct cmdarg *arg);
Packit 5f9837
static int cifscreds_clearall(struct cmdarg *arg);
Packit 5f9837
static int cifscreds_update(struct cmdarg *arg);
Packit 5f9837
Packit 5f9837
static const char *thisprogram;
Packit 5f9837
Packit 5f9837
static struct command commands[] = {
Packit 5f9837
	{ cifscreds_add,	"add",		"[-u username] [-d] <host|domain>" },
Packit 5f9837
	{ cifscreds_clear,	"clear",	"[-u username] [-d] <host|domain>" },
Packit 5f9837
	{ cifscreds_clearall,	"clearall",	"" },
Packit 5f9837
	{ cifscreds_update,	"update",	"[-u username] [-d] <host|domain>" },
Packit 5f9837
	{ NULL, "", NULL }
Packit 5f9837
};
Packit 5f9837
Packit 5f9837
static struct option longopts[] = {
Packit 5f9837
	{"username", 1, NULL, 'u'},
Packit 5f9837
	{"domain", 0, NULL, 'd' },
Packit 5f9837
	{NULL, 0, NULL, 0}
Packit 5f9837
};
Packit 5f9837
Packit 5f9837
/* display usage information */
Packit 5f9837
static int
Packit 5f9837
usage(void)
Packit 5f9837
{
Packit 5f9837
	struct command *cmd;
Packit 5f9837
Packit 5f9837
	fprintf(stderr, "Usage:\n");
Packit 5f9837
	for (cmd = commands; cmd->action; cmd++)
Packit 5f9837
		fprintf(stderr, "\t%s %s %s\n", thisprogram,
Packit 5f9837
			cmd->name, cmd->format);
Packit 5f9837
	fprintf(stderr, "\n");
Packit 5f9837
Packit 5f9837
	return EXIT_FAILURE;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* search all program's keys in keyring */
Packit 5f9837
static key_serial_t key_search_all(void)
Packit 5f9837
{
Packit 5f9837
	key_serial_t key, *pk;
Packit 5f9837
	void *keylist;
Packit 5f9837
	char *buffer;
Packit 5f9837
	int count, dpos, n, ret;
Packit 5f9837
Packit 5f9837
	/* read the key payload data */
Packit 5f9837
	count = keyctl_read_alloc(DEST_KEYRING, &keylist);
Packit 5f9837
	if (count < 0)
Packit 5f9837
		return 0;
Packit 5f9837
Packit 5f9837
	count /= sizeof(key_serial_t);
Packit 5f9837
Packit 5f9837
	if (count == 0) {
Packit 5f9837
		ret = 0;
Packit 5f9837
		goto key_search_all_out;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* list the keys in the keyring */
Packit 5f9837
	pk = keylist;
Packit 5f9837
	do {
Packit 5f9837
		key = *pk++;
Packit 5f9837
Packit 5f9837
		ret = keyctl_describe_alloc(key, &buffer);
Packit 5f9837
		if (ret < 0)
Packit 5f9837
			continue;
Packit 5f9837
Packit 5f9837
		n = sscanf(buffer, "%*[^;];%*d;%*d;%*x;%n", &dpos);
Packit 5f9837
		if (n) {
Packit 5f9837
			free(buffer);
Packit 5f9837
			continue;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		if (strstr(buffer + dpos, KEY_PREFIX ":") ==
Packit 5f9837
			buffer + dpos
Packit 5f9837
		) {
Packit 5f9837
			ret = key;
Packit 5f9837
			free(buffer);
Packit 5f9837
			goto key_search_all_out;
Packit 5f9837
		}
Packit 5f9837
		free(buffer);
Packit 5f9837
Packit 5f9837
	} while (--count);
Packit 5f9837
Packit 5f9837
	ret = 0;
Packit 5f9837
Packit 5f9837
key_search_all_out:
Packit 5f9837
	free(keylist);
Packit 5f9837
	return ret;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* add command handler */
Packit 5f9837
static int cifscreds_add(struct cmdarg *arg)
Packit 5f9837
{
Packit 5f9837
	char addrstr[MAX_ADDR_LIST_LEN];
Packit 5f9837
	char *currentaddress, *nextaddress;
Packit 5f9837
	char *pass;
Packit 5f9837
	int ret = 0;
Packit 5f9837
Packit 5f9837
	if (arg->host == NULL || arg->user == NULL)
Packit 5f9837
		return usage();
Packit 5f9837
Packit 5f9837
	if (arg->keytype == 'd')
Packit 5f9837
		strlcpy(addrstr, arg->host, MAX_ADDR_LIST_LEN);
Packit 5f9837
	else
Packit 5f9837
		ret = resolve_host(arg->host, addrstr);
Packit 5f9837
Packit 5f9837
	switch (ret) {
Packit 5f9837
	case EX_USAGE:
Packit 5f9837
		fprintf(stderr, "error: Could not resolve address "
Packit 5f9837
			"for %s\n", arg->host);
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
Packit 5f9837
	case EX_SYSERR:
Packit 5f9837
		fprintf(stderr, "error: Problem parsing address list\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (strpbrk(arg->user, USER_DISALLOWED_CHARS)) {
Packit 5f9837
		fprintf(stderr, "error: Incorrect username\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* search for same credentials stashed for current host */
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		if (key_search(currentaddress, arg->keytype) > 0) {
Packit 5f9837
			printf("You already have stashed credentials "
Packit 5f9837
				"for %s (%s)\n", currentaddress, arg->host);
Packit 5f9837
			printf("If you want to update them use:\n");
Packit 5f9837
			printf("\t%s update\n", thisprogram);
Packit 5f9837
Packit 5f9837
			return EXIT_FAILURE;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		switch(errno) {
Packit 5f9837
		case ENOKEY:
Packit 5f9837
			/* success */
Packit 5f9837
			break;
Packit 5f9837
		default:
Packit 5f9837
			printf("Key search failed: %s\n", strerror(errno));
Packit 5f9837
			return EXIT_FAILURE;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			*(currentaddress - 1) = ',';
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/*
Packit 5f9837
	 * if there isn't same credentials stashed add them to keyring
Packit 5f9837
	 * and set permisson mask
Packit 5f9837
	 */
Packit 5f9837
	pass = getpass("Password: ");
Packit 5f9837
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		key_serial_t key = key_add(currentaddress, arg->user, pass, arg->keytype);
Packit 5f9837
		if (key <= 0) {
Packit 5f9837
			fprintf(stderr, "error: Add credential key for %s: %s\n",
Packit 5f9837
				currentaddress, strerror(errno));
Packit 5f9837
		} else {
Packit 5f9837
			if (keyctl(KEYCTL_SETPERM, key, CIFS_KEY_PERMS) < 0) {
Packit 5f9837
				fprintf(stderr, "error: Setting permissons "
Packit 5f9837
					"on key, attempt to delete...\n");
Packit 5f9837
Packit 5f9837
				if (keyctl(KEYCTL_UNLINK, key, DEST_KEYRING) < 0) {
Packit 5f9837
					fprintf(stderr, "error: Deleting key from "
Packit 5f9837
						"keyring for %s (%s)\n",
Packit 5f9837
						currentaddress, arg->host);
Packit 5f9837
				}
Packit 5f9837
			}
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return EXIT_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* clear command handler */
Packit 5f9837
static int cifscreds_clear(struct cmdarg *arg)
Packit 5f9837
{
Packit 5f9837
	char addrstr[MAX_ADDR_LIST_LEN];
Packit 5f9837
	char *currentaddress, *nextaddress;
Packit 5f9837
	int ret = 0, count = 0, errors = 0;
Packit 5f9837
Packit 5f9837
	if (arg->host == NULL || arg->user == NULL)
Packit 5f9837
		return usage();
Packit 5f9837
Packit 5f9837
	if (arg->keytype == 'd')
Packit 5f9837
		strlcpy(addrstr, arg->host, MAX_ADDR_LIST_LEN);
Packit 5f9837
	else
Packit 5f9837
		ret = resolve_host(arg->host, addrstr);
Packit 5f9837
Packit 5f9837
	switch (ret) {
Packit 5f9837
	case EX_USAGE:
Packit 5f9837
		fprintf(stderr, "error: Could not resolve address "
Packit 5f9837
			"for %s\n", arg->host);
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
Packit 5f9837
	case EX_SYSERR:
Packit 5f9837
		fprintf(stderr, "error: Problem parsing address list\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (strpbrk(arg->user, USER_DISALLOWED_CHARS)) {
Packit 5f9837
		fprintf(stderr, "error: Incorrect username\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/*
Packit 5f9837
	 * search for same credentials stashed for current host
Packit 5f9837
	 * and unlink them from session keyring
Packit 5f9837
	 */
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		key_serial_t key = key_search(currentaddress, arg->keytype);
Packit 5f9837
		if (key > 0) {
Packit 5f9837
			if (keyctl(KEYCTL_UNLINK, key, DEST_KEYRING) < 0) {
Packit 5f9837
				fprintf(stderr, "error: Removing key from "
Packit 5f9837
					"keyring for %s (%s)\n",
Packit 5f9837
					currentaddress, arg->host);
Packit 5f9837
				errors++;
Packit 5f9837
			} else {
Packit 5f9837
				count++;
Packit 5f9837
			}
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (!count && !errors) {
Packit 5f9837
		printf("You have no same stashed credentials "
Packit 5f9837
			" for %s\n", arg->host);
Packit 5f9837
		printf("If you want to add them use:\n");
Packit 5f9837
		printf("\t%s add\n", thisprogram);
Packit 5f9837
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return EXIT_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* clearall command handler */
Packit 5f9837
static int cifscreds_clearall(struct cmdarg *arg __attribute__ ((unused)))
Packit 5f9837
{
Packit 5f9837
	key_serial_t key;
Packit 5f9837
	int count = 0, errors = 0;
Packit 5f9837
Packit 5f9837
	/*
Packit 5f9837
	 * search for all program's credentials stashed in session keyring
Packit 5f9837
	 * and then unlink them
Packit 5f9837
	 */
Packit 5f9837
	do {
Packit 5f9837
		key = key_search_all();
Packit 5f9837
		if (key > 0) {
Packit 5f9837
			if (keyctl(KEYCTL_UNLINK, key, DEST_KEYRING) < 0) {
Packit 5f9837
				fprintf(stderr, "error: Deleting key "
Packit 5f9837
					"from keyring");
Packit 5f9837
				errors++;
Packit 5f9837
			} else {
Packit 5f9837
				count++;
Packit 5f9837
			}
Packit 5f9837
		}
Packit 5f9837
	} while (key > 0);
Packit 5f9837
Packit 5f9837
	if (!count && !errors) {
Packit 5f9837
		printf("You have no stashed " KEY_PREFIX
Packit 5f9837
			" credentials\n");
Packit 5f9837
		printf("If you want to add them use:\n");
Packit 5f9837
		printf("\t%s add\n", thisprogram);
Packit 5f9837
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return EXIT_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/* update command handler */
Packit 5f9837
static int cifscreds_update(struct cmdarg *arg)
Packit 5f9837
{
Packit 5f9837
	char addrstr[MAX_ADDR_LIST_LEN];
Packit 5f9837
	char *currentaddress, *nextaddress, *pass;
Packit 5f9837
	char *addrs[16];
Packit 5f9837
	int ret = 0, id, count = 0;
Packit 5f9837
Packit 5f9837
	if (arg->host == NULL || arg->user == NULL)
Packit 5f9837
		return usage();
Packit 5f9837
Packit 5f9837
	if (arg->keytype == 'd')
Packit 5f9837
		strlcpy(addrstr, arg->host, MAX_ADDR_LIST_LEN);
Packit 5f9837
	else
Packit 5f9837
		ret = resolve_host(arg->host, addrstr);
Packit 5f9837
Packit 5f9837
	switch (ret) {
Packit 5f9837
	case EX_USAGE:
Packit 5f9837
		fprintf(stderr, "error: Could not resolve address "
Packit 5f9837
			"for %s\n", arg->host);
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
Packit 5f9837
	case EX_SYSERR:
Packit 5f9837
		fprintf(stderr, "error: Problem parsing address list\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (strpbrk(arg->user, USER_DISALLOWED_CHARS)) {
Packit 5f9837
		fprintf(stderr, "error: Incorrect username\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* search for necessary credentials stashed in session keyring */
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		if (key_search(currentaddress, arg->keytype) > 0) {
Packit 5f9837
			addrs[count] = currentaddress;
Packit 5f9837
			count++;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (!count) {
Packit 5f9837
		printf("You have no same stashed credentials "
Packit 5f9837
			"for %s\n", arg->host);
Packit 5f9837
		printf("If you want to add them use:\n");
Packit 5f9837
		printf("\t%s add\n", thisprogram);
Packit 5f9837
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* update payload of found keys */
Packit 5f9837
	pass = getpass("Password: ");
Packit 5f9837
Packit 5f9837
	for (id = 0; id < count; id++) {
Packit 5f9837
		key_serial_t key = key_add(addrs[id], arg->user, pass, arg->keytype);
Packit 5f9837
		if (key <= 0)
Packit 5f9837
			fprintf(stderr, "error: Update credential key "
Packit 5f9837
				"for %s: %s\n", addrs[id], strerror(errno));
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return EXIT_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static int
Packit 5f9837
check_session_keyring(void)
Packit 5f9837
{
Packit 5f9837
	key_serial_t	ses_key, uses_key;
Packit 5f9837
Packit 5f9837
	ses_key = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
Packit 5f9837
	if (ses_key == -1) {
Packit 5f9837
		if (errno == ENOKEY)
Packit 5f9837
			fprintf(stderr, "Error: you have no session keyring. "
Packit 5f9837
					"Consider using pam_keyinit to "
Packit 5f9837
					"install one.\n");
Packit 5f9837
		else
Packit 5f9837
			fprintf(stderr, "Error: unable to query session "
Packit 5f9837
					"keyring: %s\n", strerror(errno));
Packit 5f9837
		return (int)ses_key;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* A problem querying the user-session keyring isn't fatal. */
Packit 5f9837
	uses_key = keyctl_get_keyring_ID(KEY_SPEC_USER_SESSION_KEYRING, 0);
Packit 5f9837
	if (uses_key == -1)
Packit 5f9837
		return 0;
Packit 5f9837
Packit 5f9837
	if (ses_key == uses_key)
Packit 5f9837
		fprintf(stderr, "Warning: you have no persistent session "
Packit 5f9837
				"keyring. cifscreds keys will not persist "
Packit 5f9837
				"after this process exits. See "
Packit 5f9837
				"pam_keyinit(8).\n");
Packit 5f9837
	return 0;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
int main(int argc, char **argv)
Packit 5f9837
{
Packit 5f9837
	struct command *cmd, *best;
Packit 5f9837
	struct cmdarg arg;
Packit 5f9837
	int n;
Packit 5f9837
Packit 5f9837
	memset(&arg, 0, sizeof(arg));
Packit 5f9837
	arg.keytype = 'a';
Packit 5f9837
Packit 5f9837
	thisprogram = (char *)basename(argv[0]);
Packit 5f9837
	if (thisprogram == NULL)
Packit 5f9837
		thisprogram = THIS_PROGRAM_NAME;
Packit 5f9837
Packit 5f9837
	if (argc == 1)
Packit 5f9837
		return usage();
Packit 5f9837
Packit 5f9837
	while((n = getopt_long(argc, argv, "du:", longopts, NULL)) != -1) {
Packit 5f9837
		switch (n) {
Packit 5f9837
		case 'd':
Packit 5f9837
			arg.keytype = (char) n;
Packit 5f9837
			break;
Packit 5f9837
		case 'u':
Packit 5f9837
			arg.user = optarg;
Packit 5f9837
			break;
Packit 5f9837
		default:
Packit 5f9837
			return usage();
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (optind >= argc)
Packit 5f9837
		return usage();
Packit 5f9837
Packit 5f9837
	/* find the best fit command */
Packit 5f9837
	best = NULL;
Packit 5f9837
	n = strnlen(argv[optind], MAX_COMMAND_SIZE);
Packit 5f9837
Packit 5f9837
	for (cmd = commands; cmd->action; cmd++) {
Packit 5f9837
		if (memcmp(cmd->name, argv[optind], n) != 0)
Packit 5f9837
			continue;
Packit 5f9837
Packit 5f9837
		if (cmd->name[n] == 0) {
Packit 5f9837
			/* exact match */
Packit 5f9837
			best = cmd;
Packit 5f9837
			break;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		/* partial match */
Packit 5f9837
		if (best) {
Packit 5f9837
			fprintf(stderr, "Ambiguous command\n");
Packit 5f9837
			return EXIT_FAILURE;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		best = cmd;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (!best) {
Packit 5f9837
		fprintf(stderr, "Unknown command\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* second argument should be host or domain */
Packit 5f9837
	if (argc >= 3)
Packit 5f9837
		arg.host = argv[optind + 1];
Packit 5f9837
Packit 5f9837
	if (arg.host && arg.keytype == 'd' &&
Packit 5f9837
	    strpbrk(arg.host, DOMAIN_DISALLOWED_CHARS)) {
Packit 5f9837
		fprintf(stderr, "error: Domain name contains invalid characters\n");
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (arg.user == NULL)
Packit 5f9837
		arg.user = getusername(getuid());
Packit 5f9837
Packit 5f9837
	if (check_session_keyring())
Packit 5f9837
		return EXIT_FAILURE;
Packit 5f9837
Packit 5f9837
	return best->action(&arg;;
Packit 5f9837
}