[BACK]Return to auth.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / telnet

File: [local] / src / usr.bin / telnet / Attic / auth.c (download)

Revision 1.2, Tue Oct 27 23:59:44 2009 UTC (14 years, 6 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_5_5_BASE, OPENBSD_5_5, OPENBSD_5_4_BASE, OPENBSD_5_4, OPENBSD_5_3_BASE, OPENBSD_5_3, OPENBSD_5_2_BASE, OPENBSD_5_2, OPENBSD_5_1_BASE, OPENBSD_5_1, OPENBSD_5_0_BASE, OPENBSD_5_0, OPENBSD_4_9_BASE, OPENBSD_4_9, OPENBSD_4_8_BASE, OPENBSD_4_8, OPENBSD_4_7_BASE, OPENBSD_4_7
Changes since 1.1: +1 -6 lines

rcsid[] and sccsid[] and copyright[] are essentially unmaintained (and
unmaintainable).  these days, people use source.  these id's do not provide
any benefit, and do hurt the small install media
(the 33,000 line diff is essentially mechanical)
ok with the idea millert, ok dms

/*     $OpenBSD: auth.c,v 1.2 2009/10/27 23:59:44 deraadt Exp $    */

/*-
 * Copyright (c) 1991, 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. 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.
 */

/*
 * This source code is no longer held under any constraint of USA
 * `cryptographic laws' since it was exported legally.  The cryptographic
 * functions were removed from the code and a "Bones" distribution was
 * made.  A Commodity Jurisdiction Request #012-94 was filed with the
 * USA State Department, who handed it to the Commerce department.  The
 * code was determined to fall under General License GTDA under ECCN 5D96G,
 * and hence exportable.  The cryptographic interfaces were re-added by Eric
 * Young, and then KTH proceeded to maintain the code in the free world.
 *
 */

/*
 * Copyright (C) 1990 by the Massachusetts Institute of Technology
 *
 * Export of this software from the United States of America is assumed
 * to require a specific license from the United States Government.
 * It is the responsibility of any person or organization contemplating
 * export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 */

/* "$KTH: auth.c,v 1.23 2000/01/18 03:09:34 assar Exp $" */

#if	defined(AUTHENTICATION)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#define	AUTH_NAMES
#include <arpa/telnet.h>
#include <stdlib.h>
#include <string.h>

#include "encrypt.h"
#include "auth.h"
#include "misc-proto.h"
#include "auth-proto.h"

#define	typemask(x)		(1<<((x)-1))

#ifdef	KRB4_ENCPWD
extern krb4encpwd_init();
extern krb4encpwd_send();
extern krb4encpwd_is();
extern krb4encpwd_reply();
extern krb4encpwd_status();
extern krb4encpwd_printsub();
#endif

#ifdef	RSA_ENCPWD
extern rsaencpwd_init();
extern rsaencpwd_send();
extern rsaencpwd_is();
extern rsaencpwd_reply();
extern rsaencpwd_status();
extern rsaencpwd_printsub();
#endif

int auth_debug_mode = 0;
int auth_has_failed  = 0;
int auth_enable_encrypt = 0;
static 	const	char	*Name = "Noname";
static	int	Server = 0;
static	Authenticator	*authenticated = 0;
static	int	authenticating = 0;
static	int	validuser = 0;
static	unsigned char	_auth_send_data[256];
static	unsigned char	*auth_send_data;
static	int	auth_send_cnt = 0;

/*
 * Authentication types supported.  Plese note that these are stored
 * in priority order, i.e. try the first one first.
 */
Authenticator authenticators[] = {
#ifdef UNSAFE
    { AUTHTYPE_UNSAFE, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
      unsafe_init,
      unsafe_send,
      unsafe_is,
      unsafe_reply,
      unsafe_status,
      unsafe_printsub },
#endif
#ifdef SRA
    { AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
      sra_init,
      sra_send,
      sra_is,
      sra_reply,
      sra_status,
      sra_printsub },
#endif
#ifdef	SPX
    { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
      spx_init,
      spx_send,
      spx_is,
      spx_reply,
      spx_status,
      spx_printsub },
    { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
      spx_init,
      spx_send,
      spx_is,
      spx_reply,
      spx_status,
      spx_printsub },
#endif
#ifdef	KRB5
    { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
      kerberos5_init,
      kerberos5_send_mutual,
      kerberos5_is,
      kerberos5_reply,
      kerberos5_status,
      kerberos5_printsub },
    { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
      kerberos5_init,
      kerberos5_send_oneway,
      kerberos5_is,
      kerberos5_reply,
      kerberos5_status,
      kerberos5_printsub },
#endif
#ifdef	KRB4
    { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
      kerberos4_init,
      kerberos4_send_mutual,
      kerberos4_is,
      kerberos4_reply,
      kerberos4_status,
      kerberos4_printsub },
    { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
      kerberos4_init,
      kerberos4_send_oneway,
      kerberos4_is,
      kerberos4_reply,
      kerberos4_status,
      kerberos4_printsub },
#endif
#ifdef	KRB4_ENCPWD
    { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
      krb4encpwd_init,
      krb4encpwd_send,
      krb4encpwd_is,
      krb4encpwd_reply,
      krb4encpwd_status,
      krb4encpwd_printsub },
#endif
#ifdef	RSA_ENCPWD
    { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
      rsaencpwd_init,
      rsaencpwd_send,
      rsaencpwd_is,
      rsaencpwd_reply,
      rsaencpwd_status,
      rsaencpwd_printsub },
#endif
    { 0, },
};

static Authenticator NoAuth = { 0 };

static int	i_support = 0;
static int	i_wont_support = 0;

Authenticator *
findauthenticator(int type, int way)
{
    Authenticator *ap = authenticators;

    while (ap->type && (ap->type != type || ap->way != way))
	++ap;
    return(ap->type ? ap : 0);
}

void
auth_init(const char *name, int server)
{
    Authenticator *ap = authenticators;

    Server = server;
    Name = name;

    i_support = 0;
    authenticated = 0;
    authenticating = 0;
    while (ap->type) {
	if (!ap->init || (*ap->init)(ap, server)) {
	    i_support |= typemask(ap->type);
	    if (auth_debug_mode)
		printf(">>>%s: I support auth type %d %d\r\n",
		       Name,
		       ap->type, ap->way);
	}
	else if (auth_debug_mode)
	    printf(">>>%s: Init failed: auth type %d %d\r\n",
		   Name, ap->type, ap->way);
	++ap;
    }
}

void
auth_disable_name(char *name)
{
    int x;
    for (x = 0; x < AUTHTYPE_CNT; ++x) {
	if (!strcasecmp(name, AUTHTYPE_NAME(x))) {
	    i_wont_support |= typemask(x);
	    break;
	}
    }
}

int
getauthmask(char *type, int *maskp)
{
    int x;

    if (!strcasecmp(type, AUTHTYPE_NAME(0))) {
	*maskp = -1;
	return(1);
    }

    for (x = 1; x < AUTHTYPE_CNT; ++x) {
	if (!strcasecmp(type, AUTHTYPE_NAME(x))) {
	    *maskp = typemask(x);
	    return(1);
	}
    }
    return(0);
}

int
auth_enable(char *type)
{
    return(auth_onoff(type, 1));
}

int
auth_disable(char *type)
{
    return(auth_onoff(type, 0));
}

int
auth_onoff(char *type, int on)
{
    int i, mask = -1;
    Authenticator *ap;

    if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
	printf("auth %s 'type'\n", on ? "enable" : "disable");
	printf("Where 'type' is one of:\n");
	printf("\t%s\n", AUTHTYPE_NAME(0));
	mask = 0;
	for (ap = authenticators; ap->type; ap++) {
	    if ((mask & (i = typemask(ap->type))) != 0)
		continue;
	    mask |= i;
	    printf("\t%s\n", AUTHTYPE_NAME(ap->type));
	}
	return(0);
    }

    if (!getauthmask(type, &mask)) {
	printf("%s: invalid authentication type\n", type);
	return(0);
    }
    if (on)
	i_wont_support &= ~mask;
    else
	i_wont_support |= mask;
    return(1);
}

int
auth_togdebug(int on)
{
    if (on < 0)
	auth_debug_mode ^= 1;
    else
	auth_debug_mode = on;
    printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
    return(1);
}

int
auth_status(void)
{
    Authenticator *ap;
    int i, mask;

    if (i_wont_support == -1)
	printf("Authentication disabled\n");
    else
	printf("Authentication enabled\n");

    mask = 0;
    for (ap = authenticators; ap->type; ap++) {
	if ((mask & (i = typemask(ap->type))) != 0)
	    continue;
	mask |= i;
	printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
	       (i_wont_support & typemask(ap->type)) ?
	       "disabled" : "enabled");
    }
    return(1);
}

/*
 * This routine is called by the server to start authentication
 * negotiation.
 */
void
auth_request(void)
{
    static unsigned char str_request[64] = { IAC, SB,
					     TELOPT_AUTHENTICATION,
					     TELQUAL_SEND, };
    Authenticator *ap = authenticators;
    unsigned char *e = str_request + 4;

    if (!authenticating) {
	authenticating = 1;
	while (ap->type) {
	    if (i_support & ~i_wont_support & typemask(ap->type)) {
		if (auth_debug_mode) {
		    printf(">>>%s: Sending type %d %d\r\n",
			   Name, ap->type, ap->way);
		}
		*e++ = ap->type;
		*e++ = ap->way;
	    }
	    ++ap;
	}
	*e++ = IAC;
	*e++ = SE;
	telnet_net_write(str_request, e - str_request);
	printsub('>', &str_request[2], e - str_request - 2);
    }
}

/*
 * This is called when an AUTH SEND is received.
 * It should never arrive on the server side (as only the server can
 * send an AUTH SEND).
 * You should probably respond to it if you can...
 *
 * If you want to respond to the types out of order (i.e. even
 * if he sends  LOGIN KERBEROS and you support both, you respond
 * with KERBEROS instead of LOGIN (which is against what the
 * protocol says)) you will have to hack this code...
 */
void
auth_send(unsigned char *data, int cnt)
{
    Authenticator *ap;
    static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
					TELQUAL_IS, AUTHTYPE_NULL, 0,
					IAC, SE };
    if (Server) {
	if (auth_debug_mode) {
	    printf(">>>%s: auth_send called!\r\n", Name);
	}
	return;
    }

    if (auth_debug_mode) {
	printf(">>>%s: auth_send got:", Name);
	printd(data, cnt); printf("\r\n");
    }

    /*
     * Save the data, if it is new, so that we can continue looking
     * at it if the authorization we try doesn't work
     */
    if (data < _auth_send_data ||
	data > _auth_send_data + sizeof(_auth_send_data)) {
	auth_send_cnt = cnt > sizeof(_auth_send_data)
	    ? sizeof(_auth_send_data)
	    : cnt;
	memmove(_auth_send_data, data, auth_send_cnt);
	auth_send_data = _auth_send_data;
    } else {
	/*
	 * This is probably a no-op, but we just make sure
	 */
	auth_send_data = data;
	auth_send_cnt = cnt;
    }
    while ((auth_send_cnt -= 2) >= 0) {
	if (auth_debug_mode)
	    printf(">>>%s: He supports %d\r\n",
		   Name, *auth_send_data);
	if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
	    ap = findauthenticator(auth_send_data[0],
				   auth_send_data[1]);
	    if (ap && ap->send) {
		if (auth_debug_mode)
		    printf(">>>%s: Trying %d %d\r\n",
			   Name, auth_send_data[0],
			   auth_send_data[1]);
		if ((*ap->send)(ap)) {
		    /*
		     * Okay, we found one we like
		     * and did it.
		     * we can go home now.
		     */
		    if (auth_debug_mode)
			printf(">>>%s: Using type %d\r\n",
			       Name, *auth_send_data);
		    auth_send_data += 2;
		    return;
		}
	    }
	    /* else
	     *	just continue on and look for the
	     *	next one if we didn't do anything.
	     */
	}
	auth_send_data += 2;
    }
    telnet_net_write(str_none, sizeof(str_none));
    printsub('>', &str_none[2], sizeof(str_none) - 2);
    if (auth_debug_mode)
	printf(">>>%s: Sent failure message\r\n", Name);
    auth_finished(0, AUTH_REJECT);
    auth_has_failed = 1;
#ifdef KANNAN
    /*
     *  We requested strong authentication, however no mechanisms worked.
     *  Therefore, exit on client end.
     */
    printf("Unable to securely authenticate user ... exit\n");
    exit(0);
#endif /* KANNAN */
}

void
auth_send_retry(void)
{
    /*
     * if auth_send_cnt <= 0 then auth_send will end up rejecting
     * the authentication and informing the other side of this.
	 */
    auth_send(auth_send_data, auth_send_cnt);
}

void
auth_is(unsigned char *data, int cnt)
{
    Authenticator *ap;

    if (cnt < 2)
	return;

    if (data[0] == AUTHTYPE_NULL) {
	auth_finished(0, AUTH_REJECT);
	return;
    }

    if ((ap = findauthenticator(data[0], data[1]))) {
	if (ap->is)
	    (*ap->is)(ap, data+2, cnt-2);
    } else if (auth_debug_mode)
	printf(">>>%s: Invalid authentication in IS: %d\r\n",
	       Name, *data);
}

void
auth_reply(unsigned char *data, int cnt)
{
    Authenticator *ap;

    if (cnt < 2)
	return;

    if ((ap = findauthenticator(data[0], data[1]))) {
	if (ap->reply)
	    (*ap->reply)(ap, data+2, cnt-2);
    } else if (auth_debug_mode)
	printf(">>>%s: Invalid authentication in SEND: %d\r\n",
	       Name, *data);
}

void
auth_name(unsigned char *data, int cnt)
{
    char savename[256];

    if (cnt < 1) {
	if (auth_debug_mode)
	    printf(">>>%s: Empty name in NAME\r\n", Name);
	return;
    }
    if (cnt > sizeof(savename) - 1) {
	if (auth_debug_mode)
	    printf(">>>%s: Name in NAME (%d) exceeds %lu length\r\n",
		   Name, cnt, (unsigned long)(sizeof(savename)-1));
	return;
    }
    memmove(savename, data, cnt);
    savename[cnt] = '\0';	/* Null terminate */
    if (auth_debug_mode)
	printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
    auth_encrypt_user(savename);
}

int
auth_sendname(unsigned char *cp, int len)
{
    static unsigned char str_request[256+6]
	= { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
    unsigned char *e = str_request + 4;
    unsigned char *ee = &str_request[sizeof(str_request)-2];

    while (--len >= 0) {
	if ((*e++ = *cp++) == IAC)
	    *e++ = IAC;
	if (e >= ee)
	    return(0);
    }
    *e++ = IAC;
    *e++ = SE;
    telnet_net_write(str_request, e - str_request);
    printsub('>', &str_request[2], e - &str_request[2]);
    return(1);
}

void
auth_finished(Authenticator *ap, int result)
{
    if (!(authenticated = ap))
	authenticated = &NoAuth;
    validuser = result;
}

/* ARGSUSED */
static void
auth_intr(int sig)
{
    auth_finished(0, AUTH_REJECT);
}

int
auth_wait(char *name, size_t name_sz)
{
    if (auth_debug_mode)
	printf(">>>%s: in auth_wait.\r\n", Name);

    if (Server && !authenticating)
	return(0);

    signal(SIGALRM, auth_intr);
    alarm(30);
    while (!authenticated)
	if (telnet_spin())
	    break;
    alarm(0);
    signal(SIGALRM, SIG_DFL);

    /*
     * Now check to see if the user is valid or not
     */
    if (!authenticated || authenticated == &NoAuth)
	return(AUTH_REJECT);

    if (validuser == AUTH_VALID)
	validuser = AUTH_USER;

    if (authenticated->status)
	validuser = (*authenticated->status)(authenticated,
					     name, name_sz,
					     validuser);
    return(validuser);
}

void
auth_debug(int mode)
{
    auth_debug_mode = mode;
}

void
auth_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
{
    Authenticator *ap;

    if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
	(*ap->printsub)(data, cnt, buf, buflen);
    else
	auth_gen_printsub(data, cnt, buf, buflen);
}

void
auth_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
{
    unsigned char *cp;
    unsigned char tbuf[16];

    cnt -= 3;
    data += 3;
    buf[buflen-1] = '\0';
    buf[buflen-2] = '*';
    buflen -= 2;
    for (; cnt > 0; cnt--, data++) {
	snprintf(tbuf, sizeof(tbuf), " %d", *data);
	for (cp = tbuf; *cp && buflen > 0; --buflen)
	    *buf++ = *cp++;
	if (buflen <= 0)
	    return;
    }
    *buf = '\0';
}
#endif