#define HAVE_UNISTD_H
#define HAVE_MEMORY_H
#define HAVE_SETENV

/*
 * kshell - Create a subshell set up to handle a credential cache
 */

#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <errno.h>
#include <strings.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif /* HAVE_MEMORY_H */

#include <krb5.h>
#include <et/com_err.h>

#ifndef HAVE_SETENV
extern int setenv(char *, char *, int);
#endif /* HAVE_SETENV */

#define MAXARGS 100

static void usage(const char *);

int
main(int argc, char *argv[])
{
	krb5_context context;
	krb5_ccache cc;
	krb5_error_code retval;
	char *command = NULL;
	char **args;
	char *cp = NULL;
	char *args2[MAXARGS];
	char buf[1024];
	struct passwd *pw;
	int c, argnum = 1;
	int disable = 0;
	int newcache = 1;

	args = argv;		/* assume no parameters */

	while ((c = getopt(argc, argv, "dnc")) != EOF)
		switch (c) {
		case 'd':	/* disable imported Kerberos cache */
		    	disable++;
		    	break;
		case 'n':	/* disable exported  Kerberos cache */
			disable++;
			newcache = 0;	/* no new cache */
			break;
		case 'c':	/* command parameter */
			if (args[optind] == NULL)
				usage(argv[0]);
			if (strchr(args[optind], ' ')) {
				args2[0] = args[optind];
				while ((cp = strchr(args2[argnum-1], ' ')) !=
									NULL) {
					while (*cp == ' ')
						{ *cp = '\0'; cp++; }
					args2[argnum++] = cp;
					if (argnum == (MAXARGS-1)) break;
				}
				args2[argnum] = NULL;
				command = args2[0];
				args = args2;
			} else {
				command = args[optind];
				args = &argv[optind];
			}
			goto fin;
		case '?':
		default:
			usage(argv[0]);
		}

fin:
	if ((retval = krb5_init_context(&context))) {
		fprintf(stderr, "krb5_init_context failed: %s\n",
			error_message(retval));
		exit(1);
	}

	if (disable) {
		if (! krb5_cc_default(context, &cc)) {
			if (strcmp(krb5_cc_get_type(context, cc),"PIPE") == 0)
				close(atoi(krb5_cc_get_name(context, cc)));
			(void)krb5_cc_close(context,cc);
		}
		unsetenv("KRB5CCNAME");
	}

	if (newcache) {

		if ((retval = krb5_cc_resolve(context, "PIPE:NewCache", &cc))) {
			fprintf(stderr, "Unable to create credential cache "
				"server: %s\n", error_message(retval));
			exit(1);
		}

		snprintf(buf, sizeof(buf), "PIPE:%s",
			krb5_cc_get_name(context, cc));
		buf[sizeof(buf) - 1] = '\0';

		krb5_cc_close(context, cc);
		setenv("KRB5CCNAME", buf, 1);
	}

	if (command == NULL) {
		pw = getpwuid(getuid());

		if (!pw) {
			fprintf(stderr, "Unable to find uid %d in pw file, "
				"defaulting to /bin/sh\n", getuid());
			command = "/bin/sh";
			args[0] = command;
			args[1] = NULL;
		} else {
			if (pw->pw_shell[0] == '\0') {
				command = "/bin/sh";
				args[0] = command;
				args[1] = NULL;
			} else {
				command = pw->pw_shell;
				args[0] = command;
				args[1] = NULL;
			}
		}
	}

	if (execvp(command, args) < 0) {
		fprintf(stderr, "execvp(\"%s\") failed: %s\n",
			command, strerror(errno));
	}

	exit(1);
}

static void
usage(const char *argv0)
{
	fprintf(stderr, "Usage: %s [-c command params]\n", argv0);
	fprintf(stderr, "where:\n");
	fprintf(stderr, "       command - application to run\n");
	fprintf(stderr, "       params  - parameter list\n");
//	fprintf(stderr, "\nversion: %s\n",krb5_release_str());
	exit(1);
}

