From 8a775c27fc62ddb08f7705e20de34b55434dfdb1 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 27 Mar 2009 13:45:31 +0000 Subject: 2009-03-27 Sebastian Huber * Makefile.am, preinstall.am, libmisc/Makefile.am, libmisc/shell/shell.c, libmisc/shell/shell.h, telnetd/check_passwd.c, telnetd/telnetd.c, telnetd/telnetd.h: Generalized login check. * libmisc/shell/login.h, libmisc/shell/login_check.c, libmisc/shell/login_prompt.c: New files. * libmisc/stackchk/check.c: Changed format for blown stack message. * libcsupport/src/libio_sockets.c: Removed superfluous cast. * libnetworking/rtems/ftpfs.h: Documentation. --- cpukit/telnetd/check_passwd.c | 198 +++++++++-------------------------- cpukit/telnetd/telnetd.c | 238 +++++++++++++++++++++++------------------- cpukit/telnetd/telnetd.h | 120 ++++++++++++++++----- 3 files changed, 275 insertions(+), 281 deletions(-) (limited to 'cpukit/telnetd') diff --git a/cpukit/telnetd/check_passwd.c b/cpukit/telnetd/check_passwd.c index 8486058fa0..46059e8936 100644 --- a/cpukit/telnetd/check_passwd.c +++ b/cpukit/telnetd/check_passwd.c @@ -1,23 +1,18 @@ /* $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, @@ -26,18 +21,18 @@ * 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. - * + * freely use it for any purpose without restriction. + * * Maintenance of notices * ---------------------- * In the interest of clarity regarding the origin and status of this @@ -46,13 +41,23 @@ * 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 - */ + * + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * Modified by Sebastian Huber . + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ -#if !defined(INSIDE_TELNETD) && !defined(__rtems__) -#include -#endif #include #include #include @@ -61,140 +66,41 @@ #include #include -#include "passwd.h" +#include -/* 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); +#include "passwd.h" -#if !defined(INSIDE_TELNETD) -#define sockpeername(s,b,sz) (-1) -#endif +char *__des_crypt_r( const char *, const char *, char *, int); -#if defined(INSIDE_TELNETD) -static -#endif -int check_passwd(char *peername) +/** + * @brief Standard Telnet login check that uses DES to encrypt the passphrase. + * + * Takes a @a passphrase, encrypts it and compares it to the encrypted + * passphrase in the @c TELNETD_PASSWD environment variable. No password is + * required if @c TELNETD_PASSWD is unset. The argument @a user is ignored. + */ +bool rtems_telnetd_login_check( + const char *user, + const char *passphrase +) { - 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; + char *pw = getenv( "TELNETD_PASSWD"); + char cryptbuf [21]; + char salt [3]; + + if (pw == NULL || strlen( pw) == 0) { + #ifdef TELNETD_DEFAULT_PASSWD + pw = TELNETD_DEFAULT_PASSWD; + #else + return true; + #endif } - 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; + strncpy( salt, pw, 2); + salt [2] = '\0'; - /* 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; + return strcmp( + __des_crypt_r( passphrase, salt, cryptbuf, sizeof( cryptbuf)), + pw + ) == 0; } - -#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/telnetd.c b/cpukit/telnetd/telnetd.c index 7593fdca46..772b62af08 100644 --- a/cpukit/telnetd/telnetd.c +++ b/cpukit/telnetd/telnetd.c @@ -5,7 +5,7 @@ * * Author: 17,may 2001 * - * WORK: fernando.ruiz@ctv.es + * WORK: fernando.ruiz@ctv.es * HOME: correo@fernando-ruiz.com * * After start the net you can start this daemon. @@ -15,7 +15,7 @@ * * With register_telnetd() you add a new command in the shell to start * this daemon interactively. (Login in /dev/console of course) - * + * * Sorry but OOB is not still implemented. (This is the first version) * * Till Straumann @@ -23,11 +23,20 @@ * possible to have 'telnetd' run an arbitrary 'shell' * program. * - * 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. - * - * $Id$ + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * Modified by Sebastian Huber . + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ */ #ifdef HAVE_CONFIG_H @@ -73,10 +82,7 @@ typedef union uni_sa { static int sockpeername(int sock, char *buf, int bufsz); -static int initialize_telnetd(void); -static int telnetd_askForPassword; - -void * telnetd_dflt_spawn( +void *telnetd_dflt_spawn( const char *name, unsigned priority, unsigned stackSize, @@ -85,18 +91,15 @@ void * telnetd_dflt_spawn( ); /***********************************************************/ -rtems_id telnetd_task_id = 0; -uint32_t telnetd_stack_size = 32000; -rtems_task_priority telnetd_task_priority = 0; -bool telnetd_remain_on_caller_stdio = false; -void (*telnetd_shell)(char *, void*) = 0; -void *telnetd_shell_arg = NULL; -void * (*telnetd_spawn_task)( +static rtems_id telnetd_task_id = RTEMS_ID_NONE; + +void *(*telnetd_spawn_task)( const char *, unsigned, unsigned, void (*)(void*), - void *) = telnetd_dflt_spawn; + void * +) = telnetd_dflt_spawn; static char *grab_a_Connection( int des_socket, @@ -178,14 +181,6 @@ static int sockpeername(int sock, char *buf, int bufsz) return rval; } -#if 1 -#define INSIDE_TELNETD -#include "check_passwd.c" -#else -#define check_passwd(arg) 0 -#endif - - static void spawned_shell(void *arg); @@ -203,7 +198,7 @@ rtems_task_telnetd(void *task_argument) if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) { perror("telnetd:socket"); - telnetd_task_id=0; + telnetd_task_id = RTEMS_ID_NONE; rtems_task_delete(RTEMS_SELF); }; setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i)); @@ -215,13 +210,13 @@ rtems_task_telnetd(void *task_argument) if ((bind(des_socket,&srv.sa,size_adr))<0) { perror("telnetd:bind"); close(des_socket); - telnetd_task_id=0; + telnetd_task_id = RTEMS_ID_NONE; rtems_task_delete(RTEMS_SELF); }; if ((listen(des_socket,5))<0) { perror("telnetd:listen"); close(des_socket); - telnetd_task_id=0; + telnetd_task_id = RTEMS_ID_NONE; rtems_task_delete(RTEMS_SELF); }; @@ -229,28 +224,51 @@ rtems_task_telnetd(void *task_argument) * was started from the console anyways.. */ do { - if ( telnetd_remain_on_caller_stdio ) { - char device_name[32]; - ttyname_r( 1, device_name, sizeof(device_name) ); - if ( !telnetd_askForPassword || (0 == check_passwd(arg->peername)) ) - telnetd_shell(device_name, telnetd_shell_arg); + if (rtems_telnetd_config.keep_stdio) { + bool start = true; + char device_name [32]; + + ttyname_r( 1, device_name, sizeof( device_name)); + if (rtems_telnetd_config.login_check != NULL) { + start = rtems_shell_login_prompt( + stdin, + stderr, + device_name, + rtems_telnetd_config.login_check + ); + } + if (start) { + rtems_telnetd_config.command( device_name, arg->arg); + } else { + syslog( + LOG_AUTHPRIV | LOG_WARNING, + "telnetd: to many wrong passwords entered from %s", + device_name + ); + } } else { devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); if ( !devname ) { - /* if something went wrong, sleep for some time */ - sleep(10); - continue; + /* if something went wrong, sleep for some time */ + sleep(10); + continue; } arg = malloc( sizeof(*arg) ); arg->devname = devname; - arg->arg = telnetd_shell_arg; + arg->arg = rtems_telnetd_config.arg; strncpy(arg->peername, peername, sizeof(arg->peername)); - if ( !telnetd_spawn_task( &devname[5], telnetd_task_priority, - telnetd_stack_size, spawned_shell, arg) ) { + telnetd_task_id = (rtems_id) telnetd_spawn_task( + devname, + rtems_telnetd_config.priority, + rtems_telnetd_config.stack_size, + spawned_shell, + arg + ); + if (telnetd_task_id == RTEMS_ID_NONE) { FILE *dummy; if ( telnetd_spawn_task != telnetd_dflt_spawn ) { @@ -273,83 +291,71 @@ rtems_task_telnetd(void *task_argument) } } while(1); - /* TODO: how to free the connection semaphore? But then - + /* 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; + telnetd_task_id = RTEMS_ID_NONE; } -/***********************************************************/ -int rtems_telnetd_initialize( - void (*cmd)(char *, void *), - void *arg, - bool remainOnCallerSTDIO, - size_t stack, - rtems_task_priority priority, - bool askForPassword -) +rtems_status_code rtems_telnetd_initialize( void) { - rtems_status_code sc; + rtems_status_code sc = RTEMS_SUCCESSFUL; -#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 != RTEMS_ID_NONE) { + fprintf(stderr, "telnetd already started\n"); + return RTEMS_RESOURCE_IN_USE; } - if (telnetd_task_id) { - fprintf(stderr,"ERROR:telnetd already started\n"); - return 1; - }; + if (rtems_telnetd_config.command == NULL) { + fprintf(stderr, "telnetd setup with invalid command\n"); + return RTEMS_IO_ERROR; + } if ( !telnet_pty_initialize() ) { - fprintf(stderr,"PTY driver probably not properly registered\n"); - return 1; + fprintf(stderr, "telnetd cannot initialize PTY driver\n"); + return RTEMS_IO_ERROR; } - telnetd_askForPassword = askForPassword; + /* Check priority */ + if (rtems_telnetd_config.priority <= 0) { + rtems_telnetd_config.priority = rtems_bsdnet_config.network_task_priority; + } + if (rtems_telnetd_config.priority < 2) { + rtems_telnetd_config.priority = 100; + } - if (cmd) - telnetd_shell = cmd; - telnetd_shell_arg = arg; - telnetd_stack_size = stack; - if ( !priority ) { - priority = rtems_bsdnet_config.network_task_priority; + /* Check stack size */ + if (rtems_telnetd_config.stack_size <= 0) { + rtems_telnetd_config.stack_size = 32 * 1024; } - if ( priority < 2 ) - priority = 100; - telnetd_task_priority = priority; - telnetd_remain_on_caller_stdio = remainOnCallerSTDIO; - - sc = initialize_telnetd(); - if (sc != RTEMS_SUCCESSFUL) return sc; - - if ( !telnetd_remain_on_caller_stdio ) - fprintf(stderr, "rtems_telnetd() started with stacksize=%u,priority=%d\n", - (unsigned)telnetd_stack_size,(int)telnetd_task_priority); - return 0; + + /* Spawn task */ + telnetd_task_id = (rtems_id) telnetd_spawn_task( + "TNTD", + rtems_telnetd_config.priority, + RTEMS_MINIMUM_STACK_SIZE, + rtems_task_telnetd, + 0 + ); + if (telnetd_task_id == RTEMS_ID_NONE) { + return RTEMS_IO_ERROR; + } + + /* Print status */ + if (!rtems_telnetd_config.keep_stdio) { + fprintf( + stderr, + "telnetd started with stacksize = %u and priority = %d\n", + (unsigned) rtems_telnetd_config.stack_size, + (unsigned) rtems_telnetd_config.priority + ); + } + + return RTEMS_SUCCESSFUL; } /* utility wrapper */ @@ -361,6 +367,8 @@ spawned_shell(void *targ) FILE *ostd[3]={ stdin, stdout, stderr }; int i=0; struct shell_args *arg = targ; + bool login_failed = false; + bool start = true; sc=rtems_libio_set_private_env(); @@ -397,13 +405,31 @@ spawned_shell(void *targ) #endif /* call their routine */ - if ( !telnetd_askForPassword || (0 == check_passwd(arg->peername)) ) - telnetd_shell(arg->devname, arg->arg); + if (rtems_telnetd_config.login_check != NULL) { + start = rtems_shell_login_prompt( + stdin, + stderr, + arg->devname, + rtems_telnetd_config.login_check + ); + login_failed = !start; + } + if (start) { + rtems_telnetd_config.command( arg->devname, arg->arg); + } stdin = ostd[0]; stdout = ostd[1]; stderr = ostd[2]; + if (login_failed) { + syslog( + LOG_AUTHPRIV | LOG_WARNING, + "telnetd: to many wrong passwords entered from %s", + arg->peername + ); + } + cleanup: release_a_Connection(arg->devname, arg->peername, nstd, i); free(arg); @@ -433,7 +459,7 @@ void * telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSize, void (*fn)(void *), void* fnarg) { rtems_status_code sc; - rtems_id task_id; + rtems_id task_id = RTEMS_ID_NONE; char nm[4] = {'X','X','X','X' }; struct wrap_delete_args *pwa = malloc(sizeof(*pwa)); @@ -441,7 +467,7 @@ telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSi if ( !pwa ) { perror("Telnetd: no memory\n"); - return 0; + return (void *) RTEMS_ID_NONE; } pwa->t = fn; @@ -460,9 +486,9 @@ telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSi (rtems_task_argument)pwa))) { free(pwa); rtems_error(sc,"Telnetd: spawning task failed"); - return 0; + return (void *) RTEMS_ID_NONE; } - return (void*)task_id; + return (void *) task_id; } /* convenience routines for CEXP (retrieve stdio descriptors diff --git a/cpukit/telnetd/telnetd.h b/cpukit/telnetd/telnetd.h index db0ea94162..cb1ee6aa44 100644 --- a/cpukit/telnetd/telnetd.h +++ b/cpukit/telnetd/telnetd.h @@ -3,49 +3,111 @@ * 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. + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * * - * $Id$ + * Modified by Sebastian Huber . + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ */ #ifndef _RTEMS_TELNETD_H #define _RTEMS_TELNETD_H +#include +#include + #ifdef __cplusplus extern "C" { -#endif +#endif + +bool rtems_telnetd_login_check( + const char *user, + const char *passphrase +); /** - * This method initializes the telnetd subsystem. - * - * @param[in] cmd is the function which is the "shell" telnetd invokes - * @param[in] arg is the context pointer to cmd - * @param[in] remainOnCallerSTDIO is set to TRUE if telnetd takes over the - * standard in, out and error associated with task. In this case, - * it will be NOT be listening on any sockets. When this parameters - * is FALSE the telnetd will create other tasks for the shell - * which listen on sockets. - * @param[in] stack is stack size of spawned task. - * @param[in] priority is the initial priority of spawned task(s). If - * this parameter is less than 2, then the default priority of 100 is used. - * @param[in] askForPassword is set to TRUE if telnetd is to ask for a - * password. This is set to FALSE to invoke "cmd" with no password check. - * This may be OK if "cmd" includes its own check and indeed the RTEMS Shell - * uses a login with a user name and password so this is the usual case. + * @brief Telnet command type. */ -int rtems_telnetd_initialize( - void (*cmd)(char *, void *), - void *arg, - bool remainOnCallerSTDIO, - size_t stack, - rtems_task_priority priority, - bool askForPassword +typedef void (*rtems_telnetd_command)( + char * /* device name */, + void * /* arg */ ); +/** + * @brief Telnet configuration structure. + */ +typedef struct { + /** + * @brief Function invoked for each Telnet connection. + * + * The first parameter contains the device name. The second parameter + * contains the argument pointer of this configuration table. + */ + rtems_telnetd_command command; + + /** + * @brief Argument for command function. + */ + void *arg; + + /** + * @brief Task priority. + * + * If this parameter is equal to zero, then the priority of network task is + * used or 100 if this priority is less than two. + */ + rtems_task_priority priority; + + /** + * @brief Task stack size. + */ + size_t stack_size; + + /** + * @brief Login check function. + * + * Method used for login checks. Use @c NULL to disable a login check. + */ + rtems_login_check login_check; + + /** + * @brief Keep standard IO of the caller. + * + * Telnet takes over the standard input, output and error associated with + * task, if this parameter is set to @c true. In this case, it will @b not + * listen on any sockets. When this parameter is @c false, Telnet will + * create other tasks for the shell which listen on sockets. + */ + bool keep_stdio; +} rtems_telnetd_config_table; + +/** + * @brief Telnet configuration. + * + * The application must provide this configuration table. It is used by + * rtems_telnetd_initialize() to configure the Telnet subsystem. Do not modify + * the entries after the intialization since it is used internally. + */ +extern rtems_telnetd_config_table rtems_telnetd_config; + +/** + * @brief Initializes the Telnet subsystem. + * + * Uses the application provided @ref rtems_telnetd_config configuration table. + */ +rtems_status_code rtems_telnetd_initialize( void); + #ifdef __cplusplus } -#endif +#endif #endif -- cgit v1.2.3