Path: blob/main/crypto/heimdal/appl/telnet/libtelnet/auth.c
34878 views
/*-1* Copyright (c) 1991, 19932* The Regents of the University of California. All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. All advertising materials mentioning features or use of this software13* must display the following acknowledgement:14* This product includes software developed by the University of15* California, Berkeley and its contributors.16* 4. Neither the name of the University nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233/*34* Copyright (C) 1990 by the Massachusetts Institute of Technology35*36* Export of this software from the United States of America is assumed37* to require a specific license from the United States Government.38* It is the responsibility of any person or organization contemplating39* export to obtain such a license before exporting.40*41* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and42* distribute this software and its documentation for any purpose and43* without fee is hereby granted, provided that the above copyright44* notice appear in all copies and that both that copyright notice and45* this permission notice appear in supporting documentation, and that46* the name of M.I.T. not be used in advertising or publicity pertaining47* to distribution of the software without specific, written prior48* permission. M.I.T. makes no representations about the suitability of49* this software for any purpose. It is provided "as is" without express50* or implied warranty.51*/5253#include <config.h>5455RCSID("$Id$");5657#if defined(AUTHENTICATION)58#include <stdio.h>59#ifdef HAVE_SYS_TYPES_H60#include <sys/types.h>61#endif62#include <signal.h>63#define AUTH_NAMES64#ifdef HAVE_ARPA_TELNET_H65#include <arpa/telnet.h>66#endif67#include <stdlib.h>68#include <string.h>6970#include <roken.h>7172#ifdef SOCKS73#include <socks.h>74#endif7576#include "encrypt.h"77#include "auth.h"78#include "misc-proto.h"79#include "auth-proto.h"8081#define typemask(x) (1<<((x)-1))8283#ifdef RSA_ENCPWD84extern rsaencpwd_init();85extern rsaencpwd_send();86extern rsaencpwd_is();87extern rsaencpwd_reply();88extern rsaencpwd_status();89extern rsaencpwd_printsub();90#endif9192int auth_debug_mode = 0;93int auth_has_failed = 0;94int auth_enable_encrypt = 0;95static const char *Name = "Noname";96static int Server = 0;97static Authenticator *authenticated = 0;98static int authenticating = 0;99static int validuser = 0;100static unsigned char _auth_send_data[256];101static unsigned char *auth_send_data;102static int auth_send_cnt = 0;103104/*105* Authentication types supported. Plese note that these are stored106* in priority order, i.e. try the first one first.107*/108Authenticator authenticators[] = {109#ifdef UNSAFE110{ AUTHTYPE_UNSAFE, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,111unsafe_init,112unsafe_send,113unsafe_is,114unsafe_reply,115unsafe_status,116unsafe_printsub },117#endif118#ifdef SRA119{ AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,120sra_init,121sra_send,122sra_is,123sra_reply,124sra_status,125sra_printsub },126#endif127#ifdef SPX128{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,129spx_init,130spx_send,131spx_is,132spx_reply,133spx_status,134spx_printsub },135{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,136spx_init,137spx_send,138spx_is,139spx_reply,140spx_status,141spx_printsub },142#endif143#ifdef KRB5144{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,145kerberos5_init,146kerberos5_send_mutual,147kerberos5_is,148kerberos5_reply,149kerberos5_status,150kerberos5_printsub },151{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,152kerberos5_init,153kerberos5_send_oneway,154kerberos5_is,155kerberos5_reply,156kerberos5_status,157kerberos5_printsub },158#endif159#ifdef RSA_ENCPWD160{ AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,161rsaencpwd_init,162rsaencpwd_send,163rsaencpwd_is,164rsaencpwd_reply,165rsaencpwd_status,166rsaencpwd_printsub },167#endif168{ 0, },169};170171static Authenticator NoAuth = { 0 };172173static int i_support = 0;174static int i_wont_support = 0;175176Authenticator *177findauthenticator(int type, int way)178{179Authenticator *ap = authenticators;180181while (ap->type && (ap->type != type || ap->way != way))182++ap;183return(ap->type ? ap : 0);184}185186void187auth_init(const char *name, int server)188{189Authenticator *ap = authenticators;190191Server = server;192Name = name;193194i_support = 0;195authenticated = 0;196authenticating = 0;197while (ap->type) {198if (!ap->init || (*ap->init)(ap, server)) {199i_support |= typemask(ap->type);200if (auth_debug_mode)201printf(">>>%s: I support auth type %d %d\r\n",202Name,203ap->type, ap->way);204}205else if (auth_debug_mode)206printf(">>>%s: Init failed: auth type %d %d\r\n",207Name, ap->type, ap->way);208++ap;209}210}211212void213auth_disable_name(char *name)214{215int x;216for (x = 0; x < AUTHTYPE_CNT; ++x) {217if (!strcasecmp(name, AUTHTYPE_NAME(x))) {218i_wont_support |= typemask(x);219break;220}221}222}223224int225getauthmask(char *type, int *maskp)226{227int x;228229if (!strcasecmp(type, AUTHTYPE_NAME(0))) {230*maskp = -1;231return(1);232}233234for (x = 1; x < AUTHTYPE_CNT; ++x) {235if (!strcasecmp(type, AUTHTYPE_NAME(x))) {236*maskp = typemask(x);237return(1);238}239}240return(0);241}242243int244auth_enable(char *type)245{246return(auth_onoff(type, 1));247}248249int250auth_disable(char *type)251{252return(auth_onoff(type, 0));253}254255int256auth_onoff(char *type, int on)257{258int i, mask = -1;259Authenticator *ap;260261if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {262printf("auth %s 'type'\n", on ? "enable" : "disable");263printf("Where 'type' is one of:\n");264printf("\t%s\n", AUTHTYPE_NAME(0));265mask = 0;266for (ap = authenticators; ap->type; ap++) {267if ((mask & (i = typemask(ap->type))) != 0)268continue;269mask |= i;270printf("\t%s\n", AUTHTYPE_NAME(ap->type));271}272return(0);273}274275if (!getauthmask(type, &mask)) {276printf("%s: invalid authentication type\n", type);277return(0);278}279if (on)280i_wont_support &= ~mask;281else282i_wont_support |= mask;283return(1);284}285286int287auth_togdebug(int on)288{289if (on < 0)290auth_debug_mode ^= 1;291else292auth_debug_mode = on;293printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");294return(1);295}296297int298auth_status(void)299{300Authenticator *ap;301int i, mask;302303if (i_wont_support == -1)304printf("Authentication disabled\n");305else306printf("Authentication enabled\n");307308mask = 0;309for (ap = authenticators; ap->type; ap++) {310if ((mask & (i = typemask(ap->type))) != 0)311continue;312mask |= i;313printf("%s: %s\n", AUTHTYPE_NAME(ap->type),314(i_wont_support & typemask(ap->type)) ?315"disabled" : "enabled");316}317return(1);318}319320/*321* This routine is called by the server to start authentication322* negotiation.323*/324void325auth_request(void)326{327static unsigned char str_request[64] = { IAC, SB,328TELOPT_AUTHENTICATION,329TELQUAL_SEND, };330Authenticator *ap = authenticators;331unsigned char *e = str_request + 4;332333if (!authenticating) {334authenticating = 1;335while (ap->type) {336if (i_support & ~i_wont_support & typemask(ap->type)) {337if (auth_debug_mode) {338printf(">>>%s: Sending type %d %d\r\n",339Name, ap->type, ap->way);340}341*e++ = ap->type;342*e++ = ap->way;343}344++ap;345}346*e++ = IAC;347*e++ = SE;348telnet_net_write(str_request, e - str_request);349printsub('>', &str_request[2], e - str_request - 2);350}351}352353/*354* This is called when an AUTH SEND is received.355* It should never arrive on the server side (as only the server can356* send an AUTH SEND).357* You should probably respond to it if you can...358*359* If you want to respond to the types out of order (i.e. even360* if he sends LOGIN KERBEROS and you support both, you respond361* with KERBEROS instead of LOGIN (which is against what the362* protocol says)) you will have to hack this code...363*/364void365auth_send(unsigned char *data, int cnt)366{367Authenticator *ap;368static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,369TELQUAL_IS, AUTHTYPE_NULL, 0,370IAC, SE };371if (Server) {372if (auth_debug_mode) {373printf(">>>%s: auth_send called!\r\n", Name);374}375return;376}377378if (auth_debug_mode) {379printf(">>>%s: auth_send got:", Name);380printd(data, cnt); printf("\r\n");381}382383/*384* Save the data, if it is new, so that we can continue looking385* at it if the authorization we try doesn't work386*/387if (data < _auth_send_data ||388data > _auth_send_data + sizeof(_auth_send_data)) {389auth_send_cnt = cnt > sizeof(_auth_send_data)390? sizeof(_auth_send_data)391: cnt;392memmove(_auth_send_data, data, auth_send_cnt);393auth_send_data = _auth_send_data;394} else {395/*396* This is probably a no-op, but we just make sure397*/398auth_send_data = data;399auth_send_cnt = cnt;400}401while ((auth_send_cnt -= 2) >= 0) {402if (auth_debug_mode)403printf(">>>%s: He supports %d\r\n",404Name, *auth_send_data);405if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {406ap = findauthenticator(auth_send_data[0],407auth_send_data[1]);408if (ap && ap->send) {409if (auth_debug_mode)410printf(">>>%s: Trying %d %d\r\n",411Name, auth_send_data[0],412auth_send_data[1]);413if ((*ap->send)(ap)) {414/*415* Okay, we found one we like416* and did it.417* we can go home now.418*/419if (auth_debug_mode)420printf(">>>%s: Using type %d\r\n",421Name, *auth_send_data);422auth_send_data += 2;423return;424}425}426/* else427* just continue on and look for the428* next one if we didn't do anything.429*/430}431auth_send_data += 2;432}433telnet_net_write(str_none, sizeof(str_none));434printsub('>', &str_none[2], sizeof(str_none) - 2);435if (auth_debug_mode)436printf(">>>%s: Sent failure message\r\n", Name);437auth_finished(0, AUTH_REJECT);438auth_has_failed = 1;439#ifdef KANNAN440/*441* We requested strong authentication, however no mechanisms worked.442* Therefore, exit on client end.443*/444printf("Unable to securely authenticate user ... exit\n");445exit(0);446#endif /* KANNAN */447}448449void450auth_send_retry(void)451{452/*453* if auth_send_cnt <= 0 then auth_send will end up rejecting454* the authentication and informing the other side of this.455*/456auth_send(auth_send_data, auth_send_cnt);457}458459void460auth_is(unsigned char *data, int cnt)461{462Authenticator *ap;463464if (cnt < 2)465return;466467if (data[0] == AUTHTYPE_NULL) {468auth_finished(0, AUTH_REJECT);469return;470}471472if ((ap = findauthenticator(data[0], data[1]))) {473if (ap->is)474(*ap->is)(ap, data+2, cnt-2);475} else if (auth_debug_mode)476printf(">>>%s: Invalid authentication in IS: %d\r\n",477Name, *data);478}479480void481auth_reply(unsigned char *data, int cnt)482{483Authenticator *ap;484485if (cnt < 2)486return;487488if ((ap = findauthenticator(data[0], data[1]))) {489if (ap->reply)490(*ap->reply)(ap, data+2, cnt-2);491} else if (auth_debug_mode)492printf(">>>%s: Invalid authentication in SEND: %d\r\n",493Name, *data);494}495496void497auth_name(unsigned char *data, int cnt)498{499char savename[256];500501if (cnt < 1) {502if (auth_debug_mode)503printf(">>>%s: Empty name in NAME\r\n", Name);504return;505}506if (cnt > sizeof(savename) - 1) {507if (auth_debug_mode)508printf(">>>%s: Name in NAME (%d) exceeds %lu length\r\n",509Name, cnt, (unsigned long)(sizeof(savename)-1));510return;511}512memmove(savename, data, cnt);513savename[cnt] = '\0'; /* Null terminate */514if (auth_debug_mode)515printf(">>>%s: Got NAME [%s]\r\n", Name, savename);516auth_encrypt_user(savename);517}518519int520auth_sendname(unsigned char *cp, int len)521{522static unsigned char str_request[256+6]523= { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };524unsigned char *e = str_request + 4;525unsigned char *ee = &str_request[sizeof(str_request)-2];526527while (--len >= 0) {528if ((*e++ = *cp++) == IAC)529*e++ = IAC;530if (e >= ee)531return(0);532}533*e++ = IAC;534*e++ = SE;535telnet_net_write(str_request, e - str_request);536printsub('>', &str_request[2], e - &str_request[2]);537return(1);538}539540void541auth_finished(Authenticator *ap, int result)542{543if (!(authenticated = ap))544authenticated = &NoAuth;545validuser = result;546}547548/* ARGSUSED */549static void550auth_intr(int sig)551{552auth_finished(0, AUTH_REJECT);553}554555int556auth_wait(char *name, size_t name_sz)557{558if (auth_debug_mode)559printf(">>>%s: in auth_wait.\r\n", Name);560561if (Server && !authenticating)562return(0);563564signal(SIGALRM, auth_intr);565alarm(30);566while (!authenticated)567if (telnet_spin())568break;569alarm(0);570signal(SIGALRM, SIG_DFL);571572/*573* Now check to see if the user is valid or not574*/575if (!authenticated || authenticated == &NoAuth)576return(AUTH_REJECT);577578if (validuser == AUTH_VALID)579validuser = AUTH_USER;580581if (authenticated->status)582validuser = (*authenticated->status)(authenticated,583name, name_sz,584validuser);585return(validuser);586}587588void589auth_debug(int mode)590{591auth_debug_mode = mode;592}593594void595auth_printsub(unsigned char *data, size_t cnt,596unsigned char *buf, size_t buflen)597{598Authenticator *ap;599600if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)601(*ap->printsub)(data, cnt, buf, buflen);602else603auth_gen_printsub(data, cnt, buf, buflen);604}605606void607auth_gen_printsub(unsigned char *data, size_t cnt,608unsigned char *buf, size_t buflen)609{610unsigned char *cp;611unsigned char tbuf[16];612613cnt -= 3;614data += 3;615buf[buflen-1] = '\0';616buf[buflen-2] = '*';617buflen -= 2;618for (; cnt > 0; cnt--, data++) {619snprintf((char*)tbuf, sizeof(tbuf), " %d", *data);620for (cp = tbuf; *cp && buflen > 0; --buflen)621*buf++ = *cp++;622if (buflen <= 0)623return;624}625*buf = '\0';626}627#endif628629630