/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* Copyright 1990 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*
* Initialize a credentials cache.
*/
#include <k5-int.h>
#include <profile/prof_int.h>
#include <com_err.h>
#include <libintl.h>
#include <krb5.h>
#ifdef KRB5_KRB4_COMPAT
#include <kerberosIV/krb.h>
#define HAVE_KRB524
#else
#endif
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <com_err.h>
#include <netdb.h>
#include <locale.h>
#ifdef GETOPT_LONG
#include <getopt.h>
#else
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#ifdef sun
/* SunOS4 unistd didn't declare these; okay to make unconditional? */
extern int optind;
extern char *optarg;
#endif /* sun */
#else
extern int optind;
extern char *optarg;
extern int getopt();
#endif /* HAVE_UNISTD_H */
#endif /* GETOPT_LONG */
#ifndef _WIN32
#else
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
static
char * get_name_from_os()
{
return 0;
}
#else /* HAVE_PWD_H */
#ifdef _WIN32
static
char * get_name_from_os()
{
return name;
} else {
return 0;
}
}
#else /* _WIN32 */
static
char * get_name_from_os()
{
return 0;
}
#endif /* _WIN32 */
#endif /* HAVE_PWD_H */
static char* progname_v5 = 0;
#ifdef KRB5_KRB4_COMPAT
static char* progname_v4 = 0;
static char* progname_v524 = 0;
#endif
#include <locale.h>
static int got_k5 = 0;
static int got_k4 = 0;
#if defined(KRB5_KRB4_COMPAT) && defined(KINIT_DEFAULT_BOTH)
#else
static int default_k4 = 0;
#endif
static int authed_k5 = 0;
static int authed_k4 = 0;
struct k_opts
{
/* in seconds */
int forwardable;
int proxiable;
int addresses;
int not_forwardable;
int not_proxiable;
int no_addresses;
int verbose;
char* principal_name;
char* service_name;
char* keytab_name;
char* k5_cache_name;
char* k4_cache_name;
int num_pa_opts;
};
int forwardable_flag = 0;
int renewable_flag = 0;
int proxiable_flag = 0;
int no_address_flag = 0;
{ "forwardable", &forwardable_flag, 0 },
{ "renewable", &renewable_flag, 0 },
{ "proxiable", &proxiable_flag, 0 },
{ "no_addresses", &no_address_flag, 0 },
};
int lifetime_specified;
int renewtime_specified;
{ "max_life", &life_timeval, 0 },
{ "max_renewable_life", &renew_timeval, 0 },
};
struct k5_data
{
char* name;
};
struct k4_data
{
#ifdef KRB5_KRB4_COMPAT
#endif
};
/*
* Try no preauthentication first; then try the encrypted timestamp
*/
static void _kwarnd_add_warning(char *, char *, time_t);
static void _kwarnd_del_warning(char *, char *);
#ifdef GETOPT_LONG
/* if struct[2] == NULL, then long_getopt acts as if the short flag
struct[3] was specified. If struct[2] != NULL, then struct[3] is
stored in *(struct[2]), the array index which was specified is
stored in *index, and long_getopt() returns 0. */
};
#else
#endif
static void
char *progname;
{
#ifdef GETOPT_LONG
#else
#define USAGE_LONG_FORWARDABLE ""
#define USAGE_LONG_PROXIABLE ""
#define USAGE_LONG_ADDRESSES ""
#define USAGE_BREAK_LONG ""
#endif
"[-l lifetime] [-s start_time] "
"[-r renewable_life] "
"[-v] [-R] "
"[-k [-t keytab_file]] "
"[-c cachename] "
"[-S service_name]"
"[-X <attribute>[=<value>]] [principal]"
"\n\n",
#ifdef HAVE_KRB524
#else
#endif
#ifdef KRB5_KRB4_COMPAT
#else
#endif
/* This options is not yet available: */
/* ULINE("\t", "-C Kerberos 4 cache name", OPTTYPE_KRB4); */
exit(2);
}
{
const char *emsg;
}
static int
{
char *sep, *v;
krb5_gic_opt_pa_data *p, *x;
if (opts->num_pa_opts == 0) {
return ENOMEM;
} else {
if (x == NULL)
return ENOMEM;
}
if (sep) {
*sep = '\0';
v = ++sep;
p->value = v;
} else {
p->value = "yes";
}
opts->num_pa_opts++;
return 0;
}
static char *
int argc;
char **argv;
char *progname;
{
int errflg = 0;
int use_k4 = 0;
int use_k5 = 0;
int i;
!= -1) {
switch (i) {
case 'V':
break;
case 'l':
/* Lifetime */
errflg++;
}
break;
case 'r':
/* Renewable Time */
errflg++;
}
break;
case 'f':
break;
case 'F':
break;
case 'p':
break;
case 'P':
break;
case 'a':
/* Note: This is supported only with GETOPT_LONG */
break;
case 'A':
break;
case 's':
if (code != 0 || abs_starttime == 0) {
errflg++;
} else {
}
}
break;
case 'S':
break;
case 'k':
break;
case 't':
if (opts->keytab_name)
{
errflg++;
} else {
}
break;
case 'R':
break;
case 'v':
break;
case 'c':
if (opts->k5_cache_name)
{
errflg++;
} else {
}
break;
case 'X':
if (code)
{
errflg++;
}
break;
#if 0
/*
A little more work is needed before we can enable this
option.
*/
case 'C':
if (opts->k4_cache_name)
{
errflg++;
} else {
}
break;
#endif
case '4':
if (!got_k4)
{
#ifdef KRB5_KRB4_COMPAT
#else
#endif
exit(3);
}
use_k4 = 1;
break;
case '5':
if (!got_k5)
{
exit(3);
}
use_k5 = 1;
break;
default:
errflg++;
break;
}
}
{
errflg++;
}
{
errflg++;
}
{
errflg++;
}
errflg++;
}
/* At this point, if errorless, we know we only have one option
selection */
use_k5 = default_k5;
use_k4 = default_k4;
}
/* Now, we encode the OPTTYPE stuff here... */
if (!use_k5 &&
{
errflg++;
}
if (!use_k4 &&
{
errflg++;
}
if (
#ifdef HAVE_KRB524
#else
#endif
)
{
errflg++;
}
if (errflg) {
}
return opts->principal_name;
}
static int
{
if (!got_k5)
return 0;
if (code) {
return 0;
}
if (opts->k5_cache_name)
{
if (code != 0) {
return 0;
}
}
else
{
return 0;
}
}
if (opts->principal_name)
{
/* Use specified name */
return 0;
}
}
else
{
/* No principal name specified */
if (code) {
"when creating default server principal name"));
return 0;
}
} else {
/* Get default principal from cache if one exists */
if (code)
{
if (!name)
{
return 0;
}
/* use strcmp to ensure only "root" is matched */
{
"when creating default server principal name"));
return 0;
}
} else
{
name);
return 0;
}
}
}
}
if (code) {
return 0;
}
#ifdef KRB5_KRB4_COMPAT
if (got_k4)
{
/* Translate to a Kerberos 4 principal */
if (code) {
}
}
#endif
return 1;
}
static void
{
}
static int
{
#ifdef KRB5_KRB4_COMPAT
int k_errno = 0;
#endif
if (!got_k4)
return 0;
#ifdef KRB5_KRB4_COMPAT
goto skip;
if (opts->principal_name)
{
/* Use specified name */
if (k_errno)
{
return 0;
}
} else {
/* No principal name specified */
/* XXX - need to add this functionality */
"implemented\n", progname);
return 0;
} else {
/* Get default principal from cache if one exists */
if (k_errno)
{
if (!name)
{
return 0;
}
name);
if (k_errno)
{
return 0;
}
}
}
}
else
skip:
{
return 0;
}
{
return 0;
}
{
return 0;
}
#endif /* KRB5_KRB4_COMPAT */
return 1;
}
static void
{
}
#ifdef KRB5_KRB4_COMPAT
static int got_password = 0;
#endif /* KRB5_KRB4_COMPAT */
static krb5_error_code
void *data,
const char *name,
const char *banner,
int num_prompts,
)
{
int i;
for (i = 0; i < num_prompts; i++)
if ((types[i] == KRB5_PROMPT_TYPE_PASSWORD) ||
(types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN))
{
#ifdef KRB5_KRB4_COMPAT
sizeof(stash_password));
got_password = 1;
#endif
}
return rc;
}
static int
{
int i;
if (!got_k5)
return 0;
if (code)
goto cleanup;
/*
* Solaris Kerberos: added support for max_life and max_renewable_life
* which should be removed in the next minor release. See PSARC 2003/545
* for more info.
*
* Also, check krb5.conf for proxiable/forwardable/renewable/no_address
* parameter values.
*/
/* If either tkt life or renew life weren't set earlier take common steps to
* get the krb5.conf parameter values.
*/
exit(1);
}
/* realm params take precedence */
/* if the input opts doesn't have lifetime set and the krb5.conf
* parameter has been set, use that.
*/
"value in Kerberos config file %s\n"),
exit(1);
}
}
"value in Kerberos config file %s\n"),
exit(1);
}
}
}
/*
* If lifetime is not set on the cmdline or in the krb5.conf
* file, default to max.
*/
/* cmdline opts take precedence over krb5.conf file values */
}
}
if (renewable_flag) {
/*
* If this flag is set in krb5.conf, but rlife is 0, then
* set it to the max (and let the KDC sort it out).
*/
}
if (no_address_flag) {
/* cmdline opts will overwrite this below if needbe */
}
/*
From this point on, we can goto cleanup because my_creds is
initialized.
*/
if (opts->forwardable)
if (opts->not_forwardable)
if (opts->not_proxiable)
{
if (code != 0) {
goto cleanup;
}
}
if (opts->no_addresses)
{
if (code != 0) {
opts->keytab_name);
goto cleanup;
}
}
for (i = 0; i < opts->num_pa_opts; i++) {
if (code != 0) {
goto cleanup;
}
}
case INIT_PW:
0, kinit_prompter, 0,
options);
break;
case INIT_KT:
options);
break;
case VALIDATE:
opts->service_name);
break;
case RENEW:
opts->service_name);
break;
}
if (code) {
char *doing = 0;
case INIT_PW:
case INIT_KT:
break;
case VALIDATE:
break;
case RENEW:
break;
}
/* If got code == KRB5_AP_ERR_V4_REPLY && got_k4, we should
"The KDC doesn't support v5. "
"You may want the -4 option in the future",
doing);
else if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
doing);
else
goto cleanup;
}
/* We need to figure out what lifetime to use for Kerberos 4. */
}
if (code) {
goto cleanup;
}
if (code) {
goto cleanup;
}
}
notix = 0;
if (options)
}
opts->num_pa_opts = 0;
}
if (keytab)
return notix?0:1;
}
static int
{
#ifdef KRB5_KRB4_COMPAT
int k_errno = 0;
#endif
if (!got_k4)
return 0;
return 0;
#ifdef KRB5_KRB4_COMPAT
{
case INIT_PW:
if (!got_password) {
stash_password[0] = 0;
/*
Note: krb5_read_password does not actually look at the
context, so we're ok even if we don't have a context. If
we cannot dynamically load krb5, we can substitute any
decent read password function instead of the krb5 one.
*/
{
return 0;
}
got_password = 1;
}
if (k_errno) {
if (authed_k5)
"Try the -5 option next time.\n"));
return 0;
}
return 1;
#ifndef HAVE_KRB524
case INIT_KT:
return 0;
case RENEW:
progname);
return 0;
#else
/* These cases are handled by the 524 code - this prevents the compiler
warnings of not using all the enumerated types.
*/
case INIT_KT:
case RENEW:
case VALIDATE:
return 0;
#endif
}
#endif
return 0;
}
static char*
char *v, *progname;
{
if (ret)
else
return ret;
}
#ifdef HAVE_KRB524
/* Convert krb5 tickets to krb4. */
{
int icode = 0;
return 0;
/*
From this point on, we can goto cleanup because increds is
initialized.
*/
"krbtgt",
NULL))) {
"while creating service principal name"));
goto cleanup;
}
/* Prevent duplicate free calls. */
kpcserver = 0;
&increds,
&v5creds))) {
gettext("getting V5 credentials"));
goto cleanup;
}
&v4creds))) {
gettext("converting to V4 credentials"));
goto cleanup;
}
/* this is stolen from the v4 kinit */
/* initialize ticket cache */
!= KSUCCESS)) {
"trying to create the V4 ticket file"));
goto cleanup;
}
/* stash ticket, session key, etc. for future use */
v4creds.issue_date))) {
"trying to save the V4 ticket"));
goto cleanup;
}
if (v5creds)
if (kpcserver)
}
#endif /* HAVE_KRB524 */
int
int argc;
char **argv;
{
char *progname;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
#ifdef KRB5_KRB4_COMPAT
#endif
/* Ensure we can be driven from a pipe */
/*
This is where we would put in code to dynamically load Kerberos
libraries. Currenlty, we just get them implicitly.
*/
got_k5 = 1;
#ifdef KRB5_KRB4_COMPAT
got_k4 = 1;
#endif
#ifdef HAVE_KRB524
if (authed_k5)
#endif
if (!authed_k4)
#ifdef KRB5_KRB4_COMPAT
#endif
exit(1);
return 0;
}
static void
{
"%s: no ktkt_warnd warning possible\n"), progname);
return;
}
static void
{
if (kwarn_del_warning(me) != 0)
"%s: unable to delete ktkt_warnd message for %s\n"),
return;
}