From 8ad6681b6bb601c670726ca36c924f5852d01efd Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 25 Sep 2007 17:14:01 +0000 Subject: 2007-09-25 Joel Sherrill * telnetd/README, telnetd/pty.c, telnetd/pty.h, telnetd/telnetd.c, telnetd/telnetd.h: telnetd rewrite. * telnetd/check_passwd.c, telnetd/des.c, telnetd/genpw.c: New files. --- cpukit/telnetd/README | 5 +- cpukit/telnetd/check_passwd.c | 200 ++++++++++ cpukit/telnetd/des.c | 855 ++++++++++++++++++++++++++++++++++++++++++ cpukit/telnetd/genpw.c | 74 ++++ cpukit/telnetd/pty.c | 630 +++++++++++++++---------------- cpukit/telnetd/pty.h | 2 +- cpukit/telnetd/telnetd.c | 442 +++++++++++----------- cpukit/telnetd/telnetd.h | 33 +- 8 files changed, 1692 insertions(+), 549 deletions(-) create mode 100644 cpukit/telnetd/check_passwd.c create mode 100644 cpukit/telnetd/des.c create mode 100644 cpukit/telnetd/genpw.c (limited to 'cpukit/telnetd') diff --git a/cpukit/telnetd/README b/cpukit/telnetd/README index 1c84eb769f..626b458f23 100644 --- a/cpukit/telnetd/README +++ b/cpukit/telnetd/README @@ -21,8 +21,7 @@ NOTES: 2. If you have tcp/ip initialied you can start telnetd daemon. You need register pseudo-terminals driver into device drivers table. - 16 ptyX termios device terminales are created into /dev/. - Calling rtems_initialize_telnetd() starts the daemon. - Enjoy it. + +Enjoy it. FUTURE: diff --git a/cpukit/telnetd/check_passwd.c b/cpukit/telnetd/check_passwd.c new file mode 100644 index 0000000000..e1df00d2d9 --- /dev/null +++ b/cpukit/telnetd/check_passwd.c @@ -0,0 +1,200 @@ +/* $Id$ */ + +/* Read a password, encrypt it and compare to the encrypted + * password in the TELNETD_PASSWD environment variable. + * No password is required if TELNETD_PASSWD is unset + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 2003-2007 + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#if !defined(INSIDE_TELNETD) && !defined(__rtems__) +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "passwd.h" + +/* rtems has global filedescriptors but per-thread stdio streams... */ +#define STDI_FD fileno(stdin) +#define MAXPASSRETRY 3 + +extern char *__des_crypt_r(char *, char*, char*, int); + +#if !defined(INSIDE_TELNETD) +#define sockpeername(s,b,sz) (-1) +#endif + +#if defined(INSIDE_TELNETD) +static +#endif +int check_passwd(char *peername) +{ +char *pw; +int rval = -1, tmp, retries; +struct termios t,told; +int restore_flags = 0; +char buf[30], cryptbuf[21]; +char salt[3]; + + if ( !(pw=getenv("TELNETD_PASSWD")) || 0 == strlen(pw) ) +#ifdef TELNETD_DEFAULT_PASSWD + pw = TELNETD_DEFAULT_PASSWD; +#else + return 0; +#endif + + if ( tcgetattr(STDI_FD, &t) ) { + perror("check_passwd(): tcgetattr"); + goto done; + } + told = t; + t.c_lflag &= ~ECHO; + t.c_lflag &= ~ICANON; + t.c_cc[VTIME] = 255; + t.c_cc[VMIN] = 0; + + strncpy(salt,pw,2); + salt[2]=0; + + if ( tcsetattr(STDI_FD, TCSANOW, &t) ) { + perror("check_passwd(): tcsetattr"); + goto done; + } + restore_flags = 1; + + /* Here we ask for the password... */ + for ( retries = MAXPASSRETRY; retries > 0; retries-- ) { + fflush(stdin); + fprintf(stderr,"Password:"); + fflush(stderr); + if ( 0 == fgets(buf,sizeof(buf),stdin) ) { + /* Here comes an ugly hack: + * The termios driver's 'read()' handler + * returns 0 to the c library's fgets if + * it times out. 'fgets' interprets this + * (correctly) as EOF, a condition we want + * to undo since it's not really true since + * we really have a read error (termios bug??) + * + * As a workaround we push something back and + * read it again. This should simply reset the + * EOF condition. + */ + if (ungetc('?',stdin) >= 0) + fgetc(stdin); + goto done; + } + fputc('\n',stderr); + tmp = strlen(buf); + while ( tmp > 0 && ('\n' == buf[tmp-1] || '\r' == buf[tmp-1]) ) { + buf[--tmp]=0; + } + if ( !strcmp(__des_crypt_r(buf, salt, cryptbuf, sizeof(cryptbuf)), pw) ) { + rval = 0; + break; + } + fprintf(stderr,"Incorrect Password.\n"); + sleep(2); + } + + if ( 0 == retries ) { + syslog( LOG_AUTHPRIV | LOG_WARNING, + "telnetd: %i wrong passwords entered from %s", + MAXPASSRETRY, + peername ? peername : ""); + } + +done: + /* what to do if restoring the flags fails?? */ + if (restore_flags) + tcsetattr(STDI_FD, TCSANOW, &told); + + if (rval) { + sleep(2); + } + return rval; +} + +#if !defined(INSIDE_TELNETD) && !defined(__rtems__) +int +main(int argc, char **argv) +{ +char *str, *enc=0; +int ch; + +while ( (ch=getopt(argc, argv, "g:")) > 0 ) { + switch (ch) { + default: + fprintf(stderr,"Unknown option\n"); + return(1); + + case 'g': + printf("Generated encrypted password: '%s'\n", (enc=crypt(optarg,"td"))); + break; + + } +} +if (argc>optind && !enc) { + enc=argv[optind]; +} +if (enc) { + str = malloc(strlen(enc) + 30); + sprintf(str,"TELNETD_PASSWD=%s",enc); + putenv(str); +} +if (check_passwd(-1)) { + fprintf(stderr,"check_passwd() failed\n"); +} +return 0; +} + +#endif diff --git a/cpukit/telnetd/des.c b/cpukit/telnetd/des.c new file mode 100644 index 0000000000..b052fd3a05 --- /dev/null +++ b/cpukit/telnetd/des.c @@ -0,0 +1,855 @@ +/* + * FreeSec: libcrypt for NetBSD + * + * Copyright (c) 1994 David Burren + * All rights reserved. + * + * Ported to RTEMS and made reentrant by Till Straumann, 9/2003 + * + * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet + * this file should now *only* export crypt(), in order to make + * binaries of libcrypt exportable from the USA + * + * Adapted for FreeBSD-4.0 by Mark R V Murray + * this file should now *only* export crypt_des(), in order to make + * a module that can be optionally included in libcrypt. + * + * 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 author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 is an original implementation of the DES and the crypt(3) interfaces + * by David Burren . + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + * B. Schneier, Applied Cryptography: protocols, algorithms, + * and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author). A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * ARCHITECTURE ASSUMPTIONS: + * It is assumed that the 8-byte arrays passed by reference can be + * addressed as arrays of u_int32_t's (ie. the CPU is not picky about + * alignment). + */ + +#define __FORCE_GLIBC +#include +#include +#include +#include +#ifndef __rtems__ +#include +#include +#include +#endif +#include + +#define REENTRANT +/* Re-entrantify me -- all this junk needs to be in + * struct crypt_data to make this really reentrant... */ + +/* TS; not really - only the stuff in Des_Context */ +static struct fixed { +u_char inv_key_perm[64]; +u_char inv_comp_perm[56]; +u_char u_sbox[8][64]; +u_char un_pbox[32]; +u_int32_t ip_maskl[8][256], ip_maskr[8][256]; +u_int32_t fp_maskl[8][256], fp_maskr[8][256]; +u_int32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; +u_int32_t comp_maskl[8][128], comp_maskr[8][128]; +} des_f; + +#define inv_key_perm des_f.inv_key_perm +#define inv_comp_perm des_f.inv_comp_perm +#define u_sbox des_f.u_sbox +#define un_pbox des_f.un_pbox +#define ip_maskl des_f.ip_maskl +#define ip_maskr des_f.ip_maskr +#define fp_maskl des_f.fp_maskl +#define fp_maskr des_f.fp_maskr +#define key_perm_maskl des_f.key_perm_maskl +#define key_perm_maskr des_f.key_perm_maskr +#define comp_maskl des_f.comp_maskl +#define comp_maskr des_f.comp_maskr + +/* These need to be maintained per-process */ +struct Des_Context { +u_int32_t en_keysl[16], en_keysr[16]; +u_int32_t de_keysl[16], de_keysr[16]; +u_int32_t saltbits; +u_int32_t old_salt; +u_int32_t old_rawkey0, old_rawkey1; +}; + +#ifndef REENTRANT +static struct Des_Context single; +#endif + +#define en_keysl des_ctx->en_keysl +#define en_keysr des_ctx->en_keysr +#define de_keysl des_ctx->de_keysl +#define de_keysr des_ctx->de_keysr +#define saltbits des_ctx->saltbits +#define old_salt des_ctx->old_salt +#define old_rawkey0 des_ctx->old_rawkey0 +#define old_rawkey1 des_ctx->old_rawkey1 + +/* Static stuff that stays resident and doesn't change after + * being initialized, and therefore doesn't need to be made + * reentrant. */ +static u_char init_perm[64], final_perm[64]; +static u_char m_sbox[4][4096]; +static u_int32_t psbox[4][256]; + + + + +/* A pile of data */ +static const u_char ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static const u_char IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static const u_char key_perm[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +static const u_char key_shifts[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static const u_char comp_perm[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * No E box is used, as it's replaced by some ANDs, shifts, and ORs. + */ + +static const u_char sbox[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +static const u_char pbox[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +static const u_int32_t bits32[32] = +{ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static const u_char bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; +static const u_int32_t *bits28, *bits24; + + +static int +ascii_to_bin(char ch) +{ + if (ch > 'z') + return(0); + if (ch >= 'a') + return(ch - 'a' + 38); + if (ch > 'Z') + return(0); + if (ch >= 'A') + return(ch - 'A' + 12); + if (ch > '9') + return(0); + if (ch >= '.') + return(ch - '.'); + return(0); +} + +struct Des_Context * +des_ctx_init(void) +{ +struct Des_Context *des_ctx; +#ifdef REENTRANT + des_ctx = malloc(sizeof(*des_ctx)); +#else + des_ctx = &single; +#endif + old_rawkey0 = old_rawkey1 = 0L; + saltbits = 0L; + old_salt = 0L; + + return des_ctx; +} + +static void +des_init(void) +{ + int i, j, b, k, inbit, obit; + u_int32_t *p, *il, *ir, *fl, *fr; + static int des_initialised = 0; + + if (des_initialised==1) + return; + +#ifndef REENTRANT + des_ctx_init(); +#endif + + bits24 = (bits28 = bits32 + 4) + 4; + + /* + * Invert the S-boxes, reordering the input bits. + */ + for (i = 0; i < 8; i++) + for (j = 0; j < 64; j++) { + b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); + u_sbox[i][j] = sbox[i][b]; + } + + /* + * Convert the inverted S-boxes into 4 arrays of 8 bits. + * Each will handle 12 bits of the S-box input. + */ + for (b = 0; b < 4; b++) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + m_sbox[b][(i << 6) | j] = + (u_char)((u_sbox[(b << 1)][i] << 4) | + u_sbox[(b << 1) + 1][j]); + + /* + * Set up the initial & final permutations into a useful form, and + * initialise the inverted key permutation. + */ + for (i = 0; i < 64; i++) { + init_perm[final_perm[i] = IP[i] - 1] = (u_char)i; + inv_key_perm[i] = 255; + } + + /* + * Invert the key permutation and initialise the inverted key + * compression permutation. + */ + for (i = 0; i < 56; i++) { + inv_key_perm[key_perm[i] - 1] = (u_char)i; + inv_comp_perm[i] = 255; + } + + /* + * Invert the key compression permutation. + */ + for (i = 0; i < 48; i++) { + inv_comp_perm[comp_perm[i] - 1] = (u_char)i; + } + + /* + * Set up the OR-mask arrays for the initial and final permutations, + * and for the key initial and compression permutations. + */ + for (k = 0; k < 8; k++) { + for (i = 0; i < 256; i++) { + *(il = &ip_maskl[k][i]) = 0L; + *(ir = &ip_maskr[k][i]) = 0L; + *(fl = &fp_maskl[k][i]) = 0L; + *(fr = &fp_maskr[k][i]) = 0L; + for (j = 0; j < 8; j++) { + inbit = 8 * k + j; + if (i & bits8[j]) { + if ((obit = init_perm[inbit]) < 32) + *il |= bits32[obit]; + else + *ir |= bits32[obit-32]; + if ((obit = final_perm[inbit]) < 32) + *fl |= bits32[obit]; + else + *fr |= bits32[obit - 32]; + } + } + } + for (i = 0; i < 128; i++) { + *(il = &key_perm_maskl[k][i]) = 0L; + *(ir = &key_perm_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 8 * k + j; + if (i & bits8[j + 1]) { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + else + *ir |= bits28[obit - 28]; + } + } + *(il = &comp_maskl[k][i]) = 0L; + *(ir = &comp_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) { + inbit = 7 * k + j; + if (i & bits8[j + 1]) { + if ((obit=inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + else + *ir |= bits24[obit - 24]; + } + } + } + } + + /* + * Invert the P-box permutation, and convert into OR-masks for + * handling the output of the S-box arrays setup above. + */ + for (i = 0; i < 32; i++) + un_pbox[pbox[i] - 1] = (u_char)i; + + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) { + *(p = &psbox[b][i]) = 0L; + for (j = 0; j < 8; j++) { + if (i & bits8[j]) + *p |= bits32[un_pbox[8 * b + j]]; + } + } + + des_initialised = 1; +} + + +static void +setup_salt(long salt, struct Des_Context *des_ctx) +{ + u_int32_t obit, saltbit; + int i; + + if (salt == old_salt) + return; + old_salt = salt; + + saltbits = 0L; + saltbit = 1; + obit = 0x800000; + for (i = 0; i < 24; i++) { + if (salt & saltbit) + saltbits |= obit; + saltbit <<= 1; + obit >>= 1; + } +} + + +static int +des_setkey(const char *key, struct Des_Context *des_ctx) +{ + u_int32_t k0, k1, rawkey0, rawkey1; + int shifts, round; + + des_init(); + + rawkey0 = ntohl(*(const u_int32_t *) key); + rawkey1 = ntohl(*(const u_int32_t *) (key + 4)); + + if ((rawkey0 | rawkey1) + && rawkey0 == old_rawkey0 + && rawkey1 == old_rawkey1) { + /* + * Already setup for this key. + * This optimisation fails on a zero key (which is weak and + * has bad parity anyway) in order to simplify the starting + * conditions. + */ + return(0); + } + old_rawkey0 = rawkey0; + old_rawkey1 = rawkey1; + + /* + * Do key permutation and split into two 28-bit subkeys. + */ + k0 = key_perm_maskl[0][rawkey0 >> 25] + | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskl[4][rawkey1 >> 25] + | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; + k1 = key_perm_maskr[0][rawkey0 >> 25] + | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskr[4][rawkey1 >> 25] + | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; + /* + * Rotate subkeys and do compression permutation. + */ + shifts = 0; + for (round = 0; round < 16; round++) { + u_int32_t t0, t1; + + shifts += key_shifts[round]; + + t0 = (k0 << shifts) | (k0 >> (28 - shifts)); + t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + + de_keysl[15 - round] = + en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] + | comp_maskl[1][(t0 >> 14) & 0x7f] + | comp_maskl[2][(t0 >> 7) & 0x7f] + | comp_maskl[3][t0 & 0x7f] + | comp_maskl[4][(t1 >> 21) & 0x7f] + | comp_maskl[5][(t1 >> 14) & 0x7f] + | comp_maskl[6][(t1 >> 7) & 0x7f] + | comp_maskl[7][t1 & 0x7f]; + + de_keysr[15 - round] = + en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] + | comp_maskr[1][(t0 >> 14) & 0x7f] + | comp_maskr[2][(t0 >> 7) & 0x7f] + | comp_maskr[3][t0 & 0x7f] + | comp_maskr[4][(t1 >> 21) & 0x7f] + | comp_maskr[5][(t1 >> 14) & 0x7f] + | comp_maskr[6][(t1 >> 7) & 0x7f] + | comp_maskr[7][t1 & 0x7f]; + } + return(0); +} + + +static int +do_des( u_int32_t l_in, u_int32_t r_in, u_int32_t *l_out, u_int32_t *r_out, int count, struct Des_Context *des_ctx) +{ + /* + * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. + */ + u_int32_t l, r, *kl, *kr, *kl1, *kr1; + u_int32_t f, r48l, r48r; + int round; + + if (count == 0) { + return(1); + } else if (count > 0) { + /* + * Encrypting + */ + kl1 = en_keysl; + kr1 = en_keysr; + } else { + /* + * Decrypting + */ + count = -count; + kl1 = de_keysl; + kr1 = de_keysr; + } + + /* + * Do initial permutation (IP). + */ + l = ip_maskl[0][l_in >> 24] + | ip_maskl[1][(l_in >> 16) & 0xff] + | ip_maskl[2][(l_in >> 8) & 0xff] + | ip_maskl[3][l_in & 0xff] + | ip_maskl[4][r_in >> 24] + | ip_maskl[5][(r_in >> 16) & 0xff] + | ip_maskl[6][(r_in >> 8) & 0xff] + | ip_maskl[7][r_in & 0xff]; + r = ip_maskr[0][l_in >> 24] + | ip_maskr[1][(l_in >> 16) & 0xff] + | ip_maskr[2][(l_in >> 8) & 0xff] + | ip_maskr[3][l_in & 0xff] + | ip_maskr[4][r_in >> 24] + | ip_maskr[5][(r_in >> 16) & 0xff] + | ip_maskr[6][(r_in >> 8) & 0xff] + | ip_maskr[7][r_in & 0xff]; + + while (count--) { + /* + * Do each round. + */ + kl = kl1; + kr = kr1; + round = 16; + while (round--) { + /* + * Expand R to 48 bits (simulate the E-box). + */ + r48l = ((r & 0x00000001) << 23) + | ((r & 0xf8000000) >> 9) + | ((r & 0x1f800000) >> 11) + | ((r & 0x01f80000) >> 13) + | ((r & 0x001f8000) >> 15); + + r48r = ((r & 0x0001f800) << 7) + | ((r & 0x00001f80) << 5) + | ((r & 0x000001f8) << 3) + | ((r & 0x0000001f) << 1) + | ((r & 0x80000000) >> 31); + /* + * Do salting for crypt() and friends, and + * XOR with the permuted key. + */ + f = (r48l ^ r48r) & saltbits; + r48l ^= f ^ *kl++; + r48r ^= f ^ *kr++; + /* + * Do sbox lookups (which shrink it back to 32 bits) + * and do the pbox permutation at the same time. + */ + f = psbox[0][m_sbox[0][r48l >> 12]] + | psbox[1][m_sbox[1][r48l & 0xfff]] + | psbox[2][m_sbox[2][r48r >> 12]] + | psbox[3][m_sbox[3][r48r & 0xfff]]; + /* + * Now that we've permuted things, complete f(). + */ + f ^= l; + l = r; + r = f; + } + r = l; + l = f; + } + /* + * Do final permutation (inverse of IP). + */ + *l_out = fp_maskl[0][l >> 24] + | fp_maskl[1][(l >> 16) & 0xff] + | fp_maskl[2][(l >> 8) & 0xff] + | fp_maskl[3][l & 0xff] + | fp_maskl[4][r >> 24] + | fp_maskl[5][(r >> 16) & 0xff] + | fp_maskl[6][(r >> 8) & 0xff] + | fp_maskl[7][r & 0xff]; + *r_out = fp_maskr[0][l >> 24] + | fp_maskr[1][(l >> 16) & 0xff] + | fp_maskr[2][(l >> 8) & 0xff] + | fp_maskr[3][l & 0xff] + | fp_maskr[4][r >> 24] + | fp_maskr[5][(r >> 16) & 0xff] + | fp_maskr[6][(r >> 8) & 0xff] + | fp_maskr[7][r & 0xff]; + return(0); +} + + +#if 0 +static int +des_cipher(const char *in, char *out, u_int32_t salt, int count) +{ + u_int32_t l_out, r_out, rawl, rawr; + int retval; + union { + u_int32_t *ui32; + const char *c; + } trans; + + des_init(); + + setup_salt(salt); + + trans.c = in; + rawl = ntohl(*trans.ui32++); + rawr = ntohl(*trans.ui32); + + retval = do_des(rawl, rawr, &l_out, &r_out, count); + + trans.c = out; + *trans.ui32++ = htonl(l_out); + *trans.ui32 = htonl(r_out); + return(retval); +} +#endif + + +#ifndef REENTRANT +void +setkey(const char *key) +{ + int i, j; + u_int32_t packed_keys[2]; + u_char *p; + + p = (u_char *) packed_keys; + + for (i = 0; i < 8; i++) { + p[i] = 0; + for (j = 0; j < 8; j++) + if (*key++ & 1) + p[i] |= bits8[j]; + } + des_setkey(p, &single); +} +#endif + + +#ifndef REENTRANT +void +encrypt(char *block, int flag) +{ + u_int32_t io[2]; + u_char *p; + int i, j; + + des_init(); + + setup_salt(0L, &single); + p = block; + for (i = 0; i < 2; i++) { + io[i] = 0L; + for (j = 0; j < 32; j++) + if (*p++ & 1) + io[i] |= bits32[j]; + } + do_des(io[0], io[1], io, io + 1, flag ? -1 : 1, &single); + for (i = 0; i < 2; i++) + for (j = 0; j < 32; j++) + block[(i << 5) | j] = (io[i] & bits32[j]) ? 1 : 0; +} + +#endif + +char * +__des_crypt_r(const char *key, const char *setting, char *output, int sz) +{ + char *rval = 0; + struct Des_Context *des_ctx; + u_int32_t count, salt, l, r0, r1, keybuf[2]; + u_char *p, *q; + + if (sz < 21) + return NULL; + + des_init(); + des_ctx = des_ctx_init(); + + /* + * Copy the key, shifting each character up by one bit + * and padding with zeros. + */ + q = (u_char *)keybuf; + while (q - (u_char *)keybuf - 8) { + *q++ = *key << 1; + if (*(q - 1)) + key++; + } + if (des_setkey((char *)keybuf, des_ctx)) + goto bailout; + +#if 0 + if (*setting == _PASSWORD_EFMT1) { + int i; + /* + * "new"-style: + * setting - underscore, 4 bytes of count, 4 bytes of salt + * key - unlimited characters + */ + for (i = 1, count = 0L; i < 5; i++) + count |= ascii_to_bin(setting[i]) << ((i - 1) * 6); + + for (i = 5, salt = 0L; i < 9; i++) + salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6); + + while (*key) { + /* + * Encrypt the key with itself. + */ + if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1)) + goto bailout; + /* + * And XOR with the next 8 characters of the key. + */ + q = (u_char *)keybuf; + while (q - (u_char *)keybuf - 8 && *key) + *q++ ^= *key++ << 1; + + if (des_setkey((char *)keybuf)) + goto bailout; + } + strncpy(output, setting, 9); + + /* + * Double check that we weren't given a short setting. + * If we were, the above code will probably have created + * wierd values for count and salt, but we don't really care. + * Just make sure the output string doesn't have an extra + * NUL in it. + */ + output[9] = '\0'; + p = (u_char *)output + strlen(output); + } else +#endif + { + /* + * "old"-style: + * setting - 2 bytes of salt + * key - up to 8 characters + */ + count = 25; + + salt = (ascii_to_bin(setting[1]) << 6) + | ascii_to_bin(setting[0]); + + output[0] = setting[0]; + /* + * If the encrypted password that the salt was extracted from + * is only 1 character long, the salt will be corrupted. We + * need to ensure that the output string doesn't have an extra + * NUL in it! + */ + output[1] = setting[1] ? setting[1] : output[0]; + + p = (u_char *)output + 2; + } + setup_salt(salt, des_ctx); + /* + * Do it. + */ + if (do_des(0L, 0L, &r0, &r1, (int)count, des_ctx)) + goto bailout; + /* + * Now encode the result... + */ + l = (r0 >> 8); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = (r0 << 16) | ((r1 >> 16) & 0xffff); + *p++ = ascii64[(l >> 18) & 0x3f]; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + + l = r1 << 2; + *p++ = ascii64[(l >> 12) & 0x3f]; + *p++ = ascii64[(l >> 6) & 0x3f]; + *p++ = ascii64[l & 0x3f]; + *p = 0; + + rval = output; +bailout: + free(des_ctx); + return rval; +} + +char * +__des_crypt(const char *key, const char *setting) +{ + static char output[21]; + return __des_crypt_r(key, setting, output, sizeof(output)); +} + + +#ifdef DEBUG + +void +des_snap(void **pf, void **pd) +{ + *pf = malloc(sizeof(struct fixed)); + memcpy(*pf, &des_f, sizeof(des_f)); +// *pd = malloc(sizeof(struct Des_Context)); +// memcpy(*pd, &des_ctx, sizeof(des_ctx)); +} + +void +des_check(void *pf, void *pd) +{ + printf("Fixed: do%s differ"/*", Context: do%s differ"*/"\n", + memcmp(pf, &des_f, sizeof(des_f)) ? "" : "nt" +// ,memcmp(pd, &des_ctx, sizeof(des_ctx)) ? "" : "nt" + ); +} + +#endif diff --git a/cpukit/telnetd/genpw.c b/cpukit/telnetd/genpw.c new file mode 100644 index 0000000000..1ce3e41206 --- /dev/null +++ b/cpukit/telnetd/genpw.c @@ -0,0 +1,74 @@ +#include +#include +#include + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 2003-2007 + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ +static void +usage(char *nm) +{ + fprintf(stderr,"Usage: %s [-h] [-s salt] cleartext_password\n", nm); +} + +int +main(int argc, char **argv) +{ +int ch; +char *salt="td"; + while ( (ch=getopt(argc, argv, "hs:")) >=0 ) { + switch (ch) { + default: fprintf(stderr,"Unknown Option '%c'\n",ch); + case 'h': usage(argv[0]); + return 0; + case 's': salt=optarg; + break; + } + } + if ( optind >= argc ) { + usage(argv[0]); + return 1; + } + printf("#define TELNETD_DEFAULT_PASSWD \"%s\"\n",crypt(argv[optind],salt)); +} diff --git a/cpukit/telnetd/pty.c b/cpukit/telnetd/pty.c index 9ee05231b7..142a7ce4e4 100644 --- a/cpukit/telnetd/pty.c +++ b/cpukit/telnetd/pty.c @@ -144,22 +144,22 @@ static rtems_device_major_number pty_major; */ char * telnet_get_pty(int socket) { - int ndx; - if (telnet_pty_inited) { - for (ndx=0;ndxsb_buf[0]) { - case 31: /* NAWS */ - pty->width = (pty->sb_buf[1]<<8) + pty->sb_buf[2]; - pty->height = (pty->sb_buf[3]<<8) + pty->sb_buf[4]; + switch (pty->sb_buf[0]) { + case 31: /* NAWS */ + pty->width = (pty->sb_buf[1]<<8) + pty->sb_buf[2]; + pty->height = (pty->sb_buf[3]<<8) + pty->sb_buf[4]; #if DEBUG & DEBUG_WH - fprintf(stderr, - "Setting width/height to %ix%i\n", - pty->width, - pty->height); + fprintf(stderr, + "Setting width/height to %ix%i\n", + pty->width, + pty->height); #endif - break; - default: - break; - } - return 0; + break; + default: + break; + } + return 0; } static int read_pty(int minor) { /* Characters written to the client side*/ - unsigned char value; - unsigned int omod; - int count; - int result; - pty_t *pty=telnet_ptys+minor; - - count=read(pty->socket,&value,sizeof(value)); - if (count<0) - return -1; - - if (count<1) { - /* Unfortunately, there is no way of passing an EOF - * condition through the termios driver. Hence, we - * resort to an ugly hack. Setting cindex>ccount - * causes the termios driver to return a read count - * of '0' which is what we want here. We leave - * 'errno' untouched. - */ - pty->ttyp->cindex=pty->ttyp->ccount+1; - return pty->ttyp->termios.c_cc[VEOF]; - }; - - omod=pty->iac_mode; - pty->iac_mode=0; - switch(omod & 0xff) { - case IAC_ESC: - switch(value) { - case IAC_ESC : - /* in case this is an ESC ESC sequence in SB mode */ - pty->iac_mode = omod>>8; - return IAC_ESC; - case IAC_DONT: - case IAC_DO : - case IAC_WONT: - case IAC_WILL: - pty->iac_mode=value; - return -1; - case IAC_SB : + unsigned char value; + unsigned int omod; + int count; + int result; + pty_t *pty=telnet_ptys+minor; + + count=read(pty->socket,&value,sizeof(value)); + if (count<0) + return -1; + + if (count<1) { + /* Unfortunately, there is no way of passing an EOF + * condition through the termios driver. Hence, we + * resort to an ugly hack. Setting cindex>ccount + * causes the termios driver to return a read count + * of '0' which is what we want here. We leave + * 'errno' untouched. + */ + pty->ttyp->cindex=pty->ttyp->ccount+1; + return pty->ttyp->termios.c_cc[VEOF]; + }; + + omod=pty->iac_mode; + pty->iac_mode=0; + switch(omod & 0xff) { + case IAC_ESC: + switch(value) { + case IAC_ESC : + /* in case this is an ESC ESC sequence in SB mode */ + pty->iac_mode = omod>>8; + return IAC_ESC; + case IAC_DONT: + case IAC_DO : + case IAC_WONT: + case IAC_WILL: + pty->iac_mode=value; + return -1; + case IAC_SB : #if DEBUG & DEBUG_DETAIL - printk("SB\n"); + printk("SB\n"); #endif - pty->iac_mode=value; - pty->sb_ind=0; - return -100; - case IAC_GA : - return -1; - case IAC_EL : - return 0x03; /* Ctrl-C*/ - case IAC_EC : - return '\b'; - case IAC_AYT : - write(pty->socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP)); - return -1; - case IAC_AO : - return -1; - case IAC_IP : - write(pty->socket,IAC_IP_RSP,strlen(IAC_IP_RSP)); - return -1; - case IAC_BRK : - write(pty->socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP)); - return -1; - case IAC_DMARK: - return -2; - case IAC_NOP : - return -1; - case IAC_SE : + pty->iac_mode=value; + pty->sb_ind=0; + return -100; + case IAC_GA : + return -1; + case IAC_EL : + return 0x03; /* Ctrl-C*/ + case IAC_EC : + return '\b'; + case IAC_AYT : + write(pty->socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP)); + return -1; + case IAC_AO : + return -1; + case IAC_IP : + write(pty->socket,IAC_IP_RSP,strlen(IAC_IP_RSP)); + return -1; + case IAC_BRK : + write(pty->socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP)); + return -1; + case IAC_DMARK: + return -2; + case IAC_NOP : + return -1; + case IAC_SE : #if DEBUG & DEBUG_DETAIL - { - int i; - printk("SE"); - for (i=0; isb_ind; i++) - printk(" %02x",pty->sb_buf[i]); - printk("\n"); - } + { + int i; + printk("SE"); + for (i=0; isb_ind; i++) + printk(" %02x",pty->sb_buf[i]); + printk("\n"); + } #endif - handleSB(pty); - return -101; - case IAC_EOR : - return -102; - default : - return -1; - }; - break; - - case IAC_SB: - pty->iac_mode=omod; - if (IAC_ESC==value) { - pty->iac_mode=(omod<<8)|value; - } else { - if (pty->sb_ind < SB_MAX) - pty->sb_buf[pty->sb_ind++]=value; - } - return -1; - - case IAC_WILL: - if (value==34){ - send_iac(minor,IAC_DONT, 34); /*LINEMODE*/ - send_iac(minor,IAC_DO , 1); /*ECHO */ - } else if (value==31) { - send_iac(minor,IAC_DO , 31); /*NAWS */ + handleSB(pty); + return -101; + case IAC_EOR : + return -102; + default : + return -1; + }; + break; + + case IAC_SB: + pty->iac_mode=omod; + if (IAC_ESC==value) { + pty->iac_mode=(omod<<8)|value; + } else { + if (pty->sb_ind < SB_MAX) + pty->sb_buf[pty->sb_ind++]=value; + } + return -1; + + case IAC_WILL: + if (value==34){ + send_iac(minor,IAC_DONT, 34); /*LINEMODE*/ + send_iac(minor,IAC_DO , 1); /*ECHO */ + } else if (value==31) { + send_iac(minor,IAC_DO , 31); /*NAWS */ #if DEBUG & DEBUG_DETAIL - printk("replied DO NAWS\n"); + printk("replied DO NAWS\n"); #endif - } else { - send_iac(minor,IAC_DONT,value); - } - return -1; - case IAC_DONT: - return -1; - case IAC_DO : - if (value==3) { - send_iac(minor,IAC_WILL, 3); /* GO AHEAD*/ - } else if (value==1) { - /* ECHO */ - } else { - send_iac(minor,IAC_WONT,value); - }; - return -1; - case IAC_WONT: - if (value==1) {send_iac(minor,IAC_WILL, 1);} else /* ECHO */ - {send_iac(minor,IAC_WONT,value);}; - return -1; - default: - if (value==IAC_ESC) { - pty->iac_mode=value; - return -1; - } else { - result=value; - if ( 0 + } else { + send_iac(minor,IAC_DONT,value); + } + return -1; + case IAC_DONT: + return -1; + case IAC_DO : + if (value==3) { + send_iac(minor,IAC_WILL, 3); /* GO AHEAD*/ + } else if (value==1) { + /* ECHO */ + } else { + send_iac(minor,IAC_WONT,value); + }; + return -1; + case IAC_WONT: + if (value==1) {send_iac(minor,IAC_WILL, 1);} else /* ECHO */ + {send_iac(minor,IAC_WONT,value);}; + return -1; + default: + if (value==IAC_ESC) { + pty->iac_mode=value; + return -1; + } else { + result=value; + if ( 0 #if 0 /* pass CRLF through - they should use termios to handle it */ - || ((value=='\n') && (pty->last_cr)) + || ((value=='\n') && (pty->last_cr)) #endif - /* but map telnet CRNUL to CR down here */ - || ((value==0) && pty->last_cr) - ) result=-1; - pty->last_cr=(value=='\r'); - return result; - }; - }; - /* should never get here but keep compiler happy */ - return -1; + /* but map telnet CRNUL to CR down here */ + || ((value==0) && pty->last_cr) + ) result=-1; + pty->last_cr=(value=='\r'); + return result; + }; + }; + /* should never get here but keep compiler happy */ + return -1; } /*-----------------------------------------------------------*/ @@ -360,69 +360,69 @@ static const rtems_termios_callbacks * pty_get_termios_handlers(int polled) ; /*-----------------------------------------------------------*/ static int ptySetAttributes(int minor,const struct termios *t) { - if (minorc_cflag; - } else { - return -1; - }; - return 0; + if (minorc_cflag; + } else { + return -1; + }; + return 0; } /*-----------------------------------------------------------*/ static int ptyPollInitialize(int major,int minor,void * arg) { - rtems_libio_open_close_args_t * args = (rtems_libio_open_close_args_t*)arg; - struct termios t; + rtems_libio_open_close_args_t * args = (rtems_libio_open_close_args_t*)arg; + struct termios t; if (minoriop->data1; - telnet_ptys[minor].iac_mode=0; - telnet_ptys[minor].sb_ind=0; - telnet_ptys[minor].width=0; - telnet_ptys[minor].height=0; - t.c_cflag=B9600|CS8;/* termios default */ - return ptySetAttributes(minor,&t); - } else { - return -1; - }; + telnet_ptys[minor].opened=TRUE; + telnet_ptys[minor].ttyp= (struct rtems_termios_tty *) args->iop->data1; + telnet_ptys[minor].iac_mode=0; + telnet_ptys[minor].sb_ind=0; + telnet_ptys[minor].width=0; + telnet_ptys[minor].height=0; + t.c_cflag=B9600|CS8;/* termios default */ + return ptySetAttributes(minor,&t); + } else { + return -1; + }; } /*-----------------------------------------------------------*/ static int ptyShutdown(int major,int minor,void * arg) { if (minor=0) close(telnet_ptys[minor].socket); - telnet_ptys[minor].socket=-1; - chown(telnet_ptys[minor].devname,2,0); - } else { - return -1; - }; - return 0; + telnet_ptys[minor].socket=-1; + chown(telnet_ptys[minor].devname,2,0); + } else { + return -1; + }; + return 0; } /*-----------------------------------------------------------*/ /* Write Characters into pty device */ /*-----------------------------------------------------------*/ static int ptyPollWrite(int minor, const char * buf,int len) { - int count; + int count; if (minorbuffer; pty_t *p=&telnet_ptys[minor]; - switch (args->command) { + switch (args->command) { - case TIOCGWINSZ: + case TIOCGWINSZ: - wp->ws_row = p->height; - wp->ws_col = p->width; - args->ioctl_return=0; + wp->ws_row = p->height; + wp->ws_col = p->width; + args->ioctl_return=0; #if DEBUG & DEBUG_WH - fprintf(stderr, - "ioctl(TIOCGWINSZ), returning %ix%i\n", - wp->ws_col, - wp->ws_row); + fprintf(stderr, + "ioctl(TIOCGWINSZ), returning %ix%i\n", + wp->ws_col, + wp->ws_row); #endif - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; - case TIOCSWINSZ: + case TIOCSWINSZ: #if DEBUG & DEBUG_WH - fprintf(stderr, - "ioctl(TIOCGWINSZ), setting %ix%i\n", - wp->ws_col, - wp->ws_row); + fprintf(stderr, + "ioctl(TIOCGWINSZ), setting %ix%i\n", + wp->ws_col, + wp->ws_row); #endif - p->height = wp->ws_row; - p->width = wp->ws_col; - args->ioctl_return=0; + p->height = wp->ws_row; + p->width = wp->ws_col; + args->ioctl_return=0; - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; - default: + default: - break; + break; } return rtems_termios_ioctl(arg); } static rtems_driver_address_table drvPty = { - my_pty_initialize, - my_pty_open, - my_pty_close, - my_pty_read, - my_pty_write, - my_pty_control + my_pty_initialize, + my_pty_open, + my_pty_close, + my_pty_read, + my_pty_write, + my_pty_control }; /*-----------------------------------------------------------*/ static const rtems_termios_callbacks pty_poll_callbacks = { - ptyPollInitialize, /* FirstOpen*/ - ptyShutdown, /* LastClose*/ - ptyPollRead, /* PollRead */ - ptyPollWrite, /* Write */ - ptySetAttributes, /* setAttributes */ - NULL, /* stopRemoteTX */ - NULL, /* StartRemoteTX */ - 0 /* outputUsesInterrupts */ + ptyPollInitialize, /* FirstOpen*/ + ptyShutdown, /* LastClose*/ + ptyPollRead, /* PollRead */ + ptyPollWrite, /* Write */ + ptySetAttributes, /* setAttributes */ + NULL, /* stopRemoteTX */ + NULL, /* StartRemoteTX */ + 0 /* outputUsesInterrupts */ }; /*-----------------------------------------------------------*/ static const rtems_termios_callbacks * pty_get_termios_handlers(int polled) { - return &pty_poll_callbacks; + return &pty_poll_callbacks; } /*-----------------------------------------------------------*/ static int pty_do_initialize() { - if ( !telnet_pty_inited ) { - if (RTEMS_SUCCESSFUL==rtems_io_register_driver(0, &drvPty, &pty_major)) - telnet_pty_inited=TRUE; - else - fprintf(stderr,"WARNING: registering the PTY driver FAILED\n"); - } - return telnet_pty_inited; + if ( !telnet_pty_inited ) { + if (RTEMS_SUCCESSFUL==rtems_io_register_driver(0, &drvPty, &pty_major)) + telnet_pty_inited=TRUE; + else + fprintf(stderr,"WARNING: registering the PTY driver FAILED\n"); + } + return telnet_pty_inited; } #ifdef __cplusplus class TelnetPtyIni { public: - TelnetPtyIni() { if (!nest++) { - pty_do_initialize(); - } - }; - ~TelnetPtyIni(){ if (!--nest) { - pty_do_finalize(); - } - }; + TelnetPtyIni() { if (!nest++) { + pty_do_initialize(); + } + }; + ~TelnetPtyIni(){ if (!--nest) { + pty_do_finalize(); + } + }; private: static int nest; }; @@ -680,22 +680,22 @@ int TelnetPtyIni::nest=0; int telnet_pty_initialize() { - return telnet_pty_inited; + return telnet_pty_inited; } int telnet_pty_finalize() { - return telnet_pty_inited; + return telnet_pty_inited; } }; #else int telnet_pty_initialize() { - return pty_do_initialize(); + return pty_do_initialize(); } int telnet_pty_finalize() { - return pty_do_finalize(); + return pty_do_finalize(); } #endif diff --git a/cpukit/telnetd/pty.h b/cpukit/telnetd/pty.h index 7445f604a3..e786c01627 100644 --- a/cpukit/telnetd/pty.h +++ b/cpukit/telnetd/pty.h @@ -61,7 +61,7 @@ rtems_device_driver pty_control( #define PTY_DRIVER_TABLE_ENTRY \ { pty_initialize , pty_open , pty_close , \ - pty_read , pty_write , pty_control } + pty_read , pty_write , pty_control } #ifdef __cplusplus } diff --git a/cpukit/telnetd/telnetd.c b/cpukit/telnetd/telnetd.c index 24282059aa..ba3d10f25c 100644 --- a/cpukit/telnetd/telnetd.c +++ b/cpukit/telnetd/telnetd.c @@ -78,15 +78,15 @@ extern int telnet_pty_initialize(); extern int telnet_pty_finalize(); struct shell_args { - char *devname; - void *arg; - char peername[16]; - char delete_myself; + char *devname; + void *arg; + char peername[16]; + char delete_myself; }; typedef union uni_sa { - struct sockaddr_in sin; - struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr sa; } uni_sa; static int sockpeername(int sock, char *buf, int bufsz); @@ -113,35 +113,35 @@ socklen_t /* 4.6 doesn't have socklen_t */ uint32_t #endif - size_adr = sizeof(srv->sin); + size_adr = sizeof(srv->sin); int acp_sock; - acp_sock = accept(des_socket,&srv->sa,&size_adr); + acp_sock = accept(des_socket,&srv->sa,&size_adr); - if (acp_sock<0) { - perror("telnetd:accept"); - goto bailout; - }; + if (acp_sock<0) { + perror("telnetd:accept"); + goto bailout; + }; - if ( !(rval=telnet_get_pty(acp_sock)) ) { - syslog( LOG_DAEMON | LOG_ERR, "telnetd: unable to obtain PTY"); - /* NOTE: failing 'do_get_pty()' closed the socket */ - goto bailout; - } + if ( !(rval=telnet_get_pty(acp_sock)) ) { + syslog( LOG_DAEMON | LOG_ERR, "telnetd: unable to obtain PTY"); + /* NOTE: failing 'do_get_pty()' closed the socket */ + goto bailout; + } - if (sockpeername(acp_sock, peername, sz)) - strncpy(peername, "", sz); + if (sockpeername(acp_sock, peername, sz)) + strncpy(peername, "", sz); #ifdef PARANOIA - syslog(LOG_DAEMON | LOG_INFO, - "telnetd: accepted connection from %s on %s", - peername, - rval); + syslog(LOG_DAEMON | LOG_INFO, + "telnetd: accepted connection from %s on %s", + peername, + rval); #endif bailout: - return rval; + return rval; } @@ -149,14 +149,14 @@ static void release_a_Connection(char *devname, char *peername, FILE **pstd, int { #ifdef PARANOIA - syslog( LOG_DAEMON | LOG_INFO, - "telnetd: releasing connection from %s on %s", - peername, - devname ); + syslog( LOG_DAEMON | LOG_INFO, + "telnetd: releasing connection from %s on %s", + peername, + devname ); #endif - while (--n>=0) - if (pstd[n]) fclose(pstd[n]); + while (--n>=0) + if (pstd[n]) fclose(pstd[n]); } @@ -169,17 +169,17 @@ socklen_t /* 4.6 doesn't have socklen_t */ uint32_t #endif - len = sizeof(peer.sin); + len = sizeof(peer.sin); int rval = sock < 0; - if ( !rval) - rval = getpeername(sock, &peer.sa, &len); + if ( !rval) + rval = getpeername(sock, &peer.sa, &len); - if ( !rval ) - rval = !inet_ntop( AF_INET, &peer.sin.sin_addr, buf, bufsz ); + if ( !rval ) + rval = !inet_ntop( AF_INET, &peer.sin.sin_addr, buf, bufsz ); - return rval; + return rval; } #if 1 @@ -205,136 +205,144 @@ int i=1; int size_adr; struct shell_args *arg; - if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) { - perror("telnetd:socket"); - telnetd_task_id=0; - rtems_task_delete(RTEMS_SELF); - }; - setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i)); - - memset(&srv,0,sizeof(srv)); - srv.sin.sin_family=AF_INET; - srv.sin.sin_port=htons(23); - size_adr=sizeof(srv.sin); - if ((bind(des_socket,&srv.sa,size_adr))<0) { - perror("telnetd:bind"); - close(des_socket); - telnetd_task_id=0; - rtems_task_delete(RTEMS_SELF); - }; - if ((listen(des_socket,5))<0) { - perror("telnetd:listen"); - close(des_socket); - telnetd_task_id=0; - rtems_task_delete(RTEMS_SELF); - }; - - /* we don't redirect stdio as this probably - * was started from the console anyways.. - */ - do { - devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); - - if ( !devname ) { - /* if something went wrong, sleep for some time */ - sleep(10); - continue; - } - if ( telnetd_dont_spawn ) { - if ( 0 == check_passwd(peername) ) - telnetd_shell(devname, telnetd_shell_arg); - } else { - arg = malloc( sizeof(*arg) ); - - arg->devname = devname; - arg->arg = telnetd_shell_arg; - strncpy(arg->peername, peername, sizeof(arg->peername)); - - if ( !telnetd_spawn_task(&devname[5], telnetd_task_priority, telnetd_stack_size, spawned_shell, arg) ) { - - FILE *dummy; - - if ( telnetd_spawn_task != telnetd_dflt_spawn ) { - fprintf(stderr,"Telnetd: Unable to spawn child task\n"); - } - - /* hmm - the pty driver slot can only be - * released by opening and subsequently - * closing the PTY - this also closes - * the underlying socket. So we mock up - * a stream... - */ - - if ( !(dummy=fopen(devname,"r+")) ) - perror("Unable to dummy open the pty, losing a slot :-("); - release_a_Connection(devname, peername, &dummy, 1); - free(arg); - sleep(2); /* don't accept connections too fast */ + if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) { + perror("telnetd:socket"); + telnetd_task_id=0; + rtems_task_delete(RTEMS_SELF); + }; + setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i)); + + memset(&srv,0,sizeof(srv)); + srv.sin.sin_family=AF_INET; + srv.sin.sin_port=htons(23); + size_adr=sizeof(srv.sin); + if ((bind(des_socket,&srv.sa,size_adr))<0) { + perror("telnetd:bind"); + close(des_socket); + telnetd_task_id=0; + rtems_task_delete(RTEMS_SELF); + }; + if ((listen(des_socket,5))<0) { + perror("telnetd:listen"); + close(des_socket); + telnetd_task_id=0; + rtems_task_delete(RTEMS_SELF); + }; + + /* we don't redirect stdio as this probably + * was started from the console anyways.. + */ + do { + devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); + + if ( !devname ) { + /* if something went wrong, sleep for some time */ + sleep(10); + continue; + } + if ( telnetd_dont_spawn ) { + if ( 0 == check_passwd(peername) ) + telnetd_shell(devname, telnetd_shell_arg); + } else { + arg = malloc( sizeof(*arg) ); + + arg->devname = devname; + arg->arg = telnetd_shell_arg; + strncpy(arg->peername, peername, sizeof(arg->peername)); + + if ( !telnetd_spawn_task(&devname[5], telnetd_task_priority, telnetd_stack_size, spawned_shell, arg) ) { + + FILE *dummy; + + if ( telnetd_spawn_task != telnetd_dflt_spawn ) { + fprintf(stderr,"Telnetd: Unable to spawn child task\n"); + } + + /* hmm - the pty driver slot can only be + * released by opening and subsequently + * closing the PTY - this also closes + * the underlying socket. So we mock up + * a stream... + */ + + if ( !(dummy=fopen(devname,"r+")) ) + perror("Unable to dummy open the pty, losing a slot :-("); + release_a_Connection(devname, peername, &dummy, 1); + free(arg); + sleep(2); /* don't accept connections too fast */ } - } - } while(1); - /* TODO: how to free the connection semaphore? But then - - * stopping the daemon is probably only needed during - * development/debugging. - * Finalizer code should collect all the connection semaphore - * counts and eventually clean up... - */ - close(des_socket); - telnetd_task_id=0; + } + } while(1); + /* TODO: how to free the connection semaphore? But then - + * stopping the daemon is probably only needed during + * development/debugging. + * Finalizer code should collect all the connection semaphore + * counts and eventually clean up... + */ + close(des_socket); + telnetd_task_id=0; } /***********************************************************/ static int initialize_telnetd(void) { - - if (telnetd_task_id ) return RTEMS_RESOURCE_IN_USE; - if (telnetd_stack_size<=0 ) telnetd_stack_size =32000; - - if ( !telnetd_spawn_task("TNTD", telnetd_task_priority, RTEMS_MINIMUM_STACK_SIZE, rtems_task_telnetd, 0) ) { - return -1; - } - return 0; + + if (telnetd_task_id ) return RTEMS_RESOURCE_IN_USE; + if (telnetd_stack_size<=0 ) telnetd_stack_size =32000; + + if ( !telnetd_spawn_task("TNTD", telnetd_task_priority, RTEMS_MINIMUM_STACK_SIZE, rtems_task_telnetd, 0) ) { + return -1; + } + return 0; } /***********************************************************/ -int startTelnetd(void (*cmd)(char *, void *), void *arg, int dontSpawn, int stack, int priority) +int rtems_telnetd_initialize( + void (*cmd)(char *, void *), + void *arg, + int dontSpawn, + size_t stack, + rtems_task_priority priority +) { - rtems_status_code sc; - - printf("This is rtems-telnetd (modified by Till Straumann)\n"); - printf("$Id$\n"); - printf("Release $Name$\n"); - - if ( !telnetd_shell && !cmd ) { - fprintf(stderr,"startTelnetd(): setup error - NO SHELL; bailing out\n"); - return 1; - } - - if (telnetd_task_id) { - fprintf(stderr,"ERROR:telnetd already started\n"); - return 1; - }; - - if ( !telnet_pty_initialize() ) { - fprintf(stderr,"PTY driver probably not properly registered\n"); - return 1; - } - - if (cmd) - telnetd_shell = cmd; - telnetd_shell_arg = arg; - telnetd_stack_size = stack; - if ( !priority ) { - priority = rtems_bsdnet_config.network_task_priority; - } - if ( priority < 2 ) - priority=100; - telnetd_task_priority = priority; - telnetd_dont_spawn = dontSpawn; - - sc=initialize_telnetd(); + rtems_status_code sc; + +#if 0 + printf("This is rtems-telnetd (modified by Till Straumann)\n"); + printf("$Id$\n"); + printf("Release $Name$\n"); +#endif + + if ( !telnetd_shell && !cmd ) { + fprintf(stderr,"startTelnetd(): setup error - NO SHELL; bailing out\n"); + return 1; + } + + if (telnetd_task_id) { + fprintf(stderr,"ERROR:telnetd already started\n"); + return 1; + }; + + if ( !telnet_pty_initialize() ) { + fprintf(stderr,"PTY driver probably not properly registered\n"); + return 1; + } + + if (cmd) + telnetd_shell = cmd; + telnetd_shell_arg = arg; + telnetd_stack_size = stack; + if ( !priority ) { + priority = rtems_bsdnet_config.network_task_priority; + } + if ( priority < 2 ) + priority=100; + telnetd_task_priority = priority; + telnetd_dont_spawn = dontSpawn; + + sc=initialize_telnetd(); if (sc!=RTEMS_SUCCESSFUL) return sc; - printf("rtems_telnetd() started with stacksize=%u,priority=%d\n", + printf("rtems_telnetd() started with stacksize=%u,priority=%d\n", (unsigned)telnetd_stack_size,(int)telnetd_task_priority); - return 0; + return 0; } /* utility wrapper */ @@ -347,32 +355,32 @@ FILE *ostd[3]={ stdin, stdout, stderr }; int i=0; struct shell_args *arg = targ; - sc=rtems_libio_set_private_env(); + sc=rtems_libio_set_private_env(); - /* newlib hack/workaround. Before we change stdin/out/err we must make + /* newlib hack/workaround. Before we change stdin/out/err we must make * sure the internal data are initialized (fileno(stdout) has this sideeffect). - * This should probably be done from RTEMS' libc support layer... - * (T.S., newlibc-1.13; 2005/10) + * This should probably be done from RTEMS' libc support layer... + * (T.S., newlibc-1.13; 2005/10) */ - fileno(stdout); + fileno(stdout); - if (RTEMS_SUCCESSFUL != sc) { - rtems_error(sc,"rtems_libio_set_private_env"); - goto cleanup; - } + if (RTEMS_SUCCESSFUL != sc) { + rtems_error(sc,"rtems_libio_set_private_env"); + goto cleanup; + } - /* redirect stdio */ - for (i=0; i<3; i++) { - if ( !(nstd[i]=fopen(arg->devname,"r+")) ) { - perror("unable to open stdio"); - goto cleanup; - } - } + /* redirect stdio */ + for (i=0; i<3; i++) { + if ( !(nstd[i]=fopen(arg->devname,"r+")) ) { + perror("unable to open stdio"); + goto cleanup; + } + } - stdin = nstd[0]; - stdout = nstd[1]; - stderr = nstd[2]; + stdin = nstd[0]; + stdout = nstd[1]; + stderr = nstd[2]; @@ -382,22 +390,22 @@ printf("hello\n"); write(fileno(stdout),"hellofd\n",8); #endif - /* call their routine */ - if ( 0 == check_passwd(arg->peername) ) - telnetd_shell(arg->devname, arg->arg); + /* call their routine */ + if ( 0 == check_passwd(arg->peername) ) + telnetd_shell(arg->devname, arg->arg); - stdin = ostd[0]; - stdout = ostd[1]; - stderr = ostd[2]; + stdin = ostd[0]; + stdout = ostd[1]; + stderr = ostd[2]; cleanup: - release_a_Connection(arg->devname, arg->peername, nstd, i); - free(arg); + release_a_Connection(arg->devname, arg->peername, nstd, i); + free(arg); } struct wrap_delete_args { - void (*t)(void *); - void *a; + void (*t)(void *); + void *a; }; static rtems_task @@ -407,12 +415,12 @@ struct wrap_delete_args *pwa = (struct wrap_delete_args *)arg; register void (*t)(void *) = pwa->t; register void *a = pwa->a; - /* free argument before calling function (which may never return if - * they choose to delete themselves) - */ - free(pwa); - t(a); - rtems_task_delete(RTEMS_SELF); + /* free argument before calling function (which may never return if + * they choose to delete themselves) + */ + free(pwa); + t(a); + rtems_task_delete(RTEMS_SELF); } void * @@ -423,32 +431,32 @@ rtems_id task_id; char nm[4] = {'X','X','X','X' }; struct wrap_delete_args *pwa = malloc(sizeof(*pwa)); - strncpy(nm, name, 4); - - if ( !pwa ) { - perror("Telnetd: no memory\n"); - return 0; - } - - pwa->t = fn; - pwa->a = fnarg; - - if ((sc=rtems_task_create( - rtems_build_name(nm[0], nm[1], nm[2], nm[3]), - (rtems_task_priority)priority, - stackSize, - RTEMS_DEFAULT_MODES, - RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, - &task_id)) || - (sc=rtems_task_start( - task_id, - wrap_delete, - (rtems_task_argument)pwa))) { - free(pwa); - rtems_error(sc,"Telnetd: spawning task failed"); - return 0; - } - return (void*)task_id; + strncpy(nm, name, 4); + + if ( !pwa ) { + perror("Telnetd: no memory\n"); + return 0; + } + + pwa->t = fn; + pwa->a = fnarg; + + if ((sc=rtems_task_create( + rtems_build_name(nm[0], nm[1], nm[2], nm[3]), + (rtems_task_priority)priority, + stackSize, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, + &task_id)) || + (sc=rtems_task_start( + task_id, + wrap_delete, + (rtems_task_argument)pwa))) { + free(pwa); + rtems_error(sc,"Telnetd: spawning task failed"); + return 0; + } + return (void*)task_id; } /* convenience routines for CEXP (retrieve stdio descriptors diff --git a/cpukit/telnetd/telnetd.h b/cpukit/telnetd/telnetd.h index c8c068c9fb..2605bb6093 100644 --- a/cpukit/telnetd/telnetd.h +++ b/cpukit/telnetd/telnetd.h @@ -1,17 +1,15 @@ /* * (A first version for telnetd) * - * Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es) + * Original Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es) * May 2001 * + * Reworked by Till Straumann and .h overhauled by Joel Sherrill. + * * This program 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. * - * rtems_initialize_telnetd() starts the daemon. - * main_telnetd() is the main_proc for the command telnetd in the shell - * register_telnetd() add a new command in the shell to start - * interactively the telnetd daemon. * * $Id$ */ @@ -23,14 +21,23 @@ extern "C" { #endif -extern int rtems_telnetd_initialize(void); -extern int rtems_telnetd_main(int argc,char * argv[]); -extern int rtems_telnetd_register(void); - -/* OBSOLETE */ -#define rtems_initialize_telnetd rtems_telnetd_initialize -#define main_telnetd rtems_telnetd_main -#define register_telnetd rtems_telnetd_register +/* + * Initialize the telnetd subsystem. + * + * cmd - function which is the "shell" telnetd invokes + * arg - context pointer to cmd + * dontSpawn - TRUE if telnetd takes over this task. + * FALSE to create another task for the shell. + * stack - stack size of spawned task + * priority - initial priority of spawned task + */ +int rtems_telnetd_initialize( + void (*cmd)(char *, void *), + void *arg, + int dontSpawn, + size_t stack, + rtems_task_priority priority +); #ifdef __cplusplus } -- cgit v1.2.3