xref: /onnv-gate/usr/src/cmd/krb5/kinit/kinit.c (revision 7934:6aeeafc994de)
10Sstevel@tonic-gate /*
2*7934SMark.Phalan@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate 
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate  * clients/kinit/kinit.c
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * Copyright 1990 by the Massachusetts Institute of Technology.
110Sstevel@tonic-gate  * All Rights Reserved.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * Export of this software from the United States of America may
140Sstevel@tonic-gate  *   require a specific license from the United States Government.
150Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
160Sstevel@tonic-gate  *   export to obtain such a license before exporting.
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
190Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
200Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
210Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
220Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
230Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
240Sstevel@tonic-gate  * to distribution of the software without specific, written prior
250Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
260Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
270Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
280Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
290Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
300Sstevel@tonic-gate  * or implied warranty.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * Initialize a credentials cache.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate #include <k5-int.h>
360Sstevel@tonic-gate #include <profile/prof_int.h>
370Sstevel@tonic-gate #include <com_err.h>
380Sstevel@tonic-gate #include <libintl.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <krb5.h>
410Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
420Sstevel@tonic-gate #include <kerberosIV/krb.h>
430Sstevel@tonic-gate #define HAVE_KRB524
440Sstevel@tonic-gate #else
450Sstevel@tonic-gate #undef HAVE_KRB524
46*7934SMark.Phalan@Sun.COM #endif
470Sstevel@tonic-gate #include <string.h>
480Sstevel@tonic-gate #include <stdio.h>
490Sstevel@tonic-gate #include <time.h>
50*7934SMark.Phalan@Sun.COM #include <errno.h>
51*7934SMark.Phalan@Sun.COM #include <com_err.h>
520Sstevel@tonic-gate #include <netdb.h>
530Sstevel@tonic-gate #include <locale.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #ifdef GETOPT_LONG
560Sstevel@tonic-gate #include <getopt.h>
57*7934SMark.Phalan@Sun.COM #else
580Sstevel@tonic-gate #ifdef HAVE_UNISTD_H
590Sstevel@tonic-gate #include <unistd.h>
60*7934SMark.Phalan@Sun.COM #ifdef sun
61*7934SMark.Phalan@Sun.COM /* SunOS4 unistd didn't declare these; okay to make unconditional?  */
62*7934SMark.Phalan@Sun.COM extern int optind;
63*7934SMark.Phalan@Sun.COM extern char *optarg;
64*7934SMark.Phalan@Sun.COM #endif /* sun */
65*7934SMark.Phalan@Sun.COM #else
660Sstevel@tonic-gate extern int optind;
670Sstevel@tonic-gate extern char *optarg;
680Sstevel@tonic-gate extern int getopt();
690Sstevel@tonic-gate #endif /* HAVE_UNISTD_H */
700Sstevel@tonic-gate #endif /* GETOPT_LONG */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #ifndef _WIN32
730Sstevel@tonic-gate #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
74*7934SMark.Phalan@Sun.COM #else
750Sstevel@tonic-gate #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
76*7934SMark.Phalan@Sun.COM #endif
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #ifdef HAVE_PWD_H
790Sstevel@tonic-gate #include <pwd.h>
802881Smp153739 static
get_name_from_os()810Sstevel@tonic-gate char * get_name_from_os()
820Sstevel@tonic-gate {
830Sstevel@tonic-gate     struct passwd *pw;
842881Smp153739     if ((pw = getpwuid((int) getuid())))
850Sstevel@tonic-gate 	return pw->pw_name;
860Sstevel@tonic-gate     return 0;
870Sstevel@tonic-gate }
880Sstevel@tonic-gate #else /* HAVE_PWD_H */
890Sstevel@tonic-gate #ifdef _WIN32
902881Smp153739 static
get_name_from_os()910Sstevel@tonic-gate char * get_name_from_os()
920Sstevel@tonic-gate {
930Sstevel@tonic-gate     static char name[1024];
940Sstevel@tonic-gate     DWORD name_size = sizeof(name);
950Sstevel@tonic-gate     if (GetUserName(name, &name_size)) {
960Sstevel@tonic-gate 	name[sizeof(name)-1] = 0; /* Just to be extra safe */
970Sstevel@tonic-gate 	return name;
980Sstevel@tonic-gate     } else {
990Sstevel@tonic-gate 	return 0;
1000Sstevel@tonic-gate     }
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate #else /* _WIN32 */
1032881Smp153739 static
get_name_from_os()1040Sstevel@tonic-gate char * get_name_from_os()
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate     return 0;
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate #endif /* _WIN32 */
1090Sstevel@tonic-gate #endif /* HAVE_PWD_H */
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate static char* progname_v5 = 0;
1120Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
1130Sstevel@tonic-gate static char* progname_v4 = 0;
1140Sstevel@tonic-gate static char* progname_v524 = 0;
115*7934SMark.Phalan@Sun.COM #endif
1160Sstevel@tonic-gate #include <locale.h>
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate static int got_k5 = 0;
1190Sstevel@tonic-gate static int got_k4 = 0;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate static int default_k5 = 1;
1220Sstevel@tonic-gate #if defined(KRB5_KRB4_COMPAT) && defined(KINIT_DEFAULT_BOTH)
1230Sstevel@tonic-gate static int default_k4 = 1;
124*7934SMark.Phalan@Sun.COM #else
1250Sstevel@tonic-gate static int default_k4 = 0;
126*7934SMark.Phalan@Sun.COM #endif
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate static int authed_k5 = 0;
1290Sstevel@tonic-gate static int authed_k4 = 0;
1300Sstevel@tonic-gate 
1312881Smp153739 #define KRB4_BACKUP_DEFAULT_LIFE_SECS 24*60*60 /* 1 day */
1320Sstevel@tonic-gate #define	ROOT_UNAME	"root"
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate struct k_opts
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate     /* in seconds */
1390Sstevel@tonic-gate     krb5_deltat starttime;
1400Sstevel@tonic-gate     krb5_deltat lifetime;
1410Sstevel@tonic-gate     krb5_deltat rlife;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate     int forwardable;
1440Sstevel@tonic-gate     int proxiable;
1450Sstevel@tonic-gate     int addresses;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate     int not_forwardable;
1480Sstevel@tonic-gate     int not_proxiable;
1490Sstevel@tonic-gate     int no_addresses;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate     int verbose;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate     char* principal_name;
1540Sstevel@tonic-gate     char* service_name;
1550Sstevel@tonic-gate     char* keytab_name;
1560Sstevel@tonic-gate     char* k5_cache_name;
1570Sstevel@tonic-gate     char* k4_cache_name;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate     action_type action;
160*7934SMark.Phalan@Sun.COM 
161*7934SMark.Phalan@Sun.COM     int num_pa_opts;
162*7934SMark.Phalan@Sun.COM     krb5_gic_opt_pa_data *pa_opts;
1630Sstevel@tonic-gate };
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate int	forwardable_flag = 0;
1660Sstevel@tonic-gate int	renewable_flag = 0;
1670Sstevel@tonic-gate int	proxiable_flag = 0;
1680Sstevel@tonic-gate int	no_address_flag = 0;
1690Sstevel@tonic-gate profile_options_boolean	config_option[] = {
1700Sstevel@tonic-gate 	{ "forwardable",	&forwardable_flag,	0 },
1710Sstevel@tonic-gate 	{ "renewable",		&renewable_flag,	0 },
1720Sstevel@tonic-gate 	{ "proxiable",		&proxiable_flag,	0 },
1730Sstevel@tonic-gate 	{ "no_addresses",	&no_address_flag,	0 },
1740Sstevel@tonic-gate 	{ NULL,			NULL,			0 }
1750Sstevel@tonic-gate };
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate char	*renew_timeval=NULL;
1780Sstevel@tonic-gate char	*life_timeval=NULL;
1790Sstevel@tonic-gate int	lifetime_specified;
1800Sstevel@tonic-gate int	renewtime_specified;
1810Sstevel@tonic-gate profile_option_strings	config_times[] = {
1820Sstevel@tonic-gate 	{ "max_life",		&life_timeval,	0 },
1830Sstevel@tonic-gate 	{ "max_renewable_life",	&renew_timeval,	0 },
1840Sstevel@tonic-gate 	{ NULL,			NULL,		0 }
1850Sstevel@tonic-gate };
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate struct k5_data
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate     krb5_context ctx;
1900Sstevel@tonic-gate     krb5_ccache cc;
1910Sstevel@tonic-gate     krb5_principal me;
1920Sstevel@tonic-gate     char* name;
1930Sstevel@tonic-gate };
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate struct k4_data
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate     krb5_deltat lifetime;
1980Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
1990Sstevel@tonic-gate     char aname[ANAME_SZ + 1];
2000Sstevel@tonic-gate     char inst[INST_SZ + 1];
2010Sstevel@tonic-gate     char realm[REALM_SZ + 1];
2020Sstevel@tonic-gate     char name[ANAME_SZ + 1 + INST_SZ + 1 + REALM_SZ + 1];
203*7934SMark.Phalan@Sun.COM #endif
2040Sstevel@tonic-gate };
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate char	*realmdef[] = { "realms", NULL, "kinit", NULL };
2070Sstevel@tonic-gate char	*appdef[] = { "appdefaults", "kinit", NULL };
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate #define	krb_realm		(*(realmdef + 1))
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate #define	lifetime_specified	config_times[0].found
2120Sstevel@tonic-gate #define	renewtime_specified	config_times[1].found
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * Try no preauthentication first; then try the encrypted timestamp
2160Sstevel@tonic-gate  */
2170Sstevel@tonic-gate krb5_preauthtype * preauth = NULL;
2180Sstevel@tonic-gate krb5_preauthtype preauth_list[2] = { 0, -1 };
2190Sstevel@tonic-gate 
220*7934SMark.Phalan@Sun.COM static void _kwarnd_add_warning(char *, char *, time_t);
221*7934SMark.Phalan@Sun.COM static void _kwarnd_del_warning(char *, char *);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate #ifdef GETOPT_LONG
2240Sstevel@tonic-gate /* if struct[2] == NULL, then long_getopt acts as if the short flag
2250Sstevel@tonic-gate    struct[3] was specified.  If struct[2] != NULL, then struct[3] is
2260Sstevel@tonic-gate    stored in *(struct[2]), the array index which was specified is
2270Sstevel@tonic-gate    stored in *index, and long_getopt() returns 0. */
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate struct option long_options[] = {
2300Sstevel@tonic-gate     { "noforwardable", 0, NULL, 'F' },
2310Sstevel@tonic-gate     { "noproxiable", 0, NULL, 'P' },
2320Sstevel@tonic-gate     { "addresses", 0, NULL, 'a'},
2330Sstevel@tonic-gate     { "forwardable", 0, NULL, 'f' },
2340Sstevel@tonic-gate     { "proxiable", 0, NULL, 'p' },
2350Sstevel@tonic-gate     { "noaddresses", 0, NULL, 'A' },
2360Sstevel@tonic-gate     { NULL, 0, NULL, 0 }
2370Sstevel@tonic-gate };
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate #define GETOPT(argc, argv, str) getopt_long(argc, argv, str, long_options, 0)
240*7934SMark.Phalan@Sun.COM #else
2410Sstevel@tonic-gate #define GETOPT(argc, argv, str) getopt(argc, argv, str)
242*7934SMark.Phalan@Sun.COM #endif
2430Sstevel@tonic-gate 
2442881Smp153739 static void
usage(progname)2452881Smp153739 usage(progname)
246*7934SMark.Phalan@Sun.COM      char *progname;
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate #define USAGE_BREAK "\n\t"
2492881Smp153739 
2500Sstevel@tonic-gate #ifdef GETOPT_LONG
2510Sstevel@tonic-gate #define USAGE_LONG_FORWARDABLE " | --forwardable | --noforwardable"
2520Sstevel@tonic-gate #define USAGE_LONG_PROXIABLE   " | --proxiable | --noproxiable"
2530Sstevel@tonic-gate #define USAGE_LONG_ADDRESSES   " | --addresses | --noaddresses"
2540Sstevel@tonic-gate #define USAGE_BREAK_LONG       USAGE_BREAK
255*7934SMark.Phalan@Sun.COM #else
2560Sstevel@tonic-gate #define USAGE_LONG_FORWARDABLE ""
2570Sstevel@tonic-gate #define USAGE_LONG_PROXIABLE   ""
2580Sstevel@tonic-gate #define USAGE_LONG_ADDRESSES   ""
2590Sstevel@tonic-gate #define USAGE_BREAK_LONG       ""
260*7934SMark.Phalan@Sun.COM #endif
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate     fprintf(stderr, "%s : %s  [-V] "
2630Sstevel@tonic-gate 	    "[-l lifetime] [-s start_time] "
2640Sstevel@tonic-gate 	    USAGE_BREAK
2650Sstevel@tonic-gate 	    "[-r renewable_life] "
2660Sstevel@tonic-gate 	    "[-f | -F" USAGE_LONG_FORWARDABLE "] "
2670Sstevel@tonic-gate 	    USAGE_BREAK_LONG
2680Sstevel@tonic-gate 	    "[-p | -P" USAGE_LONG_PROXIABLE "] "
2690Sstevel@tonic-gate 	    USAGE_BREAK_LONG
2702881Smp153739 	    "[-a | -A" USAGE_LONG_ADDRESSES "] "
2710Sstevel@tonic-gate 	    USAGE_BREAK
2720Sstevel@tonic-gate 	    "[-v] [-R] "
2730Sstevel@tonic-gate 	    "[-k [-t keytab_file]] "
274*7934SMark.Phalan@Sun.COM 	    "[-c cachename] "
2750Sstevel@tonic-gate 	    USAGE_BREAK
276*7934SMark.Phalan@Sun.COM 	    "[-S service_name]"
277*7934SMark.Phalan@Sun.COM 	    "[-X <attribute>[=<value>]] [principal]"
2780Sstevel@tonic-gate 	    "\n\n",
2790Sstevel@tonic-gate 	    gettext("Usage"), progname);
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate #define KRB_AVAIL_STRING(x) ((x)?gettext("available"):gettext("not available"))
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate #define OPTTYPE_KRB5   "5"
2840Sstevel@tonic-gate #define OPTTYPE_KRB4   "4"
2850Sstevel@tonic-gate #define OPTTYPE_EITHER "Either 4 or 5"
2860Sstevel@tonic-gate #ifdef HAVE_KRB524
2870Sstevel@tonic-gate #define OPTTYPE_BOTH "5, or both 5 and 4"
2880Sstevel@tonic-gate #else
2890Sstevel@tonic-gate #define OPTTYPE_BOTH "5"
2900Sstevel@tonic-gate #endif
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
2930Sstevel@tonic-gate #define USAGE_OPT_FMT "%s%-50s%s\n"
2942881Smp153739 #define ULINE(indent, col1, col2) \
2952881Smp153739 fprintf(stderr, USAGE_OPT_FMT, indent, col1, col2)
2960Sstevel@tonic-gate #else
2970Sstevel@tonic-gate #define USAGE_OPT_FMT "%s%s\n"
2982881Smp153739 #define ULINE(indent, col1, col2) \
2992881Smp153739 fprintf(stderr, USAGE_OPT_FMT, indent, col1)
3000Sstevel@tonic-gate #endif
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate     ULINE("    ", "options:", "valid with Kerberos:");
3030Sstevel@tonic-gate     fprintf(stderr, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5));
3040Sstevel@tonic-gate     fprintf(stderr, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4));
3050Sstevel@tonic-gate     fprintf(stderr, "\t   (Default behavior is to try %s%s%s%s)\n",
3060Sstevel@tonic-gate 	    default_k5?"Kerberos 5":"",
3070Sstevel@tonic-gate 	    (default_k5 && default_k4)?gettext(" and "):"",
3080Sstevel@tonic-gate 	    default_k4?"Kerberos 4":"",
3090Sstevel@tonic-gate 	    (!default_k5 && !default_k4)?gettext("neither"):"");
3100Sstevel@tonic-gate     ULINE("\t", gettext("-V verbose"),                   OPTTYPE_EITHER);
3110Sstevel@tonic-gate     ULINE("\t", gettext("-l lifetime"),                  OPTTYPE_EITHER);
3120Sstevel@tonic-gate     ULINE("\t", gettext("-s start time"),                OPTTYPE_KRB5);
3130Sstevel@tonic-gate     ULINE("\t", gettext("-r renewable lifetime"),        OPTTYPE_KRB5);
3140Sstevel@tonic-gate     ULINE("\t", gettext("-f forwardable"),               OPTTYPE_KRB5);
3150Sstevel@tonic-gate     ULINE("\t", gettext("-F not forwardable"),           OPTTYPE_KRB5);
3160Sstevel@tonic-gate     ULINE("\t", gettext("-p proxiable"),                 OPTTYPE_KRB5);
3170Sstevel@tonic-gate     ULINE("\t", gettext("-P not proxiable"),             OPTTYPE_KRB5);
3180Sstevel@tonic-gate     ULINE("\t", gettext("-A do not include addresses"),  OPTTYPE_KRB5);
3192881Smp153739     ULINE("\t", gettext("-a include addresses"),         OPTTYPE_KRB5);
3200Sstevel@tonic-gate     ULINE("\t", gettext("-v validate"),                  OPTTYPE_KRB5);
3210Sstevel@tonic-gate     ULINE("\t", gettext("-R renew"),                     OPTTYPE_BOTH);
3220Sstevel@tonic-gate     ULINE("\t", gettext("-k use keytab"),                OPTTYPE_BOTH);
3230Sstevel@tonic-gate     ULINE("\t", gettext("-t filename of keytab to use"), OPTTYPE_BOTH);
3240Sstevel@tonic-gate     ULINE("\t", gettext("-c Kerberos 5 cache name"),     OPTTYPE_KRB5);
3250Sstevel@tonic-gate     /* This options is not yet available: */
3260Sstevel@tonic-gate     /* ULINE("\t", "-C Kerberos 4 cache name",     OPTTYPE_KRB4); */
3270Sstevel@tonic-gate     ULINE("\t", gettext("-S service"),                   OPTTYPE_BOTH);
328*7934SMark.Phalan@Sun.COM     ULINE("\t", gettext("-X <attribute>[=<value>]"),     OPTTYPE_KRB5);
3290Sstevel@tonic-gate     exit(2);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
332*7934SMark.Phalan@Sun.COM static krb5_context errctx;
extended_com_err_fn(const char * myprog,errcode_t code,const char * fmt,va_list args)333*7934SMark.Phalan@Sun.COM static void extended_com_err_fn (const char *myprog, errcode_t code,
334*7934SMark.Phalan@Sun.COM 				 const char *fmt, va_list args)
335*7934SMark.Phalan@Sun.COM {
336*7934SMark.Phalan@Sun.COM     const char *emsg;
337*7934SMark.Phalan@Sun.COM     emsg = krb5_get_error_message (errctx, code);
338*7934SMark.Phalan@Sun.COM     fprintf (stderr, "%s: %s ", myprog, emsg);
339*7934SMark.Phalan@Sun.COM     krb5_free_error_message (errctx, emsg);
340*7934SMark.Phalan@Sun.COM     vfprintf (stderr, fmt, args);
341*7934SMark.Phalan@Sun.COM     fprintf (stderr, "\n");
342*7934SMark.Phalan@Sun.COM }
343*7934SMark.Phalan@Sun.COM 
344*7934SMark.Phalan@Sun.COM static int
add_preauth_opt(struct k_opts * opts,char * av)345*7934SMark.Phalan@Sun.COM add_preauth_opt(struct k_opts *opts, char *av)
346*7934SMark.Phalan@Sun.COM {
347*7934SMark.Phalan@Sun.COM     char *sep, *v;
348*7934SMark.Phalan@Sun.COM     krb5_gic_opt_pa_data *p, *x;
349*7934SMark.Phalan@Sun.COM 
350*7934SMark.Phalan@Sun.COM     if (opts->num_pa_opts == 0) {
351*7934SMark.Phalan@Sun.COM 	opts->pa_opts = malloc(sizeof(krb5_gic_opt_pa_data));
352*7934SMark.Phalan@Sun.COM 	if (opts->pa_opts == NULL)
353*7934SMark.Phalan@Sun.COM 	    return ENOMEM;
354*7934SMark.Phalan@Sun.COM     } else {
355*7934SMark.Phalan@Sun.COM 	size_t newsize = (opts->num_pa_opts + 1) * sizeof(krb5_gic_opt_pa_data);
356*7934SMark.Phalan@Sun.COM 	x = realloc(opts->pa_opts, newsize);
357*7934SMark.Phalan@Sun.COM 	if (x == NULL)
358*7934SMark.Phalan@Sun.COM 	    return ENOMEM;
359*7934SMark.Phalan@Sun.COM 	opts->pa_opts = x;
360*7934SMark.Phalan@Sun.COM     }
361*7934SMark.Phalan@Sun.COM     p = &opts->pa_opts[opts->num_pa_opts];
362*7934SMark.Phalan@Sun.COM     sep = strchr(av, '=');
363*7934SMark.Phalan@Sun.COM     if (sep) {
364*7934SMark.Phalan@Sun.COM 	*sep = '\0';
365*7934SMark.Phalan@Sun.COM 	v = ++sep;
366*7934SMark.Phalan@Sun.COM 	p->value = v;
367*7934SMark.Phalan@Sun.COM     } else {
368*7934SMark.Phalan@Sun.COM 	p->value = "yes";
369*7934SMark.Phalan@Sun.COM     }
370*7934SMark.Phalan@Sun.COM     p->attr = av;
371*7934SMark.Phalan@Sun.COM     opts->num_pa_opts++;
372*7934SMark.Phalan@Sun.COM     return 0;
373*7934SMark.Phalan@Sun.COM }
374*7934SMark.Phalan@Sun.COM 
3752881Smp153739 static char *
parse_options(argc,argv,opts,progname)3762881Smp153739 parse_options(argc, argv, opts, progname)
3770Sstevel@tonic-gate     int argc;
3780Sstevel@tonic-gate     char **argv;
3790Sstevel@tonic-gate     struct k_opts* opts;
3802881Smp153739     char *progname;
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate     krb5_error_code code;
3830Sstevel@tonic-gate     int errflg = 0;
3840Sstevel@tonic-gate     int use_k4 = 0;
3850Sstevel@tonic-gate     int use_k5 = 0;
3860Sstevel@tonic-gate     int i;
3870Sstevel@tonic-gate 
388*7934SMark.Phalan@Sun.COM     while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:RS:vX:"))
3890Sstevel@tonic-gate 	   != -1) {
3900Sstevel@tonic-gate 	switch (i) {
3910Sstevel@tonic-gate 	case 'V':
3920Sstevel@tonic-gate 	    opts->verbose = 1;
3930Sstevel@tonic-gate 	    break;
3940Sstevel@tonic-gate 	case 'l':
3950Sstevel@tonic-gate 	    /* Lifetime */
3960Sstevel@tonic-gate 	    code = krb5_string_to_deltat(optarg, &opts->lifetime);
3970Sstevel@tonic-gate 	    if (code != 0 || opts->lifetime == 0) {
3980Sstevel@tonic-gate 		fprintf(stderr, gettext("Bad lifetime value %s\n"), optarg);
3990Sstevel@tonic-gate 		errflg++;
4000Sstevel@tonic-gate 	    }
4010Sstevel@tonic-gate 	    break;
4020Sstevel@tonic-gate 	case 'r':
4030Sstevel@tonic-gate 	    /* Renewable Time */
4040Sstevel@tonic-gate 	    code = krb5_string_to_deltat(optarg, &opts->rlife);
4050Sstevel@tonic-gate 	    if (code != 0 || opts->rlife == 0) {
4060Sstevel@tonic-gate 		fprintf(stderr, gettext("Bad lifetime value %s\n"), optarg);
4070Sstevel@tonic-gate 		errflg++;
4080Sstevel@tonic-gate 	    }
4090Sstevel@tonic-gate 	    break;
4100Sstevel@tonic-gate 	case 'f':
4110Sstevel@tonic-gate 	    opts->forwardable = 1;
4120Sstevel@tonic-gate 	    break;
4130Sstevel@tonic-gate 	case 'F':
4140Sstevel@tonic-gate 	    opts->not_forwardable = 1;
4150Sstevel@tonic-gate 	    break;
4160Sstevel@tonic-gate 	case 'p':
4170Sstevel@tonic-gate 	    opts->proxiable = 1;
4180Sstevel@tonic-gate 	    break;
4190Sstevel@tonic-gate 	case 'P':
4200Sstevel@tonic-gate 	    opts->not_proxiable = 1;
4210Sstevel@tonic-gate 	    break;
4220Sstevel@tonic-gate 	case 'a':
4230Sstevel@tonic-gate 	    /* Note: This is supported only with GETOPT_LONG */
4240Sstevel@tonic-gate 	    opts->addresses = 1;
4250Sstevel@tonic-gate 	    break;
4260Sstevel@tonic-gate 	case 'A':
4270Sstevel@tonic-gate 	    opts->no_addresses = 1;
4280Sstevel@tonic-gate 	    break;
4290Sstevel@tonic-gate        	case 's':
4300Sstevel@tonic-gate 	    code = krb5_string_to_deltat(optarg, &opts->starttime);
4310Sstevel@tonic-gate 	    if (code != 0 || opts->starttime == 0) {
4320Sstevel@tonic-gate 		krb5_timestamp abs_starttime;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 		code = krb5_string_to_timestamp(optarg, &abs_starttime);
4350Sstevel@tonic-gate 		if (code != 0 || abs_starttime == 0) {
4360Sstevel@tonic-gate 		    fprintf(stderr, gettext("Bad start time value %s\n"), optarg);
4370Sstevel@tonic-gate 		    errflg++;
4380Sstevel@tonic-gate 		} else {
4390Sstevel@tonic-gate 		    opts->starttime = abs_starttime - time(0);
4400Sstevel@tonic-gate 		}
4410Sstevel@tonic-gate 	    }
4420Sstevel@tonic-gate 	    break;
4430Sstevel@tonic-gate 	case 'S':
4440Sstevel@tonic-gate 	    opts->service_name = optarg;
4450Sstevel@tonic-gate 	    break;
4460Sstevel@tonic-gate 	case 'k':
4470Sstevel@tonic-gate 	    opts->action = INIT_KT;
4480Sstevel@tonic-gate 	    break;
4490Sstevel@tonic-gate 	case 't':
4500Sstevel@tonic-gate 	    if (opts->keytab_name)
4510Sstevel@tonic-gate 	    {
4520Sstevel@tonic-gate 		fprintf(stderr, gettext("Only one -t option allowed.\n"));
4530Sstevel@tonic-gate 		errflg++;
4540Sstevel@tonic-gate 	    } else {
4550Sstevel@tonic-gate 		opts->keytab_name = optarg;
4560Sstevel@tonic-gate 	    }
4570Sstevel@tonic-gate 	    break;
4580Sstevel@tonic-gate 	case 'R':
4590Sstevel@tonic-gate 	    opts->action = RENEW;
4600Sstevel@tonic-gate 	    break;
4610Sstevel@tonic-gate 	case 'v':
4620Sstevel@tonic-gate 	    opts->action = VALIDATE;
4630Sstevel@tonic-gate 	    break;
4640Sstevel@tonic-gate        	case 'c':
4650Sstevel@tonic-gate 	    if (opts->k5_cache_name)
4660Sstevel@tonic-gate 	    {
4670Sstevel@tonic-gate 		fprintf(stderr, gettext("Only one -c option allowed\n"));
4680Sstevel@tonic-gate 		errflg++;
4690Sstevel@tonic-gate 	    } else {
4700Sstevel@tonic-gate 		opts->k5_cache_name = optarg;
4710Sstevel@tonic-gate 	    }
4720Sstevel@tonic-gate 	    break;
473*7934SMark.Phalan@Sun.COM 	case 'X':
474*7934SMark.Phalan@Sun.COM 	    code = add_preauth_opt(opts, optarg);
475*7934SMark.Phalan@Sun.COM 	    if (code)
476*7934SMark.Phalan@Sun.COM 	    {
477*7934SMark.Phalan@Sun.COM 		com_err(progname, code, "while adding preauth option");
478*7934SMark.Phalan@Sun.COM 		errflg++;
479*7934SMark.Phalan@Sun.COM 	    }
480*7934SMark.Phalan@Sun.COM 	    break;
4810Sstevel@tonic-gate #if 0
4820Sstevel@tonic-gate 	    /*
4830Sstevel@tonic-gate 	      A little more work is needed before we can enable this
4840Sstevel@tonic-gate 	      option.
4850Sstevel@tonic-gate 	    */
4860Sstevel@tonic-gate 	case 'C':
4870Sstevel@tonic-gate 	    if (opts->k4_cache_name)
4880Sstevel@tonic-gate 	    {
4890Sstevel@tonic-gate 		fprintf(stderr, "Only one -C option allowed\n");
4900Sstevel@tonic-gate 		errflg++;
4910Sstevel@tonic-gate 	    } else {
4920Sstevel@tonic-gate 		opts->k4_cache_name = optarg;
4930Sstevel@tonic-gate 	    }
4940Sstevel@tonic-gate 	    break;
4950Sstevel@tonic-gate #endif
4960Sstevel@tonic-gate 	case '4':
4970Sstevel@tonic-gate 	    if (!got_k4)
4980Sstevel@tonic-gate 	    {
4990Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
5000Sstevel@tonic-gate 		fprintf(stderr, "Kerberos 4 support could not be loaded\n");
5010Sstevel@tonic-gate #else
5020Sstevel@tonic-gate 		fprintf(stderr, gettext("This was not built with Kerberos 4 support\n"));
5030Sstevel@tonic-gate #endif
5040Sstevel@tonic-gate 		exit(3);
5050Sstevel@tonic-gate 	    }
5060Sstevel@tonic-gate 	    use_k4 = 1;
5070Sstevel@tonic-gate 	    break;
5080Sstevel@tonic-gate 	case '5':
5090Sstevel@tonic-gate 	    if (!got_k5)
5100Sstevel@tonic-gate 	    {
5110Sstevel@tonic-gate 		fprintf(stderr, gettext("Kerberos 5 support could not be loaded\n"));
5120Sstevel@tonic-gate 		exit(3);
5130Sstevel@tonic-gate 	    }
5140Sstevel@tonic-gate 	    use_k5 = 1;
5150Sstevel@tonic-gate 	    break;
5160Sstevel@tonic-gate 	default:
5170Sstevel@tonic-gate 	    errflg++;
5180Sstevel@tonic-gate 	    break;
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate     }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate     if (opts->forwardable && opts->not_forwardable)
5230Sstevel@tonic-gate     {
5240Sstevel@tonic-gate 	fprintf(stderr, gettext("Only one of -f and -F allowed\n"));
5250Sstevel@tonic-gate 	errflg++;
5260Sstevel@tonic-gate     }
5270Sstevel@tonic-gate     if (opts->proxiable && opts->not_proxiable)
5280Sstevel@tonic-gate     {
5290Sstevel@tonic-gate 	fprintf(stderr, gettext("Only one of -p and -P allowed\n"));
5300Sstevel@tonic-gate 	errflg++;
5310Sstevel@tonic-gate     }
5320Sstevel@tonic-gate     if (opts->addresses && opts->no_addresses)
5330Sstevel@tonic-gate     {
5340Sstevel@tonic-gate 	fprintf(stderr, gettext("Only one of -a and -A allowed\n"));
5350Sstevel@tonic-gate 	errflg++;
5360Sstevel@tonic-gate     }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate     if (argc - optind > 1) {
5390Sstevel@tonic-gate 	fprintf(stderr, gettext("Extra arguments (starting with \"%s\").\n"),
5400Sstevel@tonic-gate 		argv[optind+1]);
5410Sstevel@tonic-gate 	errflg++;
5420Sstevel@tonic-gate     }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate     /* At this point, if errorless, we know we only have one option
5450Sstevel@tonic-gate        selection */
5460Sstevel@tonic-gate     if (!use_k5 && !use_k4) {
5470Sstevel@tonic-gate 	use_k5 = default_k5;
5480Sstevel@tonic-gate 	use_k4 = default_k4;
5490Sstevel@tonic-gate     }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate     /* Now, we encode the OPTTYPE stuff here... */
5520Sstevel@tonic-gate     if (!use_k5 &&
5530Sstevel@tonic-gate 	(opts->starttime || opts->rlife || opts->forwardable ||
5540Sstevel@tonic-gate 	 opts->proxiable || opts->addresses || opts->not_forwardable ||
5550Sstevel@tonic-gate 	 opts->not_proxiable || opts->no_addresses ||
5560Sstevel@tonic-gate 	 (opts->action == VALIDATE) || opts->k5_cache_name))
5570Sstevel@tonic-gate     {
5580Sstevel@tonic-gate 	fprintf(stderr, gettext("Specified option that requires Kerberos 5\n"));
5590Sstevel@tonic-gate 	errflg++;
5600Sstevel@tonic-gate     }
5610Sstevel@tonic-gate     if (!use_k4 &&
5620Sstevel@tonic-gate 	opts->k4_cache_name)
5630Sstevel@tonic-gate     {
5640Sstevel@tonic-gate 	fprintf(stderr, gettext("Specified option that require Kerberos 4\n"));
5650Sstevel@tonic-gate 	errflg++;
5660Sstevel@tonic-gate     }
5670Sstevel@tonic-gate     if (
5680Sstevel@tonic-gate #ifdef HAVE_KRB524
5690Sstevel@tonic-gate 	!use_k5
5700Sstevel@tonic-gate #else
5710Sstevel@tonic-gate 	use_k4
5720Sstevel@tonic-gate #endif
5730Sstevel@tonic-gate 	&& (opts->service_name || opts->keytab_name ||
5740Sstevel@tonic-gate 	    (opts->action == INIT_KT) || (opts->action == RENEW))
5750Sstevel@tonic-gate 	)
5760Sstevel@tonic-gate     {
5770Sstevel@tonic-gate 	fprintf(stderr, gettext("Specified option that requires Kerberos 5\n"));
5780Sstevel@tonic-gate 	errflg++;
5790Sstevel@tonic-gate     }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate     if (errflg) {
5822881Smp153739 	usage(progname);
5830Sstevel@tonic-gate     }
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate     got_k5 = got_k5 && use_k5;
5860Sstevel@tonic-gate     got_k4 = got_k4 && use_k4;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate     opts->principal_name = (optind == argc-1) ? argv[optind] : 0;
5890Sstevel@tonic-gate     return opts->principal_name;
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5922881Smp153739 static int
k5_begin(opts,k5,k4)5930Sstevel@tonic-gate k5_begin(opts, k5, k4)
5940Sstevel@tonic-gate     struct k_opts* opts;
5950Sstevel@tonic-gate struct k5_data* k5;
5960Sstevel@tonic-gate struct k4_data* k4;
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate     char* progname = progname_v5;
5990Sstevel@tonic-gate     krb5_error_code code = 0;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate     if (!got_k5)
6020Sstevel@tonic-gate 	return 0;
6030Sstevel@tonic-gate 
6042881Smp153739     code = krb5_init_context(&k5->ctx);
6052881Smp153739     if (code) {
6060Sstevel@tonic-gate 	com_err(progname, code, gettext("while initializing Kerberos 5 library"));
6070Sstevel@tonic-gate 	return 0;
6080Sstevel@tonic-gate     }
609*7934SMark.Phalan@Sun.COM     errctx = k5->ctx;
6100Sstevel@tonic-gate     if (opts->k5_cache_name)
6110Sstevel@tonic-gate     {
6120Sstevel@tonic-gate 	code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc);
6130Sstevel@tonic-gate 	if (code != 0) {
6140Sstevel@tonic-gate 	    com_err(progname, code, gettext("resolving ccache %s"),
6150Sstevel@tonic-gate 		    opts->k5_cache_name);
6160Sstevel@tonic-gate 	    return 0;
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate     }
6190Sstevel@tonic-gate     else
6200Sstevel@tonic-gate     {
6210Sstevel@tonic-gate 	if ((code = krb5_cc_default(k5->ctx, &k5->cc))) {
6220Sstevel@tonic-gate 	    com_err(progname, code, gettext("while getting default ccache"));
6230Sstevel@tonic-gate 	    return 0;
6240Sstevel@tonic-gate 	}
6250Sstevel@tonic-gate     }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate     if (opts->principal_name)
6280Sstevel@tonic-gate     {
6290Sstevel@tonic-gate 	/* Use specified name */
6300Sstevel@tonic-gate 	if ((code = krb5_parse_name(k5->ctx, opts->principal_name,
6310Sstevel@tonic-gate 				    &k5->me))) {
6320Sstevel@tonic-gate 	    com_err(progname, code, gettext("when parsing name %s"),
6330Sstevel@tonic-gate 		    opts->principal_name);
6340Sstevel@tonic-gate 	    return 0;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate     }
6370Sstevel@tonic-gate     else
6380Sstevel@tonic-gate     {
6390Sstevel@tonic-gate 	/* No principal name specified */
6400Sstevel@tonic-gate 	if (opts->action == INIT_KT) {
6410Sstevel@tonic-gate 	    /* Use the default host/service name */
6422881Smp153739 	  code = krb5_sname_to_principal(k5->ctx, NULL, NULL,
6432881Smp153739 					 KRB5_NT_SRV_HST, &k5->me);
6442881Smp153739 	  if (code) {
6452881Smp153739 	    com_err(progname, code, gettext(
6462881Smp153739 		    "when creating default server principal name"));
6472881Smp153739 	    return 0;
6482881Smp153739 	  }
6490Sstevel@tonic-gate 	} else {
6502881Smp153739 	  /* Get default principal from cache if one exists */
6512881Smp153739 	  code = krb5_cc_get_principal(k5->ctx, k5->cc,
6522881Smp153739 				       &k5->me);
6532881Smp153739 	  if (code)
6542881Smp153739 	    {
6552881Smp153739 	      char *name = get_name_from_os();
6562881Smp153739 	      if (!name)
6572881Smp153739 		{
6582881Smp153739 		  fprintf(stderr, gettext("Unable to identify user\n"));
6592881Smp153739 		  return 0;
6602881Smp153739 		}
6610Sstevel@tonic-gate                 /* use strcmp to ensure only "root" is matched */
6620Sstevel@tonic-gate                 if (strcmp(name, ROOT_UNAME) == 0)
6630Sstevel@tonic-gate                 {
6640Sstevel@tonic-gate                 	if (code = krb5_sname_to_principal(k5->ctx, NULL, ROOT_UNAME,
6650Sstevel@tonic-gate 				    KRB5_NT_SRV_HST, &k5->me)) {
6660Sstevel@tonic-gate 			    com_err(progname, code, gettext(
6670Sstevel@tonic-gate 				"when creating default server principal name"));
6680Sstevel@tonic-gate                                 return 0;
6690Sstevel@tonic-gate                         }
6702881Smp153739                 } else
6712881Smp153739 	      if ((code = krb5_parse_name(k5->ctx, name,
6722881Smp153739 					  &k5->me)))
6732881Smp153739 		{
6742881Smp153739 		  com_err(progname, code, gettext("when parsing name %s"),
6752881Smp153739 			  name);
6762881Smp153739 		  return 0;
6770Sstevel@tonic-gate 		}
6782881Smp153739 	    }
6792881Smp153739 	}
6800Sstevel@tonic-gate     }
6812881Smp153739 
6822881Smp153739     code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
6832881Smp153739     if (code) {
6840Sstevel@tonic-gate 	com_err(progname, code, gettext("when unparsing name"));
6850Sstevel@tonic-gate 	return 0;
6860Sstevel@tonic-gate     }
6870Sstevel@tonic-gate     opts->principal_name = k5->name;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
6900Sstevel@tonic-gate     if (got_k4)
6910Sstevel@tonic-gate     {
6920Sstevel@tonic-gate 	/* Translate to a Kerberos 4 principal */
6930Sstevel@tonic-gate 	code = krb5_524_conv_principal(k5->ctx, k5->me,
6940Sstevel@tonic-gate 				       k4->aname, k4->inst, k4->realm);
6950Sstevel@tonic-gate 	if (code) {
6960Sstevel@tonic-gate 	    k4->aname[0] = 0;
6970Sstevel@tonic-gate 	    k4->inst[0] = 0;
6980Sstevel@tonic-gate 	    k4->realm[0] = 0;
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate     }
7010Sstevel@tonic-gate #endif
7020Sstevel@tonic-gate     return 1;
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate 
7052881Smp153739 static void
k5_end(k5)7060Sstevel@tonic-gate k5_end(k5)
7070Sstevel@tonic-gate     struct k5_data* k5;
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate     if (k5->name)
7100Sstevel@tonic-gate 	krb5_free_unparsed_name(k5->ctx, k5->name);
7110Sstevel@tonic-gate     if (k5->me)
7120Sstevel@tonic-gate 	krb5_free_principal(k5->ctx, k5->me);
7130Sstevel@tonic-gate     if (k5->cc)
7140Sstevel@tonic-gate 	krb5_cc_close(k5->ctx, k5->cc);
7150Sstevel@tonic-gate     if (k5->ctx)
7160Sstevel@tonic-gate 	krb5_free_context(k5->ctx);
717*7934SMark.Phalan@Sun.COM     errctx = NULL;
7180Sstevel@tonic-gate     memset(k5, 0, sizeof(*k5));
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7212881Smp153739 static int
k4_begin(opts,k4)7220Sstevel@tonic-gate k4_begin(opts, k4)
7230Sstevel@tonic-gate     struct k_opts* opts;
7240Sstevel@tonic-gate     struct k4_data* k4;
7250Sstevel@tonic-gate {
7260Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
7270Sstevel@tonic-gate     char* progname = progname_v4;
7280Sstevel@tonic-gate     int k_errno = 0;
7290Sstevel@tonic-gate #endif
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate     if (!got_k4)
7320Sstevel@tonic-gate 	return 0;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
7350Sstevel@tonic-gate     if (k4->aname[0])
7360Sstevel@tonic-gate 	goto skip;
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate     if (opts->principal_name)
7390Sstevel@tonic-gate     {
7400Sstevel@tonic-gate 	/* Use specified name */
7412881Smp153739         k_errno = kname_parse(k4->aname, k4->inst, k4->realm,
7422881Smp153739 			      opts->principal_name);
7432881Smp153739 	if (k_errno)
7440Sstevel@tonic-gate 	{
7450Sstevel@tonic-gate 	    fprintf(stderr, "%s: %s\n", progname,
7460Sstevel@tonic-gate 		    krb_get_err_text(k_errno));
7470Sstevel@tonic-gate 	    return 0;
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate     } else {
7500Sstevel@tonic-gate 	/* No principal name specified */
7510Sstevel@tonic-gate 	if (opts->action == INIT_KT) {
7520Sstevel@tonic-gate 	    /* Use the default host/service name */
7530Sstevel@tonic-gate 	    /* XXX - need to add this functionality */
7540Sstevel@tonic-gate 	    fprintf(stderr, "%s: Kerberos 4 srvtab support is not "
7550Sstevel@tonic-gate 		    "implemented\n", progname);
7560Sstevel@tonic-gate 	    return 0;
7570Sstevel@tonic-gate 	} else {
7580Sstevel@tonic-gate 	    /* Get default principal from cache if one exists */
7592881Smp153739 	    k_errno = krb_get_tf_fullname(tkt_string(), k4->aname,
7602881Smp153739 					  k4->inst, k4->realm);
7612881Smp153739 	    if (k_errno)
7620Sstevel@tonic-gate 	    {
7630Sstevel@tonic-gate 		char *name = get_name_from_os();
7640Sstevel@tonic-gate 		if (!name)
7650Sstevel@tonic-gate 		{
7660Sstevel@tonic-gate 		    fprintf(stderr, "Unable to identify user\n");
7670Sstevel@tonic-gate 		    return 0;
7680Sstevel@tonic-gate 		}
7692881Smp153739 		k_errno = kname_parse(k4->aname, k4->inst, k4->realm,
7702881Smp153739 				      name);
7712881Smp153739 		if (k_errno)
7720Sstevel@tonic-gate 		{
7730Sstevel@tonic-gate 		    fprintf(stderr, "%s: %s\n", progname,
7740Sstevel@tonic-gate 			    krb_get_err_text(k_errno));
7750Sstevel@tonic-gate 		    return 0;
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 	    }
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate     }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate     if (!k4->realm[0])
7820Sstevel@tonic-gate 	krb_get_lrealm(k4->realm, 1);
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate     if (k4->inst[0])
7850Sstevel@tonic-gate 	sprintf(k4->name, "%s.%s@%s", k4->aname, k4->inst, k4->realm);
7860Sstevel@tonic-gate     else
7870Sstevel@tonic-gate 	sprintf(k4->name, "%s@%s", k4->aname, k4->realm);
7880Sstevel@tonic-gate     opts->principal_name = k4->name;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate  skip:
7910Sstevel@tonic-gate     if (k4->aname[0] && !k_isname(k4->aname))
7920Sstevel@tonic-gate     {
7930Sstevel@tonic-gate 	fprintf(stderr, "%s: bad Kerberos 4 name format\n", progname);
7940Sstevel@tonic-gate 	return 0;
7950Sstevel@tonic-gate     }
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate     if (k4->inst[0] && !k_isinst(k4->inst))
7980Sstevel@tonic-gate     {
7990Sstevel@tonic-gate 	fprintf(stderr, "%s: bad Kerberos 4 instance format\n", progname);
8000Sstevel@tonic-gate 	return 0;
8010Sstevel@tonic-gate     }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate     if (k4->realm[0] && !k_isrealm(k4->realm))
8040Sstevel@tonic-gate     {
8050Sstevel@tonic-gate 	fprintf(stderr, "%s: bad Kerberos 4 realm format\n", progname);
8060Sstevel@tonic-gate 	return 0;
8070Sstevel@tonic-gate     }
8080Sstevel@tonic-gate #endif /* KRB5_KRB4_COMPAT */
8090Sstevel@tonic-gate     return 1;
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate 
8122881Smp153739 static void
k4_end(k4)8130Sstevel@tonic-gate k4_end(k4)
8140Sstevel@tonic-gate     struct k4_data* k4;
8150Sstevel@tonic-gate {
8160Sstevel@tonic-gate     memset(k4, 0, sizeof(*k4));
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
8200Sstevel@tonic-gate static char stash_password[1024];
8210Sstevel@tonic-gate static int got_password = 0;
8220Sstevel@tonic-gate #endif /* KRB5_KRB4_COMPAT */
8230Sstevel@tonic-gate 
8242881Smp153739 static krb5_error_code
8250Sstevel@tonic-gate KRB5_CALLCONV
kinit_prompter(krb5_context ctx,void * data,const char * name,const char * banner,int num_prompts,krb5_prompt prompts[])8260Sstevel@tonic-gate kinit_prompter(
8270Sstevel@tonic-gate     krb5_context ctx,
8280Sstevel@tonic-gate     void *data,
8290Sstevel@tonic-gate     const char *name,
8300Sstevel@tonic-gate     const char *banner,
8310Sstevel@tonic-gate     int num_prompts,
8320Sstevel@tonic-gate     krb5_prompt prompts[]
8330Sstevel@tonic-gate     )
8340Sstevel@tonic-gate {
8350Sstevel@tonic-gate     int i;
8360Sstevel@tonic-gate     krb5_prompt_type *types;
8370Sstevel@tonic-gate     krb5_error_code rc =
8380Sstevel@tonic-gate 	krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts);
8390Sstevel@tonic-gate     if (!rc && (types = krb5_get_prompt_types(ctx)))
8400Sstevel@tonic-gate 	for (i = 0; i < num_prompts; i++)
8410Sstevel@tonic-gate 	    if ((types[i] == KRB5_PROMPT_TYPE_PASSWORD) ||
8420Sstevel@tonic-gate 		(types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN))
8430Sstevel@tonic-gate 	    {
8440Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
8450Sstevel@tonic-gate 		strncpy(stash_password, prompts[i].reply->data,
8460Sstevel@tonic-gate 			sizeof(stash_password));
8470Sstevel@tonic-gate 		got_password = 1;
8480Sstevel@tonic-gate #endif
8490Sstevel@tonic-gate 	    }
8500Sstevel@tonic-gate     return rc;
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate 
8532881Smp153739 static int
k5_kinit(opts,k5)8540Sstevel@tonic-gate k5_kinit(opts, k5)
8550Sstevel@tonic-gate     struct k_opts* opts;
8560Sstevel@tonic-gate     struct k5_data* k5;
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate     char* progname = progname_v5;
8590Sstevel@tonic-gate     int notix = 1;
8600Sstevel@tonic-gate     krb5_keytab keytab = 0;
8610Sstevel@tonic-gate     krb5_creds my_creds;
8620Sstevel@tonic-gate     krb5_error_code code = 0;
863*7934SMark.Phalan@Sun.COM     krb5_get_init_creds_opt *options = NULL;
864*7934SMark.Phalan@Sun.COM     int i;
8650Sstevel@tonic-gate     krb5_timestamp now;
8660Sstevel@tonic-gate     krb5_deltat lifetime = 0, rlife = 0, krb5_max_duration;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate     if (!got_k5)
8690Sstevel@tonic-gate 	return 0;
8700Sstevel@tonic-gate 
871*7934SMark.Phalan@Sun.COM     code = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
872*7934SMark.Phalan@Sun.COM     if (code)
873*7934SMark.Phalan@Sun.COM 	goto cleanup;
8740Sstevel@tonic-gate     memset(&my_creds, 0, sizeof(my_creds));
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate     /*
8770Sstevel@tonic-gate      * Solaris Kerberos: added support for max_life and max_renewable_life
8780Sstevel@tonic-gate      * which should be removed in the next minor release.  See PSARC 2003/545
8790Sstevel@tonic-gate      * for more info.
8800Sstevel@tonic-gate      *
8810Sstevel@tonic-gate      * Also, check krb5.conf for proxiable/forwardable/renewable/no_address
8820Sstevel@tonic-gate      * parameter values.
8830Sstevel@tonic-gate      */
8840Sstevel@tonic-gate     /* If either tkt life or renew life weren't set earlier take common steps to
8850Sstevel@tonic-gate      * get the krb5.conf parameter values.
8860Sstevel@tonic-gate      */
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate     if ((code = krb5_timeofday(k5->ctx, &now))) {
8890Sstevel@tonic-gate 	    com_err(progname, code, gettext("while getting time of day"));
8900Sstevel@tonic-gate 	    exit(1);
8910Sstevel@tonic-gate     }
8920Sstevel@tonic-gate     krb5_max_duration = KRB5_KDB_EXPIRATION - now - 60*60;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate     if (opts->lifetime == 0 || opts->rlife == 0) {
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	krb_realm = krb5_princ_realm(k5->ctx, k5->me)->data;
8970Sstevel@tonic-gate 	/* realm params take precedence */
8980Sstevel@tonic-gate 	profile_get_options_string(k5->ctx->profile, realmdef, config_times);
8990Sstevel@tonic-gate 	profile_get_options_string(k5->ctx->profile, appdef, config_times);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/* if the input opts doesn't have lifetime set and the krb5.conf
9020Sstevel@tonic-gate 	 * parameter has been set, use that.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	if (opts->lifetime == 0 && life_timeval != NULL) {
9050Sstevel@tonic-gate 	    code = krb5_string_to_deltat(life_timeval, &lifetime);
9060Sstevel@tonic-gate 	    if (code != 0 || lifetime == 0 || lifetime > krb5_max_duration) {
9070Sstevel@tonic-gate 		fprintf(stderr, gettext("Bad max_life "
9080Sstevel@tonic-gate 			    "value in Kerberos config file %s\n"),
9090Sstevel@tonic-gate 			life_timeval);
9100Sstevel@tonic-gate 		exit(1);
9110Sstevel@tonic-gate 	    }
9120Sstevel@tonic-gate 	    opts->lifetime = lifetime;
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 	if (opts->rlife == 0 && renew_timeval != NULL) {
9150Sstevel@tonic-gate 	    code = krb5_string_to_deltat(renew_timeval, &rlife);
9160Sstevel@tonic-gate 	    if (code != 0 || rlife == 0 || rlife > krb5_max_duration) {
9170Sstevel@tonic-gate 		fprintf(stderr, gettext("Bad max_renewable_life "
9180Sstevel@tonic-gate 			    "value in Kerberos config file %s\n"),
9190Sstevel@tonic-gate 			renew_timeval);
9200Sstevel@tonic-gate 		exit(1);
9210Sstevel@tonic-gate 	    }
9220Sstevel@tonic-gate 	    opts->rlife = rlife;
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate     }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate     /*
9270Sstevel@tonic-gate      * If lifetime is not set on the cmdline or in the krb5.conf
9280Sstevel@tonic-gate      * file, default to max.
9290Sstevel@tonic-gate      */
9300Sstevel@tonic-gate     if (opts->lifetime == 0)
9310Sstevel@tonic-gate 	    opts->lifetime = krb5_max_duration;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate     profile_get_options_boolean(k5->ctx->profile,
9350Sstevel@tonic-gate 				realmdef, config_option);
9360Sstevel@tonic-gate     profile_get_options_boolean(k5->ctx->profile,
9370Sstevel@tonic-gate 				appdef, config_option);
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate     /* cmdline opts take precedence over krb5.conf file values */
9410Sstevel@tonic-gate     if (!opts->not_proxiable && proxiable_flag) {
942*7934SMark.Phalan@Sun.COM 	    krb5_get_init_creds_opt_set_proxiable(options, 1);
9430Sstevel@tonic-gate     }
9440Sstevel@tonic-gate     if (!opts->not_forwardable && forwardable_flag) {
945*7934SMark.Phalan@Sun.COM 	    krb5_get_init_creds_opt_set_forwardable(options, 1);
9460Sstevel@tonic-gate     }
9470Sstevel@tonic-gate     if (renewable_flag) {
9480Sstevel@tonic-gate 	    /*
9490Sstevel@tonic-gate 	     * If this flag is set in krb5.conf, but rlife is 0, then
9500Sstevel@tonic-gate 	     * set it to the max (and let the KDC sort it out).
9510Sstevel@tonic-gate 	     */
9520Sstevel@tonic-gate 	    opts->rlife = opts->rlife ? opts->rlife : krb5_max_duration;
9530Sstevel@tonic-gate     }
9540Sstevel@tonic-gate     if (no_address_flag) {
9550Sstevel@tonic-gate 	    /* cmdline opts will overwrite this below if needbe */
956*7934SMark.Phalan@Sun.COM 	    krb5_get_init_creds_opt_set_address_list(options, NULL);
9570Sstevel@tonic-gate     }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate     /*
9610Sstevel@tonic-gate       From this point on, we can goto cleanup because my_creds is
9620Sstevel@tonic-gate       initialized.
9630Sstevel@tonic-gate     */
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate     if (opts->lifetime)
966*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime);
9670Sstevel@tonic-gate     if (opts->rlife)
968*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_renew_life(options, opts->rlife);
9690Sstevel@tonic-gate     if (opts->forwardable)
970*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_forwardable(options, 1);
9710Sstevel@tonic-gate     if (opts->not_forwardable)
972*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_forwardable(options, 0);
9730Sstevel@tonic-gate     if (opts->proxiable)
974*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_proxiable(options, 1);
9750Sstevel@tonic-gate     if (opts->not_proxiable)
976*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_proxiable(options, 0);
9770Sstevel@tonic-gate     if (opts->addresses)
9780Sstevel@tonic-gate     {
9790Sstevel@tonic-gate 	krb5_address **addresses = NULL;
9800Sstevel@tonic-gate 	code = krb5_os_localaddr(k5->ctx, &addresses);
9810Sstevel@tonic-gate 	if (code != 0) {
9820Sstevel@tonic-gate 	    com_err(progname, code, gettext("getting local addresses"));
9830Sstevel@tonic-gate 	    goto cleanup;
9840Sstevel@tonic-gate 	}
985*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_address_list(options, addresses);
9860Sstevel@tonic-gate     }
9870Sstevel@tonic-gate     if (opts->no_addresses)
988*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_set_address_list(options, NULL);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate     if ((opts->action == INIT_KT) && opts->keytab_name)
9910Sstevel@tonic-gate     {
9920Sstevel@tonic-gate 	code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
9930Sstevel@tonic-gate 	if (code != 0) {
9940Sstevel@tonic-gate 	    com_err(progname, code, gettext("resolving keytab %s"),
9950Sstevel@tonic-gate 		    opts->keytab_name);
9960Sstevel@tonic-gate 	    goto cleanup;
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate     }
9990Sstevel@tonic-gate 
1000*7934SMark.Phalan@Sun.COM     for (i = 0; i < opts->num_pa_opts; i++) {
1001*7934SMark.Phalan@Sun.COM 	code = krb5_get_init_creds_opt_set_pa(k5->ctx, options,
1002*7934SMark.Phalan@Sun.COM 					      opts->pa_opts[i].attr,
1003*7934SMark.Phalan@Sun.COM 					      opts->pa_opts[i].value);
1004*7934SMark.Phalan@Sun.COM 	if (code != 0) {
1005*7934SMark.Phalan@Sun.COM 	    com_err(progname, code, "while setting '%s'='%s'",
1006*7934SMark.Phalan@Sun.COM 		    opts->pa_opts[i].attr, opts->pa_opts[i].value);
1007*7934SMark.Phalan@Sun.COM 	    goto cleanup;
1008*7934SMark.Phalan@Sun.COM 	}
1009*7934SMark.Phalan@Sun.COM     }
1010*7934SMark.Phalan@Sun.COM 
10110Sstevel@tonic-gate     switch (opts->action) {
10120Sstevel@tonic-gate     case INIT_PW:
10130Sstevel@tonic-gate 	code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me,
10140Sstevel@tonic-gate 					    0, kinit_prompter, 0,
10150Sstevel@tonic-gate 					    opts->starttime,
10160Sstevel@tonic-gate 					    opts->service_name,
1017*7934SMark.Phalan@Sun.COM 					    options);
10180Sstevel@tonic-gate 	break;
10190Sstevel@tonic-gate     case INIT_KT:
10200Sstevel@tonic-gate 	code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me,
10210Sstevel@tonic-gate 					  keytab,
10220Sstevel@tonic-gate 					  opts->starttime,
10230Sstevel@tonic-gate 					  opts->service_name,
1024*7934SMark.Phalan@Sun.COM 					  options);
10250Sstevel@tonic-gate 	break;
10260Sstevel@tonic-gate     case VALIDATE:
10270Sstevel@tonic-gate 	code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc,
10280Sstevel@tonic-gate 					opts->service_name);
10290Sstevel@tonic-gate 	break;
10300Sstevel@tonic-gate     case RENEW:
10310Sstevel@tonic-gate 	code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc,
10320Sstevel@tonic-gate 				      opts->service_name);
10330Sstevel@tonic-gate 	break;
10340Sstevel@tonic-gate     }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate     if (code) {
10370Sstevel@tonic-gate 	char *doing = 0;
10380Sstevel@tonic-gate 	switch (opts->action) {
10390Sstevel@tonic-gate 	case INIT_PW:
10400Sstevel@tonic-gate 	case INIT_KT:
10410Sstevel@tonic-gate 	    doing = gettext("getting initial credentials");
10420Sstevel@tonic-gate 	    break;
10430Sstevel@tonic-gate 	case VALIDATE:
10440Sstevel@tonic-gate 	    doing = gettext("validating credentials");
10450Sstevel@tonic-gate 	    break;
10460Sstevel@tonic-gate 	case RENEW:
10470Sstevel@tonic-gate 	    doing = gettext("renewing credentials");
10480Sstevel@tonic-gate 	    break;
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/* If got code == KRB5_AP_ERR_V4_REPLY && got_k4, we should
10520Sstevel@tonic-gate 	   let the user know that maybe he/she wants -4. */
10530Sstevel@tonic-gate 	if (code == KRB5KRB_AP_ERR_V4_REPLY && got_k4)
10540Sstevel@tonic-gate 	    com_err(progname, code, "while %s\n"
10550Sstevel@tonic-gate 		    "The KDC doesn't support v5.  "
10560Sstevel@tonic-gate 		    "You may want the -4 option in the future",
10570Sstevel@tonic-gate 		    doing);
10580Sstevel@tonic-gate 	else if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
10590Sstevel@tonic-gate 	    fprintf(stderr, gettext("%s: Password incorrect while %s\n"), progname,
10600Sstevel@tonic-gate 		    doing);
10610Sstevel@tonic-gate 	else
10620Sstevel@tonic-gate 	    com_err(progname, code, gettext("while %s"), doing);
10630Sstevel@tonic-gate 	goto cleanup;
10640Sstevel@tonic-gate     }
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate     if (!opts->lifetime) {
10670Sstevel@tonic-gate 	/* We need to figure out what lifetime to use for Kerberos 4. */
10680Sstevel@tonic-gate 	opts->lifetime = my_creds.times.endtime - my_creds.times.authtime;
10690Sstevel@tonic-gate     }
10700Sstevel@tonic-gate 
10712881Smp153739     code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me);
10722881Smp153739     if (code) {
10730Sstevel@tonic-gate 	com_err(progname, code, gettext("when initializing cache %s"),
10740Sstevel@tonic-gate 		opts->k5_cache_name?opts->k5_cache_name:"");
10750Sstevel@tonic-gate 	goto cleanup;
10760Sstevel@tonic-gate     }
10770Sstevel@tonic-gate 
10782881Smp153739     code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds);
10792881Smp153739     if (code) {
10800Sstevel@tonic-gate 	com_err(progname, code, gettext("while storing credentials"));
10810Sstevel@tonic-gate 	goto cleanup;
10820Sstevel@tonic-gate     }
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate     if (opts->action == RENEW) {
1085*7934SMark.Phalan@Sun.COM         _kwarnd_del_warning(progname, opts->principal_name);
1086*7934SMark.Phalan@Sun.COM         _kwarnd_add_warning(progname, opts->principal_name, my_creds.times.endtime);
10870Sstevel@tonic-gate     } else if ((opts->action == INIT_KT) || (opts->action == INIT_PW)) {
1088*7934SMark.Phalan@Sun.COM         _kwarnd_add_warning(progname, opts->principal_name, my_creds.times.endtime);
10890Sstevel@tonic-gate     }
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate     notix = 0;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate  cleanup:
1094*7934SMark.Phalan@Sun.COM     if (options)
1095*7934SMark.Phalan@Sun.COM 	krb5_get_init_creds_opt_free(k5->ctx, options);
10960Sstevel@tonic-gate     if (my_creds.client == k5->me) {
10970Sstevel@tonic-gate 	my_creds.client = 0;
10980Sstevel@tonic-gate     }
1099*7934SMark.Phalan@Sun.COM     if (opts->pa_opts) {
1100*7934SMark.Phalan@Sun.COM 	free(opts->pa_opts);
1101*7934SMark.Phalan@Sun.COM 	opts->pa_opts = NULL;
1102*7934SMark.Phalan@Sun.COM 	opts->num_pa_opts = 0;
1103*7934SMark.Phalan@Sun.COM     }
11040Sstevel@tonic-gate     krb5_free_cred_contents(k5->ctx, &my_creds);
11050Sstevel@tonic-gate     if (keytab)
11060Sstevel@tonic-gate 	krb5_kt_close(k5->ctx, keytab);
11070Sstevel@tonic-gate     return notix?0:1;
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate 
11102881Smp153739 static int
k4_kinit(opts,k4,ctx)11110Sstevel@tonic-gate k4_kinit(opts, k4, ctx)
11120Sstevel@tonic-gate     struct k_opts* opts;
11130Sstevel@tonic-gate     struct k4_data* k4;
11140Sstevel@tonic-gate     krb5_context ctx;
11150Sstevel@tonic-gate {
11160Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
11170Sstevel@tonic-gate     char* progname = progname_v4;
11180Sstevel@tonic-gate     int k_errno = 0;
11190Sstevel@tonic-gate #endif
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate     if (!got_k4)
11220Sstevel@tonic-gate 	return 0;
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate     if (opts->starttime)
11250Sstevel@tonic-gate 	return 0;
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
11280Sstevel@tonic-gate     if (!k4->lifetime)
11290Sstevel@tonic-gate 	k4->lifetime = opts->lifetime;
11300Sstevel@tonic-gate     if (!k4->lifetime)
11310Sstevel@tonic-gate 	k4->lifetime = KRB4_BACKUP_DEFAULT_LIFE_SECS;
11320Sstevel@tonic-gate 
11332881Smp153739     k4->lifetime = krb_time_to_life(0, k4->lifetime);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate     switch (opts->action)
11360Sstevel@tonic-gate     {
11370Sstevel@tonic-gate     case INIT_PW:
11380Sstevel@tonic-gate 	if (!got_password) {
11392881Smp153739 	    unsigned int pwsize = sizeof(stash_password);
11400Sstevel@tonic-gate 	    krb5_error_code code;
11410Sstevel@tonic-gate 	    char prompt[1024];
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	    sprintf(prompt, gettext("Password for %s: "), opts->principal_name);
11440Sstevel@tonic-gate 	    stash_password[0] = 0;
11450Sstevel@tonic-gate 	    /*
11460Sstevel@tonic-gate 	      Note: krb5_read_password does not actually look at the
11470Sstevel@tonic-gate 	      context, so we're ok even if we don't have a context.  If
11480Sstevel@tonic-gate 	      we cannot dynamically load krb5, we can substitute any
11490Sstevel@tonic-gate 	      decent read password function instead of the krb5 one.
11500Sstevel@tonic-gate 	    */
11510Sstevel@tonic-gate 	    code = krb5_read_password(ctx, prompt, 0, stash_password, &pwsize);
11520Sstevel@tonic-gate 	    if (code || pwsize == 0)
11530Sstevel@tonic-gate 	    {
11540Sstevel@tonic-gate 		fprintf(stderr, gettext("Error while reading password for '%s'\n"),
11550Sstevel@tonic-gate 			opts->principal_name);
11560Sstevel@tonic-gate 		memset(stash_password, 0, sizeof(stash_password));
11570Sstevel@tonic-gate 		return 0;
11580Sstevel@tonic-gate 	    }
11590Sstevel@tonic-gate 	    got_password = 1;
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate 	k_errno = krb_get_pw_in_tkt(k4->aname, k4->inst, k4->realm, "krbtgt",
11620Sstevel@tonic-gate 				    k4->realm, k4->lifetime, stash_password);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	if (k_errno) {
11650Sstevel@tonic-gate 	    fprintf(stderr, "%s: %s\n", progname,
11660Sstevel@tonic-gate 		    krb_get_err_text(k_errno));
11670Sstevel@tonic-gate 	    if (authed_k5)
11682881Smp153739 	        fprintf(stderr, gettext("Maybe your KDC does not support v4.  "
11690Sstevel@tonic-gate 			"Try the -5 option next time.\n"));
11700Sstevel@tonic-gate 	    return 0;
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 	return 1;
11730Sstevel@tonic-gate #ifndef HAVE_KRB524
11740Sstevel@tonic-gate     case INIT_KT:
11750Sstevel@tonic-gate 	fprintf(stderr, gettext("%s: srvtabs are not supported\n"), progname);
11760Sstevel@tonic-gate 	return 0;
11770Sstevel@tonic-gate     case RENEW:
11780Sstevel@tonic-gate 	fprintf(stderr, gettext("%s: renewal of krb4 tickets is not supported\n"),
11790Sstevel@tonic-gate 		progname);
11800Sstevel@tonic-gate 	return 0;
11812881Smp153739 #else
11822881Smp153739     /* These cases are handled by the 524 code - this prevents the compiler
11832881Smp153739        warnings of not using all the enumerated types.
11842881Smp153739     */
11852881Smp153739     case INIT_KT:
11862881Smp153739     case RENEW:
11872881Smp153739     case VALIDATE:
11882881Smp153739         return 0;
11890Sstevel@tonic-gate #endif
11900Sstevel@tonic-gate     }
11910Sstevel@tonic-gate #endif
11920Sstevel@tonic-gate     return 0;
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate 
11952881Smp153739 static char*
getvprogname(v,progname)11962881Smp153739 getvprogname(v, progname)
11972881Smp153739     char *v, *progname;
11980Sstevel@tonic-gate {
11992881Smp153739     unsigned int len = strlen(progname) + 2 + strlen(v) + 2;
12000Sstevel@tonic-gate     char *ret = malloc(len);
12010Sstevel@tonic-gate     if (ret)
12020Sstevel@tonic-gate 	sprintf(ret, "%s(v%s)", progname, v);
12030Sstevel@tonic-gate     else
12040Sstevel@tonic-gate 	ret = progname;
12050Sstevel@tonic-gate     return ret;
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate #ifdef HAVE_KRB524
12090Sstevel@tonic-gate /* Convert krb5 tickets to krb4. */
try_convert524(k5)12102881Smp153739 static int try_convert524(k5)
12110Sstevel@tonic-gate     struct k5_data* k5;
12120Sstevel@tonic-gate {
12130Sstevel@tonic-gate     char * progname = progname_v524;
12140Sstevel@tonic-gate     krb5_error_code code = 0;
12150Sstevel@tonic-gate     int icode = 0;
12160Sstevel@tonic-gate     krb5_principal kpcserver = 0;
12170Sstevel@tonic-gate     krb5_creds *v5creds = 0;
12180Sstevel@tonic-gate     krb5_creds increds;
12190Sstevel@tonic-gate     CREDENTIALS v4creds;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate     if (!got_k4 || !got_k5)
12220Sstevel@tonic-gate 	return 0;
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate     memset((char *) &increds, 0, sizeof(increds));
12250Sstevel@tonic-gate     /*
12260Sstevel@tonic-gate       From this point on, we can goto cleanup because increds is
12270Sstevel@tonic-gate       initialized.
12280Sstevel@tonic-gate     */
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate     if ((code = krb5_build_principal(k5->ctx,
12310Sstevel@tonic-gate 				     &kpcserver,
12320Sstevel@tonic-gate 				     krb5_princ_realm(k5->ctx, k5->me)->length,
12330Sstevel@tonic-gate 				     krb5_princ_realm(k5->ctx, k5->me)->data,
12340Sstevel@tonic-gate 				     "krbtgt",
12350Sstevel@tonic-gate 				     krb5_princ_realm(k5->ctx, k5->me)->data,
12360Sstevel@tonic-gate 				     NULL))) {
12370Sstevel@tonic-gate 	com_err(progname, code, gettext(
12380Sstevel@tonic-gate 		"while creating service principal name"));
12390Sstevel@tonic-gate 	goto cleanup;
12400Sstevel@tonic-gate     }
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate     increds.client = k5->me;
12430Sstevel@tonic-gate     increds.server = kpcserver;
12440Sstevel@tonic-gate     /* Prevent duplicate free calls.  */
12450Sstevel@tonic-gate     kpcserver = 0;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate     increds.times.endtime = 0;
12480Sstevel@tonic-gate     increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
12490Sstevel@tonic-gate     if ((code = krb5_get_credentials(k5->ctx, 0,
12500Sstevel@tonic-gate 				     k5->cc,
12510Sstevel@tonic-gate 				     &increds,
12520Sstevel@tonic-gate 				     &v5creds))) {
12530Sstevel@tonic-gate 	com_err(progname, code,
12540Sstevel@tonic-gate 		gettext("getting V5 credentials"));
12550Sstevel@tonic-gate 	goto cleanup;
12560Sstevel@tonic-gate     }
12570Sstevel@tonic-gate     if ((icode = krb524_convert_creds_kdc(k5->ctx,
12580Sstevel@tonic-gate 					  v5creds,
12590Sstevel@tonic-gate 					  &v4creds))) {
12600Sstevel@tonic-gate 	com_err(progname, icode,
12610Sstevel@tonic-gate 		gettext("converting to V4 credentials"));
12620Sstevel@tonic-gate 	goto cleanup;
12630Sstevel@tonic-gate     }
12640Sstevel@tonic-gate     /* this is stolen from the v4 kinit */
12650Sstevel@tonic-gate     /* initialize ticket cache */
12660Sstevel@tonic-gate     if ((icode = in_tkt(v4creds.pname, v4creds.pinst)
12670Sstevel@tonic-gate 	 != KSUCCESS)) {
12680Sstevel@tonic-gate 	com_err(progname, icode, gettext(
12690Sstevel@tonic-gate 		"trying to create the V4 ticket file"));
12700Sstevel@tonic-gate 	goto cleanup;
12710Sstevel@tonic-gate     }
12720Sstevel@tonic-gate     /* stash ticket, session key, etc. for future use */
12730Sstevel@tonic-gate     if ((icode = krb_save_credentials(v4creds.service,
12740Sstevel@tonic-gate 				      v4creds.instance,
12750Sstevel@tonic-gate 				      v4creds.realm,
12760Sstevel@tonic-gate 				      v4creds.session,
12770Sstevel@tonic-gate 				      v4creds.lifetime,
12780Sstevel@tonic-gate 				      v4creds.kvno,
12790Sstevel@tonic-gate 				      &(v4creds.ticket_st),
12800Sstevel@tonic-gate 				      v4creds.issue_date))) {
12810Sstevel@tonic-gate 	com_err(progname, icode, gettext(
12820Sstevel@tonic-gate 		"trying to save the V4 ticket"));
12830Sstevel@tonic-gate 	goto cleanup;
12840Sstevel@tonic-gate     }
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate  cleanup:
12870Sstevel@tonic-gate     memset(&v4creds, 0, sizeof(v4creds));
12880Sstevel@tonic-gate     if (v5creds)
12890Sstevel@tonic-gate 	krb5_free_creds(k5->ctx, v5creds);
12900Sstevel@tonic-gate     increds.client = 0;
12910Sstevel@tonic-gate     krb5_free_cred_contents(k5->ctx, &increds);
12920Sstevel@tonic-gate     if (kpcserver)
12930Sstevel@tonic-gate 	krb5_free_principal(k5->ctx, kpcserver);
12940Sstevel@tonic-gate     return !(code || icode);
12950Sstevel@tonic-gate }
12960Sstevel@tonic-gate #endif /* HAVE_KRB524 */
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate int
main(argc,argv)12990Sstevel@tonic-gate main(argc, argv)
13000Sstevel@tonic-gate     int argc;
13010Sstevel@tonic-gate     char **argv;
13020Sstevel@tonic-gate {
13030Sstevel@tonic-gate     struct k_opts opts;
13040Sstevel@tonic-gate     struct k5_data k5;
13050Sstevel@tonic-gate     struct k4_data k4;
1306*7934SMark.Phalan@Sun.COM     char *progname;
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate     (void) setlocale(LC_ALL, "");
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
13110Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
13120Sstevel@tonic-gate #endif
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate     (void) textdomain(TEXT_DOMAIN);
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate     progname = GET_PROGNAME(argv[0]);
13172881Smp153739     progname_v5 = getvprogname("5", progname);
13180Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
13192881Smp153739     progname_v4 = getvprogname("4", progname);
13202881Smp153739     progname_v524 = getvprogname("524", progname);
13210Sstevel@tonic-gate #endif
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate     /* Ensure we can be driven from a pipe */
13240Sstevel@tonic-gate     if(!isatty(fileno(stdin)))
13250Sstevel@tonic-gate 	setvbuf(stdin, 0, _IONBF, 0);
13260Sstevel@tonic-gate     if(!isatty(fileno(stdout)))
13270Sstevel@tonic-gate 	setvbuf(stdout, 0, _IONBF, 0);
13280Sstevel@tonic-gate     if(!isatty(fileno(stderr)))
13290Sstevel@tonic-gate 	setvbuf(stderr, 0, _IONBF, 0);
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate     /*
13320Sstevel@tonic-gate       This is where we would put in code to dynamically load Kerberos
13330Sstevel@tonic-gate       libraries.  Currenlty, we just get them implicitly.
13340Sstevel@tonic-gate     */
13350Sstevel@tonic-gate     got_k5 = 1;
13360Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
13370Sstevel@tonic-gate     got_k4 = 1;
13380Sstevel@tonic-gate #endif
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate     memset(&opts, 0, sizeof(opts));
13410Sstevel@tonic-gate     opts.action = INIT_PW;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate     memset(&k5, 0, sizeof(k5));
13440Sstevel@tonic-gate     memset(&k4, 0, sizeof(k4));
13450Sstevel@tonic-gate 
1346*7934SMark.Phalan@Sun.COM     set_com_err_hook (extended_com_err_fn);
1347*7934SMark.Phalan@Sun.COM 
13482881Smp153739     parse_options(argc, argv, &opts, progname);
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate     got_k5 = k5_begin(&opts, &k5, &k4);
13510Sstevel@tonic-gate     got_k4 = k4_begin(&opts, &k4);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate     authed_k5 = k5_kinit(&opts, &k5);
13540Sstevel@tonic-gate #ifdef HAVE_KRB524
13550Sstevel@tonic-gate     if (authed_k5)
13560Sstevel@tonic-gate 	authed_k4 = try_convert524(&k5);
13570Sstevel@tonic-gate #endif
13580Sstevel@tonic-gate     if (!authed_k4)
13590Sstevel@tonic-gate 	authed_k4 = k4_kinit(&opts, &k4, k5.ctx);
13600Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT
13610Sstevel@tonic-gate     memset(stash_password, 0, sizeof(stash_password));
13620Sstevel@tonic-gate #endif
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate     if (authed_k5 && opts.verbose)
13650Sstevel@tonic-gate 	fprintf(stderr, gettext("Authenticated to Kerberos v5\n"));
13660Sstevel@tonic-gate     if (authed_k4 && opts.verbose)
13670Sstevel@tonic-gate 	fprintf(stderr, gettext("Authenticated to Kerberos v4\n"));
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate     k5_end(&k5);
13700Sstevel@tonic-gate     k4_end(&k4);
13710Sstevel@tonic-gate 
13722881Smp153739     if ((got_k5 && !authed_k5) || (got_k4 && !authed_k4) ||
13732881Smp153739 	(!got_k5 && !got_k4))
13740Sstevel@tonic-gate 	exit(1);
13750Sstevel@tonic-gate     return 0;
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate static void
_kwarnd_add_warning(char * progname,char * me,time_t endtime)1379*7934SMark.Phalan@Sun.COM _kwarnd_add_warning(char *progname, char *me, time_t endtime)
13800Sstevel@tonic-gate {
13810Sstevel@tonic-gate     if (kwarn_add_warning(me, endtime) != 0)
13820Sstevel@tonic-gate         fprintf(stderr, gettext(
13830Sstevel@tonic-gate             "%s:  no ktkt_warnd warning possible\n"), progname);
13840Sstevel@tonic-gate     return;
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate static void
_kwarnd_del_warning(char * progname,char * me)1389*7934SMark.Phalan@Sun.COM _kwarnd_del_warning(char *progname, char *me)
13900Sstevel@tonic-gate {
13910Sstevel@tonic-gate     if (kwarn_del_warning(me) != 0)
13920Sstevel@tonic-gate         fprintf(stderr, gettext(
13930Sstevel@tonic-gate             "%s:  unable to delete ktkt_warnd message for %s\n"),
13940Sstevel@tonic-gate             progname, me);
13950Sstevel@tonic-gate     return;
13960Sstevel@tonic-gate }
1397