aboutsummaryrefslogtreecommitdiff
path: root/src/clients/kinit/kinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/clients/kinit/kinit.c')
-rw-r--r--src/clients/kinit/kinit.c536
1 files changed, 219 insertions, 317 deletions
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 6f7b840..f02db2e 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -24,43 +24,64 @@
* Initialize a credentials cache.
*/
-#include "k5-int.h"
+#include <krb5.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef GETOPT_LONG
+#include "getopt.h"
+#else
+#include <unistd.h>
+#endif
#include "com_err.h"
-#include "adm_proto.h"
-#include <stdio.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
-#endif
-#define KRB5_DEFAULT_OPTIONS 0
-#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
-
-extern int optind;
-extern char *optarg;
+void get_name_from_passwd_file(program_name, kcontext, me)
+ char * program_name;
+ krb5_context kcontext;
+ krb5_principal * me;
+{
+ struct passwd *pw;
+ krb5_error_code code;
+ if (pw = getpwuid((int) getuid())) {
+ if ((code = krb5_parse_name(kcontext, pw->pw_name, me))) {
+ com_err (program_name, code, "when parsing name %s", pw->pw_name);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "Unable to identify user from password file\n");
+ exit(1);
+ }
+}
+#else /* HAVE_PWD_H */
+void get_name_from_passwd_file(kcontext, me)
+ krb5_context kcontext;
+ krb5_principal * me;
+{
+ fprintf(stderr, "Unable to identify user\n");
+ exit(1);
+}
+#endif /* HAVE_PWD_H */
-krb5_data tgtname = {
- 0,
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME
+#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. */
+
+struct option long_options[] = {
+ { "noforwardable", 0, NULL, 'f'+0200 },
+ { "noproxiable", 0, NULL, 'p'+0200 },
+ { "addresses", 0, NULL, 'A'+0200},
+ { "forwardable", 0, NULL, 'f' },
+ { "proxiable", 0, NULL, 'p' },
+ { "noaddresses", 0, NULL, 'A'},
+ { "version", 0, NULL, 0x01 },
+ { NULL, 0, NULL, 0 }
};
-
-/* Internal prototypes */
-static krb5_error_code krb5_validate_tgt
- KRB5_PROTOTYPE((krb5_context, krb5_ccache,
- krb5_principal, krb5_data *));
-static krb5_error_code krb5_renew_tgt
- KRB5_PROTOTYPE((krb5_context, krb5_ccache,
- krb5_principal, krb5_data *));
-static krb5_error_code krb5_tgt_gen
- KRB5_PROTOTYPE((krb5_context, krb5_ccache,
- krb5_principal, krb5_data *, int opt));
-
-/*
- * Try no preauthentication first; then try the encrypted timestamp
- */
-krb5_preauthtype * preauth = NULL;
-krb5_preauthtype preauth_list[2] = { 0, -1 };
+#endif
int
main(argc, argv)
@@ -68,114 +89,147 @@ main(argc, argv)
char **argv;
{
krb5_context kcontext;
+ krb5_principal me = NULL;
+ krb5_deltat start_time = 0;
+ krb5_address **addresses = NULL;
+ krb5_get_init_creds_opt opts;
+ char *service_name = NULL;
+ krb5_keytab keytab = NULL;
+ char *cache_name;
krb5_ccache ccache = NULL;
- char *cache_name = NULL; /* -f option */
- char *keytab_name = NULL; /* -t option */
- char *service_name = NULL; /* -s option */
- krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */
- krb5_timestamp starttime = 0;
- krb5_deltat rlife = 0;
- int options = KRB5_DEFAULT_OPTIONS;
- int option;
- int errflg = 0;
- krb5_error_code code;
- krb5_principal me;
- krb5_principal server;
+ enum { INIT_PW, INIT_KT, RENEW, VALIDATE} action;
+ int errflg = 0, idx, i;
krb5_creds my_creds;
- krb5_timestamp now;
- krb5_address *null_addr = (krb5_address *)0;
- krb5_address **addrs = (krb5_address **)0;
- int use_keytab = 0; /* -k option */
- krb5_keytab keytab = NULL;
- struct passwd *pw = 0;
- int pwsize;
- char password[255], *client_name, prompt[1024];
+ krb5_error_code code;
- code = krb5_init_context(&kcontext);
- if (code) {
- com_err(argv[0], code, "while initializing krb5");
- exit(1);
- }
+ /* Ensure we can be driven from a pipe */
+ if(!isatty(fileno(stdin)))
+ setvbuf(stdin, 0, _IONBF, 0);
+ if(!isatty(fileno(stdout)))
+ setvbuf(stdout, 0, _IONBF, 0);
+ if(!isatty(fileno(stderr)))
+ setvbuf(stderr, 0, _IONBF, 0);
- if ((code = krb5_timeofday(kcontext, &now))) {
- com_err(argv[0], code, "while getting time of day");
+ if (code = krb5_init_context(&kcontext)) {
+ com_err(argv[0], code, "while initializing kerberos library");
exit(1);
}
+ krb5_get_init_creds_opt_init(&opts);
+
+ action = INIT_PW;
+
if (strrchr(argv[0], '/'))
argv[0] = strrchr(argv[0], '/')+1;
- while ((option = getopt(argc, argv, "r:Rfpl:s:c:kt:vS:")) != -1) {
- switch (option) {
- case 'r':
- options |= KDC_OPT_RENEWABLE;
- code = krb5_string_to_deltat(optarg, &rlife);
- if (code != 0 || rlife == 0) {
- fprintf(stderr, "Bad lifetime value %s\n", optarg);
- errflg++;
+ while (
+#ifdef GETOPT_LONG
+ (i = getopt_long(argc, argv, "r:fpAl:s:c:kt:RS:v",
+ long_options, &idx)) != -1
+#else
+ (i = getopt(argc, argv, "r:fpAl:s:c:kt:RS:v")) != -1
+#endif
+ ) {
+ switch (i) {
+#ifdef GETOPT_LONG
+ case 1: /* Print the version */
+ printf("%s\n", krb5_version);
+ exit(0);
+#endif
+ case 'l':
+ {
+ krb5_deltat lifetime;
+ code = krb5_string_to_deltat(optarg, &lifetime);
+ if (code != 0 || lifetime == 0) {
+ fprintf(stderr, "Bad lifetime value %s\n", optarg);
+ errflg++;
+ }
+ krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
}
break;
- case 'R':
- /* renew the ticket */
- options |= KDC_OPT_RENEW;
+ case 'r':
+ {
+ krb5_deltat rlife;
+
+ code = krb5_string_to_deltat(optarg, &rlife);
+ if (code != 0 || rlife == 0) {
+ fprintf(stderr, "Bad lifetime value %s\n", optarg);
+ errflg++;
+ }
+ krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
+ }
break;
- case 'v':
- /* validate the ticket */
- options |= KDC_OPT_VALIDATE;
+ case 'f':
+ krb5_get_init_creds_opt_set_forwardable(&opts, 1);
break;
- case 'S':
- service_name = optarg;
+#ifdef GETOPT_LONG
+ case 'f'+0200:
+ krb5_get_init_creds_opt_set_forwardable(&opts, 0);
break;
+#endif
case 'p':
- options |= KDC_OPT_PROXIABLE;
+ krb5_get_init_creds_opt_set_proxiable(&opts, 1);
break;
- case 'f':
- options |= KDC_OPT_FORWARDABLE;
+#ifdef GETOPT_LONG
+ case 'p'+0200:
+ krb5_get_init_creds_opt_set_proxiable(&opts, 0);
break;
-#ifndef NO_KEYTAB
- case 'k':
- use_keytab = 1;
+#endif
+ case 'A':
+ krb5_get_init_creds_opt_set_address_list(&opts, NULL);
break;
- case 't':
- if (keytab == NULL) {
- keytab_name = optarg;
+#ifdef GETOPT_LONG
+ case 'A'+0200:
+ krb5_os_localaddr(kcontext, &addresses);
+ krb5_get_init_creds_opt_set_address_list(&opts, addresses);
+ break;
+#endif
+ case 's':
+ code = krb5_string_to_deltat(optarg, &start_time);
+ if (code != 0 || start_time == 0) {
+ krb5_timestamp abs_starttime;
+ krb5_timestamp now;
+
+ code = krb5_string_to_timestamp(optarg, &abs_starttime);
+ if (code != 0 || abs_starttime == 0) {
+ fprintf(stderr, "Bad start time value %s\n", optarg);
+ errflg++;
+ } else {
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ com_err(argv[0], code,
+ "while getting time of day");
+ exit(1);
+ }
- code = krb5_kt_resolve(kcontext, keytab_name, &keytab);
+ start_time = abs_starttime - now;
+ }
+ }
+ break;
+ case 'S':
+ service_name = optarg;
+ break;
+ case 'k':
+ action = INIT_KT;
+ break;
+ case 't':
+ if (keytab == NULL) {
+ code = krb5_kt_resolve(kcontext, optarg, &keytab);
if (code != 0) {
- com_err(argv[0], code, "resolving keytab %s",
- keytab_name);
- errflg++;
+ com_err(argv[0], code, "resolving keytab %s", optarg);
+ errflg++;
}
} else {
fprintf(stderr, "Only one -t option allowed.\n");
errflg++;
}
break;
-#endif
- case 'l':
- code = krb5_string_to_deltat(optarg, &lifetime);
- if (code != 0 || lifetime == 0) {
- fprintf(stderr, "Bad lifetime value %s\n", optarg);
- errflg++;
- }
+ case 'R':
+ action = RENEW;
break;
- case 's':
- code = krb5_string_to_timestamp(optarg, &starttime);
- if (code != 0 || starttime == 0) {
- krb5_deltat ktmp;
- code = krb5_string_to_deltat(optarg, &ktmp);
- if (code == 0 && ktmp != 0) {
- starttime = now + ktmp;
- options |= KDC_OPT_POSTDATED;
- } else {
- fprintf(stderr, "Bad postdate start time value %s\n", optarg);
- errflg++;
- }
- } else {
- options |= KDC_OPT_POSTDATED;
- }
+ case 'v':
+ action = VALIDATE;
break;
- case 'c':
+ case 'c':
if (ccache == NULL) {
cache_name = optarg;
@@ -190,7 +244,6 @@ main(argc, argv)
errflg++;
}
break;
- case '?':
default:
errflg++;
break;
@@ -204,7 +257,11 @@ main(argc, argv)
}
if (errflg) {
- fprintf(stderr, "Usage: %s [-r time] [-R] [-s time] [-v] [-puf] [-l lifetime] [-c cachename] [-k] [-t keytab] [-S target_service] [principal]\n", argv[0]);
+#ifdef GETOPT_LONG
+ fprintf(stderr, "Usage: %s [--version] [-l lifetime] [-r renewable_life] [-f | --forwardable | --noforwardable] [-p | --proxiable | --noproxiable] [-A | --noaddresses | --addresses] [-s start_time] [-S target_service] [-k [-t keytab_file]] [-R] [-v] [-c cachename] [principal]\n", argv[0]);
+#else
+ fprintf(stderr, "Usage: %s [-l lifetime] [-r renewable_life] [-f] [-p] [-A] [-s start_time] [-S target_service] [-k [-t keytab_file]] [-R] [-v] [-c cachename] [principal]\n", argv[0]);
+#endif
exit(2);
}
@@ -215,147 +272,51 @@ main(argc, argv)
}
}
- if (optind != argc-1) { /* No principal name specified */
-#ifndef NO_KEYTAB
- if (use_keytab) {
- /* Use the default host/service name */
- code = krb5_sname_to_principal(kcontext, NULL, NULL,
- KRB5_NT_SRV_HST, &me);
- if (code) {
- com_err(argv[0], code,
- "when creating default server principal name");
- exit(1);
- }
- } else
-#endif
- {
- /* Get default principal from cache if one exists */
- code = krb5_cc_get_principal(kcontext, ccache, &me);
- if (code) {
-#ifdef HAVE_PWD_H
- /* Else search passwd file for client */
- pw = getpwuid((int) getuid());
- if (pw) {
- if ((code = krb5_parse_name(kcontext,pw->pw_name,
- &me))) {
- com_err (argv[0], code, "when parsing name %s",
- pw->pw_name);
- exit(1);
- }
- } else {
- fprintf(stderr,
- "Unable to identify user from password file\n");
- exit(1);
- }
-#else /* HAVE_PWD_H */
- fprintf(stderr, "Unable to identify user\n");
- exit(1);
-#endif /* HAVE_PWD_H */
- }
- }
- } /* Use specified name */
- else if ((code = krb5_parse_name (kcontext, argv[optind], &me))) {
- com_err (argv[0], code, "when parsing name %s",argv[optind]);
- exit(1);
- }
-
- if ((code = krb5_unparse_name(kcontext, me, &client_name))) {
- com_err (argv[0], code, "when unparsing name");
- exit(1);
- }
-
- memset((char *)&my_creds, 0, sizeof(my_creds));
-
- my_creds.client = me;
-
- if (service_name == NULL) {
- if((code = krb5_build_principal_ext(kcontext, &server,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- tgtname.length, tgtname.data,
- krb5_princ_realm(kcontext, me)->length,
- krb5_princ_realm(kcontext, me)->data,
- 0))) {
- com_err(argv[0], code, "while building server name");
- exit(1);
- }
- } else {
- if ((code = krb5_parse_name(kcontext, service_name, &server))) {
- com_err(argv[0], code, "while parsing service name %s",
- service_name);
- exit(1);
- }
- }
-
- my_creds.server = server;
-
- if (options & KDC_OPT_POSTDATED) {
- my_creds.times.starttime = starttime;
- my_creds.times.endtime = starttime + lifetime;
+ if (optind == argc-1) {
+ /* Use specified name */
+ if ((code = krb5_parse_name (kcontext, argv[optind], &me))) {
+ com_err (argv[0], code, "when parsing name %s",argv[optind]);
+ exit(1);
+ }
} else {
- my_creds.times.starttime = 0; /* start timer when request
- gets to KDC */
- my_creds.times.endtime = now + lifetime;
- }
- if (options & KDC_OPT_RENEWABLE) {
- my_creds.times.renew_till = now + rlife;
- } else
- my_creds.times.renew_till = 0;
-
- if (options & KDC_OPT_VALIDATE) {
- /* don't use get_in_tkt, just use mk_req... */
- krb5_data outbuf;
-
- code = krb5_validate_tgt(kcontext, ccache, server, &outbuf);
- if (code) {
- com_err (argv[0], code, "validating tgt");
- exit(1);
+ /* No principal name specified */
+ if (action == INIT_KT) {
+ /* Use the default host/service name */
+ if (code = krb5_sname_to_principal(kcontext, NULL, NULL,
+ KRB5_NT_SRV_HST, &me)) {
+ com_err(argv[0], code,
+ "when creating default server principal name");
+ exit(1);
+ }
+ } else {
+ /* Get default principal from cache if one exists */
+ if (code = krb5_cc_get_principal(kcontext, ccache, &me))
+ get_name_from_passwd_file(argv[0], kcontext, &me);
}
- /* should be done... */
- exit(0);
}
-
- if (options & KDC_OPT_RENEW) {
- /* don't use get_in_tkt, just use mk_req... */
- krb5_data outbuf;
-
- code = krb5_renew_tgt(kcontext, ccache, server, &outbuf);
- if (code) {
- com_err (argv[0], code, "renewing tgt");
- exit(1);
- }
- /* should be done... */
- exit(0);
+
+ switch (action) {
+ case INIT_PW:
+ code = krb5_get_init_creds_password(kcontext, &my_creds, me, NULL,
+ krb5_prompter_posix, NULL,
+ start_time, service_name,
+ &opts);
+ break;
+ case INIT_KT:
+ code = krb5_get_init_creds_keytab(kcontext, &my_creds, me, keytab,
+ start_time, service_name,
+ &opts);
+ break;
+ case VALIDATE:
+ code = krb5_get_validated_creds(kcontext, &my_creds, me, ccache,
+ service_name);
+ break;
+ case RENEW:
+ code = krb5_get_renewed_creds(kcontext, &my_creds, me, ccache,
+ service_name);
+ break;
}
-#ifndef NO_KEYTAB
- if (!use_keytab)
-#endif
- {
- (void) sprintf(prompt, "Password for %.*s: ",
- sizeof(prompt)-32, (char *) client_name);
-
- pwsize = sizeof(password);
- code = krb5_read_password(kcontext, prompt, 0, password, &pwsize);
- if (code || pwsize == 0) {
- fprintf(stderr, "Error while reading password for '%s'\n",
- client_name);
- memset(password, 0, sizeof(password));
- exit(1);
- }
-
- code = krb5_get_in_tkt_with_password(kcontext, options, addrs,
- NULL, preauth, password, 0,
- &my_creds, 0);
- memset(password, 0, sizeof(password));
-#ifndef NO_KEYTAB
- } else {
- code = krb5_get_in_tkt_with_keytab(kcontext, options, addrs,
- NULL, preauth, keytab, 0,
- &my_creds, 0);
-#endif
- }
-
if (code) {
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
fprintf (stderr, "%s: Password incorrect\n", argv[0]);
@@ -364,86 +325,27 @@ main(argc, argv)
exit(1);
}
- code = krb5_cc_initialize (kcontext, ccache, me);
- if (code != 0) {
+ if (code = krb5_cc_initialize(kcontext, ccache, me)) {
com_err (argv[0], code, "when initializing cache %s",
cache_name?cache_name:"");
exit(1);
}
- code = krb5_cc_store_cred(kcontext, ccache, &my_creds);
- if (code) {
+ if (code = krb5_cc_store_cred(kcontext, ccache, &my_creds)) {
com_err (argv[0], code, "while storing credentials");
exit(1);
}
- /* my_creds is pointing at server */
- krb5_free_principal(kcontext, server);
+ if (me)
+ krb5_free_principal(kcontext, me);
+ if (keytab)
+ krb5_kt_close(kcontext, keytab);
+ if (ccache)
+ krb5_cc_close(kcontext, ccache);
+ if (addresses)
+ krb5_free_addresses(kcontext, addresses);
krb5_free_context(kcontext);
-
+
exit(0);
}
-
-#define VALIDATE 0
-#define RENEW 1
-
-/* stripped down version of krb5_mk_req */
-static krb5_error_code krb5_validate_tgt(context, ccache, server, outbuf)
- krb5_context context;
- krb5_ccache ccache;
- krb5_principal server; /* tgtname */
- krb5_data *outbuf;
-{
- return krb5_tgt_gen(context, ccache, server, outbuf, VALIDATE);
-}
-
-/* stripped down version of krb5_mk_req */
-static krb5_error_code krb5_renew_tgt(context, ccache, server, outbuf)
- krb5_context context;
- krb5_ccache ccache;
- krb5_principal server; /* tgtname */
- krb5_data *outbuf;
-{
- return krb5_tgt_gen(context, ccache, server, outbuf, RENEW);
-}
-
-
-/* stripped down version of krb5_mk_req */
-static krb5_error_code krb5_tgt_gen(context, ccache, server, outbuf, opt)
- krb5_context context;
- krb5_ccache ccache;
- krb5_principal server; /* tgtname */
- krb5_data *outbuf;
- int opt;
-{
- krb5_error_code retval;
- krb5_creds * credsp;
- krb5_creds creds;
-
- /* obtain ticket & session key */
- memset((char *)&creds, 0, sizeof(creds));
- if ((retval = krb5_copy_principal(context, server, &creds.server)))
- goto cleanup;
-
- if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
- goto cleanup_creds;
-
- if(opt == VALIDATE) {
- if ((retval = krb5_get_credentials_validate(context, 0,
- ccache, &creds, &credsp)))
- goto cleanup_creds;
- } else {
- if ((retval = krb5_get_credentials_renew(context, 0,
- ccache, &creds, &credsp)))
- goto cleanup_creds;
- }
-
- /* we don't actually need to do the mk_req, just get the creds. */
-cleanup_creds:
- krb5_free_cred_contents(context, &creds);
-
-cleanup:
-
- return retval;
-}