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/ChangeLog | 12 ++ cpukit/Makefile.am | 3 +- cpukit/libcsupport/src/libio_sockets.c | 2 +- cpukit/libmisc/Makefile.am | 2 +- cpukit/libmisc/shell/shell.c | 185 +++++++------------------ cpukit/libmisc/shell/shell.h | 44 +++--- cpukit/libmisc/stackchk/check.c | 56 ++++---- cpukit/libnetworking/rtems/ftpfs.h | 9 +- cpukit/preinstall.am | 4 + cpukit/telnetd/check_passwd.c | 198 +++++++-------------------- cpukit/telnetd/telnetd.c | 238 ++++++++++++++++++--------------- cpukit/telnetd/telnetd.h | 120 +++++++++++++---- 12 files changed, 394 insertions(+), 479 deletions(-) diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 49666f77db..cc11a2a227 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,15 @@ +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. + 2009-03-26 Sebastian Huber * libmisc/shell/shell.h: Pointer to diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am index 8a5089f63c..910bbf0c10 100644 --- a/cpukit/Makefile.am +++ b/cpukit/Makefile.am @@ -125,7 +125,8 @@ include_rtems_HEADERS += libmisc/mw-fb/mw_fb.h libmisc/mw-fb/mw_uid.h ## shell if LIBSHELL -include_rtems_HEADERS += libmisc/shell/shell.h libmisc/shell/shellconfig.h +include_rtems_HEADERS += libmisc/shell/shell.h libmisc/shell/shellconfig.h \ + libmisc/shell/login.h endif ## i2c diff --git a/cpukit/libcsupport/src/libio_sockets.c b/cpukit/libcsupport/src/libio_sockets.c index 152ab157b3..db7562b4e9 100644 --- a/cpukit/libcsupport/src/libio_sockets.c +++ b/cpukit/libcsupport/src/libio_sockets.c @@ -70,6 +70,6 @@ int rtems_bsdnet_makeFdForSocket( iop->flags |= LIBIO_FLAGS_WRITE | LIBIO_FLAGS_READ; iop->data0 = fd; iop->data1 = so; - iop->handlers = (rtems_filesystem_file_handlers_r *) h; + iop->handlers = h; return fd; } diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am index 6bf7c40531..5063a740ce 100644 --- a/cpukit/libmisc/Makefile.am +++ b/cpukit/libmisc/Makefile.am @@ -85,7 +85,7 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \ shell/err.c shell/errx.c shell/verr.c shell/vis.c \ shell/verrx.c shell/vwarn.c shell/vwarnx.c shell/warn.c shell/warnx.c \ shell/fts.c shell/print_heapinfo.c shell/main_wkspaceinfo.c \ - shell/shell_script.c + shell/shell_script.c shell/login_prompt.c shell/login_check.c if LIBNETWORKING libshell_a_SOURCES += shell/main_mount_ftp.c shell/main_mount_tftp.c \ shell/main_ifconfig.c shell/main_route.c shell/main_netstats.c \ diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c index 8592c6aaa8..4561f3dd45 100644 --- a/cpukit/libmisc/shell/shell.c +++ b/cpukit/libmisc/shell/shell.c @@ -40,7 +40,7 @@ #include #include -rtems_shell_env_t rtems_global_shell_env = { +rtems_shell_env_t rtems_global_shell_env = { .magic = rtems_build_name('S', 'E', 'N', 'V'), .devname = CONSOLE_DEVICE_NAME, .taskname = "SHGL", @@ -53,7 +53,7 @@ rtems_shell_env_t rtems_global_shell_env = { .output = NULL, .output_append = false, .wake_on_end = RTEMS_ID_NONE, - .login = true + .login_check = NULL }; rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env; @@ -118,23 +118,23 @@ int rtems_shell_line_editor( int up; int cmd = -1; int inserting = 1; - + output = (out && isatty(fileno(in))); col = last_col = 0; - + tcdrain(fileno(in)); if (out) tcdrain(fileno(out)); if (output && prompt) fprintf(out, "\r%s", prompt); - + line[0] = 0; new_line[0] = 0; - + for (;;) { - + if (output) fflush(out); @@ -142,16 +142,16 @@ int rtems_shell_line_editor( if (extended_key == EOF) return -2; - + c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK; - + /* * Make the extended_key usable as a boolean. */ extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK; - + up = 0; - + if (extended_key) { switch (c) @@ -199,14 +199,14 @@ int rtems_shell_line_editor( /* drop through */ case RTEMS_SHELL_KEYS_DARROW: - + { int last_cmd = cmd; int clen = strlen (line); if (prompt) clen += strlen(prompt); - + if (up) { cmd++; } else { @@ -226,9 +226,9 @@ int rtems_shell_line_editor( memcpy (line, new_line, size); else memcpy (line, cmds[cmd], size); - + col = strlen (line); - + if (output) { fprintf(out,"\r%*c", clen, ' '); fprintf(out,"\r%s%s", prompt, line); @@ -271,7 +271,7 @@ int rtems_shell_line_editor( } col = 0; break; - + case 5:/*Control-e*/ if (output) fprintf(out,line + col); @@ -290,7 +290,7 @@ int rtems_shell_line_editor( line[col] = '\0'; } break; - + case 0x04:/*Control-d*/ if (strlen(line)) break; @@ -298,7 +298,7 @@ int rtems_shell_line_editor( if (output) fputc('\n', out); return -2; - + case '\f': if (output) { int end; @@ -334,7 +334,7 @@ int rtems_shell_line_editor( */ if (output) fprintf(out,"\n"); - + /* * Only process the command if we have a command and it is not * repeated in the history. @@ -378,68 +378,6 @@ int rtems_shell_line_editor( return -2; } -int rtems_shell_scanline( - char *line, - int size, - FILE *in, - FILE *out -) -{ - int c; - int col; - int doEcho; - - doEcho = (out && isatty(fileno(in))); - - col = 0; - if (*line) { - col = strlen(line); - if (doEcho) fprintf(out,"%s",line); - } - tcdrain(fileno(in)); - if (out) - tcdrain(fileno(out)); - for (;;) { - line[col] = 0; - c = fgetc(in); - switch (c) { - case EOF: - return 0; - case '\n': - case '\r': - if (doEcho) - fputc('\n',out); - return 1; - case 127: - case '\b': - if (col) { - if (doEcho) { - fputc('\b',out); - fputc(' ',out); - fputc('\b',out); - } - col--; - } else { - if (doEcho) fputc('\a',out); - } - break; - default: - if (!iscntrl(c)) { - if (col3) break; - if (out) fprintf(out,"\nlogin: "); - if (!rtems_shell_scanline(name,sizeof(name),in,out )) break; - if (out) fprintf(out,"Password: "); - if (!rtems_shell_scanline(pass,sizeof(pass),in,NULL)) break; - if (out) fprintf(out,"\n"); - if ((passwd=getpwnam(name))) { - if (strcmp(passwd->pw_passwd,"!")) { /* valid user */ - setuid(passwd->pw_uid); - setgid(passwd->pw_gid); - rtems_current_user_env->euid = - rtems_current_user_env->egid = 0; - chown(rtems_current_shell_env->devname,passwd->pw_uid,0); - rtems_current_user_env->euid = passwd->pw_uid; - rtems_current_user_env->egid = passwd->pw_gid; - if (!strcmp(passwd->pw_passwd,"*")) { - /* /etc/shadow */ - return 0; - } else { - /* crypt() */ - return 0; - } - } - } - if (out) - fprintf(out,"Login incorrect\n"); - strcpy(name,""); - strcpy(pass,""); - } - return -1; + return rtems_shell_login_prompt( + in, + out, + rtems_current_shell_env->devname, + rtems_current_shell_env->login_check + ); } #if defined(SHELL_DEBUG) @@ -686,7 +595,7 @@ bool rtems_shell_main_loop( shell_env = rtems_current_shell_env = rtems_shell_init_env( shell_env_arg ); - + /* * @todo chrisj * Remove the use of task variables. Change to have a single @@ -711,7 +620,7 @@ bool rtems_shell_main_loop( fileno(stdout); - /* fprintf( stderr, + /* fprintf( stderr, "-%s-%s-\n", shell_env->input, shell_env->output ); */ @@ -732,7 +641,7 @@ bool rtems_shell_main_loop( stdoutToClose = output; } } - + if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) { FILE *input = fopen(shell_env_arg->input, "r"); if (!input) { @@ -772,7 +681,7 @@ bool rtems_shell_main_loop( setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/ rtems_shell_initialize_command_set(); - + /* * Allocate the command line buffers. */ @@ -780,7 +689,7 @@ bool rtems_shell_main_loop( if (!cmd_argv) { fprintf(stderr, "no memory for command line buffers\n" ); } - + cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE); if (!cmds[0]) { fprintf(stderr, "no memory for command line buffers\n" ); @@ -793,7 +702,7 @@ bool rtems_shell_main_loop( for (cmd = 1; cmd < cmd_count; cmd++) { cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE; } - + do { /* Set again root user and root filesystem, side effect of set_priv..*/ sc = rtems_libio_set_private_env(); @@ -808,8 +717,8 @@ bool rtems_shell_main_loop( * loop when the connection is dropped during login and * keep on trucking. */ - if (shell_env->login) { - result = rtems_shell_login(stdin,stdout) == 0; + if (shell_env->login_check != NULL) { + result = rtems_shell_login(stdin,stdout); } else { result = true; } @@ -829,18 +738,18 @@ bool rtems_shell_main_loop( chdir(shell_env->cwd); else chdir("/"); /* XXX: chdir to getpwent homedir */ - + shell_env->exit_shell = false; for (;;) { int cmd; - + /* Prompt section */ if (prompt) { rtems_shell_get_prompt(shell_env, prompt, RTEMS_SHELL_PROMPT_SIZE); } - + /* getcmd section */ cmd = rtems_shell_line_editor(cmds, cmd_count, RTEMS_SHELL_CMD_SIZE, prompt, @@ -848,7 +757,7 @@ bool rtems_shell_main_loop( if (cmd == -1) continue; /* empty line */ - + if (cmd == -2) break; /*EOF*/ @@ -856,7 +765,7 @@ bool rtems_shell_main_loop( if (shell_env->echo) fprintf(stdout, "%d: %s\n", line, cmds[cmd]); - + /* evaluate cmd section */ c = cmds[cmd]; while (*c) { @@ -944,12 +853,12 @@ static rtems_status_code rtems_shell_run ( const char *devname, bool forever, bool wait, - const char* input, - const char* output, + const char *input, + const char *output, bool output_append, rtems_id wake_on_end, bool echo, - bool login + rtems_login_check login_check ) { rtems_id task_id; @@ -991,7 +900,7 @@ static rtems_status_code rtems_shell_run ( shell_env->output = strdup (output); shell_env->output_append = output_append; shell_env->wake_on_end = wake_on_end; - shell_env->login = login; + shell_env->login_check = login_check; getcwd(shell_env->cwd, sizeof(shell_env->cwd)); @@ -1017,7 +926,7 @@ rtems_status_code rtems_shell_init( const char *devname, bool forever, bool wait, - bool login + rtems_login_check login_check ) { rtems_id to_wake = RTEMS_ID_NONE; @@ -1037,7 +946,7 @@ rtems_status_code rtems_shell_init( false, /* output_append */ to_wake, /* wake_on_end */ false, /* echo */ - login /* login */ + login_check /* login check */ ); } @@ -1060,7 +969,7 @@ rtems_status_code rtems_shell_script ( if (sc != RTEMS_SUCCESSFUL) return sc; } - + sc = rtems_shell_run( task_name, /* task_name */ task_stacksize, /* task_stacksize */ @@ -1073,7 +982,7 @@ rtems_status_code rtems_shell_script ( output_append, /* output_append */ current_task, /* wake_on_end */ echo, /* echo */ - false /* login */ + NULL /* login check */ ); if (sc != RTEMS_SUCCESSFUL) return sc; diff --git a/cpukit/libmisc/shell/shell.h b/cpukit/libmisc/shell/shell.h index 9e5baccf42..0df4cbec2b 100644 --- a/cpukit/libmisc/shell/shell.h +++ b/cpukit/libmisc/shell/shell.h @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -99,18 +100,11 @@ rtems_shell_cmd_t * rtems_shell_alias_cmd( int rtems_shell_make_args( char *commandLine, - int *argc_p, - char **argv_p, + int *argc_p, + char **argv_p, int max_args ); -int rtems_shell_scanline( - char *line, - int size, - FILE *in, - FILE *out -); - int rtems_shell_cat_file( FILE *out, const char *name @@ -135,7 +129,7 @@ int rtems_shell_script_file( * @param task_priority The priority the shell runs at. * @param forever Repeat logins. * @param wait Caller should block until shell exits. - * @param login Demand user login. + * @param login_check User login check function, NULL disables login checks. * */ rtems_status_code rtems_shell_init( @@ -145,7 +139,7 @@ rtems_status_code rtems_shell_init( const char *devname, bool forever, bool wait, - bool login + rtems_login_check login_check ); /** @@ -179,20 +173,20 @@ rtems_status_code rtems_shell_script( int rtems_shell_str2int(const char * s); typedef struct { - rtems_name magic; /* 'S','E','N','V': Shell Environment */ - const char *devname; - const char *taskname; + rtems_name magic; /* 'S','E','N','V': Shell Environment */ + const char *devname; + const char *taskname; /* user extensions */ - bool exit_shell; /* logout */ - bool forever ; /* repeat login */ - int errorlevel; - bool echo; - char cwd[256]; - const char* input; - const char* output; - bool output_append; - rtems_id wake_on_end; - bool login; + bool exit_shell; /* logout */ + bool forever; /* repeat login */ + int errorlevel; + bool echo; + char cwd[256]; + const char *input; + const char *output; + bool output_append; + rtems_id wake_on_end; + rtems_login_check login_check; } rtems_shell_env_t; bool rtems_shell_main_loop( @@ -210,7 +204,7 @@ extern rtems_shell_env_t *rtems_current_shell_env; * all possible file systems being included it would force the * networking stack into the applcation and this may not be * required. - */ + */ struct rtems_shell_filesystems_tt; typedef struct rtems_shell_filesystems_tt rtems_shell_filesystems_t; diff --git a/cpukit/libmisc/stackchk/check.c b/cpukit/libmisc/stackchk/check.c index f63adc94cc..4cca9800fc 100644 --- a/cpukit/libmisc/stackchk/check.c +++ b/cpukit/libmisc/stackchk/check.c @@ -205,45 +205,49 @@ void rtems_stack_checker_begin_extension( * NOTE: The system is in a questionable state... we may not get * the following message out. */ -void Stack_check_report_blown_task( - Thread_Control *running, - bool pattern_ok -) +void Stack_check_report_blown_task(Thread_Control *running, bool pattern_ok) { Stack_Control *stack = &running->Start.Initial_stack; + char *pattern_area = Stack_check_Get_pattern_area(stack); + char name [32]; + printk("BLOWN STACK!!!\n"); + printk("task control block: 0x%08lx\n", (unsigned long) running); + printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id); + printk( + "task name: 0x%08lx\n", + (unsigned long) running->Object.name.name_u32 + ); + printk( + "task name string: %s\n", + rtems_object_get_name(running->Object.id, sizeof(name), name) + ); printk( - "BLOWN STACK!!! Offending task(0x%p): " - "id=0x%08" PRIx32 "; name=0x%08" PRIx32, - running, - running->Object.id, - running->Object.name.name_u32 + "task stack area (%lu Bytes): 0x%08lx .. 0x%08lx\n", + (unsigned long) stack->size, + (unsigned long) stack->area, + (unsigned long) ((char *) stack->area + stack->size) ); + if (!pattern_ok) { + printk( + "damaged pattern area (%lu Bytes): 0x%08lx .. 0x%08lx\n", + (unsigned long) PATTERN_SIZE_BYTES, + (unsigned long) pattern_area, + (unsigned long) (pattern_area + PATTERN_SIZE_BYTES) + ); + } #if defined(RTEMS_MULTIPROCESSING) if (rtems_configuration_get_user_multiprocessing_table()) { printk( - "; node=%d", - rtems_configuration_get_user_multiprocessing_table()->node + "node: 0x%08lx\n", + (unsigned long) + rtems_configuration_get_user_multiprocessing_table()->node ); } #endif - printk( - "\n stack covers range 0x%p - 0x%p (%d bytes)\n", - stack->area, - stack->area + stack->size - 1, - stack->size - ); - - if ( !pattern_ok ) { - printk( - " Damaged pattern begins at 0x%08lx and is %d bytes long\n", - (unsigned long) Stack_check_Get_pattern_area(stack), - PATTERN_SIZE_BYTES); - } - - rtems_fatal_error_occurred( 0x81 ); + rtems_fatal_error_occurred(0x81); } /* diff --git a/cpukit/libnetworking/rtems/ftpfs.h b/cpukit/libnetworking/rtems/ftpfs.h index d3275ad4c1..3d48da2ca5 100644 --- a/cpukit/libnetworking/rtems/ftpfs.h +++ b/cpukit/libnetworking/rtems/ftpfs.h @@ -56,16 +56,13 @@ extern "C" { * To open a file @c file.txt in the directory @c dir (relative to home * directory of the server) on a server named @c host using the user name * @c user and the password @c pw you must specify the following path: - * - * @c /FTP/user:pw@host/dir/file.txt + * /FTP/user:pw@@host/dir/file.txt. * * If the server is the default server specified in BOOTP, it can be ommitted: - * - * @c /FTP/user:pw/dir/file.txt + * /FTP/user:pw/dir/file.txt. * * The user name will be used for the password if it is ommitted: - * - * @c /FTP/user@host/dir/file.txt + * /FTP/user@@host/dir/file.txt. * * For the data transfer passive (= default) and active (= fallback) mode are * supported. diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am index 87aa19701b..f7faebd45d 100644 --- a/cpukit/preinstall.am +++ b/cpukit/preinstall.am @@ -237,6 +237,10 @@ PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/shell.h $(PROJECT_INCLUDE)/rtems/shellconfig.h: libmisc/shell/shellconfig.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/shellconfig.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/shellconfig.h + +$(PROJECT_INCLUDE)/rtems/login.h: libmisc/shell/login.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/login.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/login.h endif $(PROJECT_INCLUDE)/rtems/libi2c.h: libi2c/libi2c.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/libi2c.h 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