Ticket #1389: login_v1.patch
File login_v1.patch, 41.6 KB (added by Sebastian Huber, on 03/10/09 at 11:46:15) |
---|
-
cpukit/telnetd/check_passwd.c
RCS file: /usr1/CVS/rtems/cpukit/telnetd/check_passwd.c,v retrieving revision 1.2 diff -u -r1.2 check_passwd.c
1 1 /* $Id: check_passwd.c,v 1.2 2008/10/15 17:37:15 joel Exp $ */ 2 2 3 /* Read a password, encrypt it and compare to the encrypted 4 * password in the TELNETD_PASSWD environment variable. 5 * No password is required if TELNETD_PASSWD is unset 6 */ 7 8 /* 3 /* 9 4 * Authorship 10 5 * ---------- 11 6 * This software was created by 12 7 * Till Straumann <strauman@slac.stanford.edu>, 2003-2007 13 8 * Stanford Linear Accelerator Center, Stanford University. 14 * 9 * 15 10 * Acknowledgement of sponsorship 16 11 * ------------------------------ 17 12 * This software was produced by 18 13 * the Stanford Linear Accelerator Center, Stanford University, 19 14 * under Contract DE-AC03-76SFO0515 with the Department of Energy. 20 * 15 * 21 16 * Government disclaimer of liability 22 17 * ---------------------------------- 23 18 * Neither the United States nor the United States Department of Energy, … … 26 21 * completeness, or usefulness of any data, apparatus, product, or process 27 22 * disclosed, or represents that its use would not infringe privately owned 28 23 * rights. 29 * 24 * 30 25 * Stanford disclaimer of liability 31 26 * -------------------------------- 32 27 * Stanford University makes no representations or warranties, express or 33 28 * implied, nor assumes any liability for the use of this software. 34 * 29 * 35 30 * Stanford disclaimer of copyright 36 31 * -------------------------------- 37 32 * Stanford University, owner of the copyright, hereby disclaims its 38 33 * copyright and all other rights in this software. Hence, anyone may 39 * freely use it for any purpose without restriction. 40 * 34 * freely use it for any purpose without restriction. 35 * 41 36 * Maintenance of notices 42 37 * ---------------------- 43 38 * In the interest of clarity regarding the origin and status of this … … 46 41 * or distributed by the recipient and are to be affixed to any copy of 47 42 * software made or distributed by the recipient that contains a copy or 48 43 * derivative of this software. 49 * 44 * 50 45 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 51 */ 46 * 47 * Modified by Sebastian Huber (2009). 48 */ 52 49 53 #if !defined(INSIDE_TELNETD) && !defined(__rtems__)54 #include <crypt.h>55 #endif56 50 #include <termios.h> 57 51 #include <errno.h> 58 52 #include <stdio.h> … … 61 55 #include <string.h> 62 56 #include <syslog.h> 63 57 64 #include "passwd.h"58 #include <rtems/telnetd.h> 65 59 66 /* rtems has global filedescriptors but per-thread stdio streams... */ 67 #define STDI_FD fileno(stdin) 68 #define MAXPASSRETRY 3 69 70 extern char *__des_crypt_r(char *, char*, char*, int); 71 72 #if !defined(INSIDE_TELNETD) 73 #define sockpeername(s,b,sz) (-1) 74 #endif 75 76 #if defined(INSIDE_TELNETD) 77 static 78 #endif 79 int check_passwd(char *peername) 80 { 81 char *pw; 82 int rval = -1, tmp, retries; 83 struct termios t,told; 84 int restore_flags = 0; 85 char buf[30], cryptbuf[21]; 86 char salt[3]; 87 88 if ( !(pw=getenv("TELNETD_PASSWD")) || 0 == strlen(pw) ) 89 #ifdef TELNETD_DEFAULT_PASSWD 90 pw = TELNETD_DEFAULT_PASSWD; 91 #else 92 return 0; 93 #endif 94 95 if ( tcgetattr(STDI_FD, &t) ) { 96 perror("check_passwd(): tcgetattr"); 97 goto done; 98 } 99 told = t; 100 t.c_lflag &= ~ECHO; 101 t.c_lflag &= ~ICANON; 102 t.c_cc[VTIME] = 255; 103 t.c_cc[VMIN] = 0; 104 105 strncpy(salt,pw,2); 106 salt[2]=0; 107 108 if ( tcsetattr(STDI_FD, TCSANOW, &t) ) { 109 perror("check_passwd(): tcsetattr"); 110 goto done; 111 } 112 restore_flags = 1; 113 114 /* Here we ask for the password... */ 115 for ( retries = MAXPASSRETRY; retries > 0; retries-- ) { 116 fflush(stdin); 117 fprintf(stderr,"Password:"); 118 fflush(stderr); 119 if ( 0 == fgets(buf,sizeof(buf),stdin) ) { 120 /* Here comes an ugly hack: 121 * The termios driver's 'read()' handler 122 * returns 0 to the c library's fgets if 123 * it times out. 'fgets' interprets this 124 * (correctly) as EOF, a condition we want 125 * to undo since it's not really true since 126 * we really have a read error (termios bug??) 127 * 128 * As a workaround we push something back and 129 * read it again. This should simply reset the 130 * EOF condition. 131 */ 132 if (ungetc('?',stdin) >= 0) 133 fgetc(stdin); 134 goto done; 135 } 136 fputc('\n',stderr); 137 tmp = strlen(buf); 138 while ( tmp > 0 && ('\n' == buf[tmp-1] || '\r' == buf[tmp-1]) ) { 139 buf[--tmp]=0; 140 } 141 if ( !strcmp(__des_crypt_r(buf, salt, cryptbuf, sizeof(cryptbuf)), pw) ) { 142 rval = 0; 143 break; 144 } 145 fprintf(stderr,"Incorrect Password.\n"); 146 sleep(2); 147 } 148 149 if ( 0 == retries ) { 150 syslog( LOG_AUTHPRIV | LOG_WARNING, 151 "telnetd: %i wrong passwords entered from %s", 152 MAXPASSRETRY, 153 peername ? peername : "<UNKNOWN>"); 154 } 60 #include "passwd.h" 155 61 156 done: 157 /* what to do if restoring the flags fails?? */ 158 if (restore_flags) 159 tcsetattr(STDI_FD, TCSANOW, &told); 160 161 if (rval) { 162 sleep(2); 163 } 164 return rval; 165 } 62 char *__des_crypt_r( const char *, const char *, char *, int); 166 63 167 #if !defined(INSIDE_TELNETD) && !defined(__rtems__) 168 int 169 main(int argc, char **argv) 64 /** 65 * @brief Standard Telnet login check that uses DES to encrypt the passphrase. 66 * 67 * Takes a @a passphrase, encrypts it and compares it to the encrypted 68 * passphrase in the @c TELNETD_PASSWD environment variable. No password is 69 * required if @c TELNETD_PASSWD is unset. The argument @a user is ignored. 70 */ 71 bool rtems_telnetd_login_check( 72 const char *user, 73 const char *passphrase 74 ) 170 75 { 171 char *str, *enc=0; 172 int ch; 173 174 while ( (ch=getopt(argc, argv, "g:")) > 0 ) { 175 switch (ch) { 176 default: 177 fprintf(stderr,"Unknown option\n"); 178 return(1); 179 180 case 'g': 181 printf("Generated encrypted password: '%s'\n", (enc=crypt(optarg,"td"))); 182 break; 183 184 } 76 char *pw = getenv( "TELNETD_PASSWD"); 77 char cryptbuf [21]; 78 char salt [3]; 79 80 if (pw == NULL || strlen( pw) == 0) { 81 #ifdef TELNETD_DEFAULT_PASSWD 82 pw = TELNETD_DEFAULT_PASSWD; 83 #else 84 return true; 85 #endif 86 } 87 88 strncpy( salt, pw, 2); 89 salt [2] = '\0'; 90 91 return strcmp( 92 __des_crypt_r( passphrase, salt, cryptbuf, sizeof( cryptbuf)), 93 pw 94 ) == 0; 185 95 } 186 if (argc>optind && !enc) {187 enc=argv[optind];188 }189 if (enc) {190 str = malloc(strlen(enc) + 30);191 sprintf(str,"TELNETD_PASSWD=%s",enc);192 putenv(str);193 }194 if (check_passwd(-1)) {195 fprintf(stderr,"check_passwd() failed\n");196 }197 return 0;198 }199 200 #endif -
cpukit/telnetd/telnetd.c
RCS file: /usr1/CVS/rtems/cpukit/telnetd/telnetd.c,v retrieving revision 1.13 diff -u -r1.13 telnetd.c
5 5 * 6 6 * Author: 17,may 2001 7 7 * 8 * WORK: fernando.ruiz@ctv.es 8 * WORK: fernando.ruiz@ctv.es 9 9 * HOME: correo@fernando-ruiz.com 10 10 * 11 11 * After start the net you can start this daemon. … … 15 15 * 16 16 * With register_telnetd() you add a new command in the shell to start 17 17 * this daemon interactively. (Login in /dev/console of course) 18 * 18 * 19 19 * Sorry but OOB is not still implemented. (This is the first version) 20 20 * 21 21 * Till Straumann <strauman@slac.stanford.edu> … … 23 23 * possible to have 'telnetd' run an arbitrary 'shell' 24 24 * program. 25 25 * 26 * Modified by Sebastian Huber (2009). 27 * 26 28 * This program is distributed in the hope that it will be useful, 27 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 29 * 31 * 30 32 * $Id: telnetd.c,v 1.13 2008/10/15 17:37:15 joel Exp $ 31 33 */ 32 34 … … 73 75 74 76 static int sockpeername(int sock, char *buf, int bufsz); 75 77 76 static int initialize_telnetd(void); 77 static int telnetd_askForPassword; 78 79 void * telnetd_dflt_spawn( 78 void *telnetd_dflt_spawn( 80 79 const char *name, 81 80 unsigned priority, 82 81 unsigned stackSize, … … 85 84 ); 86 85 87 86 /***********************************************************/ 88 rtems_id telnetd_task_id = 0; 89 uint32_t telnetd_stack_size = 32000; 90 rtems_task_priority telnetd_task_priority = 0; 91 bool telnetd_remain_on_caller_stdio = false; 92 void (*telnetd_shell)(char *, void*) = 0; 93 void *telnetd_shell_arg = NULL; 94 void * (*telnetd_spawn_task)( 87 static rtems_id telnetd_task_id = RTEMS_ID_NONE; 88 89 void *(*telnetd_spawn_task)( 95 90 const char *, 96 91 unsigned, 97 92 unsigned, 98 93 void (*)(void*), 99 void *) = telnetd_dflt_spawn; 94 void * 95 ) = telnetd_dflt_spawn; 100 96 101 97 static char *grab_a_Connection( 102 98 int des_socket, … … 178 174 return rval; 179 175 } 180 176 181 #if 1182 #define INSIDE_TELNETD183 #include "check_passwd.c"184 #else185 #define check_passwd(arg) 0186 #endif187 188 189 177 static void 190 178 spawned_shell(void *arg); 191 179 … … 203 191 204 192 if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) { 205 193 perror("telnetd:socket"); 206 telnetd_task_id =0;194 telnetd_task_id = RTEMS_ID_NONE; 207 195 rtems_task_delete(RTEMS_SELF); 208 196 }; 209 197 setsockopt(des_socket,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i)); … … 215 203 if ((bind(des_socket,&srv.sa,size_adr))<0) { 216 204 perror("telnetd:bind"); 217 205 close(des_socket); 218 telnetd_task_id =0;206 telnetd_task_id = RTEMS_ID_NONE; 219 207 rtems_task_delete(RTEMS_SELF); 220 208 }; 221 209 if ((listen(des_socket,5))<0) { 222 210 perror("telnetd:listen"); 223 211 close(des_socket); 224 telnetd_task_id =0;212 telnetd_task_id = RTEMS_ID_NONE; 225 213 rtems_task_delete(RTEMS_SELF); 226 214 }; 227 215 … … 229 217 * was started from the console anyways.. 230 218 */ 231 219 do { 232 if ( telnetd_remain_on_caller_stdio ) { 233 char device_name[32]; 234 ttyname_r( 1, device_name, sizeof(device_name) ); 235 if ( !telnetd_askForPassword || (0 == check_passwd(arg->peername)) ) 236 telnetd_shell(device_name, telnetd_shell_arg); 220 if (rtems_telnetd_config.keep_stdio) { 221 bool start = true; 222 char device_name [32]; 223 224 ttyname_r( 1, device_name, sizeof( device_name)); 225 if (rtems_telnetd_config.login_check != NULL) { 226 start = rtems_shell_login_prompt( 227 stdin, 228 stderr, 229 device_name, 230 rtems_telnetd_config.login_check 231 ); 232 } 233 if (start) { 234 rtems_telnetd_config.command( device_name, arg->arg); 235 } else { 236 syslog( 237 LOG_AUTHPRIV | LOG_WARNING, 238 "telnetd: to many wrong passwords entered from %s", 239 device_name 240 ); 241 } 237 242 } else { 238 243 devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); 239 244 240 245 if ( !devname ) { 241 242 243 246 /* if something went wrong, sleep for some time */ 247 sleep(10); 248 continue; 244 249 } 245 250 246 251 arg = malloc( sizeof(*arg) ); 247 252 248 253 arg->devname = devname; 249 arg->arg = telnetd_shell_arg;254 arg->arg = rtems_telnetd_config.arg; 250 255 strncpy(arg->peername, peername, sizeof(arg->peername)); 251 256 252 if ( !telnetd_spawn_task( &devname[5], telnetd_task_priority, 253 telnetd_stack_size, spawned_shell, arg) ) { 257 telnetd_task_id = (rtems_id) telnetd_spawn_task( 258 devname, 259 rtems_telnetd_config.priority, 260 rtems_telnetd_config.stack_size, 261 spawned_shell, 262 arg 263 ); 264 if (telnetd_task_id == RTEMS_ID_NONE) { 254 265 FILE *dummy; 255 266 256 267 if ( telnetd_spawn_task != telnetd_dflt_spawn ) { … … 273 284 } 274 285 } while(1); 275 286 276 /* TODO: how to free the connection semaphore? But then - 287 /* TODO: how to free the connection semaphore? But then - 277 288 * stopping the daemon is probably only needed during 278 289 * development/debugging. 279 290 * Finalizer code should collect all the connection semaphore 280 291 * counts and eventually clean up... 281 292 */ 282 293 close(des_socket); 283 telnetd_task_id =0;294 telnetd_task_id = RTEMS_ID_NONE; 284 295 } 285 296 286 /***********************************************************/ 287 static int initialize_telnetd(void) { 288 289 if (telnetd_task_id ) return RTEMS_RESOURCE_IN_USE; 290 if (telnetd_stack_size<=0 ) telnetd_stack_size =32000; 291 292 if ( !telnetd_spawn_task("TNTD", telnetd_task_priority, 293 RTEMS_MINIMUM_STACK_SIZE, rtems_task_telnetd, 0) ) { 294 return -1; 297 rtems_status_code rtems_telnetd_initialize( void) 298 { 299 rtems_status_code sc = RTEMS_SUCCESSFUL; 300 301 if (telnetd_task_id != RTEMS_ID_NONE) { 302 fprintf(stderr, "telnetd already started\n"); 303 return RTEMS_RESOURCE_IN_USE; 295 304 } 296 return 0;297 }298 305 299 /***********************************************************/ 300 int rtems_telnetd_initialize( 301 void (*cmd)(char *, void *), 302 void *arg, 303 bool remainOnCallerSTDIO, 304 size_t stack, 305 rtems_task_priority priority, 306 bool askForPassword 307 ) 308 { 309 rtems_status_code sc; 306 if (rtems_telnetd_config.command == NULL) { 307 fprintf(stderr, "telnetd setup with invalid command\n"); 308 return RTEMS_IO_ERROR; 309 } 310 310 311 #if 0 312 printf("This is rtems-telnetd (modified by Till Straumann)\n"); 313 printf("$Id: telnetd.c,v 1.13 2008/10/15 17:37:15 joel Exp $\n"); 314 printf("Release $Name: $\n"); 315 #endif 311 if ( !telnet_pty_initialize() ) { 312 fprintf(stderr, "telnetd cannot initialize PTY driver\n"); 313 return RTEMS_IO_ERROR; 314 } 316 315 317 if ( !telnetd_shell && !cmd ) { 318 fprintf(stderr,"startTelnetd(): setup error - NO SHELL; bailing out\n"); 319 return 1; 316 /* Check priority */ 317 if (rtems_telnetd_config.priority <= 0) { 318 rtems_telnetd_config.priority = rtems_bsdnet_config.network_task_priority; 319 } 320 if (rtems_telnetd_config.priority < 2) { 321 rtems_telnetd_config.priority = 100; 320 322 } 321 323 322 if (telnetd_task_id) {323 fprintf(stderr,"ERROR:telnetd already started\n");324 r eturn 1;325 } ;324 /* Check stack size */ 325 if (rtems_telnetd_config.stack_size <= 0) { 326 rtems_telnetd_config.stack_size = 32 * 1024; 327 } 326 328 327 if ( !telnet_pty_initialize() ) { 328 fprintf(stderr,"PTY driver probably not properly registered\n"); 329 return 1; 329 /* Spawn task */ 330 telnetd_task_id = (rtems_id) telnetd_spawn_task( 331 "TNTD", 332 rtems_telnetd_config.priority, 333 RTEMS_MINIMUM_STACK_SIZE, 334 rtems_task_telnetd, 335 0 336 ); 337 if (telnetd_task_id == RTEMS_ID_NONE) { 338 return RTEMS_IO_ERROR; 330 339 } 331 340 332 telnetd_askForPassword = askForPassword; 341 /* Print status */ 342 if (!rtems_telnetd_config.keep_stdio) { 343 fprintf( 344 stderr, 345 "telnetd started with stacksize = %u and priority = %d\n", 346 (unsigned) rtems_telnetd_config.stack_size, 347 (unsigned) rtems_telnetd_config.priority 348 ); 349 } 333 350 334 if (cmd) 335 telnetd_shell = cmd; 336 telnetd_shell_arg = arg; 337 telnetd_stack_size = stack; 338 if ( !priority ) { 339 priority = rtems_bsdnet_config.network_task_priority; 340 } 341 if ( priority < 2 ) 342 priority = 100; 343 telnetd_task_priority = priority; 344 telnetd_remain_on_caller_stdio = remainOnCallerSTDIO; 345 346 sc = initialize_telnetd(); 347 if (sc != RTEMS_SUCCESSFUL) return sc; 348 349 if ( !telnetd_remain_on_caller_stdio ) 350 fprintf(stderr, "rtems_telnetd() started with stacksize=%u,priority=%d\n", 351 (unsigned)telnetd_stack_size,(int)telnetd_task_priority); 352 return 0; 351 return RTEMS_SUCCESSFUL; 353 352 } 354 353 355 354 /* utility wrapper */ … … 361 360 FILE *ostd[3]={ stdin, stdout, stderr }; 362 361 int i=0; 363 362 struct shell_args *arg = targ; 363 bool login_failed = false; 364 bool start = true; 364 365 365 366 sc=rtems_libio_set_private_env(); 366 367 … … 397 398 #endif 398 399 399 400 /* call their routine */ 400 if ( !telnetd_askForPassword || (0 == check_passwd(arg->peername)) ) 401 telnetd_shell(arg->devname, arg->arg); 401 if (rtems_telnetd_config.login_check != NULL) { 402 start = rtems_shell_login_prompt( 403 stdin, 404 stderr, 405 arg->devname, 406 rtems_telnetd_config.login_check 407 ); 408 login_failed = !start; 409 } 410 if (start) { 411 rtems_telnetd_config.command( arg->devname, arg->arg); 412 } 402 413 403 414 stdin = ostd[0]; 404 415 stdout = ostd[1]; 405 416 stderr = ostd[2]; 406 417 418 if (login_failed) { 419 syslog( 420 LOG_AUTHPRIV | LOG_WARNING, 421 "telnetd: to many wrong passwords entered from %s", 422 arg->peername 423 ); 424 } 425 407 426 cleanup: 408 427 release_a_Connection(arg->devname, arg->peername, nstd, i); 409 428 free(arg); … … 433 452 telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSize, void (*fn)(void *), void* fnarg) 434 453 { 435 454 rtems_status_code sc; 436 rtems_id task_id ;455 rtems_id task_id = RTEMS_ID_NONE; 437 456 char nm[4] = {'X','X','X','X' }; 438 457 struct wrap_delete_args *pwa = malloc(sizeof(*pwa)); 439 458 … … 441 460 442 461 if ( !pwa ) { 443 462 perror("Telnetd: no memory\n"); 444 return 0;463 return (void *) RTEMS_ID_NONE; 445 464 } 446 465 447 466 pwa->t = fn; … … 460 479 (rtems_task_argument)pwa))) { 461 480 free(pwa); 462 481 rtems_error(sc,"Telnetd: spawning task failed"); 463 return 0;482 return (void *) RTEMS_ID_NONE; 464 483 } 465 return (void *)task_id;484 return (void *) task_id; 466 485 } 467 486 468 487 /* convenience routines for CEXP (retrieve stdio descriptors -
cpukit/telnetd/telnetd.h
RCS file: /usr1/CVS/rtems/cpukit/telnetd/telnetd.h,v retrieving revision 1.8 diff -u -r1.8 telnetd.h
3 3 * May 2001 4 4 * Reworked by Till Straumann and .h overhauled by Joel Sherrill. 5 5 * 6 * Modified by Sebastian Huber (2009). 7 * 6 8 * This program is distributed in the hope that it will be useful, 7 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. … … 13 15 #ifndef _RTEMS_TELNETD_H 14 16 #define _RTEMS_TELNETD_H 15 17 18 #include <rtems.h> 19 #include <rtems/login.h> 20 16 21 #ifdef __cplusplus 17 22 extern "C" { 18 #endif 23 #endif 24 25 bool rtems_telnetd_login_check( 26 const char *user, 27 const char *passphrase 28 ); 29 30 /** 31 * @brief Telnet command type. 32 */ 33 typedef void (*rtems_telnetd_command)(char * /* device name */, void * /* arg */); 34 35 /** 36 * @brief Telnet configuration structure. 37 */ 38 typedef struct { 39 /** 40 * @brief Function invoked for each Telnet connection. 41 * 42 * The first parameter contains the device name. The second parameter 43 * contains the argument pointer of this configuration table. 44 */ 45 rtems_telnetd_command command; 46 47 /** 48 * @brief Argument for command function. 49 */ 50 void *arg; 51 52 /** 53 * @brief Task priority. 54 * 55 * If this parameter is equal to zero, then the priority of network task is 56 * used or 100 if this priority is less than two. 57 */ 58 rtems_task_priority priority; 59 60 /** 61 * @brief Task stack size. 62 */ 63 size_t stack_size; 64 65 /** 66 * @brief Login check function. 67 * 68 * Method used for login checks. Use @c NULL to disable a login check. 69 */ 70 rtems_login_check login_check; 71 72 /** 73 * @brief Keep standard IO of the caller. 74 * 75 * Telnet takes over the standard input, output and error associated with 76 * task, if this parameter is set to @c true. In this case, it will @b not 77 * listen on any sockets. When this parameter is @c false, Telnet will 78 * create other tasks for the shell which listen on sockets. 79 */ 80 bool keep_stdio; 81 } rtems_telnetd_config_table; 19 82 20 83 /** 21 * This method initializes the telnetd subsystem.84 * @brief Telnet configuration. 22 85 * 23 * @param[in] cmd is the function which is the "shell" telnetd invokes 24 * @param[in] arg is the context pointer to cmd 25 * @param[in] remainOnCallerSTDIO is set to TRUE if telnetd takes over the 26 * standard in, out and error associated with task. In this case, 27 * it will be NOT be listening on any sockets. When this parameters 28 * is FALSE the telnetd will create other tasks for the shell 29 * which listen on sockets. 30 * @param[in] stack is stack size of spawned task. 31 * @param[in] priority is the initial priority of spawned task(s). If 32 * this parameter is less than 2, then the default priority of 100 is used. 33 * @param[in] askForPassword is set to TRUE if telnetd is to ask for a 34 * password. This is set to FALSE to invoke "cmd" with no password check. 35 * This may be OK if "cmd" includes its own check and indeed the RTEMS Shell 36 * uses a login with a user name and password so this is the usual case. 86 * The application must provide this configuration table. It is used by 87 * rtems_telnetd_initialize() to configure the Telnet subsystem. Do not modify 88 * the entries after the intialization since it is used internally. 37 89 */ 38 int rtems_telnetd_initialize( 39 void (*cmd)(char *, void *), 40 void *arg, 41 bool remainOnCallerSTDIO,42 size_t stack,43 rtems_task_priority priority,44 bool askForPassword45 );90 extern rtems_telnetd_config_table rtems_telnetd_config; 91 92 /** 93 * @brief Initializes the Telnet subsystem. 94 * 95 * Uses the application provided @ref rtems_telnetd_config configuration table. 96 */ 97 rtems_status_code rtems_telnetd_initialize( void); 46 98 47 99 #ifdef __cplusplus 48 100 } 49 #endif 101 #endif 50 102 51 103 #endif -
cpukit/libmisc/Makefile.am
RCS file: /usr1/CVS/rtems/cpukit/libmisc/Makefile.am,v retrieving revision 1.66 diff -u -r1.66 Makefile.am
85 85 shell/err.c shell/errx.c shell/verr.c shell/vis.c \ 86 86 shell/verrx.c shell/vwarn.c shell/vwarnx.c shell/warn.c shell/warnx.c \ 87 87 shell/fts.c shell/print_heapinfo.c shell/main_wkspaceinfo.c \ 88 shell/shell_script.c 88 shell/shell_script.c shell/login_prompt.c shell/login_check.c 89 89 if LIBNETWORKING 90 90 libshell_a_SOURCES += shell/main_mount_ftp.c shell/main_mount_tftp.c \ 91 91 shell/main_ifconfig.c shell/main_route.c shell/main_netstats.c \ -
new file cpukit/libmisc/shell/login.h
RCS file: cpukit/libmisc/shell/login.h diff -N cpukit/libmisc/shell/login.h
- + 1 /** 2 * @file 3 * 4 * @author Sebastian Huber <sebastian.huber@embedded-brains.de> 5 * 6 * @brief Login types and functions. 7 */ 8 9 /* 10 * Copyright (c) 2009 11 * Embedded Brains GmbH 12 * Obere Lagerstr. 30 13 * D-82178 Puchheim 14 * Germany 15 * rtems@embedded-brains.de 16 * 17 * Based on work from Chris Johns, Fernando Ruiz and Till Straumann. 18 * 19 * The license and distribution terms for this file may be 20 * found in the file LICENSE in this distribution or at 21 * http://www.rtems.com/license/LICENSE. 22 */ 23 24 #ifndef RTEMS_LOGIN_H 25 #define RTEMS_LOGIN_H 26 27 #include <stdio.h> 28 29 #include <rtems.h> 30 31 #ifdef __cplusplus 32 extern "C" { 33 #endif /* __cplusplus */ 34 35 typedef bool (*rtems_login_check)( 36 const char * /* user */, 37 const char * /* passphrase */ 38 ); 39 40 bool rtems_shell_login_prompt( 41 FILE *in, 42 FILE *out, 43 const char *device, 44 rtems_login_check check 45 ); 46 47 bool rtems_shell_login_check( 48 const char *user, 49 const char *passphrase 50 ); 51 52 #ifdef __cplusplus 53 } 54 #endif /* __cplusplus */ 55 56 #endif /* RTEMS_LOGIN_H */ -
new file cpukit/libmisc/shell/login_check.c
RCS file: cpukit/libmisc/shell/login_check.c diff -N cpukit/libmisc/shell/login_check.c
- + 1 /** 2 * @file 3 * 4 * @author Sebastian Huber <sebastian.huber@embedded-brains.de> 5 * 6 * @brief Shell login check function. 7 */ 8 9 /* 10 * Copyright (c) 2009 11 * Embedded Brains GmbH 12 * Obere Lagerstr. 30 13 * D-82178 Puchheim 14 * Germany 15 * rtems@embedded-brains.de 16 * 17 * Based on work from Chris Johns, Fernando Ruiz and Till Straumann. 18 * 19 * The license and distribution terms for this file may be 20 * found in the file LICENSE in this distribution or at 21 * http://www.rtems.com/license/LICENSE. 22 */ 23 24 #include <sys/types.h> 25 #include <unistd.h> 26 #include <pwd.h> 27 28 #include <rtems/login.h> 29 #include <rtems/shell.h> 30 #include <rtems/userenv.h> 31 32 bool rtems_shell_login_check( 33 const char *user, 34 const char *passphrase 35 ) 36 { 37 struct passwd *pw = getpwnam( user); 38 39 /* Valid user? */ 40 if (pw != NULL && strcmp( pw->pw_passwd, "!") != 0) { 41 setuid( pw->pw_uid); 42 setgid( pw->pw_gid); 43 rtems_current_user_env->euid = 0; 44 rtems_current_user_env->egid = 0; 45 chown( rtems_current_shell_env->devname, pw->pw_uid, 0); 46 rtems_current_user_env->euid = pw->pw_uid; 47 rtems_current_user_env->egid = pw->pw_gid; 48 if (strcmp( pw->pw_passwd, "*") == 0) { 49 /* TODO: /etc/shadow */ 50 return true; 51 } else { 52 /* TODO: crypt() */ 53 return true; 54 } 55 } 56 57 return false; 58 } -
new file cpukit/libmisc/shell/login_prompt.c
RCS file: cpukit/libmisc/shell/login_prompt.c diff -N cpukit/libmisc/shell/login_prompt.c
- + 1 /** 2 * @file 3 * 4 * @author Sebastian Huber <sebastian.huber@embedded-brains.de> 5 * 6 * @brief Shell login prompt functions. 7 */ 8 9 /* 10 * Copyright (c) 2009 11 * Embedded Brains GmbH 12 * Obere Lagerstr. 30 13 * D-82178 Puchheim 14 * Germany 15 * rtems@embedded-brains.de 16 * 17 * Based on work from Chris Johns, Fernando Ruiz and Till Straumann. 18 * 19 * The license and distribution terms for this file may be 20 * found in the file LICENSE in this distribution or at 21 * http://www.rtems.com/license/LICENSE. 22 */ 23 24 #include <stdio.h> 25 #include <termios.h> 26 #include <unistd.h> 27 #include <ctype.h> 28 29 #include <rtems/login.h> 30 31 static int rtems_shell_discard( int c, FILE *stream) 32 { 33 return c; 34 } 35 36 static void rtems_shell_get_text( 37 FILE *in, 38 FILE *out, 39 char *line, 40 size_t size 41 ) 42 { 43 int fd_in = fileno( in); 44 int (*put)( int, FILE *) = 45 out != NULL && isatty( fd_in) 46 ? fputc 47 : rtems_shell_discard; 48 size_t i = 0; 49 50 if (size < 1) { 51 return; 52 } 53 54 tcdrain( fd_in); 55 if (out != NULL){ 56 tcdrain( fileno( out)); 57 } 58 59 while (true) { 60 int c = fgetc( in); 61 62 switch (c) { 63 case EOF: 64 /* Here comes an ugly hack: The Termios driver's read() handler returns 65 * 0 to the C library's fgets() if it times out. fgets() interprets 66 * this (correctly) as EOF, a condition we want to undo since it's not 67 * really true since we really have a read error (Termios bug?). 68 * 69 * As a workaround we push something back and read it again. This 70 * should simply reset the EOF condition. 71 */ 72 if (ungetc( '?', in) == '?') { 73 fgetc( in); 74 } 75 break; 76 case '\n': 77 case '\r': 78 put( '\n', out); 79 line [i] = '\0'; 80 return; 81 case 127: 82 case '\b': 83 if (i > 0) { 84 put( '\b', out); 85 put( ' ', out); 86 put( '\b', out); 87 --i; 88 } else { 89 put( '\a', out); 90 } 91 break; 92 default: 93 if (!iscntrl( c)) { 94 if (i < size - 1) { 95 line [i] = (char) c; 96 ++i; 97 put( c, out); 98 } else { 99 put( '\a', out); 100 } 101 } else { 102 put( '\a', out); 103 } 104 break; 105 } 106 } 107 } 108 109 bool rtems_shell_login_prompt( 110 FILE *in, 111 FILE *out, 112 const char *device, 113 rtems_login_check check 114 ) 115 { 116 int fd_in = fileno( in); 117 struct termios termios_previous; 118 bool restore_termios = false; 119 int i = 0; 120 bool result = false; 121 122 if (tcgetattr( fd_in, &termios_previous) == 0) { 123 struct termios termios_new = termios_previous; 124 125 termios_new.c_lflag &= ~ECHO; 126 termios_new.c_lflag &= ~ICANON; 127 termios_new.c_cc [VTIME] = 255; 128 termios_new.c_cc [VMIN] = 0; 129 130 restore_termios = tcsetattr( fd_in, TCSANOW, &termios_new) == 0; 131 } 132 133 for (i = 0; i < 3; ++i) { 134 char user [32]; 135 char passphrase [128]; 136 137 fprintf( out, "%s login: ", device); 138 fflush( out); 139 rtems_shell_get_text( in, out, user, sizeof( user)); 140 141 fflush( in); 142 fprintf( out, "Password: "); 143 fflush( out); 144 rtems_shell_get_text( in, NULL, passphrase, sizeof( passphrase)); 145 fputc( '\n', out); 146 147 result = check( user, passphrase); 148 if (result) { 149 break; 150 } 151 152 fprintf( out, "Login incorrect\n\n"); 153 sleep( 2); 154 } 155 156 if (restore_termios) { 157 /* What to do if restoring the flags fails? */ 158 tcsetattr( fd_in, TCSANOW, &termios_previous); 159 } 160 161 return result; 162 } -
cpukit/libmisc/shell/shell.c
RCS file: /usr1/CVS/rtems/cpukit/libmisc/shell/shell.c,v retrieving revision 1.41 diff -u -r1.41 shell.c
7 7 * WORK: fernando.ruiz@ctv.es 8 8 * HOME: correo@fernando-ruiz.com 9 9 * 10 * Modified by Sebastian Huber (2009). 11 * 10 12 * The license and distribution terms for this file may be 11 13 * found in the file LICENSE in this distribution or at 12 14 * http://www.rtems.com/license/LICENSE. … … 40 42 #include <errno.h> 41 43 #include <pwd.h> 42 44 43 rtems_shell_env_t 45 rtems_shell_env_t rtems_global_shell_env = { 44 46 .magic = rtems_build_name('S', 'E', 'N', 'V'), 45 47 .devname = CONSOLE_DEVICE_NAME, 46 48 .taskname = "SHGL", … … 53 55 .output = NULL, 54 56 .output_append = false, 55 57 .wake_on_end = RTEMS_ID_NONE, 56 .login = true58 .login_check = NULL 57 59 }; 58 60 59 61 rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env; … … 118 120 int up; 119 121 int cmd = -1; 120 122 int inserting = 1; 121 123 122 124 output = (out && isatty(fileno(in))); 123 125 124 126 col = last_col = 0; 125 127 126 128 tcdrain(fileno(in)); 127 129 if (out) 128 130 tcdrain(fileno(out)); 129 131 130 132 if (output && prompt) 131 133 fprintf(out, "\r%s", prompt); 132 134 133 135 line[0] = 0; 134 136 new_line[0] = 0; 135 137 136 138 for (;;) { 137 139 138 140 if (output) 139 141 fflush(out); 140 142 … … 142 144 143 145 if (extended_key == EOF) 144 146 return -2; 145 147 146 148 c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK; 147 149 148 150 /* 149 151 * Make the extended_key usable as a boolean. 150 152 */ 151 153 extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK; 152 154 153 155 up = 0; 154 156 155 157 if (extended_key) 156 158 { 157 159 switch (c) … … 199 201 200 202 /* drop through */ 201 203 case RTEMS_SHELL_KEYS_DARROW: 202 204 203 205 { 204 206 int last_cmd = cmd; 205 207 int clen = strlen (line); 206 208 207 209 if (prompt) 208 210 clen += strlen(prompt); 209 211 210 212 if (up) { 211 213 cmd++; 212 214 } else { … … 226 228 memcpy (line, new_line, size); 227 229 else 228 230 memcpy (line, cmds[cmd], size); 229 231 230 232 col = strlen (line); 231 233 232 234 if (output) { 233 235 fprintf(out,"\r%*c", clen, ' '); 234 236 fprintf(out,"\r%s%s", prompt, line); … … 271 273 } 272 274 col = 0; 273 275 break; 274 276 275 277 case 5:/*Control-e*/ 276 278 if (output) 277 279 fprintf(out,line + col); … … 290 292 line[col] = '\0'; 291 293 } 292 294 break; 293 295 294 296 case 0x04:/*Control-d*/ 295 297 if (strlen(line)) 296 298 break; … … 298 300 if (output) 299 301 fputc('\n', out); 300 302 return -2; 301 303 302 304 case '\f': 303 305 if (output) { 304 306 int end; … … 334 336 */ 335 337 if (output) 336 338 fprintf(out,"\n"); 337 339 338 340 /* 339 341 * Only process the command if we have a command and it is not 340 342 * repeated in the history. … … 378 380 return -2; 379 381 } 380 382 381 int rtems_shell_scanline(382 char *line,383 int size,384 FILE *in,385 FILE *out386 )387 {388 int c;389 int col;390 int doEcho;391 392 doEcho = (out && isatty(fileno(in)));393 394 col = 0;395 if (*line) {396 col = strlen(line);397 if (doEcho) fprintf(out,"%s",line);398 }399 tcdrain(fileno(in));400 if (out)401 tcdrain(fileno(out));402 for (;;) {403 line[col] = 0;404 c = fgetc(in);405 switch (c) {406 case EOF:407 return 0;408 case '\n':409 case '\r':410 if (doEcho)411 fputc('\n',out);412 return 1;413 case 127:414 case '\b':415 if (col) {416 if (doEcho) {417 fputc('\b',out);418 fputc(' ',out);419 fputc('\b',out);420 }421 col--;422 } else {423 if (doEcho) fputc('\a',out);424 }425 break;426 default:427 if (!iscntrl(c)) {428 if (col<size-1) {429 line[col++] = c;430 if (doEcho) fputc(c,out);431 } else {432 if (doEcho) fputc('\a',out);433 }434 } else {435 if (doEcho)436 if (c=='\a') fputc('\a',out);437 }438 break;439 }440 }441 }442 443 383 /* ----------------------------------------------- * 444 384 * - The shell TASK 445 385 * Poor but enough.. … … 473 413 } 474 414 } 475 415 476 intrtems_shell_login(FILE * in,FILE * out) {416 static bool rtems_shell_login(FILE * in,FILE * out) { 477 417 FILE *fd; 478 418 int c; 479 419 time_t t; … … 584 524 } 585 525 } 586 526 587 times=0; 588 strcpy(name,""); 589 strcpy(pass,""); 590 for (;;) { 591 times++; 592 if (times>3) break; 593 if (out) fprintf(out,"\nlogin: "); 594 if (!rtems_shell_scanline(name,sizeof(name),in,out )) break; 595 if (out) fprintf(out,"Password: "); 596 if (!rtems_shell_scanline(pass,sizeof(pass),in,NULL)) break; 597 if (out) fprintf(out,"\n"); 598 if ((passwd=getpwnam(name))) { 599 if (strcmp(passwd->pw_passwd,"!")) { /* valid user */ 600 setuid(passwd->pw_uid); 601 setgid(passwd->pw_gid); 602 rtems_current_user_env->euid = 603 rtems_current_user_env->egid = 0; 604 chown(rtems_current_shell_env->devname,passwd->pw_uid,0); 605 rtems_current_user_env->euid = passwd->pw_uid; 606 rtems_current_user_env->egid = passwd->pw_gid; 607 if (!strcmp(passwd->pw_passwd,"*")) { 608 /* /etc/shadow */ 609 return 0; 610 } else { 611 /* crypt() */ 612 return 0; 613 } 614 } 615 } 616 if (out) 617 fprintf(out,"Login incorrect\n"); 618 strcpy(name,""); 619 strcpy(pass,""); 620 } 621 return -1; 527 return rtems_shell_login_prompt( 528 in, 529 out, 530 rtems_current_shell_env->devname, 531 rtems_current_shell_env->login_check 532 ); 622 533 } 623 534 624 535 #if defined(SHELL_DEBUG) … … 686 597 687 598 shell_env = 688 599 rtems_current_shell_env = rtems_shell_init_env( shell_env_arg ); 689 600 690 601 /* 691 602 * @todo chrisj 692 603 * Remove the use of task variables. Change to have a single … … 711 622 712 623 fileno(stdout); 713 624 714 /* fprintf( stderr, 625 /* fprintf( stderr, 715 626 "-%s-%s-\n", shell_env->input, shell_env->output ); 716 627 */ 717 628 … … 732 643 stdoutToClose = output; 733 644 } 734 645 } 735 646 736 647 if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) { 737 648 FILE *input = fopen(shell_env_arg->input, "r"); 738 649 if (!input) { … … 772 683 setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/ 773 684 774 685 rtems_shell_initialize_command_set(); 775 686 776 687 /* 777 688 * Allocate the command line buffers. 778 689 */ … … 780 691 if (!cmd_argv) { 781 692 fprintf(stderr, "no memory for command line buffers\n" ); 782 693 } 783 694 784 695 cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE); 785 696 if (!cmds[0]) { 786 697 fprintf(stderr, "no memory for command line buffers\n" ); … … 793 704 for (cmd = 1; cmd < cmd_count; cmd++) { 794 705 cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE; 795 706 } 796 707 797 708 do { 798 709 /* Set again root user and root filesystem, side effect of set_priv..*/ 799 710 sc = rtems_libio_set_private_env(); … … 808 719 * loop when the connection is dropped during login and 809 720 * keep on trucking. 810 721 */ 811 if (shell_env->login ) {812 result = rtems_shell_login(stdin,stdout) == 0;722 if (shell_env->login_check != NULL) { 723 result = rtems_shell_login(stdin,stdout); 813 724 } else { 814 725 result = true; 815 726 } … … 829 740 chdir(shell_env->cwd); 830 741 else 831 742 chdir("/"); /* XXX: chdir to getpwent homedir */ 832 743 833 744 shell_env->exit_shell = false; 834 745 835 746 for (;;) { 836 747 int cmd; 837 748 838 749 /* Prompt section */ 839 750 if (prompt) { 840 751 rtems_shell_get_prompt(shell_env, prompt, 841 752 RTEMS_SHELL_PROMPT_SIZE); 842 753 } 843 754 844 755 /* getcmd section */ 845 756 cmd = rtems_shell_line_editor(cmds, cmd_count, 846 757 RTEMS_SHELL_CMD_SIZE, prompt, … … 848 759 849 760 if (cmd == -1) 850 761 continue; /* empty line */ 851 762 852 763 if (cmd == -2) 853 764 break; /*EOF*/ 854 765 … … 856 767 857 768 if (shell_env->echo) 858 769 fprintf(stdout, "%d: %s\n", line, cmds[cmd]); 859 770 860 771 /* evaluate cmd section */ 861 772 c = cmds[cmd]; 862 773 while (*c) { … … 944 855 const char *devname, 945 856 bool forever, 946 857 bool wait, 947 const char *input,948 const char *output,858 const char *input, 859 const char *output, 949 860 bool output_append, 950 861 rtems_id wake_on_end, 951 862 bool echo, 952 bool login863 rtems_login_check login_check 953 864 ) 954 865 { 955 866 rtems_id task_id; … … 991 902 shell_env->output = strdup (output); 992 903 shell_env->output_append = output_append; 993 904 shell_env->wake_on_end = wake_on_end; 994 shell_env->login = login;905 shell_env->login_check = login_check; 995 906 996 907 getcwd(shell_env->cwd, sizeof(shell_env->cwd)); 997 908 … … 1017 928 const char *devname, 1018 929 bool forever, 1019 930 bool wait, 1020 bool login931 rtems_login_check login_check 1021 932 ) 1022 933 { 1023 934 rtems_id to_wake = RTEMS_ID_NONE; … … 1037 948 false, /* output_append */ 1038 949 to_wake, /* wake_on_end */ 1039 950 false, /* echo */ 1040 login /* login*/951 login_check /* login check */ 1041 952 ); 1042 953 } 1043 954 … … 1060 971 if (sc != RTEMS_SUCCESSFUL) 1061 972 return sc; 1062 973 } 1063 974 1064 975 sc = rtems_shell_run( 1065 976 task_name, /* task_name */ 1066 977 task_stacksize, /* task_stacksize */ … … 1073 984 output_append, /* output_append */ 1074 985 current_task, /* wake_on_end */ 1075 986 echo, /* echo */ 1076 false /* login*/987 NULL /* login check */ 1077 988 ); 1078 989 if (sc != RTEMS_SUCCESSFUL) 1079 990 return sc; -
cpukit/libmisc/shell/shell.h
RCS file: /usr1/CVS/rtems/cpukit/libmisc/shell/shell.h,v retrieving revision 1.23 diff -u -r1.23 shell.h
24 24 #include <termios.h> 25 25 #include <rtems/fs.h> 26 26 #include <rtems/libio.h> 27 #include <rtems/login.h> 27 28 28 29 #ifdef __cplusplus 29 30 extern "C" { … … 99 100 100 101 int rtems_shell_make_args( 101 102 char *commandLine, 102 int *argc_p, 103 char **argv_p, 103 int *argc_p, 104 char **argv_p, 104 105 int max_args 105 106 ); 106 107 107 int rtems_shell_scanline(108 char *line,109 int size,110 FILE *in,111 FILE *out112 );113 114 108 int rtems_shell_cat_file( 115 109 FILE *out, 116 110 const char *name … … 135 129 * @param task_priority The priority the shell runs at. 136 130 * @param forever Repeat logins. 137 131 * @param wait Caller should block until shell exits. 138 * @param login Demand user login.132 * @param login_check User login check function, NULL disables login checks. 139 133 * 140 134 */ 141 135 rtems_status_code rtems_shell_init( … … 145 139 const char *devname, 146 140 bool forever, 147 141 bool wait, 148 bool login142 rtems_login_check login_check 149 143 ); 150 144 151 145 /** … … 179 173 int rtems_shell_str2int(const char * s); 180 174 181 175 typedef struct { 182 rtems_name magic; /* 'S','E','N','V': Shell Environment */183 const char *devname;184 const char *taskname;176 rtems_name magic; /* 'S','E','N','V': Shell Environment */ 177 const char *devname; 178 const char *taskname; 185 179 /* user extensions */ 186 bool exit_shell; /* logout */187 bool forever; /* repeat login */188 int errorlevel;189 bool echo;190 char cwd[256];191 const char *input;192 const char *output;193 bool output_append;194 rtems_id wake_on_end;195 bool login;180 bool exit_shell; /* logout */ 181 bool forever; /* repeat login */ 182 int errorlevel; 183 bool echo; 184 char cwd[256]; 185 const char *input; 186 const char *output; 187 bool output_append; 188 rtems_id wake_on_end; 189 rtems_login_check login_check; 196 190 } rtems_shell_env_t; 197 191 198 192 bool rtems_shell_main_loop( … … 210 204 * all possible file systems being included it would force the 211 205 * networking stack into the applcation and this may not be 212 206 * required. 213 */ 207 */ 214 208 struct rtems_shell_filesystems_tt; 215 209 typedef struct rtems_shell_filesystems_tt rtems_shell_filesystems_t; 216 210