/
niceSOFT
/
inetutils
Обзор
Документация
Войти
/
niceSOFT
/
inetutils
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
libtelnet/auth.c
736 строк
17 KB
Simon Josefsson
libtelnet: Don't use printsub
29 апр 2026, 09:47
Не верифицирован
29 апр 2026, 09:47
cceb734
Код
Авторство
О чём код?
/* Copyright (C) 1993-2026 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Inetutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see `http://www.gnu.org/licenses/'. */ /* * 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. */ /* * 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. */ #include <config.h> #include "attribute.h" #if defined AUTHENTICATION # include <stdio.h> # include <sys/types.h> # include <signal.h> # define AUTH_NAMES # define AUTHTYPE_NAMES /* Needed by Solaris. */ # include <arpa/telnet.h> # include <stdlib.h> # ifdef NO_STRING_H # include <strings.h> # else # include <string.h> # endif # include <unistd.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; static char *Name = "Noname"; static int Server = 0; static TN_Authenticator *authenticated = NULL; 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. Please note that these are stored * in priority order, i.e. try the first one first. */ TN_Authenticator authenticators[] = { # 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 SHISHI {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL, krb5shishi_init, krb5shishi_send, krb5shishi_is, krb5shishi_reply, krb5shishi_status, krb5shishi_printsub, }, {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_ONE_WAY, krb5shishi_init, krb5shishi_send, krb5shishi_is, krb5shishi_reply, krb5shishi_status, krb5shishi_printsub, }, # endif # ifdef KRB5 # ifdef ENCRYPTION {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL, kerberos5_init, kerberos5_send, kerberos5_is, kerberos5_reply, kerberos5_status, kerberos5_printsub}, # endif /* ENCRYPTION */ {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_ONE_WAY, kerberos5_init, kerberos5_send, kerberos5_is, kerberos5_reply, kerberos5_status, kerberos5_printsub}, # endif # ifdef KRB4 # ifdef ENCRYPTION {AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL, kerberos4_init, kerberos4_send, kerberos4_is, kerberos4_reply, kerberos4_status, kerberos4_printsub}, # endif /* ENCRYPTION */ {AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT | AUTH_HOW_ONE_WAY, kerberos4_init, kerberos4_send, 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 TN_Authenticator NoAuth = { 0 }; static int i_support = 0; static int i_wont_support = 0; TN_Authenticator * findauthenticator (int type, int way) { TN_Authenticator *ap = authenticators; while (ap->type && (ap->type != type || ap->way != way)) ++ap; return (ap->type ? ap : 0); } void auth_init (char *name, int server) { TN_Authenticator *ap = authenticators; Server = server; Name = name; i_support = 0; authenticated = NULL; 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 %s (%d) %s (%d)\r\n", Name, (AUTHTYPE_NAME_OK (ap->type) && AUTHTYPE_NAME (ap->type)) ? AUTHTYPE_NAME (ap->type) : "unknown", ap->type, (ap->way & AUTH_HOW_MASK & AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONEWAY", 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 (AUTHTYPE_NAME (x) && !strcasecmp (name, AUTHTYPE_NAME (x))) { i_wont_support |= typemask (x); break; } } } int getauthmask (char *type, int *maskp) { int x; if (AUTHTYPE_NAME (0) && !strcasecmp (type, AUTHTYPE_NAME (0))) { *maskp = -1; return (1); } for (x = 1; x < AUTHTYPE_CNT; ++x) { if (AUTHTYPE_NAME (x) && !strcasecmp (type, AUTHTYPE_NAME (x))) { *maskp = typemask (x); return (1); } } return (0); } int auth_onoff (char *, int); 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; TN_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++) { i = typemask (ap->type); if ((mask & i) != 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) { TN_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++) { i = typemask (ap->type); if ((mask & i) != 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, }; TN_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; net_write (str_request, e - str_request); } } /* * 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) { TN_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 > (int) sizeof (_auth_send_data)) ? (int) sizeof (_auth_send_data) : cnt; memmove ((void *) _auth_send_data, (void *) 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 %s (%d) %s (%d)\r\n", Name, (AUTHTYPE_NAME_OK (auth_send_data[0]) && AUTHTYPE_NAME (auth_send_data[0])) ? AUTHTYPE_NAME (auth_send_data[0]) : "unknown", auth_send_data[0], (auth_send_data[1] & AUTH_HOW_MASK & AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONEWAY", auth_send_data[1]); 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 %s (%d) %s (%d)\r\n", Name, (AUTHTYPE_NAME_OK (auth_send_data[0]) && AUTHTYPE_NAME (auth_send_data[0])) ? AUTHTYPE_NAME (auth_send_data[0]) : "unknown", auth_send_data[0], (auth_send_data[1] & AUTH_HOW_MASK & AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONEWAY", 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 %s (%d)\r\n", Name, (AUTHTYPE_NAME_OK (*auth_send_data) && AUTHTYPE_NAME (*auth_send_data)) ? AUTHTYPE_NAME (*auth_send_data) : "unknown", *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; } net_write (str_none, sizeof (str_none)); if (auth_debug_mode) printf (">>>%s: Sent failure message\r\n", Name); auth_finished (0, AUTH_REJECT); # ifdef KANNAN /* * We requested strong authentication, however no mechanisms worked. * Therefore, exit on client end. */ printf ("Unable to securely authenticate user ... exit\n"); exit (EXIT_SUCCESS); # 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) { TN_Authenticator *ap; if (cnt < 2) return; if (data[0] == AUTHTYPE_NULL) { auth_finished (0, AUTH_REJECT); return; } ap = findauthenticator (data[0], data[1]); if (ap) { 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) { TN_Authenticator *ap; if (cnt < 2) return; ap = findauthenticator (data[0], data[1]); if (ap) { 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 + 1 > (int) sizeof (savename)) { if (auth_debug_mode) printf (">>>%s: Name in NAME (len %d) overflows buffer (len %zu).\r\n", Name, cnt, sizeof (savename) - 1); return; } memmove ((void *) savename, (void *) 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 (char *name, 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]; unsigned char *cp = (unsigned char *) name; while (--len >= 0) { if ((*e++ = *cp++) == IAC) *e++ = IAC; if (e >= ee) return (0); } *e++ = IAC; *e++ = SE; net_write (str_request, e - str_request); return (1); } void auth_finished (TN_Authenticator *ap, int result) { if (ap && ap->cleanup) (*ap->cleanup) (ap); authenticated = ap; if (!authenticated) authenticated = &NoAuth; validuser = result; } static void auth_intr (int sig MAYBE_UNUSED) { auth_finished (0, AUTH_REJECT); } int auth_wait (char *name, size_t len) { 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, len, validuser); return (validuser); } void auth_debug (int mode) { auth_debug_mode = mode; } static void auth_gen_printsub (unsigned char *data, int cnt, char *buf, int buflen) { char *cp; char tbuf[16]; cnt -= 3; data += 3; buf[buflen - 1] = '\0'; buf[buflen - 2] = '*'; buflen -= 2; for (; cnt > 0; cnt--, data++) { sprintf (tbuf, " %d", *data); for (cp = tbuf; *cp && buflen > 0; --buflen) *buf++ = *cp++; if (buflen <= 0) return; } *buf = '\0'; } void auth_printsub (unsigned char *data, int cnt, char *buf, int buflen) { TN_Authenticator *ap; ap = findauthenticator (data[1], data[2]); if (ap && ap->printsub) (*ap->printsub) (data, cnt, buf, buflen); else auth_gen_printsub (data, cnt, buf, buflen); } #endif