NetBSD/lib/libtelnet/spx.c
thorpej 5c099b14c1 Bring the telnet situation back into better shape. Specifically,
pull in just about all of the differences from the crypto-us telnet
suite (which includes Kerberos 4 and connection encryption support).
Also bring in the Kerberos 5 support from the Heimdal telnet, and
frob a little so that it can work with the non-Heimdal telnet suite.

There is still some work left to do, specifically:
- Add Heimdal's ticket forwarding support to the Berkeley Kerberos 4
  module.
- Add connection encryption support to the Heimdal Kerberos 5
  module.  Hints on this can be taken from the MIT Kerberos 5
  module which still exists in crypto-us.

However, even with the shortcomings listed above, this is a
better situation than using the stock Heimdal telnet suite,
which does not understand the IPSec policy stuff, and is also
based on much older code which contains bugs that we have already
fixed in the NetBSD sources.
2000-06-22 06:47:42 +00:00

597 lines
16 KiB
C

/* $NetBSD: spx.c,v 1.1 2000/06/22 06:47:46 thorpej Exp $ */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 THE REGENTS AND 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 THE REGENTS OR 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 <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)spx.c 8.2 (Berkeley) 5/30/95";
#else
__RCSID("$NetBSD: spx.c,v 1.1 2000/06/22 06:47:46 thorpej Exp $");
#endif
#endif /* not lint */
#ifdef SPX
/*
* COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
* ALL RIGHTS RESERVED
*
* "Digital Equipment Corporation authorizes the reproduction,
* distribution and modification of this software subject to the following
* restrictions:
*
* 1. Any partial or whole copy of this software, or any modification
* thereof, must include this copyright notice in its entirety.
*
* 2. This software is supplied "as is" with no warranty of any kind,
* expressed or implied, for any purpose, including any warranty of fitness
* or merchantibility. DIGITAL assumes no responsibility for the use or
* reliability of this software, nor promises to provide any form of
* support for it on any basis.
*
* 3. Distribution of this software is authorized only if no profit or
* remuneration of any kind is received in exchange for such distribution.
*
* 4. This software produces public key authentication certificates
* bearing an expiration date established by DIGITAL and RSA Data
* Security, Inc. It may cease to generate certificates after the expiration
* date. Any modification of this software that changes or defeats
* the expiration date or its effect is unauthorized.
*
* 5. Software that will renew or extend the expiration date of
* authentication certificates produced by this software may be obtained
* from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
* 94065, (415)595-8782, or from DIGITAL"
*
*/
#include <sys/types.h>
#include <arpa/telnet.h>
#include <stdio.h>
#include "gssapi_defs.h"
#ifdef __STDC__
#include <stdlib.h>
#endif
#ifdef NO_STRING_H
#include <strings.h>
#else
#include <string.h>
#endif
#include <pwd.h>
#include "encrypt.h"
#include "auth.h"
#include "misc.h"
extern auth_debug_mode;
static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
AUTHTYPE_SPX, };
static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
TELQUAL_NAME, };
#define SPX_AUTH 0 /* Authentication data follows */
#define SPX_REJECT 1 /* Rejected (reason might follow) */
#define SPX_ACCEPT 2 /* Accepted */
#ifdef ENCRYPTION
static Block session_key = { 0 };
#endif /* ENCRYPTION */
static Schedule sched;
static Block challenge = { 0 };
/*******************************************************************/
gss_OID_set actual_mechs;
gss_OID actual_mech_type, output_name_type;
int major_status, status, msg_ctx = 0, new_status;
int req_flags = 0, ret_flags, lifetime_rec;
gss_cred_id_t gss_cred_handle;
gss_ctx_id_t actual_ctxhandle, context_handle;
gss_buffer_desc output_token, input_token, input_name_buffer;
gss_buffer_desc status_string;
gss_name_t desired_targname, src_name;
gss_channel_bindings input_chan_bindings;
char lhostname[GSS_C_MAX_PRINTABLE_NAME];
char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
int to_addr=0, from_addr=0;
char *address;
gss_buffer_desc fullname_buffer;
gss_OID fullname_type;
gss_cred_id_t gss_delegated_cred_handle;
/*******************************************************************/
static int
Data(ap, type, d, c)
Authenticator *ap;
int type;
void *d;
int c;
{
unsigned char *p = str_data + 4;
unsigned char *cd = (unsigned char *)d;
if (c == -1)
c = strlen((char *)cd);
if (0) {
printf("%s:%d: [%d] (%d)",
str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
str_data[3],
type, c);
printd(d, c);
printf("\r\n");
}
*p++ = ap->type;
*p++ = ap->way;
*p++ = type;
while (c-- > 0) {
if ((*p++ = *cd++) == IAC)
*p++ = IAC;
}
*p++ = IAC;
*p++ = SE;
if (str_data[3] == TELQUAL_IS)
printsub('>', &str_data[2], p - (&str_data[2]));
return(telnet_net_write(str_data, p - str_data));
}
int
spx_init(ap, server)
Authenticator *ap;
int server;
{
gss_cred_id_t tmp_cred_handle;
if (server) {
str_data[3] = TELQUAL_REPLY;
gethostname(lhostname, sizeof(lhostname));
strcpy(targ_printable, "SERVICE:rcmd@");
strcat(targ_printable, lhostname);
input_name_buffer.length = strlen(targ_printable);
input_name_buffer.value = targ_printable;
major_status = gss_import_name(&status,
&input_name_buffer,
GSS_C_NULL_OID,
&desired_targname);
major_status = gss_acquire_cred(&status,
desired_targname,
0,
GSS_C_NULL_OID_SET,
GSS_C_ACCEPT,
&tmp_cred_handle,
&actual_mechs,
&lifetime_rec);
if (major_status != GSS_S_COMPLETE) return(0);
} else {
str_data[3] = TELQUAL_IS;
}
return(1);
}
int
spx_send(ap)
Authenticator *ap;
{
Block enckey;
int r;
gss_OID actual_mech_type, output_name_type;
int msg_ctx = 0, new_status, status;
int req_flags = 0, ret_flags, lifetime_rec, major_status;
gss_buffer_desc output_token, input_token, input_name_buffer;
gss_buffer_desc output_name_buffer, status_string;
gss_name_t desired_targname;
gss_channel_bindings input_chan_bindings;
char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
int from_addr=0, to_addr=0, myhostlen, j;
int deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0;
char *address;
printf("[ Trying SPX ... ]\n");
strcpy(targ_printable, "SERVICE:rcmd@");
strcat(targ_printable, RemoteHostName);
input_name_buffer.length = strlen(targ_printable);
input_name_buffer.value = targ_printable;
if (!UserNameRequested) {
return(0);
}
major_status = gss_import_name(&status,
&input_name_buffer,
GSS_C_NULL_OID,
&desired_targname);
major_status = gss_display_name(&status,
desired_targname,
&output_name_buffer,
&output_name_type);
printf("target is '%s'\n", output_name_buffer.value); fflush(stdout);
major_status = gss_release_buffer(&status, &output_name_buffer);
input_chan_bindings = (gss_channel_bindings)
malloc(sizeof(gss_channel_bindings_desc));
input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
input_chan_bindings->initiator_address.length = 4;
address = (char *) malloc(4);
input_chan_bindings->initiator_address.value = (char *) address;
address[0] = ((from_addr & 0xff000000) >> 24);
address[1] = ((from_addr & 0xff0000) >> 16);
address[2] = ((from_addr & 0xff00) >> 8);
address[3] = (from_addr & 0xff);
input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
input_chan_bindings->acceptor_address.length = 4;
address = (char *) malloc(4);
input_chan_bindings->acceptor_address.value = (char *) address;
address[0] = ((to_addr & 0xff000000) >> 24);
address[1] = ((to_addr & 0xff0000) >> 16);
address[2] = ((to_addr & 0xff00) >> 8);
address[3] = (to_addr & 0xff);
input_chan_bindings->application_data.length = 0;
req_flags = 0;
if (deleg_flag) req_flags = req_flags | 1;
if (mutual_flag) req_flags = req_flags | 2;
if (replay_flag) req_flags = req_flags | 4;
if (seq_flag) req_flags = req_flags | 8;
major_status = gss_init_sec_context(&status, /* minor status */
GSS_C_NO_CREDENTIAL, /* cred handle */
&actual_ctxhandle, /* ctx handle */
desired_targname, /* target name */
GSS_C_NULL_OID, /* mech type */
req_flags, /* req flags */
0, /* time req */
input_chan_bindings, /* chan binding */
GSS_C_NO_BUFFER, /* input token */
&actual_mech_type, /* actual mech */
&output_token, /* output token */
&ret_flags, /* ret flags */
&lifetime_rec); /* time rec */
if ((major_status != GSS_S_COMPLETE) &&
(major_status != GSS_S_CONTINUE_NEEDED)) {
gss_display_status(&new_status,
status,
GSS_C_MECH_CODE,
GSS_C_NULL_OID,
&msg_ctx,
&status_string);
printf("%s\n", status_string.value);
return(0);
}
if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
return(0);
}
if (!Data(ap, SPX_AUTH, (void *)output_token.value, output_token.length)) {
return(0);
}
return(1);
}
void
spx_is(ap, data, cnt)
Authenticator *ap;
unsigned char *data;
int cnt;
{
Session_Key skey;
Block datablock;
int r;
if (cnt-- < 1)
return;
switch (*data++) {
case SPX_AUTH:
input_token.length = cnt;
input_token.value = (char *) data;
gethostname(lhostname, sizeof(lhostname));
strcpy(targ_printable, "SERVICE:rcmd@");
strcat(targ_printable, lhostname);
input_name_buffer.length = strlen(targ_printable);
input_name_buffer.value = targ_printable;
major_status = gss_import_name(&status,
&input_name_buffer,
GSS_C_NULL_OID,
&desired_targname);
major_status = gss_acquire_cred(&status,
desired_targname,
0,
GSS_C_NULL_OID_SET,
GSS_C_ACCEPT,
&gss_cred_handle,
&actual_mechs,
&lifetime_rec);
major_status = gss_release_name(&status, desired_targname);
input_chan_bindings = (gss_channel_bindings)
malloc(sizeof(gss_channel_bindings_desc));
input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
input_chan_bindings->initiator_address.length = 4;
address = (char *) malloc(4);
input_chan_bindings->initiator_address.value = (char *) address;
address[0] = ((from_addr & 0xff000000) >> 24);
address[1] = ((from_addr & 0xff0000) >> 16);
address[2] = ((from_addr & 0xff00) >> 8);
address[3] = (from_addr & 0xff);
input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
input_chan_bindings->acceptor_address.length = 4;
address = (char *) malloc(4);
input_chan_bindings->acceptor_address.value = (char *) address;
address[0] = ((to_addr & 0xff000000) >> 24);
address[1] = ((to_addr & 0xff0000) >> 16);
address[2] = ((to_addr & 0xff00) >> 8);
address[3] = (to_addr & 0xff);
input_chan_bindings->application_data.length = 0;
major_status = gss_accept_sec_context(&status,
&context_handle,
gss_cred_handle,
&input_token,
input_chan_bindings,
&src_name,
&actual_mech_type,
&output_token,
&ret_flags,
&lifetime_rec,
&gss_delegated_cred_handle);
if (major_status != GSS_S_COMPLETE) {
major_status = gss_display_name(&status,
src_name,
&fullname_buffer,
&fullname_type);
Data(ap, SPX_REJECT, (void *)"auth failed", -1);
auth_finished(ap, AUTH_REJECT);
return;
}
major_status = gss_display_name(&status,
src_name,
&fullname_buffer,
&fullname_type);
Data(ap, SPX_ACCEPT, (void *)output_token.value, output_token.length);
auth_finished(ap, AUTH_USER);
break;
default:
Data(ap, SPX_REJECT, 0, 0);
break;
}
}
void
spx_reply(ap, data, cnt)
Authenticator *ap;
unsigned char *data;
int cnt;
{
Session_Key skey;
if (cnt-- < 1)
return;
switch (*data++) {
case SPX_REJECT:
if (cnt > 0) {
printf("[ SPX refuses authentication because %.*s ]\r\n",
cnt, data);
} else
printf("[ SPX refuses authentication ]\r\n");
auth_send_retry();
return;
case SPX_ACCEPT:
printf("[ SPX accepts you ]\n");
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
/*
* Send over the encrypted challenge.
*/
input_token.value = (char *) data;
input_token.length = cnt;
major_status = gss_init_sec_context(&status, /* minor stat */
GSS_C_NO_CREDENTIAL, /* cred handle */
&actual_ctxhandle, /* ctx handle */
desired_targname, /* target name */
GSS_C_NULL_OID, /* mech type */
req_flags, /* req flags */
0, /* time req */
input_chan_bindings, /* chan binding */
&input_token, /* input token */
&actual_mech_type, /* actual mech */
&output_token, /* output token */
&ret_flags, /* ret flags */
&lifetime_rec); /* time rec */
if (major_status != GSS_S_COMPLETE) {
gss_display_status(&new_status,
status,
GSS_C_MECH_CODE,
GSS_C_NULL_OID,
&msg_ctx,
&status_string);
printf("[ SPX mutual response fails ... '%s' ]\r\n",
status_string.value);
auth_send_retry();
return;
}
}
auth_finished(ap, AUTH_USER);
return;
default:
return;
}
}
int
spx_status(ap, name, level)
Authenticator *ap;
char *name;
int level;
{
gss_buffer_desc fullname_buffer, acl_file_buffer;
gss_OID fullname_type;
char acl_file[160], fullname[160];
int major_status, status = 0;
struct passwd *pwd;
/*
* hard code fullname to
* "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan"
* and acl_file to "~kannan/.sphinx"
*/
pwd = getpwnam(UserNameRequested);
if (pwd == NULL) {
return(AUTH_USER); /* not authenticated */
}
strcpy(acl_file, pwd->pw_dir);
strcat(acl_file, "/.sphinx");
acl_file_buffer.value = acl_file;
acl_file_buffer.length = strlen(acl_file);
major_status = gss_display_name(&status,
src_name,
&fullname_buffer,
&fullname_type);
if (level < AUTH_USER)
return(level);
major_status = gss__check_acl(&status, &fullname_buffer,
&acl_file_buffer);
if (major_status == GSS_S_COMPLETE) {
strcpy(name, UserNameRequested);
return(AUTH_VALID);
} else {
return(AUTH_USER);
}
}
#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
void
spx_printsub(data, cnt, buf, buflen)
unsigned char *data, *buf;
int cnt, buflen;
{
char lbuf[32];
register int i;
buf[buflen-1] = '\0'; /* make sure its NULL terminated */
buflen -= 1;
switch(data[3]) {
case SPX_REJECT: /* Rejected (reason might follow) */
strncpy((char *)buf, " REJECT ", buflen);
goto common;
case SPX_ACCEPT: /* Accepted (name might follow) */
strncpy((char *)buf, " ACCEPT ", buflen);
common:
BUMP(buf, buflen);
if (cnt <= 4)
break;
ADDC(buf, buflen, '"');
for (i = 4; i < cnt; i++)
ADDC(buf, buflen, data[i]);
ADDC(buf, buflen, '"');
ADDC(buf, buflen, '\0');
break;
case SPX_AUTH: /* Authentication data follows */
strncpy((char *)buf, " AUTH", buflen);
goto common2;
default:
sprintf(lbuf, " %d (unknown)", data[3]);
strncpy((char *)buf, lbuf, buflen);
common2:
BUMP(buf, buflen);
for (i = 4; i < cnt; i++) {
sprintf(lbuf, " %d", data[i]);
strncpy((char *)buf, lbuf, buflen);
BUMP(buf, buflen);
}
break;
}
}
#endif
#ifdef notdef
prkey(msg, key)
char *msg;
unsigned char *key;
{
register int i;
printf("%s:", msg);
for (i = 0; i < 8; i++)
printf(" %3d", key[i]);
printf("\r\n");
}
#endif