gss-token: turn initiator and acceptor into loops.

This commit is contained in:
Roland C. Dowdeswell
2020-10-07 18:56:19 +01:00
parent 0055c1c80b
commit 4336c944e0
2 changed files with 84 additions and 32 deletions

View File

@@ -78,6 +78,23 @@ takes one argument, a
specifier. specifier.
The argument is required when running as an initiator but is optional as The argument is required when running as an initiator but is optional as
an acceptor. an acceptor.
.Pp
.Nm
will try to read a token whenever the GSS mechanism expects one
and will output a token whenever the GSS mechanism provides one.
Tokens are base64 encoded and terminated by either two successive
newlines or one newline and EOF.
The base64 encoding may be broken up by single newlines which will
be ignored when read. No extra whitespace will be ignored.
.Sh EXAMPLES
To test a simple GSS mechanism which doesn't require a round trip,
a single
.Pa /bin/sh
pipeline will suffice:
.Bd -literal -offset indent
$ export KRB5_KTNAME=/path/to/keytab
$ gss-token HTTP@$(hostname) | gss-token -r
.Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr gssapi 3 , .Xr gssapi 3 ,
.Xr kerberos 8 . .Xr kerberos 8 .

View File

@@ -203,17 +203,25 @@ read_buffer(FILE *fp)
} }
static int static int
write_token(gss_buffer_t out, int negotiate) write_and_free_token(gss_buffer_t out, int negotiate)
{ {
char *outstr = NULL; OM_uint32 min;
char *p = out->value; char *outstr = NULL;
size_t len = out->length; char *p = out->value;
size_t inc; size_t len = out->length;
int ret; size_t inc;
int first = 1; int ret = 0;
int first = 1;
if (nflag) if (nflag)
return 0; goto bail;
/*
* According to RFC 2744 page 25, we simply don't output
* zero length output tokens.
*/
if (len == 0)
goto bail;
inc = len; inc = len;
if (Sflag) if (Sflag)
@@ -229,7 +237,8 @@ write_token(gss_buffer_t out, int negotiate)
ret = rk_base64_encode(p, inc, &outstr); ret = rk_base64_encode(p, inc, &outstr);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Out of memory.\n"); fprintf(stderr, "Out of memory.\n");
return 1; ret = 1;
goto bail;
} }
printf("%s%s\n", negotiate?"Negotiate ":"", outstr); printf("%s%s\n", negotiate?"Negotiate ":"", outstr);
free(outstr); free(outstr);
@@ -237,6 +246,8 @@ write_token(gss_buffer_t out, int negotiate)
len -= inc; len -= inc;
} while (len > 0); } while (len > 0);
bail:
gss_release_buffer(&min, out);
return 0; return 0;
} }
@@ -248,6 +259,9 @@ read_token(gss_buffer_t in, int negotiate)
size_t len; size_t len;
int ret = 0; int ret = 0;
/* We must flush before we block wanting input */
fflush(stdout);
inbuf = read_buffer(stdin); inbuf = read_buffer(stdin);
if (!inbuf) if (!inbuf)
/* Just a couple of \n's in a row or EOF, no error. */ /* Just a couple of \n's in a row or EOF, no error. */
@@ -301,28 +315,42 @@ initiate_one(gss_name_t service, int delegate, int negotiate)
OM_uint32 maj; OM_uint32 maj;
OM_uint32 min; OM_uint32 min;
OM_uint32 flags = 0; OM_uint32 flags = 0;
int first = 1;
int ret = 0; int ret = 0;
in.length = 0;
in.value = 0;
out.length = 0;
out.value = 0;
if (delegate) if (delegate)
flags |= GSS_C_DELEG_FLAG; flags |= GSS_C_DELEG_FLAG;
maj = gss_init_sec_context(&min, GSS_C_NO_CREDENTIAL, &ctx, service, do {
GSS_C_NO_OID, flags, 0, GSS_C_NO_CHANNEL_BINDINGS, &in, NULL, &out, out.length = 0;
NULL, NULL); out.value = 0;
GBAIL("gss_init_sec_context", maj, min); if (first) {
in.length = 0;
in.value = 0;
first = 0;
} else {
printf("\n");
ret = read_token(&in, negotiate);
if (ret)
return ret;
if (feof(stdin))
return -1;
}
write_token(&out, negotiate); 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);
ret = write_and_free_token(&out, negotiate);
if (ret)
return ret;
GBAIL("gss_init_sec_context", maj, min);
} while (maj & GSS_S_CONTINUE_NEEDED);
bail: bail:
if (out.value)
gss_release_buffer(&min, &out);
if (ctx != GSS_C_NO_CONTEXT) { if (ctx != GSS_C_NO_CONTEXT) {
/* /*
* XXXrcd: here we ignore the fact that we might have an * XXXrcd: here we ignore the fact that we might have an
@@ -425,18 +453,25 @@ accept_one(gss_name_t service, const char *ccname, int negotiate)
GBAIL("gss_acquire_cred", maj, min); GBAIL("gss_acquire_cred", maj, min);
} }
ret = read_token(&in, negotiate); do {
if (ret) if (feof(stdin))
return ret; return -1;
ret = read_token(&in, negotiate);
if (ret)
return ret;
out.length = 0; out.length = 0;
out.value = 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); maj = gss_accept_sec_context(&min, &ctx, cred, &in,
GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out,
NULL, NULL, &deleg_creds);
ret = write_and_free_token(&out, negotiate);
if (ret)
return ret;
GBAIL("gss_accept_sec_context", maj, min);
} while (maj & GSS_S_CONTINUE_NEEDED);
/* /*
* XXXrcd: not bothering to clean up because we're about to exit. * XXXrcd: not bothering to clean up because we're about to exit.