summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2009-03-27 13:45:31 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2009-03-27 13:45:31 +0000
commit8a775c27fc62ddb08f7705e20de34b55434dfdb1 (patch)
tree53c42ea9c99c5ff07a75166e3d23fc801a3fb7b0
parent * libmisc/shell/shell.h: Pointer to (diff)
downloadrtems-8a775c27fc62ddb08f7705e20de34b55434dfdb1.tar.bz2
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.
-rw-r--r--cpukit/ChangeLog12
-rw-r--r--cpukit/Makefile.am3
-rw-r--r--cpukit/libcsupport/src/libio_sockets.c2
-rw-r--r--cpukit/libmisc/Makefile.am2
-rw-r--r--cpukit/libmisc/shell/shell.c185
-rw-r--r--cpukit/libmisc/shell/shell.h44
-rw-r--r--cpukit/libmisc/stackchk/check.c56
-rw-r--r--cpukit/libnetworking/rtems/ftpfs.h9
-rw-r--r--cpukit/preinstall.am4
-rw-r--r--cpukit/telnetd/check_passwd.c198
-rw-r--r--cpukit/telnetd/telnetd.c238
-rw-r--r--cpukit/telnetd/telnetd.h120
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 <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>
* 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 <errno.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'),
.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 (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
* 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;
int c;
time_t t;
@@ -584,41 +522,12 @@ int rtems_shell_login(FILE * in,FILE * out) {
}
}
- times=0;
- strcpy(name,"");
- strcpy(pass,"");
- for (;;) {
- times++;
- 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;
+ 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 <termios.h>
#include <rtems/fs.h>
#include <rtems/libio.h>
+#include <rtems/login.h>
#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
+ * <tt>/FTP/user:pw@@host/dir/file.txt</tt>.
*
* If the server is the default server specified in BOOTP, it can be ommitted:
- *
- * @c /FTP/user:pw/dir/file.txt
+ * <tt>/FTP/user:pw/dir/file.txt</tt>.
*
* The user name will be used for the password if it is ommitted:
- *
- * @c /FTP/user@host/dir/file.txt
+ * <tt>/FTP/user@@host/dir/file.txt</tt>.
*
* 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 <strauman@slac.stanford.edu>, 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
+ * <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 <errno.h>
#include <stdio.h>
@@ -61,140 +66,41 @@
#include <string.h>
#include <syslog.h>
-#include "passwd.h"
+#include <rtems/telnetd.h>
-/* rtems has global filedescriptors but per-thread stdio streams... */
-#define STDI_FD fileno(stdin)
-#define MAXPASSRETRY 3
-
-extern char *__des_crypt_r(char *, char*, char*, int);
+#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 : "<UNKNOWN>");
- }
-
-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 <strauman@slac.stanford.edu>
@@ -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
+ * <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.
+ *
+ * $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
+ * <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
#define _RTEMS_TELNETD_H
+#include <rtems.h>
+#include <rtems/login.h>
+
#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