summaryrefslogtreecommitdiffstats
path: root/src/clients/kvno
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2009-09-13 02:52:23 +0000
committerGreg Hudson <ghudson@mit.edu>2009-09-13 02:52:23 +0000
commit0e39f8a3ad915eeb0131fb4a87b0fef304101cfd (patch)
tree6c6d7fd4b23f4724156300b5505433b13cfe9fb6 /src/clients/kvno
parentf89b62fe9fd7b0cb10d7e2ff542fb18c1b56d35d (diff)
downloadkrb5-0e39f8a3ad915eeb0131fb4a87b0fef304101cfd.tar.gz
krb5-0e39f8a3ad915eeb0131fb4a87b0fef304101cfd.tar.xz
krb5-0e39f8a3ad915eeb0131fb4a87b0fef304101cfd.zip
Implement s4u extensions
Merge Luke's users/lhoward/s4u branch to trunk. Implements S4U2Self and S4U2Proxy extensions. ticket: 6563 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22736 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/clients/kvno')
-rw-r--r--src/clients/kvno/kvno.M14
-rw-r--r--src/clients/kvno/kvno.c166
2 files changed, 133 insertions, 47 deletions
diff --git a/src/clients/kvno/kvno.M b/src/clients/kvno/kvno.M
index b7e4d46a0d..37b0bcbd53 100644
--- a/src/clients/kvno/kvno.M
+++ b/src/clients/kvno/kvno.M
@@ -51,6 +51,13 @@ suppress printing
.B \-h
prints a usage statement and exits
.TP
+.B \-P
+specifies that the
+.B service1 service2 ...
+arguments are to be treated as services for which credentials should
+be acquired using constrained delegation. This option is only valid
+when used in conjunction with protocol transition.
+.TP
.B \-S sname
specifies that krb5_sname_to_principal() will be used to build
principal names. If this flag is specified, the
@@ -59,6 +66,13 @@ arguments are interpreted as hostnames (rather than principal names),
and
.B sname
is interpreted as the service name.
+.TP
+.B \-U for_user
+specifies that protocol transition (S4U2Self) is to be used to acquire
+a ticket on behalf of
+.B for_user.
+If constrained delegation is not requested, the service name
+must match the credentials cache client principal.
.SH ENVIRONMENT
.B Kvno
uses the following environment variable:
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
index b98b85d304..58702525f6 100644
--- a/src/clients/kvno/kvno.c
+++ b/src/clients/kvno/kvno.c
@@ -39,8 +39,9 @@ static char *prog;
static void xusage()
{
- fprintf(stderr, "usage: %s [-C] [-u] [-c ccache] [-e etype] [-k keytab] [-S sname] service1 service2 ...\n",
- prog);
+ fprintf(stderr, "usage: %s [-C] [-u] [-c ccache] [-e etype]\n", prog);
+ fprintf(stderr, "\t[-k keytab] [-S sname] [-U for_user [-P]]\n");
+ fprintf(stderr, "\tservice1 service2 ...\n");
exit(1);
}
@@ -48,7 +49,8 @@ int quiet = 0;
static void do_v5_kvno (int argc, char *argv[],
char *ccachestr, char *etypestr, char *keytab_name,
- char *sname, int canon, int unknown);
+ char *sname, int canon, int unknown,
+ char *for_user, int proxy);
#include <com_err.h>
static void extended_com_err_fn (const char *, errcode_t, const char *,
@@ -58,8 +60,8 @@ int main(int argc, char *argv[])
{
int option;
char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL;
- char *sname = NULL;
- int canon = 0, unknown = 0;
+ char *sname = NULL, *for_user = NULL;
+ int canon = 0, unknown = 0, proxy = 0;
set_com_err_hook (extended_com_err_fn);
@@ -67,7 +69,7 @@ int main(int argc, char *argv[])
prog = strrchr(argv[0], '/');
prog = prog ? (prog + 1) : argv[0];
- while ((option = getopt(argc, argv, "uCc:e:hk:qS:")) != -1) {
+ while ((option = getopt(argc, argv, "uCc:e:hk:qPS:U:")) != -1) {
switch (option) {
case 'C':
canon = 1;
@@ -87,6 +89,9 @@ int main(int argc, char *argv[])
case 'q':
quiet = 1;
break;
+ case 'P':
+ proxy = 1; /* S4U2Proxy - constrained delegation */
+ break;
case 'S':
sname = optarg;
if (unknown == 1){
@@ -101,21 +106,37 @@ int main(int argc, char *argv[])
xusage();
}
break;
+ case 'U':
+ for_user = optarg; /* S4U2Self - protocol transition */
+ break;
default:
xusage();
break;
}
}
+ if (proxy) {
+ if (keytab_name == NULL) {
+ fprintf(stderr, "Option -P (constrained delegation) "
+ "requires keytab to be specified\n");
+ xusage();
+ } else if (for_user == NULL) {
+ fprintf(stderr, "Option -P (constrained delegation) requires "
+ "option -U (protocol transition)\n");
+ xusage();
+ }
+ }
+
if ((argc - optind) < 1)
xusage();
do_v5_kvno(argc - optind, argv + optind,
- ccachestr, etypestr, keytab_name, sname, canon, unknown);
+ ccachestr, etypestr, keytab_name, sname,
+ canon, unknown, for_user, proxy);
return 0;
}
-#include <krb5.h>
+#include <k5-int.h>
static krb5_context context;
static void extended_com_err_fn (const char *myprog, errcode_t code,
const char *fmt, va_list args)
@@ -130,17 +151,18 @@ static void extended_com_err_fn (const char *myprog, errcode_t code,
static void do_v5_kvno (int count, char *names[],
char * ccachestr, char *etypestr, char *keytab_name,
- char *sname, int canon, int unknown)
+ char *sname, int canon, int unknown, char *for_user,
+ int proxy)
{
krb5_error_code ret;
int i, errors;
krb5_enctype etype;
krb5_ccache ccache;
krb5_principal me;
- krb5_creds in_creds, *out_creds;
- krb5_ticket *ticket;
- char *princ;
+ krb5_creds in_creds;
krb5_keytab keytab = NULL;
+ krb5_principal for_user_princ = NULL;
+ krb5_flags options;
ret = krb5_init_context(&context);
if (ret) {
@@ -175,6 +197,16 @@ static void do_v5_kvno (int count, char *names[],
}
}
+ if (for_user) {
+ ret = krb5_parse_name_flags(context, for_user,
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE,
+ &for_user_princ);
+ if (ret) {
+ com_err(prog, ret, "while parsing principal name %s", for_user);
+ exit(1);
+ }
+ }
+
ret = krb5_cc_get_principal(context, ccache, &me);
if (ret) {
com_err(prog, ret, "while getting client principal name");
@@ -183,91 +215,131 @@ static void do_v5_kvno (int count, char *names[],
errors = 0;
+ options = 0;
+ if (canon)
+ options |= KRB5_GC_CANONICALIZE;
+
for (i = 0; i < count; i++) {
- memset(&in_creds, 0, sizeof(in_creds));
+ krb5_principal server = NULL;
+ krb5_ticket *ticket = NULL;
+ krb5_creds *out_creds = NULL;
+ char *princ = NULL;
- in_creds.client = me;
+ memset(&in_creds, 0, sizeof(in_creds));
if (sname != NULL) {
ret = krb5_sname_to_principal(context, names[i],
sname, KRB5_NT_SRV_HST,
- &in_creds.server);
+ &server);
} else {
- ret = krb5_parse_name(context, names[i], &in_creds.server);
+ ret = krb5_parse_name(context, names[i], &server);
}
if (ret) {
if (!quiet)
com_err(prog, ret, "while parsing principal name %s", names[i]);
- errors++;
- continue;
+ goto error;
}
if (unknown == 1) {
- krb5_princ_type(context, in_creds.server) = KRB5_NT_UNKNOWN;
+ krb5_princ_type(context, server) = KRB5_NT_UNKNOWN;
}
- ret = krb5_unparse_name(context, in_creds.server, &princ);
+ ret = krb5_unparse_name(context, server, &princ);
if (ret) {
com_err(prog, ret,
"while formatting parsed principal name for '%s'",
names[i]);
- errors++;
- continue;
+ goto error;
}
in_creds.keyblock.enctype = etype;
- ret = krb5_get_credentials(context, canon ? KRB5_GC_CANONICALIZE : 0,
- ccache, &in_creds, &out_creds);
+ if (for_user) {
+ if (!proxy &&
+ !krb5_principal_compare(context, me, server)) {
+ com_err(prog, EINVAL,
+ "client and server principal names must match");
+ goto error;
+ }
- krb5_free_principal(context, in_creds.server);
+ in_creds.client = for_user_princ;
+ in_creds.server = me;
+
+ ret = krb5_get_credentials_for_user(context, options, ccache,
+ &in_creds, NULL, &out_creds);
+ } else {
+ in_creds.client = me;
+ in_creds.server = server;
+ ret = krb5_get_credentials(context, options, ccache,
+ &in_creds, &out_creds);
+ }
if (ret) {
com_err(prog, ret, "while getting credentials for %s", princ);
-
- krb5_free_unparsed_name(context, princ);
-
- errors++;
- continue;
+ goto error;
}
/* we need a native ticket */
ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
if (ret) {
com_err(prog, ret, "while decoding ticket for %s", princ);
- krb5_free_creds(context, out_creds);
- krb5_free_unparsed_name(context, princ);
-
- errors++;
- continue;
+ goto error;
}
-
+
if (keytab) {
ret = krb5_server_decrypt_ticket_keytab(context, keytab, ticket);
if (ret) {
- if (!quiet)
- printf("%s: kvno = %d, keytab entry invalid", princ, ticket->enc_part.kvno);
+ if (!quiet) {
+ fprintf(stderr, "%s: kvno = %d, keytab entry invalid\n",
+ princ, ticket->enc_part.kvno);
+ }
com_err(prog, ret, "while decrypting ticket for %s", princ);
- krb5_free_ticket(context, ticket);
- krb5_free_creds(context, out_creds);
- krb5_free_unparsed_name(context, princ);
-
- errors++;
- continue;
+ goto error;
}
if (!quiet)
- printf("%s: kvno = %d, keytab entry valid\n", princ, ticket->enc_part.kvno);
+ printf("%s: kvno = %d, keytab entry valid\n",
+ princ, ticket->enc_part.kvno);
+ if (proxy) {
+ krb5_free_creds(context, out_creds);
+ out_creds = NULL;
+
+ in_creds.client = ticket->enc_part2->client;
+ in_creds.server = server;
+
+ ret = krb5_get_credentials_for_proxy(context,
+ KRB5_GC_CANONICALIZE,
+ ccache,
+ &in_creds,
+ ticket,
+ &out_creds);
+ if (ret) {
+ com_err(prog, ret,
+ "%s: constrained delegation failed", princ);
+ goto error;
+ }
+ }
} else {
if (!quiet)
printf("%s: kvno = %d\n", princ, ticket->enc_part.kvno);
}
- krb5_free_creds(context, out_creds);
- krb5_free_unparsed_name(context, princ);
+ continue;
+
+error:
+ if (server != NULL)
+ krb5_free_principal(context, server);
+ if (ticket != NULL)
+ krb5_free_ticket(context, ticket);
+ if (out_creds != NULL)
+ krb5_free_creds(context, out_creds);
+ if (princ != NULL)
+ krb5_free_unparsed_name(context, princ);
+ errors++;
}
if (keytab)
krb5_kt_close(context, keytab);
krb5_free_principal(context, me);
+ krb5_free_principal(context, for_user_princ);
krb5_cc_close(context, ccache);
krb5_free_context(context);