* 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.
This commit is contained in:
Joel Sherrill
2009-03-27 13:45:31 +00:00
parent 8916bdc71b
commit 8a775c27fc
12 changed files with 392 additions and 477 deletions

View File

@@ -1,3 +1,15 @@
2009-03-27 Sebastian Huber <sebastian.huber@embedded-brains.de>
* 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 <sebastian.huber@embedded-brains.de> 2009-03-26 Sebastian Huber <sebastian.huber@embedded-brains.de>
* libmisc/shell/shell.h: Pointer to * libmisc/shell/shell.h: Pointer to

View File

@@ -125,7 +125,8 @@ include_rtems_HEADERS += libmisc/mw-fb/mw_fb.h libmisc/mw-fb/mw_uid.h
## shell ## shell
if LIBSHELL 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 endif
## i2c ## i2c

View File

@@ -70,6 +70,6 @@ int rtems_bsdnet_makeFdForSocket(
iop->flags |= LIBIO_FLAGS_WRITE | LIBIO_FLAGS_READ; iop->flags |= LIBIO_FLAGS_WRITE | LIBIO_FLAGS_READ;
iop->data0 = fd; iop->data0 = fd;
iop->data1 = so; iop->data1 = so;
iop->handlers = (rtems_filesystem_file_handlers_r *) h; iop->handlers = h;
return fd; return fd;
} }

View File

@@ -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/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/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/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 if LIBNETWORKING
libshell_a_SOURCES += shell/main_mount_ftp.c shell/main_mount_tftp.c \ 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 \ shell/main_ifconfig.c shell/main_route.c shell/main_netstats.c \

View File

@@ -40,7 +40,7 @@
#include <errno.h> #include <errno.h>
#include <pwd.h> #include <pwd.h>
rtems_shell_env_t rtems_global_shell_env = { rtems_shell_env_t rtems_global_shell_env = {
.magic = rtems_build_name('S', 'E', 'N', 'V'), .magic = rtems_build_name('S', 'E', 'N', 'V'),
.devname = CONSOLE_DEVICE_NAME, .devname = CONSOLE_DEVICE_NAME,
.taskname = "SHGL", .taskname = "SHGL",
@@ -53,7 +53,7 @@ rtems_shell_env_t rtems_global_shell_env = {
.output = NULL, .output = NULL,
.output_append = false, .output_append = false,
.wake_on_end = RTEMS_ID_NONE, .wake_on_end = RTEMS_ID_NONE,
.login = true .login_check = NULL
}; };
rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env; rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env;
@@ -378,68 +378,6 @@ int rtems_shell_line_editor(
return -2; 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 (col<size-1) {
line[col++] = c;
if (doEcho) fputc(c,out);
} else {
if (doEcho) fputc('\a',out);
}
} else {
if (doEcho)
if (c=='\a') fputc('\a',out);
}
break;
}
}
}
/* ----------------------------------------------- * /* ----------------------------------------------- *
* - The shell TASK * - The shell TASK
* Poor but enough.. * Poor but enough..
@@ -473,7 +411,7 @@ void rtems_shell_init_issue(void)
} }
} }
int rtems_shell_login(FILE * in,FILE * out) { static bool rtems_shell_login(FILE * in,FILE * out) {
FILE *fd; FILE *fd;
int c; int c;
time_t t; time_t t;
@@ -584,41 +522,12 @@ int rtems_shell_login(FILE * in,FILE * out) {
} }
} }
times=0; return rtems_shell_login_prompt(
strcpy(name,""); in,
strcpy(pass,""); out,
for (;;) { rtems_current_shell_env->devname,
times++; rtems_current_shell_env->login_check
if (times>3) 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;
} }
#if defined(SHELL_DEBUG) #if defined(SHELL_DEBUG)
@@ -808,8 +717,8 @@ bool rtems_shell_main_loop(
* loop when the connection is dropped during login and * loop when the connection is dropped during login and
* keep on trucking. * keep on trucking.
*/ */
if (shell_env->login) { if (shell_env->login_check != NULL) {
result = rtems_shell_login(stdin,stdout) == 0; result = rtems_shell_login(stdin,stdout);
} else { } else {
result = true; result = true;
} }
@@ -944,12 +853,12 @@ static rtems_status_code rtems_shell_run (
const char *devname, const char *devname,
bool forever, bool forever,
bool wait, bool wait,
const char* input, const char *input,
const char* output, const char *output,
bool output_append, bool output_append,
rtems_id wake_on_end, rtems_id wake_on_end,
bool echo, bool echo,
bool login rtems_login_check login_check
) )
{ {
rtems_id task_id; rtems_id task_id;
@@ -991,7 +900,7 @@ static rtems_status_code rtems_shell_run (
shell_env->output = strdup (output); shell_env->output = strdup (output);
shell_env->output_append = output_append; shell_env->output_append = output_append;
shell_env->wake_on_end = wake_on_end; 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)); getcwd(shell_env->cwd, sizeof(shell_env->cwd));
@@ -1017,7 +926,7 @@ rtems_status_code rtems_shell_init(
const char *devname, const char *devname,
bool forever, bool forever,
bool wait, bool wait,
bool login rtems_login_check login_check
) )
{ {
rtems_id to_wake = RTEMS_ID_NONE; rtems_id to_wake = RTEMS_ID_NONE;
@@ -1037,7 +946,7 @@ rtems_status_code rtems_shell_init(
false, /* output_append */ false, /* output_append */
to_wake, /* wake_on_end */ to_wake, /* wake_on_end */
false, /* echo */ false, /* echo */
login /* login */ login_check /* login check */
); );
} }
@@ -1073,7 +982,7 @@ rtems_status_code rtems_shell_script (
output_append, /* output_append */ output_append, /* output_append */
current_task, /* wake_on_end */ current_task, /* wake_on_end */
echo, /* echo */ echo, /* echo */
false /* login */ NULL /* login check */
); );
if (sc != RTEMS_SUCCESSFUL) if (sc != RTEMS_SUCCESSFUL)
return sc; return sc;

View File

@@ -24,6 +24,7 @@
#include <termios.h> #include <termios.h>
#include <rtems/fs.h> #include <rtems/fs.h>
#include <rtems/libio.h> #include <rtems/libio.h>
#include <rtems/login.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -104,13 +105,6 @@ int rtems_shell_make_args(
int max_args int max_args
); );
int rtems_shell_scanline(
char *line,
int size,
FILE *in,
FILE *out
);
int rtems_shell_cat_file( int rtems_shell_cat_file(
FILE *out, FILE *out,
const char *name const char *name
@@ -135,7 +129,7 @@ int rtems_shell_script_file(
* @param task_priority The priority the shell runs at. * @param task_priority The priority the shell runs at.
* @param forever Repeat logins. * @param forever Repeat logins.
* @param wait Caller should block until shell exits. * @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( rtems_status_code rtems_shell_init(
@@ -145,7 +139,7 @@ rtems_status_code rtems_shell_init(
const char *devname, const char *devname,
bool forever, bool forever,
bool wait, 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); int rtems_shell_str2int(const char * s);
typedef struct { typedef struct {
rtems_name magic; /* 'S','E','N','V': Shell Environment */ rtems_name magic; /* 'S','E','N','V': Shell Environment */
const char *devname; const char *devname;
const char *taskname; const char *taskname;
/* user extensions */ /* user extensions */
bool exit_shell; /* logout */ bool exit_shell; /* logout */
bool forever ; /* repeat login */ bool forever; /* repeat login */
int errorlevel; int errorlevel;
bool echo; bool echo;
char cwd[256]; char cwd[256];
const char* input; const char *input;
const char* output; const char *output;
bool output_append; bool output_append;
rtems_id wake_on_end; rtems_id wake_on_end;
bool login; rtems_login_check login_check;
} rtems_shell_env_t; } rtems_shell_env_t;
bool rtems_shell_main_loop( bool rtems_shell_main_loop(

View File

@@ -205,45 +205,49 @@ void rtems_stack_checker_begin_extension(
* NOTE: The system is in a questionable state... we may not get * NOTE: The system is in a questionable state... we may not get
* the following message out. * the following message out.
*/ */
void Stack_check_report_blown_task( void Stack_check_report_blown_task(Thread_Control *running, bool pattern_ok)
Thread_Control *running,
bool pattern_ok
)
{ {
Stack_Control *stack = &running->Start.Initial_stack; 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( printk(
"BLOWN STACK!!! Offending task(0x%p): " "task name: 0x%08lx\n",
"id=0x%08" PRIx32 "; name=0x%08" PRIx32, (unsigned long) running->Object.name.name_u32
running,
running->Object.id,
running->Object.name.name_u32
); );
printk(
"task name string: %s\n",
rtems_object_get_name(running->Object.id, sizeof(name), name)
);
printk(
"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 defined(RTEMS_MULTIPROCESSING)
if (rtems_configuration_get_user_multiprocessing_table()) { if (rtems_configuration_get_user_multiprocessing_table()) {
printk( printk(
"; node=%d", "node: 0x%08lx\n",
rtems_configuration_get_user_multiprocessing_table()->node (unsigned long)
rtems_configuration_get_user_multiprocessing_table()->node
); );
} }
#endif #endif
printk( rtems_fatal_error_occurred(0x81);
"\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 );
} }
/* /*

View File

@@ -56,16 +56,13 @@ extern "C" {
* To open a file @c file.txt in the directory @c dir (relative to home * 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 * 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 user and the password @c pw you must specify the following path:
* * <tt>/FTP/user:pw@@host/dir/file.txt</tt>.
* @c /FTP/user:pw@host/dir/file.txt
* *
* If the server is the default server specified in BOOTP, it can be ommitted: * If the server is the default server specified in BOOTP, it can be ommitted:
* * <tt>/FTP/user:pw/dir/file.txt</tt>.
* @c /FTP/user:pw/dir/file.txt
* *
* The user name will be used for the password if it is ommitted: * The user name will be used for the password if it is ommitted:
* * <tt>/FTP/user@@host/dir/file.txt</tt>.
* @c /FTP/user@host/dir/file.txt
* *
* For the data transfer passive (= default) and active (= fallback) mode are * For the data transfer passive (= default) and active (= fallback) mode are
* supported. * supported.

View File

@@ -237,6 +237,10 @@ PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/shell.h
$(PROJECT_INCLUDE)/rtems/shellconfig.h: libmisc/shell/shellconfig.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(PROJECT_INCLUDE)/rtems/shellconfig.h: libmisc/shell/shellconfig.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/shellconfig.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/shellconfig.h
PREINSTALL_FILES += $(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 endif
$(PROJECT_INCLUDE)/rtems/libi2c.h: libi2c/libi2c.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(PROJECT_INCLUDE)/rtems/libi2c.h: libi2c/libi2c.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/libi2c.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/libi2c.h

View File

@@ -1,10 +1,5 @@
/* $Id$ */ /* $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 * Authorship
* ---------- * ----------
@@ -48,11 +43,21 @@
* derivative of this software. * derivative of this software.
* *
* ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
*
* Copyright (c) 2009
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>.
*
* 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 <crypt.h>
#endif
#include <termios.h> #include <termios.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -61,140 +66,41 @@
#include <string.h> #include <string.h>
#include <syslog.h> #include <syslog.h>
#include <rtems/telnetd.h>
#include "passwd.h" #include "passwd.h"
/* rtems has global filedescriptors but per-thread stdio streams... */ char *__des_crypt_r( const char *, const char *, char *, int);
#define STDI_FD fileno(stdin)
#define MAXPASSRETRY 3
extern char *__des_crypt_r(char *, char*, char*, int); /**
* @brief Standard Telnet login check that uses DES to encrypt the passphrase.
#if !defined(INSIDE_TELNETD) *
#define sockpeername(s,b,sz) (-1) * Takes a @a passphrase, encrypts it and compares it to the encrypted
#endif * passphrase in the @c TELNETD_PASSWD environment variable. No password is
* required if @c TELNETD_PASSWD is unset. The argument @a user is ignored.
#if defined(INSIDE_TELNETD) */
static bool rtems_telnetd_login_check(
#endif const char *user,
int check_passwd(char *peername) const char *passphrase
)
{ {
char *pw; char *pw = getenv( "TELNETD_PASSWD");
int rval = -1, tmp, retries; char cryptbuf [21];
struct termios t,told; char salt [3];
int restore_flags = 0;
char buf[30], cryptbuf[21];
char salt[3];
if ( !(pw=getenv("TELNETD_PASSWD")) || 0 == strlen(pw) ) if (pw == NULL || strlen( pw) == 0) {
#ifdef TELNETD_DEFAULT_PASSWD #ifdef TELNETD_DEFAULT_PASSWD
pw = TELNETD_DEFAULT_PASSWD; pw = TELNETD_DEFAULT_PASSWD;
#else #else
return 0; return true;
#endif #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 ) { strncpy( salt, pw, 2);
syslog( LOG_AUTHPRIV | LOG_WARNING, salt [2] = '\0';
"telnetd: %i wrong passwords entered from %s",
MAXPASSRETRY,
peername ? peername : "<UNKNOWN>");
}
done: return strcmp(
/* what to do if restoring the flags fails?? */ __des_crypt_r( passphrase, salt, cryptbuf, sizeof( cryptbuf)),
if (restore_flags) pw
tcsetattr(STDI_FD, TCSANOW, &told); ) == 0;
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

View File

@@ -23,11 +23,20 @@
* possible to have 'telnetd' run an arbitrary 'shell' * possible to have 'telnetd' run an arbitrary 'shell'
* program. * program.
* *
* This program is distributed in the hope that it will be useful, * Copyright (c) 2009
* but WITHOUT ANY WARRANTY; without even the implied warranty of * embedded brains GmbH
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* *
* $Id$ * Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>.
*
* 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 #ifdef HAVE_CONFIG_H
@@ -73,10 +82,7 @@ typedef union uni_sa {
static int sockpeername(int sock, char *buf, int bufsz); static int sockpeername(int sock, char *buf, int bufsz);
static int initialize_telnetd(void); void *telnetd_dflt_spawn(
static int telnetd_askForPassword;
void * telnetd_dflt_spawn(
const char *name, const char *name,
unsigned priority, unsigned priority,
unsigned stackSize, unsigned stackSize,
@@ -85,18 +91,15 @@ void * telnetd_dflt_spawn(
); );
/***********************************************************/ /***********************************************************/
rtems_id telnetd_task_id = 0; static rtems_id telnetd_task_id = RTEMS_ID_NONE;
uint32_t telnetd_stack_size = 32000;
rtems_task_priority telnetd_task_priority = 0; void *(*telnetd_spawn_task)(
bool telnetd_remain_on_caller_stdio = false;
void (*telnetd_shell)(char *, void*) = 0;
void *telnetd_shell_arg = NULL;
void * (*telnetd_spawn_task)(
const char *, const char *,
unsigned, unsigned,
unsigned, unsigned,
void (*)(void*), void (*)(void*),
void *) = telnetd_dflt_spawn; void *
) = telnetd_dflt_spawn;
static char *grab_a_Connection( static char *grab_a_Connection(
int des_socket, int des_socket,
@@ -178,14 +181,6 @@ static int sockpeername(int sock, char *buf, int bufsz)
return rval; return rval;
} }
#if 1
#define INSIDE_TELNETD
#include "check_passwd.c"
#else
#define check_passwd(arg) 0
#endif
static void static void
spawned_shell(void *arg); spawned_shell(void *arg);
@@ -203,7 +198,7 @@ rtems_task_telnetd(void *task_argument)
if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) { if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) {
perror("telnetd:socket"); perror("telnetd:socket");
telnetd_task_id=0; telnetd_task_id = RTEMS_ID_NONE;
rtems_task_delete(RTEMS_SELF); rtems_task_delete(RTEMS_SELF);
}; };
setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i)); 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) { if ((bind(des_socket,&srv.sa,size_adr))<0) {
perror("telnetd:bind"); perror("telnetd:bind");
close(des_socket); close(des_socket);
telnetd_task_id=0; telnetd_task_id = RTEMS_ID_NONE;
rtems_task_delete(RTEMS_SELF); rtems_task_delete(RTEMS_SELF);
}; };
if ((listen(des_socket,5))<0) { if ((listen(des_socket,5))<0) {
perror("telnetd:listen"); perror("telnetd:listen");
close(des_socket); close(des_socket);
telnetd_task_id=0; telnetd_task_id = RTEMS_ID_NONE;
rtems_task_delete(RTEMS_SELF); rtems_task_delete(RTEMS_SELF);
}; };
@@ -229,28 +224,51 @@ rtems_task_telnetd(void *task_argument)
* was started from the console anyways.. * was started from the console anyways..
*/ */
do { do {
if ( telnetd_remain_on_caller_stdio ) { if (rtems_telnetd_config.keep_stdio) {
char device_name[32]; bool start = true;
ttyname_r( 1, device_name, sizeof(device_name) ); char device_name [32];
if ( !telnetd_askForPassword || (0 == check_passwd(arg->peername)) )
telnetd_shell(device_name, telnetd_shell_arg); 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 { } else {
devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername));
if ( !devname ) { if ( !devname ) {
/* if something went wrong, sleep for some time */ /* if something went wrong, sleep for some time */
sleep(10); sleep(10);
continue; continue;
} }
arg = malloc( sizeof(*arg) ); arg = malloc( sizeof(*arg) );
arg->devname = devname; arg->devname = devname;
arg->arg = telnetd_shell_arg; arg->arg = rtems_telnetd_config.arg;
strncpy(arg->peername, peername, sizeof(arg->peername)); strncpy(arg->peername, peername, sizeof(arg->peername));
if ( !telnetd_spawn_task( &devname[5], telnetd_task_priority, telnetd_task_id = (rtems_id) telnetd_spawn_task(
telnetd_stack_size, spawned_shell, arg) ) { devname,
rtems_telnetd_config.priority,
rtems_telnetd_config.stack_size,
spawned_shell,
arg
);
if (telnetd_task_id == RTEMS_ID_NONE) {
FILE *dummy; FILE *dummy;
if ( telnetd_spawn_task != telnetd_dflt_spawn ) { if ( telnetd_spawn_task != telnetd_dflt_spawn ) {
@@ -280,76 +298,64 @@ rtems_task_telnetd(void *task_argument)
* counts and eventually clean up... * counts and eventually clean up...
*/ */
close(des_socket); close(des_socket);
telnetd_task_id=0; telnetd_task_id = RTEMS_ID_NONE;
} }
/***********************************************************/ rtems_status_code rtems_telnetd_initialize( void)
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;
}
/***********************************************************/
int rtems_telnetd_initialize(
void (*cmd)(char *, void *),
void *arg,
bool remainOnCallerSTDIO,
size_t stack,
rtems_task_priority priority,
bool askForPassword
)
{ {
rtems_status_code sc; rtems_status_code sc = RTEMS_SUCCESSFUL;
#if 0 if (telnetd_task_id != RTEMS_ID_NONE) {
printf("This is rtems-telnetd (modified by Till Straumann)\n"); fprintf(stderr, "telnetd already started\n");
printf("$Id$\n"); return RTEMS_RESOURCE_IN_USE;
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) { if (rtems_telnetd_config.command == NULL) {
fprintf(stderr,"ERROR:telnetd already started\n"); fprintf(stderr, "telnetd setup with invalid command\n");
return 1; return RTEMS_IO_ERROR;
}; }
if ( !telnet_pty_initialize() ) { if ( !telnet_pty_initialize() ) {
fprintf(stderr,"PTY driver probably not properly registered\n"); fprintf(stderr, "telnetd cannot initialize PTY driver\n");
return 1; return RTEMS_IO_ERROR;
} }
telnetd_askForPassword = askForPassword; /* Check priority */
if (rtems_telnetd_config.priority <= 0) {
if (cmd) rtems_telnetd_config.priority = rtems_bsdnet_config.network_task_priority;
telnetd_shell = cmd; }
telnetd_shell_arg = arg; if (rtems_telnetd_config.priority < 2) {
telnetd_stack_size = stack; rtems_telnetd_config.priority = 100;
if ( !priority ) {
priority = rtems_bsdnet_config.network_task_priority;
} }
if ( priority < 2 )
priority = 100;
telnetd_task_priority = priority;
telnetd_remain_on_caller_stdio = remainOnCallerSTDIO;
sc = initialize_telnetd(); /* Check stack size */
if (sc != RTEMS_SUCCESSFUL) return sc; if (rtems_telnetd_config.stack_size <= 0) {
rtems_telnetd_config.stack_size = 32 * 1024;
}
if ( !telnetd_remain_on_caller_stdio ) /* Spawn task */
fprintf(stderr, "rtems_telnetd() started with stacksize=%u,priority=%d\n", telnetd_task_id = (rtems_id) telnetd_spawn_task(
(unsigned)telnetd_stack_size,(int)telnetd_task_priority); "TNTD",
return 0; 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 */ /* utility wrapper */
@@ -361,6 +367,8 @@ spawned_shell(void *targ)
FILE *ostd[3]={ stdin, stdout, stderr }; FILE *ostd[3]={ stdin, stdout, stderr };
int i=0; int i=0;
struct shell_args *arg = targ; struct shell_args *arg = targ;
bool login_failed = false;
bool start = true;
sc=rtems_libio_set_private_env(); sc=rtems_libio_set_private_env();
@@ -397,13 +405,31 @@ spawned_shell(void *targ)
#endif #endif
/* call their routine */ /* call their routine */
if ( !telnetd_askForPassword || (0 == check_passwd(arg->peername)) ) if (rtems_telnetd_config.login_check != NULL) {
telnetd_shell(arg->devname, arg->arg); 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]; stdin = ostd[0];
stdout = ostd[1]; stdout = ostd[1];
stderr = ostd[2]; stderr = ostd[2];
if (login_failed) {
syslog(
LOG_AUTHPRIV | LOG_WARNING,
"telnetd: to many wrong passwords entered from %s",
arg->peername
);
}
cleanup: cleanup:
release_a_Connection(arg->devname, arg->peername, nstd, i); release_a_Connection(arg->devname, arg->peername, nstd, i);
free(arg); free(arg);
@@ -433,7 +459,7 @@ void *
telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSize, void (*fn)(void *), void* fnarg) telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSize, void (*fn)(void *), void* fnarg)
{ {
rtems_status_code sc; rtems_status_code sc;
rtems_id task_id; rtems_id task_id = RTEMS_ID_NONE;
char nm[4] = {'X','X','X','X' }; char nm[4] = {'X','X','X','X' };
struct wrap_delete_args *pwa = malloc(sizeof(*pwa)); 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 ) { if ( !pwa ) {
perror("Telnetd: no memory\n"); perror("Telnetd: no memory\n");
return 0; return (void *) RTEMS_ID_NONE;
} }
pwa->t = fn; pwa->t = fn;
@@ -460,9 +486,9 @@ telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSi
(rtems_task_argument)pwa))) { (rtems_task_argument)pwa))) {
free(pwa); free(pwa);
rtems_error(sc,"Telnetd: spawning task failed"); 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 /* convenience routines for CEXP (retrieve stdio descriptors

View File

@@ -3,47 +3,109 @@
* May 2001 * May 2001
* Reworked by Till Straumann and .h overhauled by Joel Sherrill. * Reworked by Till Straumann and .h overhauled by Joel Sherrill.
* *
* This program is distributed in the hope that it will be useful, * Copyright (c) 2009
* but WITHOUT ANY WARRANTY; without even the implied warranty of * embedded brains GmbH
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* *
* $Id$ * Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>.
*
* 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 #ifndef _RTEMS_TELNETD_H
#define _RTEMS_TELNETD_H #define _RTEMS_TELNETD_H
#include <rtems.h>
#include <rtems/login.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/** bool rtems_telnetd_login_check(
* This method initializes the telnetd subsystem. const char *user,
* const char *passphrase
* @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.
*/
int rtems_telnetd_initialize(
void (*cmd)(char *, void *),
void *arg,
bool remainOnCallerSTDIO,
size_t stack,
rtems_task_priority priority,
bool askForPassword
); );
/**
* @brief Telnet command type.
*/
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 #ifdef __cplusplus
} }
#endif #endif