Files
heimdal/appl/gssmask/gssmask.c
Roland C. Dowdeswell cc47c8fa7b Turn on -Wextra -Wno-sign-compare -Wno-unused-paramter and fix issues.
We turn on a few extra warnings and fix the fallout that occurs
when building with --enable-developer.  Note that we get different
warnings on different machines and so this will be a work in
progress.  So far, we have built on NetBSD/amd64 5.99.64 (which
uses gcc 4.5.3) and Ubuntu 10.04.3 LTS (which uses gcc 4.4.3).

Notably, we fixed

	1.  a lot of missing structure initialisers,

	2.  unchecked return values for functions that glibc
	    marks as __attribute__((warn-unused-result)),

	3.  made minor modifications to slc and asn1_compile
	    which can generate code which generates warnings,
	    and

	4.  a few stragglers here and there.

We turned off the extended warnings for many programs in appl/ as
they are nearing the end of their useful lifetime, e.g.  rsh, rcp,
popper, ftp and telnet.

Interestingly, glibc's strncmp() macro needed to be worked around
whereas the function calls did not.

We have not yet tried this on 32 bit platforms, so there will be
a few more warnings when we do.
2012-02-20 19:45:41 +00:00

1266 lines
27 KiB
C

/*
* Copyright (c) 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* 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 in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of KTH nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``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 KTH OR ITS CONTRIBUTORS 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 "common.h"
RCSID("$Id$");
/*
*
*/
enum handle_type { handle_context, handle_cred };
struct handle {
int32_t idx;
enum handle_type type;
void *ptr;
struct handle *next;
};
struct client {
krb5_storage *sock;
krb5_storage *logging;
char *moniker;
int32_t nHandle;
struct handle *handles;
struct sockaddr_storage sa;
socklen_t salen;
char servername[MAXHOSTNAMELEN];
};
FILE *logfile;
static char *targetname;
krb5_context context;
/*
*
*/
static void
logmessage(struct client *c, const char *file, unsigned int lineno,
int level, const char *fmt, ...)
{
char *message;
va_list ap;
int32_t ackid;
int ret;
va_start(ap, fmt);
ret = vasprintf(&message, fmt, ap);
va_end(ap);
if (ret == -1)
errx(1, "out of memory");
if (logfile)
fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
if (c->logging) {
if (krb5_store_int32(c->logging, eLogInfo) != 0)
errx(1, "krb5_store_int32: log level");
if (krb5_store_string(c->logging, file) != 0)
errx(1, "krb5_store_string: filename");
if (krb5_store_int32(c->logging, lineno) != 0)
errx(1, "krb5_store_string: filename");
if (krb5_store_string(c->logging, message) != 0)
errx(1, "krb5_store_string: message");
if (krb5_ret_int32(c->logging, &ackid) != 0)
errx(1, "krb5_ret_int32: ackid");
}
free(message);
}
/*
*
*/
static int32_t
add_handle(struct client *c, enum handle_type type, void *data)
{
struct handle *h;
h = ecalloc(1, sizeof(*h));
h->idx = ++c->nHandle;
h->type = type;
h->ptr = data;
h->next = c->handles;
c->handles = h;
return h->idx;
}
static void
del_handle(struct handle **h, int32_t idx)
{
OM_uint32 min_stat;
if (idx == 0)
return;
while (*h) {
if ((*h)->idx == idx) {
struct handle *p = *h;
*h = (*h)->next;
switch(p->type) {
case handle_context: {
gss_ctx_id_t c = p->ptr;
gss_delete_sec_context(&min_stat, &c, NULL);
break; }
case handle_cred: {
gss_cred_id_t c = p->ptr;
gss_release_cred(&min_stat, &c);
break; }
}
free(p);
return;
}
h = &((*h)->next);
}
errx(1, "tried to delete an unexisting handle");
}
static void *
find_handle(struct handle *h, int32_t idx, enum handle_type type)
{
if (idx == 0)
return NULL;
while (h) {
if (h->idx == idx) {
if (type == h->type)
return h->ptr;
errx(1, "monger switched type on handle!");
}
h = h->next;
}
return NULL;
}
static int32_t
convert_gss_to_gsm(OM_uint32 maj_stat)
{
switch(maj_stat) {
case 0:
return GSMERR_OK;
case GSS_S_CONTINUE_NEEDED:
return GSMERR_CONTINUE_NEEDED;
case GSS_S_DEFECTIVE_TOKEN:
return GSMERR_INVALID_TOKEN;
case GSS_S_BAD_MIC:
return GSMERR_AP_MODIFIED;
default:
return GSMERR_ERROR;
}
}
static int32_t
convert_krb5_to_gsm(krb5_error_code ret)
{
switch(ret) {
case 0:
return GSMERR_OK;
default:
return GSMERR_ERROR;
}
}
/*
*
*/
static int32_t
acquire_cred(struct client *c,
krb5_principal principal,
krb5_get_init_creds_opt *opt,
int32_t *handle)
{
krb5_error_code ret;
krb5_creds cred;
krb5_ccache id;
gss_cred_id_t gcred;
OM_uint32 maj_stat, min_stat;
*handle = 0;
krb5_get_init_creds_opt_set_forwardable (opt, 1);
krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
memset(&cred, 0, sizeof(cred));
ret = krb5_get_init_creds_password (context,
&cred,
principal,
NULL,
NULL,
NULL,
0,
NULL,
opt);
if (ret) {
logmessage(c, __FILE__, __LINE__, 0,
"krb5_get_init_creds failed: %d", ret);
return convert_krb5_to_gsm(ret);
}
ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
if (ret)
krb5_err (context, 1, ret, "krb5_cc_initialize");
ret = krb5_cc_initialize (context, id, cred.client);
if (ret)
krb5_err (context, 1, ret, "krb5_cc_initialize");
ret = krb5_cc_store_cred (context, id, &cred);
if (ret)
krb5_err (context, 1, ret, "krb5_cc_store_cred");
krb5_free_cred_contents (context, &cred);
maj_stat = gss_krb5_import_cred(&min_stat,
id,
NULL,
NULL,
&gcred);
krb5_cc_close(context, id);
if (maj_stat) {
logmessage(c, __FILE__, __LINE__, 0,
"krb5 import creds failed with: %d", maj_stat);
return convert_gss_to_gsm(maj_stat);
}
*handle = add_handle(c, handle_cred, gcred);
return 0;
}
/*
*
*/
#define HandleOP(h) \
handle##h(enum gssMaggotOp op, struct client *c)
/*
*
*/
static int
HandleOP(GetVersionInfo)
{
put32(c, GSSMAGGOTPROTOCOL);
errx(1, "GetVersionInfo");
}
static int
HandleOP(GoodBye)
{
struct handle *h = c->handles;
unsigned int i = 0;
while (h) {
h = h->next;
i++;
}
if (i)
logmessage(c, __FILE__, __LINE__, 0,
"Did not toast all resources: %d", i);
return 1;
}
static int
HandleOP(InitContext)
{
OM_uint32 maj_stat, min_stat, ret_flags;
int32_t hContext, hCred, flags;
krb5_data target_name, in_token;
int32_t new_context_id = 0, gsm_error = 0;
krb5_data out_token = { 0 , NULL };
gss_ctx_id_t ctx;
gss_cred_id_t creds;
gss_name_t gss_target_name;
gss_buffer_desc input_token, output_token;
gss_OID oid = GSS_C_NO_OID;
gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
ret32(c, hContext);
ret32(c, hCred);
ret32(c, flags);
retdata(c, target_name);
retdata(c, in_token);
logmessage(c, __FILE__, __LINE__, 0,
"targetname: <%.*s>", (int)target_name.length,
(char *)target_name.data);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
hContext = 0;
creds = find_handle(c->handles, hCred, handle_cred);
if (creds == NULL)
abort();
input_token.length = target_name.length;
input_token.value = target_name.data;
maj_stat = gss_import_name(&min_stat,
&input_token,
GSS_KRB5_NT_PRINCIPAL_NAME,
&gss_target_name);
if (GSS_ERROR(maj_stat)) {
logmessage(c, __FILE__, __LINE__, 0,
"import name creds failed with: %d", maj_stat);
gsm_error = convert_gss_to_gsm(maj_stat);
goto out;
}
/* oid from flags */
if (in_token.length) {
input_token.length = in_token.length;
input_token.value = in_token.data;
input_token_ptr = &input_token;
if (ctx == NULL)
krb5_errx(context, 1, "initcreds, context NULL, but not first req");
} else {
input_token.length = 0;
input_token.value = NULL;
if (ctx)
krb5_errx(context, 1, "initcreds, context not NULL, but first req");
}
if ((flags & GSS_C_DELEG_FLAG) != 0)
logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");
if ((flags & GSS_C_DCE_STYLE) != 0)
logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");
maj_stat = gss_init_sec_context(&min_stat,
creds,
&ctx,
gss_target_name,
oid,
flags & 0x7f,
0,
NULL,
input_token_ptr,
NULL,
&output_token,
&ret_flags,
NULL);
if (GSS_ERROR(maj_stat)) {
if (hContext != 0)
del_handle(&c->handles, hContext);
new_context_id = 0;
logmessage(c, __FILE__, __LINE__, 0,
"gss_init_sec_context returns code: %d/%d",
maj_stat, min_stat);
} else {
if (input_token.length == 0)
new_context_id = add_handle(c, handle_context, ctx);
else
new_context_id = hContext;
}
gsm_error = convert_gss_to_gsm(maj_stat);
if (output_token.length) {
out_token.data = output_token.value;
out_token.length = output_token.length;
}
out:
logmessage(c, __FILE__, __LINE__, 0,
"InitContext return code: %d", gsm_error);
put32(c, new_context_id);
put32(c, gsm_error);
putdata(c, out_token);
gss_release_name(&min_stat, &gss_target_name);
if (output_token.length)
gss_release_buffer(&min_stat, &output_token);
krb5_data_free(&in_token);
krb5_data_free(&target_name);
return 0;
}
static int
HandleOP(AcceptContext)
{
OM_uint32 maj_stat, min_stat, ret_flags;
int32_t hContext, deleg_hcred, flags;
krb5_data in_token;
int32_t new_context_id = 0, gsm_error = 0;
krb5_data out_token = { 0 , NULL };
gss_ctx_id_t ctx;
gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
gss_buffer_desc input_token, output_token;
ret32(c, hContext);
ret32(c, flags);
retdata(c, in_token);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
hContext = 0;
if (in_token.length) {
input_token.length = in_token.length;
input_token.value = in_token.data;
} else {
input_token.length = 0;
input_token.value = NULL;
}
maj_stat = gss_accept_sec_context(&min_stat,
&ctx,
GSS_C_NO_CREDENTIAL,
&input_token,
GSS_C_NO_CHANNEL_BINDINGS,
NULL,
NULL,
&output_token,
&ret_flags,
NULL,
&deleg_cred);
if (GSS_ERROR(maj_stat)) {
if (hContext != 0)
del_handle(&c->handles, hContext);
logmessage(c, __FILE__, __LINE__, 0,
"gss_accept_sec_context returns code: %d/%d",
maj_stat, min_stat);
new_context_id = 0;
} else {
if (hContext == 0)
new_context_id = add_handle(c, handle_context, ctx);
else
new_context_id = hContext;
}
if (output_token.length) {
out_token.data = output_token.value;
out_token.length = output_token.length;
}
if ((ret_flags & GSS_C_DCE_STYLE) != 0)
logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
deleg_hcred = add_handle(c, handle_cred, deleg_cred);
logmessage(c, __FILE__, __LINE__, 0,
"accept_context delegated handle: %d", deleg_hcred);
} else {
gss_release_cred(&min_stat, &deleg_cred);
deleg_hcred = 0;
}
gsm_error = convert_gss_to_gsm(maj_stat);
put32(c, new_context_id);
put32(c, gsm_error);
putdata(c, out_token);
put32(c, deleg_hcred);
if (output_token.length)
gss_release_buffer(&min_stat, &output_token);
krb5_data_free(&in_token);
return 0;
}
static int
HandleOP(ToastResource)
{
int32_t handle;
ret32(c, handle);
logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
del_handle(&c->handles, handle);
put32(c, GSMERR_OK);
return 0;
}
static int
HandleOP(AcquireCreds)
{
char *name, *password;
int32_t gsm_error, flags, handle = 0;
krb5_principal principal = NULL;
krb5_get_init_creds_opt *opt = NULL;
krb5_error_code ret;
retstring(c, name);
retstring(c, password);
ret32(c, flags);
logmessage(c, __FILE__, __LINE__, 0,
"username: %s password: %s", name, password);
ret = krb5_parse_name(context, name, &principal);
if (ret) {
gsm_error = convert_krb5_to_gsm(ret);
goto out;
}
ret = krb5_get_init_creds_opt_alloc (context, &opt);
if (ret)
krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
gsm_error = acquire_cred(c, principal, opt, &handle);
out:
logmessage(c, __FILE__, __LINE__, 0,
"AcquireCreds handle: %d return code: %d", handle, gsm_error);
if (opt)
krb5_get_init_creds_opt_free (context, opt);
if (principal)
krb5_free_principal(context, principal);
free(name);
free(password);
put32(c, gsm_error);
put32(c, handle);
return 0;
}
static int
HandleOP(Sign)
{
OM_uint32 maj_stat, min_stat;
int32_t hContext, flags, seqno;
krb5_data token;
gss_ctx_id_t ctx;
gss_buffer_desc input_token, output_token;
ret32(c, hContext);
ret32(c, flags);
ret32(c, seqno);
retdata(c, token);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
errx(1, "sign: reference to unknown context");
input_token.length = token.length;
input_token.value = token.data;
maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,
&output_token);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_get_mic failed");
krb5_data_free(&token);
token.data = output_token.value;
token.length = output_token.length;
put32(c, 0); /* XXX fix gsm_error */
putdata(c, token);
gss_release_buffer(&min_stat, &output_token);
return 0;
}
static int
HandleOP(Verify)
{
OM_uint32 maj_stat, min_stat;
int32_t hContext, flags, seqno;
krb5_data msg, mic;
gss_ctx_id_t ctx;
gss_buffer_desc msg_token, mic_token;
gss_qop_t qop;
ret32(c, hContext);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
errx(1, "verify: reference to unknown context");
ret32(c, flags);
ret32(c, seqno);
retdata(c, msg);
msg_token.length = msg.length;
msg_token.value = msg.data;
retdata(c, mic);
mic_token.length = mic.length;
mic_token.value = mic.data;
maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
&mic_token, &qop);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_verify_mic failed");
krb5_data_free(&mic);
krb5_data_free(&msg);
put32(c, 0); /* XXX fix gsm_error */
return 0;
}
static int
HandleOP(GetVersionAndCapabilities)
{
int32_t cap = HAS_MONIKER;
char name[256] = "unknown", *str;
int ret;
if (targetname)
cap |= ISSERVER; /* is server */
#ifdef HAVE_UNAME
{
struct utsname ut;
if (uname(&ut) == 0) {
snprintf(name, sizeof(name), "%s-%s-%s",
ut.sysname, ut.version, ut.machine);
}
}
#endif
ret = asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
if (ret == -1)
errx(1, "out of memory");
put32(c, GSSMAGGOTPROTOCOL);
put32(c, cap);
putstring(c, str);
free(str);
return 0;
}
static int
HandleOP(GetTargetName)
{
if (targetname)
putstring(c, targetname);
else
putstring(c, "");
return 0;
}
static int
HandleOP(SetLoggingSocket)
{
int32_t portnum;
int fd, ret;
ret32(c, portnum);
logmessage(c, __FILE__, __LINE__, 0,
"logging port on peer is: %d", (int)portnum);
socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
if (fd < 0)
return 0;
ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);
if (ret < 0) {
logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
strerror(errno));
close(fd);
return 0;
}
if (c->logging)
krb5_storage_free(c->logging);
c->logging = krb5_storage_from_fd(fd);
close(fd);
krb5_store_int32(c->logging, eLogSetMoniker);
store_string(c->logging, c->moniker);
logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
return 0;
}
static int
HandleOP(ChangePassword)
{
errx(1, "ChangePassword");
}
static int
HandleOP(SetPasswordSelf)
{
errx(1, "SetPasswordSelf");
}
static int
HandleOP(Wrap)
{
OM_uint32 maj_stat, min_stat;
int32_t hContext, flags, seqno;
krb5_data token;
gss_ctx_id_t ctx;
gss_buffer_desc input_token, output_token;
int conf_state;
ret32(c, hContext);
ret32(c, flags);
ret32(c, seqno);
retdata(c, token);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
errx(1, "wrap: reference to unknown context");
input_token.length = token.length;
input_token.value = token.data;
maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,
&conf_state, &output_token);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_wrap failed");
krb5_data_free(&token);
token.data = output_token.value;
token.length = output_token.length;
put32(c, 0); /* XXX fix gsm_error */
putdata(c, token);
gss_release_buffer(&min_stat, &output_token);
return 0;
}
static int
HandleOP(Unwrap)
{
OM_uint32 maj_stat, min_stat;
int32_t hContext, flags, seqno;
krb5_data token;
gss_ctx_id_t ctx;
gss_buffer_desc input_token, output_token;
int conf_state;
gss_qop_t qop_state;
ret32(c, hContext);
ret32(c, flags);
ret32(c, seqno);
retdata(c, token);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
errx(1, "unwrap: reference to unknown context");
input_token.length = token.length;
input_token.value = token.data;
maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
&output_token, &conf_state, &qop_state);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
krb5_data_free(&token);
if (maj_stat == GSS_S_COMPLETE) {
token.data = output_token.value;
token.length = output_token.length;
} else {
token.data = NULL;
token.length = 0;
}
put32(c, 0); /* XXX fix gsm_error */
putdata(c, token);
if (maj_stat == GSS_S_COMPLETE)
gss_release_buffer(&min_stat, &output_token);
return 0;
}
static int
HandleOP(Encrypt)
{
return handleWrap(op, c);
}
static int
HandleOP(Decrypt)
{
return handleUnwrap(op, c);
}
static int
HandleOP(ConnectLoggingService2)
{
errx(1, "ConnectLoggingService2");
}
static int
HandleOP(GetMoniker)
{
putstring(c, c->moniker);
return 0;
}
static int
HandleOP(CallExtension)
{
errx(1, "CallExtension");
}
static int
HandleOP(AcquirePKInitCreds)
{
int32_t flags;
krb5_data pfxdata;
char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
krb5_principal principal = NULL;
int fd;
ret32(c, flags);
retdata(c, pfxdata);
fd = mkstemp(fn + 5);
if (fd < 0)
errx(1, "mkstemp");
net_write(fd, pfxdata.data, pfxdata.length);
krb5_data_free(&pfxdata);
close(fd);
if (principal)
krb5_free_principal(context, principal);
put32(c, -1); /* hResource */
put32(c, GSMERR_NOT_SUPPORTED);
return 0;
}
static int
HandleOP(WrapExt)
{
OM_uint32 maj_stat, min_stat;
int32_t hContext, flags, bflags;
krb5_data token, header, trailer;
gss_ctx_id_t ctx;
unsigned char *p;
int conf_state, iov_len;
gss_iov_buffer_desc iov[6];
ret32(c, hContext);
ret32(c, flags);
ret32(c, bflags);
retdata(c, header);
retdata(c, token);
retdata(c, trailer);
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
errx(1, "wrap: reference to unknown context");
memset(&iov, 0, sizeof(iov));
iov_len = sizeof(iov)/sizeof(iov[0]);
if (bflags & WRAP_EXP_ONLY_HEADER)
iov_len -= 2; /* skip trailer and padding, aka dce-style */
iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
if (header.length != 0) {
iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
iov[1].buffer.length = header.length;
iov[1].buffer.value = header.data;
} else {
iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
}
iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
iov[2].buffer.length = token.length;
iov[2].buffer.value = token.data;
if (trailer.length != 0) {
iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
iov[3].buffer.length = trailer.length;
iov[3].buffer.value = trailer.data;
} else {
iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
}
iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
iov, iov_len);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_wrap_iov_length failed");
maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
iov, iov_len);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_wrap_iov failed");
krb5_data_free(&token);
token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;
token.data = malloc(token.length);
p = token.data;
memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
p += iov[0].buffer.length;
memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
p += iov[2].buffer.length;
memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
p += iov[4].buffer.length;
memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
p += iov[5].buffer.length;
gss_release_iov_buffer(NULL, iov, iov_len);
put32(c, 0); /* XXX fix gsm_error */
putdata(c, token);
free(token.data);
return 0;
}
static int
HandleOP(UnwrapExt)
{
OM_uint32 maj_stat, min_stat;
int32_t hContext, flags, bflags;
krb5_data token, header, trailer;
gss_ctx_id_t ctx;
gss_iov_buffer_desc iov[3];
int conf_state, iov_len;
gss_qop_t qop_state;
ret32(c, hContext);
ret32(c, flags);
ret32(c, bflags);
retdata(c, header);
retdata(c, token);
retdata(c, trailer);
iov_len = sizeof(iov)/sizeof(iov[0]);
if (bflags & WRAP_EXP_ONLY_HEADER)
iov_len -= 1; /* skip trailer and padding, aka dce-style */
ctx = find_handle(c->handles, hContext, handle_context);
if (ctx == NULL)
errx(1, "unwrap: reference to unknown context");
if (header.length != 0) {
iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
iov[0].buffer.length = header.length;
iov[0].buffer.value = header.data;
} else {
iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
}
iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
iov[1].buffer.length = token.length;
iov[1].buffer.value = token.data;
if (trailer.length != 0) {
iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
iov[2].buffer.length = trailer.length;
iov[2].buffer.value = trailer.data;
} else {
iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
}
maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
iov, iov_len);
if (maj_stat != GSS_S_COMPLETE)
errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
if (maj_stat == GSS_S_COMPLETE) {
token.data = iov[1].buffer.value;
token.length = iov[1].buffer.length;
} else {
token.data = NULL;
token.length = 0;
}
put32(c, 0); /* XXX fix gsm_error */
putdata(c, token);
return 0;
}
/*
*
*/
struct handler {
enum gssMaggotOp op;
const char *name;
int (*func)(enum gssMaggotOp, struct client *);
};
#define S(a) { e##a, #a, handle##a }
struct handler handlers[] = {
S(GetVersionInfo),
S(GoodBye),
S(InitContext),
S(AcceptContext),
S(ToastResource),
S(AcquireCreds),
S(Encrypt),
S(Decrypt),
S(Sign),
S(Verify),
S(GetVersionAndCapabilities),
S(GetTargetName),
S(SetLoggingSocket),
S(ChangePassword),
S(SetPasswordSelf),
S(Wrap),
S(Unwrap),
S(ConnectLoggingService2),
S(GetMoniker),
S(CallExtension),
S(AcquirePKInitCreds),
S(WrapExt),
S(UnwrapExt),
};
#undef S
/*
*
*/
static struct handler *
find_op(int32_t op)
{
int i;
for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
if (handlers[i].op == op)
return &handlers[i];
return NULL;
}
static struct client *
create_client(int fd, int port, const char *moniker)
{
struct client *c;
int ret;
c = ecalloc(1, sizeof(*c));
if (moniker) {
c->moniker = estrdup(moniker);
} else {
char hostname[MAXHOSTNAMELEN];
gethostname(hostname, sizeof(hostname));
ret = asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
if (ret == -1)
c->moniker = NULL;
}
if (!c->moniker)
errx(1, "out of memory");
{
c->salen = sizeof(c->sa);
getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
getnameinfo((struct sockaddr *)&c->sa, c->salen,
c->servername, sizeof(c->servername),
NULL, 0, NI_NUMERICHOST);
}
c->sock = krb5_storage_from_fd(fd);
if (c->sock == NULL)
errx(1, "krb5_storage_from_fd");
close(fd);
return c;
}
static void
free_client(struct client *c)
{
while(c->handles)
del_handle(&c->handles, c->handles->idx);
free(c->moniker);
krb5_storage_free(c->sock);
if (c->logging)
krb5_storage_free(c->logging);
free(c);
}
static void *
handleServer(void *ptr)
{
struct handler *handler;
struct client *c;
int32_t op;
c = (struct client *)ptr;
while(1) {
ret32(c, op);
handler = find_op(op);
if (handler == NULL) {
logmessage(c, __FILE__, __LINE__, 0,
"op %d not supported", (int)op);
exit(1);
}
logmessage(c, __FILE__, __LINE__, 0,
"---> Got op %s from server %s",
handler->name, c->servername);
if ((handler->func)(handler->op, c))
break;
}
return NULL;
}
static char *port_str;
static int version_flag;
static int help_flag;
static char *logfile_str;
static char *moniker_str;
static int port = 4711;
struct getargs args[] = {
{ "spn", 0, arg_string, &targetname, "This host's SPN",
"service/host@REALM" },
{ "port", 'p', arg_string, &port_str, "Use this port",
"number-of-service" },
{ "logfile", 0, arg_string, &logfile_str, "logfile",
"number-of-service" },
{ "moniker", 0, arg_string, &moniker_str, "nickname",
"name" },
{ "version", 0, arg_flag, &version_flag, "Print version",
NULL },
{ "help", 0, arg_flag, &help_flag, NULL,
NULL }
};
static void
usage(int ret)
{
arg_printusage (args,
sizeof(args) / sizeof(args[0]),
NULL,
"");
exit (ret);
}
int
main(int argc, char **argv)
{
int optidx = 0;
setprogname (argv[0]);
if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
usage (1);
if (help_flag)
usage (0);
if (version_flag) {
print_version (NULL);
return 0;
}
if (optidx != argc)
usage (1);
if (port_str) {
char *ptr;
port = strtol (port_str, &ptr, 10);
if (port == 0 && ptr == port_str)
errx (1, "Bad port `%s'", port_str);
}
krb5_init_context(&context);
{
const char *lf = logfile_str;
if (lf == NULL)
lf = "/dev/tty";
logfile = fopen(lf, "w");
if (logfile == NULL)
err(1, "error opening %s", lf);
}
mini_inetd(htons(port), NULL);
fprintf(logfile, "connected\n");
{
struct client *c;
c = create_client(0, port, moniker_str);
/* close(0); */
handleServer(c);
free_client(c);
}
krb5_free_context(context);
return 0;
}