gssapi: Import elric1's gss-token
This commit is contained in:
@@ -235,7 +235,7 @@ libgssapi_la_LIBADD = \
|
|||||||
$(LIB_hcrypto) \
|
$(LIB_hcrypto) \
|
||||||
$(LIBADD_roken)
|
$(LIBADD_roken)
|
||||||
|
|
||||||
man_MANS = gssapi.3 gss_acquire_cred.3 mech/mech.5
|
man_MANS = gssapi.3 gss_acquire_cred.3 mech/mech.5 gss-token.1
|
||||||
|
|
||||||
include_HEADERS = gssapi.h
|
include_HEADERS = gssapi.h
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
@@ -311,7 +311,7 @@ test_cfx_SOURCES = krb5/test_cfx.c
|
|||||||
|
|
||||||
check_PROGRAMS = test_acquire_cred $(TESTS)
|
check_PROGRAMS = test_acquire_cred $(TESTS)
|
||||||
|
|
||||||
bin_PROGRAMS = gsstool
|
bin_PROGRAMS = gsstool gss-token
|
||||||
noinst_PROGRAMS = test_cred test_kcred test_context test_ntlm test_add_store_cred
|
noinst_PROGRAMS = test_cred test_kcred test_context test_ntlm test_add_store_cred
|
||||||
|
|
||||||
test_context_SOURCES = test_context.c test_common.c test_common.h
|
test_context_SOURCES = test_context.c test_common.c test_common.h
|
||||||
@@ -332,6 +332,7 @@ LDADD = libgssapi.la \
|
|||||||
|
|
||||||
dist_gsstool_SOURCES = gsstool.c
|
dist_gsstool_SOURCES = gsstool.c
|
||||||
nodist_gsstool_SOURCES = gss-commands.c gss-commands.h
|
nodist_gsstool_SOURCES = gss-commands.c gss-commands.h
|
||||||
|
dist_gss_token_SOURCES = gss-token.c
|
||||||
|
|
||||||
gsstool_LDADD = libgssapi.la \
|
gsstool_LDADD = libgssapi.la \
|
||||||
$(top_builddir)/lib/sl/libsl.la \
|
$(top_builddir)/lib/sl/libsl.la \
|
||||||
@@ -339,6 +340,10 @@ gsstool_LDADD = libgssapi.la \
|
|||||||
$(LIB_readline) \
|
$(LIB_readline) \
|
||||||
$(LIB_roken)
|
$(LIB_roken)
|
||||||
|
|
||||||
|
gss_token_LDADD = libgssapi.la \
|
||||||
|
$(top_builddir)/lib/krb5/libkrb5.la \
|
||||||
|
$(LIB_roken)
|
||||||
|
|
||||||
gss-commands.c gss-commands.h: gss-commands.in
|
gss-commands.c gss-commands.h: gss-commands.in
|
||||||
$(SLC) $(srcdir)/gss-commands.in
|
$(SLC) $(srcdir)/gss-commands.in
|
||||||
|
|
||||||
|
75
lib/gssapi/gss-token.1
Normal file
75
lib/gssapi/gss-token.1
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.Dd May 12, 2014
|
||||||
|
.Os
|
||||||
|
.Dt GSS-TOKEN 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm gss-token
|
||||||
|
.Nd generate and consume base64 GSS tokens
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl DNn
|
||||||
|
.Op Fl c count
|
||||||
|
.Ar service@host
|
||||||
|
.Nm
|
||||||
|
.Fl r
|
||||||
|
.Op Fl MNln
|
||||||
|
.Op Fl C Ar ccache
|
||||||
|
.Op Fl c count
|
||||||
|
.Op Ar service@host
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
generates and consumes base64 encoded GSS tokens.
|
||||||
|
It is mostly useful for testing.
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
supports the following options:
|
||||||
|
.Bl -tag -width indentxxxx
|
||||||
|
.It Fl C Ar ccache
|
||||||
|
write an accepted delegated credential into
|
||||||
|
.Ar ccache .
|
||||||
|
This only makes sense if
|
||||||
|
.Fl r
|
||||||
|
is specified.
|
||||||
|
.It Fl D
|
||||||
|
delegate credentials.
|
||||||
|
This only makes sense as a client, that is when
|
||||||
|
.Fl r
|
||||||
|
is not specified.
|
||||||
|
.It Fl M
|
||||||
|
copy the default ccache to a MEMORY: ccache before each
|
||||||
|
separate write operation.
|
||||||
|
The default ccache will not pick up any obtained service
|
||||||
|
tickets.
|
||||||
|
If specified with
|
||||||
|
.Fl c ,
|
||||||
|
the cache will revert to its original state before each
|
||||||
|
new token is written.
|
||||||
|
This can be used to load test the KDC.
|
||||||
|
.It Fl N
|
||||||
|
prepend
|
||||||
|
.Dq Negotiate\
|
||||||
|
to generated tokens and expect it on consumed tokens.
|
||||||
|
.It Fl c Ar count
|
||||||
|
repeat the operation
|
||||||
|
.Ar count
|
||||||
|
times.
|
||||||
|
This is good for very basic benchmarking.
|
||||||
|
.It Fl l
|
||||||
|
loop infinitely in read mode.
|
||||||
|
This is to support a multiple round trip GSS mechanism.
|
||||||
|
.It Fl n
|
||||||
|
do not output the generated token.
|
||||||
|
.It Fl r
|
||||||
|
read a token rather than generate a token.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
takes one argument, a
|
||||||
|
.Ar host@service
|
||||||
|
specifier.
|
||||||
|
The argument is required when generating a token but is optional if
|
||||||
|
consuming (reading) a token.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr gssapi 3 ,
|
||||||
|
.Xr kerberos 8 .
|
563
lib/gssapi/gss-token.c
Normal file
563
lib/gssapi/gss-token.c
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
/* */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1997-2011 Roland C. Dowdeswell
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer and
|
||||||
|
* dedication in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <malloc/malloc.h>
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <gssapi/gssapi.h>
|
||||||
|
#include <gssapi/gssapi_krb5.h>
|
||||||
|
#include <krb5.h>
|
||||||
|
#include <base64.h>
|
||||||
|
#include <getarg.h>
|
||||||
|
#include <roken.h>
|
||||||
|
#include <vers.h>
|
||||||
|
|
||||||
|
#define GBAIL(x, _maj, _min) do { \
|
||||||
|
if (GSS_ERROR(_maj)) { \
|
||||||
|
char *the_gss_err; \
|
||||||
|
\
|
||||||
|
ret = 1; \
|
||||||
|
the_gss_err = gss_mk_err(_maj, _min, x); \
|
||||||
|
if (the_gss_err) \
|
||||||
|
fprintf(stderr, "%s\n", the_gss_err); \
|
||||||
|
else \
|
||||||
|
fprintf(stderr, "err making err\n"); \
|
||||||
|
free(the_gss_err); \
|
||||||
|
goto bail; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define K5BAIL(x) do { \
|
||||||
|
kret = x; \
|
||||||
|
if (kret) { \
|
||||||
|
const char *k5err; \
|
||||||
|
\
|
||||||
|
k5err = krb5_get_error_message(kctx, kret); \
|
||||||
|
if (k5err) { \
|
||||||
|
fprintf(stderr, "%s in %s:%s\n", k5err, \
|
||||||
|
#x, __func__); \
|
||||||
|
krb5_free_error_message(kctx, k5err); \
|
||||||
|
} else { \
|
||||||
|
fprintf(stderr, "unknown error %d in " \
|
||||||
|
"%s:%s\n", kret, #x, __func__); \
|
||||||
|
} \
|
||||||
|
exit(1); /* XXXrcd: shouldn't exit */ \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* global variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
int nflag = 0;
|
||||||
|
|
||||||
|
static char *
|
||||||
|
gss_mk_err(OM_uint32 maj_stat, OM_uint32 min_stat, const char *preamble)
|
||||||
|
{
|
||||||
|
gss_buffer_desc status;
|
||||||
|
OM_uint32 new_stat;
|
||||||
|
OM_uint32 cur_stat;
|
||||||
|
OM_uint32 msg_ctx = 0;
|
||||||
|
OM_uint32 ret;
|
||||||
|
int type;
|
||||||
|
size_t newlen;
|
||||||
|
char *str = NULL;
|
||||||
|
char *tmp = NULL;
|
||||||
|
|
||||||
|
cur_stat = maj_stat;
|
||||||
|
type = GSS_C_GSS_CODE;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GSS_S_FAILURE produces a rather unhelpful message, so
|
||||||
|
* we skip straight to the mech specific error in this case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (type == GSS_C_GSS_CODE && cur_stat == GSS_S_FAILURE) {
|
||||||
|
type = GSS_C_MECH_CODE;
|
||||||
|
cur_stat = min_stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gss_display_status(&new_stat, cur_stat, type,
|
||||||
|
GSS_C_NO_OID, &msg_ctx, &status);
|
||||||
|
|
||||||
|
if (GSS_ERROR(ret))
|
||||||
|
return str; /* XXXrcd: hmmm, not quite?? */
|
||||||
|
|
||||||
|
if (str)
|
||||||
|
newlen = strlen(str);
|
||||||
|
else
|
||||||
|
newlen = strlen(preamble);
|
||||||
|
|
||||||
|
newlen += status.length + 3;
|
||||||
|
|
||||||
|
tmp = str;
|
||||||
|
str = malloc(newlen);
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
gss_release_buffer(&new_stat, &status);
|
||||||
|
return tmp; /* XXXrcd: hmmm, not quite?? */
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(str, newlen, "%s%s%.*s", tmp?tmp:preamble,
|
||||||
|
tmp?", ":": ", (int)status.length, (char *)status.value);
|
||||||
|
|
||||||
|
gss_release_buffer(&new_stat, &status);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are finished processing for maj_stat, then
|
||||||
|
* move onto min_stat.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (msg_ctx == 0 && type == GSS_C_GSS_CODE && min_stat != 0) {
|
||||||
|
type = GSS_C_MECH_CODE;
|
||||||
|
cur_stat = min_stat;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg_ctx == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_one_token(gss_name_t service, int delegate, int negotiate)
|
||||||
|
{
|
||||||
|
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
|
||||||
|
gss_buffer_desc in;
|
||||||
|
gss_buffer_desc out;
|
||||||
|
OM_uint32 maj;
|
||||||
|
OM_uint32 min;
|
||||||
|
OM_uint32 flags = 0;
|
||||||
|
int ret = 0;
|
||||||
|
char *base64_output = NULL;
|
||||||
|
|
||||||
|
in.length = 0;
|
||||||
|
in.value = 0;
|
||||||
|
out.length = 0;
|
||||||
|
out.value = 0;
|
||||||
|
|
||||||
|
if (delegate)
|
||||||
|
flags |= GSS_C_DELEG_FLAG;
|
||||||
|
|
||||||
|
maj = gss_init_sec_context(&min, GSS_C_NO_CREDENTIAL, &ctx, service,
|
||||||
|
GSS_C_NO_OID, flags, 0, GSS_C_NO_CHANNEL_BINDINGS, &in, NULL, &out,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
GBAIL("gss_init_sec_context", maj, min);
|
||||||
|
|
||||||
|
if (rk_base64_encode(out.value, out.length, &base64_output) < 0) {
|
||||||
|
fprintf(stderr, "Out of memory.\n");
|
||||||
|
ret = 1;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nflag)
|
||||||
|
printf("%s%s\n", negotiate?"Negotiate ":"", base64_output);
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (out.value)
|
||||||
|
gss_release_buffer(&min, &out);
|
||||||
|
|
||||||
|
if (ctx != GSS_C_NO_CONTEXT) {
|
||||||
|
/*
|
||||||
|
* XXXrcd: here we ignore the fact that we might have an
|
||||||
|
* output token as this program doesn't do terribly
|
||||||
|
* well in that case.
|
||||||
|
*/
|
||||||
|
gss_delete_sec_context(&min, &ctx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(base64_output);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
copy_cache(krb5_context kctx, krb5_ccache from, krb5_ccache to)
|
||||||
|
{
|
||||||
|
krb5_error_code kret;
|
||||||
|
krb5_principal princ = NULL;
|
||||||
|
krb5_cc_cursor cursor;
|
||||||
|
krb5_creds cred;
|
||||||
|
|
||||||
|
K5BAIL(krb5_cc_get_principal(kctx, from, &princ));
|
||||||
|
K5BAIL(krb5_cc_initialize(kctx, to, princ));
|
||||||
|
K5BAIL(krb5_cc_start_seq_get(kctx, from, &cursor));
|
||||||
|
for (;;) {
|
||||||
|
kret = krb5_cc_next_cred(kctx, from, &cursor, &cred);
|
||||||
|
if (kret)
|
||||||
|
break;
|
||||||
|
kret = krb5_cc_store_cred(kctx, to, &cred);
|
||||||
|
krb5_free_cred_contents(kctx, &cred);
|
||||||
|
if (kret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
krb5_cc_end_seq_get(kctx, from, &cursor);
|
||||||
|
|
||||||
|
if (kret == KRB5_CC_END)
|
||||||
|
kret = 0;
|
||||||
|
K5BAIL(kret);
|
||||||
|
|
||||||
|
if (princ)
|
||||||
|
krb5_free_principal(kctx, princ);
|
||||||
|
|
||||||
|
return kret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_token(gss_name_t service, int delegate, int negotiate, int memcache,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
krb5_error_code kret;
|
||||||
|
krb5_context kctx = NULL;
|
||||||
|
krb5_ccache def_cache = NULL;
|
||||||
|
krb5_ccache mem_cache = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (memcache) {
|
||||||
|
K5BAIL(krb5_init_context(&kctx));
|
||||||
|
K5BAIL(krb5_cc_default(kctx, &def_cache));
|
||||||
|
K5BAIL(krb5_cc_resolve(kctx, "MEMORY:mem_cache", &mem_cache));
|
||||||
|
putenv("KRB5CCNAME=MEMORY:mem_cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < count; i++) {
|
||||||
|
if (memcache)
|
||||||
|
K5BAIL(copy_cache(kctx, def_cache, mem_cache));
|
||||||
|
kret = write_one_token(service, delegate, negotiate);
|
||||||
|
|
||||||
|
if (!nflag && i < count - 1)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kctx)
|
||||||
|
krb5_free_context(kctx);
|
||||||
|
if (def_cache)
|
||||||
|
krb5_cc_close(kctx, def_cache);
|
||||||
|
if (mem_cache)
|
||||||
|
krb5_cc_close(kctx, mem_cache);
|
||||||
|
|
||||||
|
return kret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
read_buffer(FILE *fp)
|
||||||
|
{
|
||||||
|
char buf[65536];
|
||||||
|
char *p;
|
||||||
|
char *ret = NULL;
|
||||||
|
size_t buflen;
|
||||||
|
size_t retlen = 0;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||||
|
if ((p = strchr(buf, '\n')) == NULL) {
|
||||||
|
fprintf(stderr, "Long line, exiting.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
buflen = strlen(buf);
|
||||||
|
|
||||||
|
if (buflen == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = realloc(ret, retlen + buflen + 1);
|
||||||
|
|
||||||
|
memcpy(ret + retlen, buf, buflen);
|
||||||
|
ret[retlen + buflen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferror(stdin)) {
|
||||||
|
perror("fgets");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_one_token(gss_name_t service, const char *ccname, int negotiate)
|
||||||
|
{
|
||||||
|
gss_cred_id_t cred = NULL;
|
||||||
|
gss_cred_id_t deleg_creds = NULL;
|
||||||
|
gss_name_t client;
|
||||||
|
gss_OID mech_oid;
|
||||||
|
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
|
||||||
|
gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
|
||||||
|
gss_buffer_desc out, dname;
|
||||||
|
krb5_context kctx = NULL;
|
||||||
|
krb5_ccache ccache = NULL;
|
||||||
|
krb5_error_code kret;
|
||||||
|
OM_uint32 maj, min;
|
||||||
|
size_t len;
|
||||||
|
char *inbuf = NULL;
|
||||||
|
char *tmp;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (service) {
|
||||||
|
maj = gss_acquire_cred(&min, service, 0, NULL, GSS_C_ACCEPT,
|
||||||
|
&cred, NULL, NULL);
|
||||||
|
GBAIL("gss_acquire_cred", maj, min);
|
||||||
|
}
|
||||||
|
|
||||||
|
inbuf = read_buffer(stdin);
|
||||||
|
if (!inbuf)
|
||||||
|
/* Just a couple of \n's in a row or EOF, not an error. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tmp = inbuf;
|
||||||
|
if (negotiate) {
|
||||||
|
if (strncasecmp("Negotiate ", inbuf, 10)) {
|
||||||
|
fprintf(stderr, "Token doesn't begin with "
|
||||||
|
"\"Negotiate \"\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(tmp);
|
||||||
|
in.value = malloc(len + 1);
|
||||||
|
if (!in.value) {
|
||||||
|
fprintf(stderr, "Out of memory.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = rk_base64_decode(tmp, in.value);
|
||||||
|
if (ret < 0) {
|
||||||
|
free(in.value);
|
||||||
|
if (errno == EOVERFLOW)
|
||||||
|
fprintf(stderr, "Token is too big\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Token encoding is not valid base64\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.length = 0;
|
||||||
|
out.value = 0;
|
||||||
|
|
||||||
|
maj = gss_accept_sec_context(&min, &ctx, cred, &in,
|
||||||
|
GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out,
|
||||||
|
NULL, NULL, &deleg_creds);
|
||||||
|
|
||||||
|
GBAIL("gss_accept_sec_context", maj, min);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXXrcd: not bothering to clean up because we're about to exit.
|
||||||
|
* Probably should fix this in case the code is used as
|
||||||
|
* an example by someone.
|
||||||
|
*/
|
||||||
|
|
||||||
|
maj = gss_display_name(&min, client, &dname, NULL);
|
||||||
|
GBAIL("gss_display_name", maj, min);
|
||||||
|
|
||||||
|
if (!nflag)
|
||||||
|
printf("Authenticated: %.*s\n", (int)dname.length,
|
||||||
|
(char *)dname.value);
|
||||||
|
|
||||||
|
if (ccname) {
|
||||||
|
#ifdef HAVE_GSS_STORE_CRED_INTO
|
||||||
|
gss_key_value_set_desc store;
|
||||||
|
gss_key_value_element_desc elem;
|
||||||
|
int overwrite_cred = 1;
|
||||||
|
int default_cred = 0;
|
||||||
|
|
||||||
|
elem.key = "ccache";
|
||||||
|
elem.value = ccname;
|
||||||
|
store.count = 1;
|
||||||
|
store.elements = &elem;
|
||||||
|
|
||||||
|
maj = gss_store_cred_into(&min, deleg_creds, GSS_C_INITIATE,
|
||||||
|
GSS_C_NO_OID, overwrite_cred, default_cred, &store, NULL,
|
||||||
|
NULL);
|
||||||
|
GBAIL("gss_store_cred_into", maj, min);
|
||||||
|
#else
|
||||||
|
K5BAIL(krb5_init_context(&kctx));
|
||||||
|
K5BAIL(krb5_cc_resolve(kctx, ccname, &ccache));
|
||||||
|
|
||||||
|
maj = gss_krb5_copy_ccache(&min, deleg_creds, ccache);
|
||||||
|
GBAIL("gss_krb5_copy_ccache", maj, min);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (kctx)
|
||||||
|
krb5_free_context(kctx);
|
||||||
|
if (ccache)
|
||||||
|
krb5_cc_close(kctx, ccache);
|
||||||
|
if (cred)
|
||||||
|
gss_release_cred(&min, &cred);
|
||||||
|
if (deleg_creds)
|
||||||
|
gss_release_cred(&min, &deleg_creds);
|
||||||
|
|
||||||
|
free(in.value);
|
||||||
|
free(inbuf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_token(gss_name_t service, const char *ccname, int negotiate, size_t count)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (i=0; i < count; i++) {
|
||||||
|
ret = read_one_token(service, ccname, negotiate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gss_name_t
|
||||||
|
import_service(char *service)
|
||||||
|
{
|
||||||
|
gss_buffer_desc name;
|
||||||
|
gss_name_t svc = NULL;
|
||||||
|
OM_uint32 maj;
|
||||||
|
OM_uint32 min;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
name.length = strlen(service);
|
||||||
|
name.value = service;
|
||||||
|
|
||||||
|
maj = gss_import_name(&min, &name, GSS_C_NT_HOSTBASED_SERVICE, &svc);
|
||||||
|
|
||||||
|
GBAIL("gss_import_name", maj, min);
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (ret)
|
||||||
|
exit(1);
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(int ecode)
|
||||||
|
{
|
||||||
|
FILE *f = ecode == 0 ? stdout : stderr;
|
||||||
|
fprintf(f, "Usage: gss-token [-DNn] [-c count] service@host\n");
|
||||||
|
fprintf(f, " gss-token -r [-Nln] [-C ccache] [-c count] "
|
||||||
|
"[service@host]\n");
|
||||||
|
exit(ecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
OM_uint32 min;
|
||||||
|
gss_name_t service = NULL;
|
||||||
|
size_t count = 1;
|
||||||
|
int Dflag = 0;
|
||||||
|
int Mflag = 0;
|
||||||
|
int Nflag = 0;
|
||||||
|
int hflag = 0;
|
||||||
|
int lflag = 0;
|
||||||
|
int rflag = 0;
|
||||||
|
int version_flag = 0;
|
||||||
|
int ret = 0;
|
||||||
|
int optidx = 0;
|
||||||
|
char *ccname = NULL;
|
||||||
|
struct getargs args[] = {
|
||||||
|
{ "help", 'h', arg_flag, &hflag, NULL, NULL },
|
||||||
|
{ "version", 0, arg_flag, &version_flag, NULL, NULL },
|
||||||
|
{ NULL, 'C', arg_string, &ccname, NULL, NULL },
|
||||||
|
{ NULL, 'D', arg_flag, &Dflag, NULL, NULL },
|
||||||
|
{ NULL, 'M', arg_flag, &Mflag, NULL, NULL },
|
||||||
|
{ NULL, 'N', arg_flag, &Nflag, NULL, NULL },
|
||||||
|
{ NULL, 'r', arg_flag, &rflag, NULL, NULL },
|
||||||
|
{ NULL, 'l', arg_flag, &lflag, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
setprogname(argv[0]);
|
||||||
|
if (argc == 1 ||
|
||||||
|
getarg(args, sizeof(args)/sizeof(args[0]), argc, argv, &optidx))
|
||||||
|
usage(1);
|
||||||
|
if (hflag)
|
||||||
|
usage(0);
|
||||||
|
if (version_flag) {
|
||||||
|
print_version(NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optidx;
|
||||||
|
argv += optidx;
|
||||||
|
|
||||||
|
if (argc > 0)
|
||||||
|
service = import_service(*argv);
|
||||||
|
|
||||||
|
if (!rflag) {
|
||||||
|
if (!argc) {
|
||||||
|
fprintf(stderr, "Without -r, hostbased_service must "
|
||||||
|
"be provided.\n");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
if (ccname) {
|
||||||
|
fprintf(stderr, "Specifying a target ccache doesn't "
|
||||||
|
"make sense without -r.\n");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
ret = write_token(service, Dflag, Nflag, Mflag, count);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Dflag) {
|
||||||
|
fprintf(stderr, "Delegating credentials (-D) doesn't make "
|
||||||
|
"sense when reading tokens (-r).\n");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = read_token(service, ccname, Nflag, count);
|
||||||
|
} while (lflag && !ret && !feof(stdin));
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (service)
|
||||||
|
gss_release_name(&min, &service);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
Reference in New Issue
Block a user