Changeset 3f777d0e in rtems
- Timestamp:
- 01/12/01 13:51:56 (22 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- c2a4084f
- Parents:
- d1941587
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/exec/libnetworking/ChangeLog
rd1941587 r3f777d0e 1 2001-01-12 Sergei Organov <osv@javad.ru> 2 3 * rtems_servers/ftpd.c, rtems_servers/ftpd.h: Major enhancements 4 as listed below: 5 - use pool of pre-created threads to handle sessions instead of 6 creating/deleting threads on the fly 7 - LIST output is now similar to what "/bin/ls -al" would output, 8 thus FTP clients such Netscape are happy with it. 9 - LIST NAME now works (both for files and directories) 10 - added support for NLST, CDUP, and MDTM FTP commands to make 11 more FTP clients happy 12 - keep track of CWD for every session separately 13 - ability to specify root directory name for FTPD in configuration 14 table. FTPD will then create illusion for FTP clients that this 15 is actually root directory. 16 - ignore options sent in commands, thus LIST -al FILE works and 17 doesn't try to list "-al" directory. 18 - buffers are allocated on stack instead of heap where possible to 19 eliminate malloc/free calls (avoid possible heap fragmentation 20 troubles). 21 - drop using of task notepad to pass parameters - use function 22 arguments instead 23 - use snprintf() instead of sprintf() as the latter is unsafe 24 - use of PF_INET in socket() instead of AF_INET 25 26 Here are ftp clients I've tried new FTPD with (all of them 27 running on Debian GNU/Linux 2.2): 28 29 Lftp 2.1.10 30 NcFTP 2.4.3 31 Netscape 4.75 32 ftp 33 mc 4.5.49 34 1 35 2001-01-02 Joel Sherrill <joel@OARcorp.com> 2 36 -
c/src/libnetworking/ChangeLog
rd1941587 r3f777d0e 1 2001-01-12 Sergei Organov <osv@javad.ru> 2 3 * rtems_servers/ftpd.c, rtems_servers/ftpd.h: Major enhancements 4 as listed below: 5 - use pool of pre-created threads to handle sessions instead of 6 creating/deleting threads on the fly 7 - LIST output is now similar to what "/bin/ls -al" would output, 8 thus FTP clients such Netscape are happy with it. 9 - LIST NAME now works (both for files and directories) 10 - added support for NLST, CDUP, and MDTM FTP commands to make 11 more FTP clients happy 12 - keep track of CWD for every session separately 13 - ability to specify root directory name for FTPD in configuration 14 table. FTPD will then create illusion for FTP clients that this 15 is actually root directory. 16 - ignore options sent in commands, thus LIST -al FILE works and 17 doesn't try to list "-al" directory. 18 - buffers are allocated on stack instead of heap where possible to 19 eliminate malloc/free calls (avoid possible heap fragmentation 20 troubles). 21 - drop using of task notepad to pass parameters - use function 22 arguments instead 23 - use snprintf() instead of sprintf() as the latter is unsafe 24 - use of PF_INET in socket() instead of AF_INET 25 26 Here are ftp clients I've tried new FTPD with (all of them 27 running on Debian GNU/Linux 2.2): 28 29 Lftp 2.1.10 30 NcFTP 2.4.3 31 Netscape 4.75 32 ftp 33 mc 4.5.49 34 1 35 2001-01-02 Joel Sherrill <joel@OARcorp.com> 2 36 -
c/src/libnetworking/rtems_servers/ftpd.c
rd1941587 r3f777d0e 1 1 /* FIXME: 1. Parse command is a hack. We can do better. 2 * 2. chdir is a hack. We can do better. 3 * 3. PWD doesn't work. 4 * 4. Some sort of access control? 5 * 6 * FTP Server Daemon 2 * 2. Some sort of access control? 3 * 3. OSV: Timeouts on sockets. 4 * 4. OSV: hooks support seems to be a joke, as it requires storing of 5 * entire input file in memory. Seem to be better to change it to 6 * something more reasonable, like having 7 * 'hook_write(void const *buf, int count)' routine that will be 8 * called multiple times while file is being received. 9 * 5. OSV: Remove hack with "/dev/null"? 10 * 6. OSV: data_addr field of SessionInfo structure is not initialized. 11 * This will lead to undefined behavior if FTP client doesn't send 12 * PORT command. Seems we need to implement usage of default port 13 * (ftp port - 1). I didn't find any FTP client that doesn't send 14 * PORT command though. 15 * 7. OSV: while server claims TYPE ASCII command succeeds (to make 16 * happy some clients), ASCII mode isn't actually implemented. 17 * 8. Passive Mode? 18 * 19 * FTP Server Daemon 7 20 * 8 21 * Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu> 22 * 23 * Changed by: Sergei Organov <osv@javad.ru> (OSV) 24 * Changes: 25 * - use pool of pre-created threads to handle sessions 26 * - LIST output now similar to what "/bin/ls -al" would output, thus 27 * FTP clients could parse it. 28 * - LIST NAME now works (both for files and directories) 29 * - keep track of CWD for every session separately 30 * - ability to specify root directory name in configuration table 31 * - options sent in commands are ignored, thus LIST -al FILE works 32 * - added support for NLST, CDUP and MDTM commands 33 * - buffers are allocated on stack instead of heap where possible 34 * - drop using of task notepad to pass parameters - use function 35 * arguments instead 36 * - various bug-fixes, e.g., use of PF_INET in socket() instead of 37 * AF_INET, use snprintf() instead of sprintf() everywhere for safety, 38 * etc. 9 39 * 10 40 * $Id$ … … 25 55 * Organization: * 26 56 * * 27 * The FTP daemon is started upon boot. It runs all the time * 28 * and waits for connections on the known FTP port (21). When * 29 * a connection is made, it starts a 'session' task. That * 57 * The FTP daemon is started upon boot along with a (configurable) * 58 * number of tasks to handle sessions. It runs all the time and * 59 * waits for connections on the known FTP port (21). When * 60 * a connection is made, it wakeups a 'session' task. That * 30 61 * session then interacts with the remote host. When the session * 31 * is complete, the session task deletes itself. The daemon still*62 * is complete, the session task goes to sleep. The daemon still * 32 63 * runs, however. * 33 64 * * … … 38 69 * STOR xxx - Receives a file from the client. xxx = filename. * 39 70 * LIST xxx - Sends a file list to the client. * 40 * (LIST xxx isn't working yet...)*71 * NLST xxx - Sends a file list to the client. * 41 72 * USER - Does nothing. * 42 73 * PASS - Does nothing. * … … 47 78 * PWD - Print working directory. * 48 79 * CWD xxx - Change working directory. * 80 * CDUP - Change to upper directory. * 49 81 * SITE CHMOD xxx yyy - Change permissions on file yyy to xxx. * 50 82 * PORT a,b,c,d,x,y - Setup for a data port to IP address a.b.c.d * 51 83 * and port (x*256 + y). * 84 * MDTM xxx - Send date/time to the client. xxx = filename. * 52 85 * * 53 86 * * 54 87 * The public routines contained in this file are: * 55 88 * * 56 * rtems_initialize_ftpd_start - Starts the server daemon, then * 57 * returns to its caller. * 58 * * 59 * * 60 * The private routines contained in this file are: * 61 * * 62 * rtems_ftpd_send_reply - Sends a reply code and text through the * 63 * control port. * 64 * rtems_ftpd_command_retrieve - Performs to "RETR" command. * 65 * rtems_ftpd_command_store - Performs the "STOR" command. * 66 * rtems_ftpd_command_list - Performs the "LIST" command. * 67 * rtems_ftpd_command_port - Opens a data port (the "PORT" command). * 68 * rtems_ftpd_parse_command - Parses an incoming command. * 69 * rtmes_ftpd_session - Begins a service session. * 70 * rtems_ftpd_daemon - Listens on the FTP port for service * 71 * requests. * 89 * rtems_initialize_ftpd - Initializes and starts the server daemon, * 90 * then returns to its caller. * 91 * * 72 92 *------------------------------------------------------------------------* 73 93 * Jake Janovetz * … … 77 97 ************************************************************************** 78 98 * Change History: * 79 * 12/01/97 - Creation (JWJ) * 99 * 12/01/97 - Creation (JWJ) * 100 * 2001-01-08 - Changes by OSV * 80 101 *************************************************************************/ 81 82 #include <stdio.h>83 #include <stdlib.h>84 #include <string.h>85 #include <unistd.h>86 #include <fcntl.h>87 #include <dirent.h>88 89 #include <rtems.h>90 #include <rtems/rtems_bsdnet.h>91 #include <rtems/error.h>92 #include <syslog.h>93 94 #include <sys/types.h>95 #include <sys/socket.h>96 #include <arpa/ftp.h>97 #include <netinet/in.h>98 99 #include "ftpd.h"100 101 102 extern struct rtems_ftpd_configuration rtems_ftpd_configuration;103 102 104 103 /************************************************************************** … … 115 114 * not take place, but the error condition is temporary so the 116 115 * command can be reissued later. 117 * 5yz Permanent negative completion reply. The command was not 116 * 5yz Permanent negative completion reply. The command was not 118 117 * accepted and should not be retried. 119 118 *------------------------------------------------------------------------- … … 128 127 *************************************************************************/ 129 128 130 131 /************************************************************************** 132 * SessionInfo structure. 133 * 134 * The following structure is allocated for each session. The pointer 135 * to this structure is contained in the tasks notepad entry. 136 *************************************************************************/ 137 typedef struct 138 { 139 struct sockaddr_in data_addr; /* Data address for PORT commands */ 140 FILE *ctrl_fp; /* File pointer for control connection */ 141 char cwd[255]; /* Current working directory */ 142 /* Login -- future use -- */ 143 int xfer_mode; /* Transfer mode (ASCII/binary) */ 144 } FTPD_SessionInfo_t; 145 146 147 #define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.0-JWJ) ready." 129 #include <stdio.h> 130 #include <stdlib.h> 131 #include <string.h> 132 #include <unistd.h> 133 #include <fcntl.h> 134 #include <dirent.h> 135 #include <errno.h> 136 137 #include <rtems.h> 138 #include <rtems/rtems_bsdnet.h> 139 #include <rtems/error.h> 140 #include <syslog.h> 141 142 #include <sys/types.h> 143 #include <sys/socket.h> 144 #include <arpa/ftp.h> 145 #include <netinet/in.h> 146 147 #include "ftpd.h" 148 149 150 #ifdef __GNUC__ 151 /* change to #if 1 to disable syslog entirely */ 152 #if 0 153 #undef syslog 154 #define syslog(a, b, ...) while(0){} 155 #endif 156 #endif 157 158 #define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.1-JWJ) ready." 159 160 #define FTPD_SYSTYPE "RTEMS" 161 162 /* Seem to be unused */ 163 #if 0 148 164 #define FTPD_WELCOME_MESSAGE \ 149 165 "Welcome to the RTEMS FTP server.\n" \ 150 166 "\n" \ 151 167 "Login accepted.\n" 168 #endif 169 170 /* Various buffer sizes */ 171 enum 172 { 173 FTPD_BUFSIZE = 256, /* Size for temporary buffers */ 174 FTPD_DATASIZE = 1024, /* Size for file transfer buffers */ 175 FTPD_STACKSIZE = 8 * 1024, /* Tasks stack size */ 176 }; 177 178 /* Event to be used by session tasks for waiting */ 179 enum 180 { 181 FTPD_RTEMS_EVENT = RTEMS_EVENT_1 182 }; 183 184 /* Configuration table */ 185 extern struct rtems_ftpd_configuration rtems_ftpd_configuration; 186 187 /* this is not prototyped in strict ansi mode */ 188 FILE *fdopen (int fildes, const char *mode); 189 190 /* 191 * SessionInfo structure. 192 * 193 * The following structure is allocated for each session. 194 */ 195 typedef struct 196 { 197 struct sockaddr_in data_addr; /* Data address for PORT commands */ 198 FILE *ctrl_fp; /* File pointer for control connection */ 199 int socket; /* Socket descriptor for ctrl connection */ 200 char cwd[FTPD_BUFSIZE]; /* Current working directory */ 201 /* Login -- future use -- */ 202 int xfer_mode; /* Transfer mode (ASCII/binary) */ 203 rtems_id tid; /* Task id */ 204 } FTPD_SessionInfo_t; 205 206 207 /* 208 * TaskPool structure. 209 */ 210 typedef struct 211 { 212 FTPD_SessionInfo_t *info; 213 FTPD_SessionInfo_t **queue; 214 int count; 215 int head; 216 int tail; 217 rtems_id mutex; 218 rtems_id sem; 219 } FTPD_TaskPool_t; 220 221 /* 222 * Task pool instance. 223 */ 224 static FTPD_TaskPool_t task_pool; 225 226 /* 227 * Root node for FTPD without trailing slash. Even '/' node is denoted as 228 * empty string here. 229 */ 230 static char root[FTPD_BUFSIZE]; 231 232 233 /*PAGE 234 * 235 * serr 236 * 237 * Return errror string corresponding to current 'errno'. 238 * 239 */ 240 static char const* 241 serr(void) 242 { 243 return strerror(errno); 244 } 245 246 247 /* 248 * Utility routines to manage root directory and session local 249 * current working directory. 250 */ 251 252 253 /*PAGE 254 * 255 * squeeze_path 256 * 257 * Squeezes path according to OS rules, i.e., eliminates /./, /../, and // 258 * from the path. Does nothing if the path is relative, i.e. doesn't begin 259 * with '/'. The trailing slash is always removed, even when alone, i.e. "/" 260 * will be "" after squeeze. 261 * 262 * Input parameters: 263 * path - the path to be squeezed 264 * 265 * Output parameters: 266 * path - squeezed path 267 * 268 */ 269 static void 270 squeeze_path(char* path) 271 { 272 if(path[0] == '/') 273 { 274 char* e = path + 1; 275 int rest = strlen(e); 276 while(rest >= 0) 277 { 278 int len; 279 char* s = e; 280 e = strchr(s, '/'); 281 if(e) 282 ++e; 283 else 284 e = s + rest + 1; 285 len = e - s; 286 rest -= len; 287 if(len == 1 || (len == 2 && s[0] == '.')) 288 { 289 if(rest >= 0) 290 memmove(s, e, rest + 1); 291 else 292 *s++ = '\0'; 293 e = s; 294 } 295 else if(len == 3 && s[0] == '.' && s[1] == '.') 296 { 297 char* ps = s; 298 if(ps - 1 > path) { 299 do 300 --ps; 301 while(ps[-1] != '/'); 302 } 303 if(rest >= 0) 304 memmove(ps, e, rest + 1); 305 else 306 *ps++ = '\0'; 307 e = ps; 308 } 309 } 310 if(e[-2] == '/') 311 e[-2] = '\0'; 312 } 313 } 314 315 316 /*PAGE 317 * 318 * make_path 319 * 320 * Makes full path given file name, current working directory and root 321 * directory (file scope variable 'root'). 322 * 323 * Input parameters: 324 * cwd - current working directory 325 * name - file name 326 * root (file scope variable) - FTPD root directory 327 * 328 * Output parameters: 329 * buf - full path 330 * returns pointer to non-root part of the 'buf', i.e. to first character 331 * different from '/' after root part. 332 * 333 */ 334 static char const* 335 make_path(char* buf, char const* cwd, char const* name) 336 { 337 char* res = NULL; 338 339 int rlen = strlen(root); 340 int clen = strlen(cwd); 341 int nlen = strlen(name); 342 int len = rlen + nlen; 343 344 if (name[0] != '/') 345 { 346 ++len; 347 if (clen > 0) 348 len += clen + 1; 349 } 350 351 if (FTPD_BUFSIZE > len) 352 { 353 char* b = buf; 354 memcpy(b, root, rlen); b += rlen; 355 if (name[0] != '/') 356 { 357 *b++ = '/'; 358 if (clen > 0) 359 { 360 memcpy(b, cwd, clen); b += clen; 361 *b++ = '/'; 362 } 363 } 364 memcpy(b, name, nlen); b += nlen; 365 *b = '\0'; 366 367 res = buf + rlen; 368 while(rlen-- > 0 && res[-1] == '/') 369 --res; 370 squeeze_path(res); 371 } 372 373 return res; 374 } 375 376 /* 377 * Task pool management routines 378 */ 379 380 381 /*PAGE 382 * 383 * task_pool_done 384 * 385 * Cleanup task pool. 386 * 387 * Input parameters: 388 * count - number of entries in task pool to cleanup 389 * 390 * Output parameters: 391 * NONE 392 * 393 */ 394 static void 395 task_pool_done(int count) 396 { 397 int i; 398 for(i = 0; i < count; ++i) 399 rtems_task_delete(task_pool.info[i].tid); 400 if(task_pool.info) 401 free(task_pool.info); 402 if(task_pool.queue) 403 free(task_pool.queue); 404 if(task_pool.mutex != (rtems_id)-1) 405 rtems_semaphore_delete(task_pool.mutex); 406 if(task_pool.sem != (rtems_id)-1) 407 rtems_semaphore_delete(task_pool.sem); 408 task_pool.info = 0; 409 task_pool.queue = 0; 410 task_pool.count = 0; 411 task_pool.sem = -1; 412 task_pool.mutex = -1; 413 } 414 415 /* Forward declare */ 416 static void session(rtems_task_argument arg); 417 418 /*PAGE 419 * 420 * task_pool_init 421 * 422 * Initialize task pool. 423 * 424 * Input parameters: 425 * count - number of entries in task pool to create 426 * priority - priority tasks are started with 427 * 428 * Output parameters: 429 * returns 1 on success, 0 on failure. 430 * 431 */ 432 static int 433 task_pool_init(int count, rtems_task_priority priority) 434 { 435 int i; 436 rtems_status_code sc; 437 char id = 'a'; 438 439 task_pool.count = 0; 440 task_pool.head = task_pool.tail = 0; 441 task_pool.mutex = (rtems_id)-1; 442 task_pool.sem = (rtems_id)-1; 443 444 sc = rtems_semaphore_create( 445 rtems_build_name('F', 'T', 'P', 'M'), 446 1, 447 RTEMS_DEFAULT_ATTRIBUTES 448 | RTEMS_BINARY_SEMAPHORE 449 | RTEMS_INHERIT_PRIORITY 450 | RTEMS_PRIORITY, 451 RTEMS_NO_PRIORITY, 452 &task_pool.mutex); 453 454 if(sc == RTEMS_SUCCESSFUL) 455 sc = rtems_semaphore_create( 456 rtems_build_name('F', 'T', 'P', 'S'), 457 count, 458 RTEMS_DEFAULT_ATTRIBUTES, 459 RTEMS_NO_PRIORITY, 460 &task_pool.sem); 461 462 if(sc != RTEMS_SUCCESSFUL) { 463 task_pool_done(0); 464 syslog(LOG_ERR, "ftpd: Can not create semaphores"); 465 return 0; 466 } 467 468 task_pool.info = (FTPD_SessionInfo_t*) 469 malloc(sizeof(FTPD_SessionInfo_t) * count); 470 task_pool.queue = (FTPD_SessionInfo_t**) 471 malloc(sizeof(FTPD_SessionInfo_t*) * count); 472 if (NULL == task_pool.info || NULL == task_pool.queue) 473 { 474 task_pool_done(0); 475 syslog(LOG_ERR, "ftpd: Not enough memory"); 476 return 0; 477 } 478 479 for(i = 0; i < count; ++i) 480 { 481 FTPD_SessionInfo_t *info = &task_pool.info[i]; 482 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', id), 483 priority, FTPD_STACKSIZE, 484 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | 485 RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), 486 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 487 &info->tid); 488 if (sc == RTEMS_SUCCESSFUL) 489 { 490 sc = rtems_task_start( 491 info->tid, session, (rtems_task_argument)info); 492 if (sc != RTEMS_SUCCESSFUL) 493 task_pool_done(i); 494 } 495 else 496 task_pool_done(i + 1); 497 if (sc != RTEMS_SUCCESSFUL) 498 { 499 syslog(LOG_ERR, "ftpd: Could not create/start FTPD session: %s", 500 rtems_status_text(sc)); 501 return 0; 502 } 503 task_pool.queue[i] = task_pool.info + i; 504 info->ctrl_fp = NULL; 505 info->socket = -1; 506 if (++id > 'z') 507 id = 'a'; 508 } 509 task_pool.count = count; 510 return 1; 511 } 512 513 /*PAGE 514 * 515 * task_pool_obtain 516 * 517 * Obtain free task from task pool. 518 * 519 * Input parameters: 520 * NONE 521 * 522 * Output parameters: 523 * returns pointer to the corresponding SessionInfo structure on success, 524 * NULL if there are no free tasks in the pool. 525 * 526 */ 527 static FTPD_SessionInfo_t* 528 task_pool_obtain() 529 { 530 FTPD_SessionInfo_t* info = 0; 531 rtems_status_code sc; 532 sc = rtems_semaphore_obtain(task_pool.sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); 533 if (sc == RTEMS_SUCCESSFUL) 534 { 535 rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 536 info = task_pool.queue[task_pool.head]; 537 if(++task_pool.head >= task_pool.count) 538 task_pool.head = 0; 539 info->socket = -1; 540 info->ctrl_fp = NULL; 541 rtems_semaphore_release(task_pool.mutex); 542 } 543 return info; 544 } 545 546 /*PAGE 547 * 548 * task_pool_release 549 * 550 * Return task obtained by 'obtain()' back to the task pool. 551 * 552 * Input parameters: 553 * info - pointer to corresponding SessionInfo structure. 554 * 555 * Output parameters: 556 * NONE 557 * 558 */ 559 static void 560 task_pool_release(FTPD_SessionInfo_t* info) 561 { 562 rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 563 task_pool.queue[task_pool.tail] = info; 564 if(++task_pool.tail >= task_pool.count) 565 task_pool.tail = 0; 566 rtems_semaphore_release(task_pool.mutex); 567 rtems_semaphore_release(task_pool.sem); 568 } 569 570 /* 571 * End of task pool routines 572 */ 573 574 /*PAGE 575 * 576 * close_socket 577 * 578 * Close socket. 579 * 580 * Input parameters: 581 * s - socket descriptor to be closed. 582 * 583 * Output parameters: 584 * returns 1 on success, 0 on failure 585 * 586 */ 587 static int 588 close_socket(int s) 589 { 590 if (0 <= s) 591 { 592 if (0 != close(s)) 593 { 594 shutdown(s, 2); 595 if (0 != close(s)) 596 return 0; 597 } 598 } 599 return 1; 600 } 601 602 /*PAGE 603 * 604 * close_stream 605 * 606 * Close data stream of session. 607 * 608 * Input parameters: 609 * info - corresponding SessionInfo structure 610 * 611 * Output parameters: 612 * NONE 613 * 614 */ 615 static void 616 close_stream(FTPD_SessionInfo_t* info) 617 { 618 if (NULL != info->ctrl_fp) 619 { 620 if (0 != fclose(info->ctrl_fp)) 621 { 622 syslog(LOG_ERR, "ftpd: Could not close control stream: %s", serr()); 623 } 624 else 625 info->socket = -1; 626 } 627 628 if (!close_socket(info->socket)) 629 syslog(LOG_ERR, "ftpd: Could not close control socket: %s", serr()); 630 631 info->ctrl_fp = NULL; 632 info->socket = -1; 633 } 152 634 153 635 154 636 /************************************************************************** 155 * Function: rtems_ftpd_send_reply*637 * Function: send_reply * 156 638 ************************************************************************** 157 639 * Description: * … … 170 652 * none * 171 653 * * 172 **************************************************************************173 * Change History: *174 * 12/01/97 - Creation (JWJ) *175 654 *************************************************************************/ 176 655 static void 177 rtems_ftpd_send_reply(int code, char *text) 178 { 179 rtems_status_code sc; 180 FTPD_SessionInfo_t *info = NULL; 181 char str[80]; 182 183 184 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 185 (rtems_unsigned32 *)&info); 186 187 /*********************************************************************** 188 * code must be a 3-digit number. 189 **********************************************************************/ 190 if ((code < 100) || (code > 999)) 191 { 192 syslog(LOG_ERR, "ftpd: Code not 3-digits."); 193 return; 194 } 195 196 /*********************************************************************** 197 * If a text reply exists, add it to the reply data. 198 **********************************************************************/ 199 if (text != NULL) 200 { 201 sprintf(str, "%d %.70s\r\n", code, text); 202 fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text); 203 } 204 else 205 { 206 sprintf(str, "%d\r\n", code); 207 fprintf(info->ctrl_fp, "%d\r\n", code); 208 } 209 fflush(info->ctrl_fp); 210 } 211 656 send_reply(FTPD_SessionInfo_t *info, int code, char *text) 657 { 658 char const* s; 659 660 661 /*********************************************************************** 662 * code must be a 3-digit number. 663 **********************************************************************/ 664 if ((code < 100) || (code > 999)) 665 { 666 syslog(LOG_ERR, "ftpd: Code not 3-digits."); 667 return; 668 } 669 670 /*********************************************************************** 671 * If a text reply exists, add it to the reply data. 672 **********************************************************************/ 673 s = (info->xfer_mode == TYPE_A) ? "\r" : ""; 674 if (text != NULL) 675 fprintf(info->ctrl_fp, "%d %.70s%s\n", code, text, s); 676 else 677 fprintf(info->ctrl_fp, "%d%s\n", code, s); 678 fflush(info->ctrl_fp); 679 } 680 681 682 /*PAGE 683 * 684 * send_mode_reply 685 * 686 * Sends BINARY/ASCII reply string depending on current transfer mode. 687 * 688 * Input parameters: 689 * info - corresponding SessionInfo structure 690 * 691 * Output parameters: 692 * NONE 693 * 694 */ 695 static void 696 send_mode_reply(FTPD_SessionInfo_t *info) 697 { 698 if(info->xfer_mode == TYPE_I) 699 send_reply(info, 150, "Opening BINARY mode data connection."); 700 else 701 send_reply(info, 150, "Opening ASCII mode data connection."); 702 } 703 704 /*PAGE 705 * 706 * data_socket 707 * 708 * Create data socket for session. 709 * 710 * Input parameters: 711 * info - corresponding SessionInfo structure 712 * 713 * Output parameters: 714 * returns socket descriptor, or -1 if failure 715 * 716 */ 717 static int 718 data_socket(FTPD_SessionInfo_t *info) 719 { 720 int s = socket(PF_INET, SOCK_STREAM, 0); 721 if(0 > s) 722 send_reply(info, 420, "Server error - could not create socket."); 723 else if(0 > connect(s, (struct sockaddr *)&info->data_addr, 724 sizeof(struct sockaddr))) 725 { 726 send_reply(info, 420, "Server error - could not connect socket."); 727 close_socket(s); 728 s = -1; 729 } 730 return s; 731 } 212 732 213 733 /************************************************************************** 214 * Function: rtems_ftpd_command_retrieve*734 * Function: command_retrieve * 215 735 ************************************************************************** 216 736 * Description: * … … 230 750 * 1 for no reply sent. * 231 751 * * 232 **************************************************************************233 * Change History: *234 * 04/29/98 - Creation (JWJ) *235 752 *************************************************************************/ 236 753 static int 237 rtems_ftpd_command_retrieve(char *filename) 238 { 239 int s; 240 int n; 241 int fd; 242 unsigned char *bufr; 243 rtems_status_code sc; 244 FTPD_SessionInfo_t *info = NULL; 245 246 247 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 248 (rtems_unsigned32 *)&info); 249 250 if ((fd = open(filename, O_RDONLY)) == -1) 251 { 252 rtems_ftpd_send_reply(450, "Error opening file."); 253 return(0); 254 } 255 256 bufr = (unsigned char *)malloc(BUFSIZ); 257 if (bufr == NULL) 258 { 259 rtems_ftpd_send_reply(440, "Server error - malloc fail."); 260 close(fd); 261 return(0); 262 } 263 264 /*********************************************************************** 265 * Connect to the data connection (PORT made in an earlier PORT call). 266 **********************************************************************/ 267 rtems_ftpd_send_reply(150, "BINARY data connection."); 268 s = socket(AF_INET, SOCK_STREAM, 0); 269 if (connect(s, (struct sockaddr *)&info->data_addr, 270 sizeof(struct sockaddr)) < 0) 271 { 272 rtems_ftpd_send_reply(420, "Server error - could not connect socket."); 273 free(bufr); 274 close(fd); 275 close(s); 276 return(1); 277 } 278 279 /*********************************************************************** 280 * Send the data over the ether. 281 **********************************************************************/ 282 while ((n = read(fd, bufr, BUFSIZ)) > 0) 283 { 284 send(s, bufr, n, 0); 285 bufr[n-1] = '\0'; 286 } 287 288 if (n == 0) 289 { 290 rtems_ftpd_send_reply(210, "File sent successfully."); 291 } 292 else 293 { 294 rtems_ftpd_send_reply(450, "Retrieve failed."); 295 } 296 297 if (close(s) != 0) 298 { 299 syslog(LOG_ERR, "ftpd: Error closing data socket"); 300 } 301 302 free(bufr); 303 close(fd); 304 return(0); 754 command_retrieve(FTPD_SessionInfo_t *info, char *filename) 755 { 756 int s = -1; 757 int n; 758 int fd = -1; 759 char buf[FTPD_DATASIZE]; 760 int res = 0; 761 762 char const* r = make_path(buf, info->cwd, filename); 763 764 if (NULL == r || 0 > (fd = open(buf, O_RDONLY))) 765 { 766 send_reply(info, 450, "Error opening file."); 767 return(res); 768 } 769 770 send_mode_reply(info); 771 772 /*********************************************************************** 773 * Connect to the data connection (PORT made in an earlier PORT call). 774 **********************************************************************/ 775 s = data_socket(info); 776 if (0 <= s) 777 { 778 /*********************************************************************** 779 * Send the data over the ether. 780 **********************************************************************/ 781 while ((n = read(fd, buf, FTPD_DATASIZE)) > 0) 782 { 783 send(s, buf, n, 0); 784 } 785 786 if (0 == n) 787 { 788 if (0 == close(fd)) 789 { 790 fd = -1; 791 res = 1; 792 } 793 } 794 } 795 796 if (0 == res) 797 send_reply(info, 450, "Retrieve failed."); 798 else 799 send_reply(info, 210, "File sent successfully."); 800 801 if (-1 != fd) 802 close(fd); 803 804 if (!close_socket(s)) 805 syslog(LOG_ERR, "ftpd: Error closing data socket"); 806 807 return(res); 305 808 } 306 809 307 810 308 811 /************************************************************************** 309 * Function: rtems_ftpd_command_store*812 * Function: command_store * 310 813 ************************************************************************** 311 814 * Description: * … … 325 828 * 1 for failure. * 326 829 * * 327 **************************************************************************328 * Change History: *329 * 12/01/97 - Creation (JWJ) *330 830 *************************************************************************/ 331 831 static int 332 rtems_ftpd_command_store(char *filename) 333 { 334 char *bufr; 335 int s; 336 int n; 337 unsigned long size = 0; 338 rtems_status_code sc; 339 FTPD_SessionInfo_t *info = NULL; 340 struct rtems_ftpd_hook *usehook = NULL; 341 342 343 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 344 (rtems_unsigned32 *)&info); 345 346 bufr = (char *)malloc(BUFSIZ * sizeof(char)); 347 if (bufr == NULL) 348 { 349 rtems_ftpd_send_reply(440, "Server error - malloc fail."); 832 command_store(FTPD_SessionInfo_t *info, char *filename) 833 { 834 int s; 835 int n; 836 unsigned long size = 0; 837 struct rtems_ftpd_hook *usehook = NULL; 838 char buf[FTPD_DATASIZE]; 839 840 int null = !strcmp("/dev/null", filename); 841 842 if(!null) 843 { 844 if (NULL == make_path(buf, info->cwd, filename)) 845 { 846 send_reply(info, 450, "Error creating file."); 847 return(0); 848 } 849 } 850 851 send_mode_reply(info); 852 853 s = data_socket(info); 854 if(0 > s) 855 { 856 return(1); 857 } 858 859 860 /*********************************************************************** 861 * File: "/dev/null" just throws the data away. 862 * Otherwise, search our list of hooks to see if we need to do something 863 * special. 864 * OSV: FIXME: this is hack. Using /dev/null filesystem entry would be 865 * better. However, it's not clear how to handle root directory 866 * other than '/' then. 867 **********************************************************************/ 868 if (null) 869 { 870 while ((n = read(s, buf, FTPD_DATASIZE)) > 0); 871 } 872 else if (rtems_ftpd_configuration.hooks != NULL) 873 { 874 struct rtems_ftpd_hook *hook; 875 int i; 876 877 i = 0; 878 hook = &rtems_ftpd_configuration.hooks[i++]; 879 while (hook->filename != NULL) 880 { 881 if (!strcmp(hook->filename, buf)) 882 { 883 usehook = hook; 884 break; 885 } 886 hook = &rtems_ftpd_configuration.hooks[i++]; 887 } 888 } 889 890 if (usehook != NULL) 891 { 892 /* 893 * OSV: FIXME: Small buffer could be used and hook routine 894 * called multiple times instead. Alternatively, the support could be 895 * removed entirely in favor of configuring RTEMS pseudo-device with 896 * given name. 897 */ 898 899 char *bigBufr; 900 size_t filesize = rtems_ftpd_configuration.max_hook_filesize + 1; 901 902 /*********************************************************************** 903 * Allocate space for our "file". 904 **********************************************************************/ 905 bigBufr = (char *)malloc(filesize); 906 if (bigBufr == NULL) 907 { 908 send_reply(info, 440, "Server error - malloc fail."); 350 909 return(1); 351 } 352 353 rtems_ftpd_send_reply(150, "BINARY data connection."); 354 355 s = socket(AF_INET, SOCK_STREAM, 0); 356 if (connect(s, (struct sockaddr *)&info->data_addr, 357 sizeof(struct sockaddr)) < 0) 358 { 359 free(bufr); 360 close(s); 910 } 911 912 /*********************************************************************** 913 * Retrieve the file into our buffer space. 914 **********************************************************************/ 915 size = 0; 916 while ((n = read(s, bigBufr + size, filesize - size)) > 0) 917 { 918 size += n; 919 } 920 if (size >= filesize) 921 { 922 send_reply(info, 440, "Server error - Buffer size exceeded."); 923 free(bigBufr); 924 close_socket(s); 361 925 return(1); 362 } 363 364 365 /*********************************************************************** 366 * File: "/dev/null" just throws the data away. 367 * Otherwise, search our list of hooks to see if we need to do something 368 * special. 369 **********************************************************************/ 370 if (!strncmp("/dev/null", filename, 9)) 371 { 372 while ((n = read(s, bufr, BUFSIZ)) > 0); 373 } 374 else if (rtems_ftpd_configuration.hooks != NULL) 375 { 376 struct rtems_ftpd_hook *hook; 377 int i; 378 379 i = 0; 380 hook = &rtems_ftpd_configuration.hooks[i++]; 381 while (hook->filename != NULL) 926 } 927 close_socket(s); 928 929 /*********************************************************************** 930 * Call our hook. 931 **********************************************************************/ 932 if ((usehook->hook_function)(bigBufr, size) == 0) 933 { 934 send_reply(info, 210, "File transferred successfully."); 935 } 936 else 937 { 938 send_reply(info, 440, "File transfer failed."); 939 } 940 free(bigBufr); 941 } 942 else 943 { 944 int fd = 945 creat(buf, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 946 947 if (0 > fd) 948 { 949 send_reply(info, 450, "Error creating file."); 950 close_socket(s); 951 return(0); 952 } 953 954 while ((n = read(s, buf, FTPD_DATASIZE)) > 0) 955 { 956 if (0 > write(fd, buf, n)) 382 957 { 383 if (!strcmp(hook->filename, filename)) 384 { 385 usehook = hook; 386 break; 387 } 388 hook = &rtems_ftpd_configuration.hooks[i++]; 958 send_reply(info, 450, "Error during write."); 959 close(fd); 960 close_socket(s); 961 return(1); 389 962 } 390 } 391 392 if (usehook != NULL) 393 { 394 char *bigBufr; 395 396 /*********************************************************************** 397 * Allocate space for our "file". 398 **********************************************************************/ 399 bigBufr = (char *)malloc( 400 rtems_ftpd_configuration.max_hook_filesize * sizeof(char)); 401 if (bigBufr == NULL) 963 } 964 if (0 > close(fd)) 965 { 966 send_reply(info, 450, "Error during write."); 967 close_socket(s); 968 return(1); 969 } 970 close_socket(s); 971 send_reply(info, 226, "Transfer complete."); 972 } 973 974 return(0); 975 } 976 977 978 /*PAGE 979 * 980 * send_dirline 981 * 982 * Sends one line of LIST command reply corresponding to single file. 983 * 984 * Input parameters: 985 * s - socket descriptor to send data to 986 * wide - if 0, send only file name. If not 0, send 'stat' info as well in 987 * "ls -l" format. 988 * curTime - current time 989 * path - path to be prepended to what is given by 'add' 990 * add - path to be appended to what is given by 'path', the resulting path 991 * is then passed to 'stat()' routine 992 * name - file name to be reported in output 993 * buf - buffer for temporary data 994 * 995 * Output parameters: 996 * NONE 997 * 998 */ 999 static void 1000 send_dirline(int s, int wide, time_t curTime, char const* path, 1001 char const* add, char const* fname, char* buf) 1002 { 1003 if(wide) 1004 { 1005 struct stat stat_buf; 1006 1007 int plen = strlen(path); 1008 int alen = strlen(add); 1009 if(plen == 0) 1010 { 1011 buf[plen++] = '/'; 1012 buf[plen] = '\0'; 1013 } 1014 else 1015 { 1016 strcpy(buf, path); 1017 if(alen > 0 && buf[plen - 1] != '/') 402 1018 { 403 rtems_ftpd_send_reply(440, "Server error - malloc fail."); 404 free(bufr); 405 return(1); 1019 buf[plen++] = '/'; 1020 if(plen >= FTPD_BUFSIZE) 1021 return; 1022 buf[plen] = '\0'; 406 1023 } 407 408 /*********************************************************************** 409 * Retrieve the file into our buffer space. 410 **********************************************************************/ 411 size = 0; 412 while ((n = read(s, bufr, BUFSIZ)) > 0) 413 { 414 if (size + n > 415 rtems_ftpd_configuration.max_hook_filesize * sizeof(char)) 416 { 417 rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded."); 418 free(bufr); 419 free(bigBufr); 420 close(s); 421 return(1); 422 } 423 memcpy(&bigBufr[size], bufr, n); 424 size += n; 425 } 426 close(s); 427 428 /*********************************************************************** 429 * Call our hook. 430 **********************************************************************/ 431 if ((usehook->hook_function)(bigBufr, size) == 0) 432 { 433 rtems_ftpd_send_reply(210, "File transferred successfully."); 434 } 1024 } 1025 if(plen + alen >= FTPD_BUFSIZE) 1026 return; 1027 strcpy(buf + plen, add); 1028 1029 if (stat(buf, &stat_buf) == 0) 1030 { 1031 int len; 1032 struct tm bt; 1033 time_t tf = stat_buf.st_mtime; 1034 enum { SIZE = 80 }; 1035 enum { SIX_MONTHS = 365*24*60*60/2 }; 1036 char timeBuf[SIZE]; 1037 gmtime_r(&tf, &bt); 1038 if(curTime > tf + SIX_MONTHS || tf > curTime + SIX_MONTHS) 1039 strftime (timeBuf, SIZE, "%b %d %Y", &bt); 435 1040 else 436 { 437 rtems_ftpd_send_reply(440, "File transfer failed."); 438 } 439 free(bigBufr); 440 } 441 else 442 { 443 int fd; 444 size_t written; 445 446 fd = creat(filename, S_IRUSR | S_IWUSR | 447 S_IRGRP | S_IWGRP | 448 S_IROTH | S_IWOTH); 449 if (fd == -1) 450 { 451 rtems_ftpd_send_reply(450, "Could not open file."); 452 close(s); 453 free(bufr); 454 return(1); 455 } 456 while ((n = read(s, bufr, BUFSIZ)) > 0) 457 { 458 written = write(fd, bufr, n); 459 if (written == -1) 460 { 461 rtems_ftpd_send_reply(450, "Error during write."); 462 close(fd); 463 close(s); 464 free(bufr); 465 return(1); 466 } 467 } 468 close(fd); 469 close(s); 470 rtems_ftpd_send_reply(226, "Transfer complete."); 471 } 472 473 free(bufr); 474 return(0); 475 } 476 1041 strftime (timeBuf, SIZE, "%b %d %H:%M", &bt); 1042 1043 len = snprintf(buf, FTPD_BUFSIZE, 1044 "%c%c%c%c%c%c%c%c%c%c 1 %5d %5d %11u %s %s\r\n", 1045 (S_ISLNK(stat_buf.st_mode)?('l'): 1046 (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), 1047 (stat_buf.st_mode & S_IRUSR)?('r'):('-'), 1048 (stat_buf.st_mode & S_IWUSR)?('w'):('-'), 1049 (stat_buf.st_mode & S_IXUSR)?('x'):('-'), 1050 (stat_buf.st_mode & S_IRGRP)?('r'):('-'), 1051 (stat_buf.st_mode & S_IWGRP)?('w'):('-'), 1052 (stat_buf.st_mode & S_IXGRP)?('x'):('-'), 1053 (stat_buf.st_mode & S_IROTH)?('r'):('-'), 1054 (stat_buf.st_mode & S_IWOTH)?('w'):('-'), 1055 (stat_buf.st_mode & S_IXOTH)?('x'):('-'), 1056 (int)stat_buf.st_uid, 1057 (int)stat_buf.st_gid, 1058 (int)stat_buf.st_size, 1059 timeBuf, 1060 fname 1061 ); 1062 1063 send(s, buf, len, 0); 1064 } 1065 } 1066 else 1067 { 1068 int len = snprintf(buf, FTPD_BUFSIZE, "%s\r\n", fname); 1069 send(s, buf, len, 0); 1070 } 1071 } 477 1072 478 1073 /************************************************************************** 479 * Function: rtems_ftpd_command_list *1074 * Function: command_list * 480 1075 ************************************************************************** 481 1076 * Description: * … … 493 1088 * none * 494 1089 * * 495 **************************************************************************496 * Change History: *497 * 12/01/97 - Creation (JWJ) *498 1090 *************************************************************************/ 499 1091 static void 500 rtems_ftpd_command_list(char *fname) 501 { 502 int s; 503 rtems_status_code sc; 504 FTPD_SessionInfo_t *info = NULL; 505 DIR *dirp; 506 struct dirent *dp; 507 char dirline[255]; 508 struct stat stat_buf; 509 510 511 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 512 (rtems_unsigned32 *)&info); 513 514 rtems_ftpd_send_reply(150, "ASCII data connection for LIST."); 515 516 s = socket(AF_INET, SOCK_STREAM, 0); 517 if (connect(s, (struct sockaddr *)&info->data_addr, 518 sizeof(struct sockaddr)) < 0) 519 { 520 syslog(LOG_ERR, "ftpd: Error connecting to data socket."); 521 return; 522 } 523 524 if ((dirp = opendir(fname)) == NULL) 525 { 526 sprintf(dirline, "%s: No such file or directory.%s\n", 527 fname, (info->xfer_mode==TYPE_A)?("\r"):("")); 528 send(s, dirline, strlen(dirline), 0); 529 close(s); 530 rtems_ftpd_send_reply(226, "Transfer complete."); 531 return; 532 } 533 while ((dp = readdir(dirp)) != NULL) 534 { 535 if (stat(dp->d_name, &stat_buf) == 0) 536 { 537 sprintf(dirline, "%c%c%c%c%c%c%c%c%c%c %5d %5d %11d %s%s\n", 538 (S_ISLNK(stat_buf.st_mode)?('l'): 539 (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), 540 (stat_buf.st_mode & S_IRUSR)?('r'):('-'), 541 (stat_buf.st_mode & S_IWUSR)?('w'):('-'), 542 (stat_buf.st_mode & S_IXUSR)?('x'):('-'), 543 (stat_buf.st_mode & S_IRGRP)?('r'):('-'), 544 (stat_buf.st_mode & S_IWGRP)?('w'):('-'), 545 (stat_buf.st_mode & S_IXGRP)?('x'):('-'), 546 (stat_buf.st_mode & S_IROTH)?('r'):('-'), 547 (stat_buf.st_mode & S_IWOTH)?('w'):('-'), 548 (stat_buf.st_mode & S_IXOTH)?('x'):('-'), 549 (int)stat_buf.st_uid, 550 (int)stat_buf.st_gid, 551 (int)stat_buf.st_size, 552 dp->d_name, 553 (info->xfer_mode==TYPE_A)?("\r"):("")); 554 send(s, dirline, strlen(dirline), 0); 555 } 556 } 557 closedir(dirp); 558 559 close(s); 560 rtems_ftpd_send_reply(226, "Transfer complete."); 561 } 562 563 564 /* 565 * Cheesy way to change directories 1092 command_list(FTPD_SessionInfo_t *info, char const *fname, int wide) 1093 { 1094 int s; 1095 DIR *dirp = 0; 1096 struct dirent *dp = 0; 1097 struct stat stat_buf; 1098 char buf[FTPD_BUFSIZE]; 1099 char path[FTPD_BUFSIZE]; 1100 time_t curTime; 1101 char const* res; 1102 char const* cwd = info->cwd; 1103 1104 send_reply(info, 150, "Opening ASCII mode data connection for LIST."); 1105 1106 s = data_socket(info); 1107 if(0 > s) 1108 { 1109 syslog(LOG_ERR, "ftpd: Error connecting to data socket."); 1110 return; 1111 } 1112 1113 if(fname[0] == '\0') 1114 fname = "."; 1115 1116 res = make_path(path, cwd, fname); 1117 1118 if (NULL == res || 0 > stat(path, &stat_buf)) 1119 { 1120 snprintf(buf, FTPD_BUFSIZE, 1121 "%s: No such file or directory.\r\n", fname); 1122 send(s, buf, strlen(buf), 0); 1123 } 1124 else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(path)))) 1125 { 1126 snprintf(buf, FTPD_BUFSIZE, 1127 "%s: Can not open directory.\r\n", fname); 1128 send(s, buf, strlen(buf), 0); 1129 } 1130 else 1131 { 1132 time(&curTime); 1133 if(!dirp) 1134 send_dirline(s, wide, curTime, path, "", fname, buf); 1135 else { 1136 /* FIXME: need "." and ".." only when '-a' option is given */ 1137 send_dirline(s, wide, curTime, path, "", ".", buf); 1138 if(!strcmp(path, root)) 1139 send_dirline(s, wide, curTime, path, "", "..", buf); 1140 else 1141 send_dirline(s, wide, curTime, path, "..", "..", buf); 1142 while ((dp = readdir(dirp)) != NULL) 1143 send_dirline(s, wide, curTime, path, dp->d_name, dp->d_name, buf); 1144 } 1145 } 1146 1147 if(dirp) 1148 closedir(dirp); 1149 close_socket(s); 1150 send_reply(info, 226, "Transfer complete."); 1151 } 1152 1153 1154 /*PAGE 1155 * 1156 * rtems_ftpd_cwd 1157 * 1158 * Change current working directory. We use 'chdir' here only to validate the 1159 * new directory. We keep track of current working directory ourselves because 1160 * current working directory in RTEMS isn't thread local, but we need it to be 1161 * session local. 1162 * 1163 * Input parameters: 1164 * info - corresponding SessionInfo structure 1165 * dir - directory name passed in CWD command 1166 * 1167 * Output parameters: 1168 * info->cwd is set to new CWD value. 1169 * 566 1170 */ 567 1171 static void 568 rtems_ftpd_CWD(char *dir) 569 { 570 rtems_status_code sc; 571 FTPD_SessionInfo_t *info = NULL; 572 573 574 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 575 (rtems_unsigned32 *)&info); 576 577 if (chdir(dir) == 0) 578 { 579 rtems_ftpd_send_reply(250, "CWD command successful."); 580 } 581 else 582 { 583 rtems_ftpd_send_reply(550, "CWD command failed."); 584 } 585 } 586 1172 rtems_ftpd_cwd(FTPD_SessionInfo_t *info, char *dir) 1173 { 1174 char buf[FTPD_BUFSIZE]; 1175 char const* cwd = make_path(buf, info->cwd, dir); 1176 if(cwd && chdir(buf) == 0) 1177 { 1178 send_reply(info, 250, "CWD command successful."); 1179 strcpy(info->cwd, cwd); 1180 } 1181 else 1182 { 1183 send_reply(info, 550, "CWD command failed."); 1184 } 1185 } 1186 1187 1188 1189 /*PAGE 1190 * 1191 * command_mdtm 1192 * 1193 * Handle FTP MDTM command 1194 * 1195 * Input parameters: 1196 * info - corresponding SessionInfo structure 1197 * fname - file name passed in MDTM command 1198 * 1199 * Output parameters: 1200 * info->cwd is set to new CWD value. 1201 * 1202 */ 1203 static void 1204 command_mdtm(FTPD_SessionInfo_t *info, char const* fname) 1205 { 1206 struct stat stbuf; 1207 char buf[FTPD_BUFSIZE]; 1208 1209 if(*fname == '\0') 1210 fname = "."; 1211 1212 if (stat(fname, &stbuf) < 0) 1213 { 1214 snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr()); 1215 send_reply(info, 550, buf); 1216 } 1217 else 1218 { 1219 struct tm *t = gmtime(&stbuf.st_mtime); 1220 snprintf(buf, FTPD_BUFSIZE, "%04d%02d%02d%02d%02d%02d", 1221 1900 + t->tm_year, 1222 t->tm_mon+1, t->tm_mday, 1223 t->tm_hour, t->tm_min, t->tm_sec); 1224 send_reply(info, 213, buf); 1225 } 1226 } 587 1227 588 1228 /************************************************************************** 589 * Function: rtems_ftpd_command_port*1229 * Function: command_port * 590 1230 ************************************************************************** 591 1231 * Description: * … … 605 1245 * none * 606 1246 * * 607 **************************************************************************608 * Change History: *609 * 12/01/97 - Creation (JWJ) *610 1247 *************************************************************************/ 611 1248 static void 612 rtems_ftpd_command_port(char *bufr) 613 { 614 char *ip; 615 char *port; 616 int ip0, ip1, ip2, ip3, port0, port1; 617 rtems_status_code sc; 618 FTPD_SessionInfo_t *info = NULL; 619 620 621 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 622 (rtems_unsigned32 *)&info); 623 624 sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); 625 ip = (char *)&(info->data_addr.sin_addr); 626 ip[0] = ip0 & 0xff; 627 ip[1] = ip1 & 0xff; 628 ip[2] = ip2 & 0xff; 629 ip[3] = ip3 & 0xff; 630 port = (char *)&(info->data_addr.sin_port); 631 port[0] = port0 & 0xff; 632 port[1] = port1 & 0xff; 633 info->data_addr.sin_family = AF_INET; 634 } 635 1249 command_port(FTPD_SessionInfo_t *info, char *bufr) 1250 { 1251 char *ip; 1252 char *port; 1253 int ip0, ip1, ip2, ip3, port0, port1; 1254 1255 sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); 1256 ip = (char *)&(info->data_addr.sin_addr); 1257 ip[0] = ip0 & 0xff; 1258 ip[1] = ip1 & 0xff; 1259 ip[2] = ip2 & 0xff; 1260 ip[3] = ip3 & 0xff; 1261 port = (char *)&(info->data_addr.sin_port); 1262 port[0] = port0 & 0xff; 1263 port[1] = port1 & 0xff; 1264 info->data_addr.sin_family = AF_INET; 1265 } 1266 1267 1268 /*PAGE 1269 * 1270 * skip_options 1271 * 1272 * Utility routine to skip options (if any) from input command. 1273 * 1274 * Input parameters: 1275 * p - pointer to pointer to command 1276 * 1277 * Output parameters: 1278 * p - is changed to point to first non-option argument 1279 * 1280 */ 1281 static void 1282 skip_options(char **p) 1283 { 1284 char* buf = *p; 1285 while(1) { 1286 while(*buf == ' ') 1287 ++buf; 1288 if(*buf == '-') { 1289 if(*++buf == '-') { /* `--' should terminate options */ 1290 ++buf; 1291 while(*buf == ' ') 1292 ++buf; 1293 break; 1294 } 1295 while(*buf != ' ' && *buf != '\0') 1296 ++buf; 1297 } 1298 else 1299 break; 1300 } 1301 *p = buf; 1302 } 636 1303 637 1304 /************************************************************************** 638 * Function: rtems_ftpd_parse_command *1305 * Function: parse_command * 639 1306 ************************************************************************** 640 1307 * Description: * … … 655 1322 * none * 656 1323 * * 657 **************************************************************************658 * Change History: *659 * 12/01/97 - Creation (JWJ) *660 1324 *************************************************************************/ 661 1325 static void 662 rtems_ftpd_parse_command(char *bufr) 663 { 664 char fname[255]; 665 rtems_status_code sc; 666 FTPD_SessionInfo_t *info = NULL; 667 668 669 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 670 (rtems_unsigned32 *)&info); 671 672 if (!strncmp("PORT", bufr, 4)) 673 { 674 rtems_ftpd_send_reply(200, "PORT command successful."); 675 rtems_ftpd_command_port(&bufr[5]); 676 } 677 else if (!strncmp("RETR", bufr, 4)) 678 { 679 sscanf(&bufr[5], "%254s", fname); 680 rtems_ftpd_command_retrieve(fname); 681 } 682 else if (!strncmp("STOR", bufr, 4)) 683 { 684 sscanf(&bufr[5], "%254s", fname); 685 rtems_ftpd_command_store(fname); 686 } 687 else if (!strncmp("LIST", bufr, 4)) 688 { 689 if (bufr[5] == '\n') 690 { 691 rtems_ftpd_command_list("."); 692 } 693 else 694 { 695 sscanf(&bufr[5], "%254s", fname); 696 rtems_ftpd_command_list(fname); 697 } 698 } 699 else if (!strncmp("USER", bufr, 4)) 700 { 701 rtems_ftpd_send_reply(230, "User logged in."); 702 } 703 else if (!strncmp("SYST", bufr, 4)) 704 { 705 rtems_ftpd_send_reply(240, "RTEMS"); 706 } 707 else if (!strncmp("TYPE", bufr, 4)) 708 { 709 if (bufr[5] == 'I') 710 { 711 info->xfer_mode = TYPE_I; 712 rtems_ftpd_send_reply(200, "Type set to I."); 713 } 714 else if (bufr[5] == 'A') 715 { 716 info->xfer_mode = TYPE_A; 717 rtems_ftpd_send_reply(200, "Type set to A."); 718 } 719 else 720 { 721 info->xfer_mode = TYPE_I; 722 rtems_ftpd_send_reply(504, "Type not implemented. Set to I."); 723 } 724 } 725 else if (!strncmp("PASS", bufr, 4)) 726 { 727 rtems_ftpd_send_reply(230, "User logged in."); 728 } 729 else if (!strncmp("DELE", bufr, 4)) 730 { 731 sscanf(&bufr[4], "%254s", fname); 732 if (unlink(fname) == 0) 733 { 734 rtems_ftpd_send_reply(257, "DELE successful."); 735 } 736 else 737 { 738 rtems_ftpd_send_reply(550, "DELE failed."); 739 } 740 } 741 else if (!strncmp("SITE CHMOD", bufr, 10)) 742 { 743 int mask; 744 745 sscanf(&bufr[11], "%o %254s", &mask, fname); 746 if (chmod(fname, (mode_t)mask) == 0) 747 { 748 rtems_ftpd_send_reply(257, "CHMOD successful."); 749 } 750 else 751 { 752 rtems_ftpd_send_reply(550, "CHMOD failed."); 753 } 754 } 755 else if (!strncmp("RMD", bufr, 3)) 756 { 757 sscanf(&bufr[4], "%254s", fname); 758 if (rmdir(fname) == 0) 759 { 760 rtems_ftpd_send_reply(257, "RMD successful."); 761 } 762 else 763 { 764 rtems_ftpd_send_reply(550, "RMD failed."); 765 } 766 } 767 else if (!strncmp("MKD", bufr, 3)) 768 { 769 sscanf(&bufr[4], "%254s", fname); 770 if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 771 { 772 rtems_ftpd_send_reply(257, "MKD successful."); 773 } 774 else 775 { 776 rtems_ftpd_send_reply(550, "MKD failed."); 777 } 778 } 779 else if (!strncmp("CWD", bufr, 3)) 780 { 781 sscanf(&bufr[4], "%254s", fname); 782 rtems_ftpd_CWD(fname); 783 } 784 else if (!strncmp("PWD", bufr, 3)) 785 { 786 char *cwd = getcwd(0, 0); 787 sprintf(bufr, "\"%s\" is the current directory.", cwd); 788 rtems_ftpd_send_reply(250, bufr); 789 free(cwd); 790 } 791 else 792 { 793 rtems_ftpd_send_reply(500, "Unrecognized/unsupported command."); 794 } 1326 parse_command(FTPD_SessionInfo_t *info, char *bufr) 1327 { 1328 char fname[FTPD_BUFSIZE]; 1329 1330 if (!strncmp("PORT", bufr, 4)) 1331 { 1332 send_reply(info, 200, "PORT command successful."); 1333 command_port(info, &bufr[5]); 1334 } 1335 else if (!strncmp("RETR", bufr, 4)) 1336 { 1337 sscanf(&bufr[5], "%254s", fname); 1338 command_retrieve(info, fname); 1339 } 1340 else if (!strncmp("STOR", bufr, 4)) 1341 { 1342 sscanf(&bufr[5], "%254s", fname); 1343 command_store(info, fname); 1344 } 1345 else if (!strncmp("LIST", bufr, 4)) 1346 { 1347 bufr += 4; 1348 skip_options(&bufr); 1349 sscanf(bufr, "%254s", fname); 1350 command_list(info, fname, 1); 1351 } 1352 else if (!strncmp("NLST", bufr, 4)) 1353 { 1354 bufr += 4; 1355 skip_options(&bufr); 1356 sscanf(bufr, "%254s", fname); 1357 command_list(info, fname, 0); 1358 } 1359 else if (!strncmp("MDTM", bufr, 4)) 1360 { 1361 bufr += 4; 1362 skip_options(&bufr); 1363 sscanf(bufr, "%254s", fname); 1364 command_mdtm(info, fname); 1365 } 1366 else if (!strncmp("USER", bufr, 4)) 1367 { 1368 send_reply(info, 230, "User logged in."); 1369 } 1370 else if (!strncmp("SYST", bufr, 4)) 1371 { 1372 send_reply(info, 240, FTPD_SYSTYPE); 1373 } 1374 else if (!strncmp("TYPE", bufr, 4)) 1375 { 1376 if (bufr[5] == 'I') 1377 { 1378 info->xfer_mode = TYPE_I; 1379 send_reply(info, 200, "Type set to I."); 1380 } 1381 else if (bufr[5] == 'A') 1382 { 1383 /* FIXME: ASCII mode isn't actually supported yet. */ 1384 info->xfer_mode = TYPE_A; 1385 send_reply(info, 200, "Type set to A."); 1386 } 1387 else 1388 { 1389 info->xfer_mode = TYPE_I; 1390 send_reply(info, 504, "Type not implemented. Set to I."); 1391 } 1392 } 1393 else if (!strncmp("PASS", bufr, 4)) 1394 { 1395 send_reply(info, 230, "User logged in."); 1396 } 1397 else if (!strncmp("DELE", bufr, 4)) 1398 { 1399 sscanf(&bufr[4], "%254s", fname); 1400 if (unlink(fname) == 0) 1401 { 1402 send_reply(info, 257, "DELE successful."); 1403 } 1404 else 1405 { 1406 send_reply(info, 550, "DELE failed."); 1407 } 1408 } 1409 else if (!strncmp("SITE CHMOD", bufr, 10)) 1410 { 1411 int mask; 1412 1413 sscanf(&bufr[11], "%o %254s", &mask, fname); 1414 if (chmod(fname, (mode_t)mask) == 0) 1415 { 1416 send_reply(info, 257, "CHMOD successful."); 1417 } 1418 else 1419 { 1420 send_reply(info, 550, "CHMOD failed."); 1421 } 1422 } 1423 else if (!strncmp("RMD", bufr, 3)) 1424 { 1425 sscanf(&bufr[4], "%254s", fname); 1426 if (rmdir(fname) == 0) 1427 { 1428 send_reply(info, 257, "RMD successful."); 1429 } 1430 else 1431 { 1432 send_reply(info, 550, "RMD failed."); 1433 } 1434 } 1435 else if (!strncmp("MKD", bufr, 3)) 1436 { 1437 sscanf(&bufr[4], "%254s", fname); 1438 if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 1439 { 1440 send_reply(info, 257, "MKD successful."); 1441 } 1442 else 1443 { 1444 send_reply(info, 550, "MKD failed."); 1445 } 1446 } 1447 else if (!strncmp("CWD", bufr, 3)) 1448 { 1449 sscanf(&bufr[4], "%254s", fname); 1450 rtems_ftpd_cwd(info, fname); 1451 } 1452 else if (!strncmp("CDUP", bufr, 4)) 1453 { 1454 rtems_ftpd_cwd(info, ".."); 1455 } 1456 else if (!strncmp("PWD", bufr, 3)) 1457 { 1458 char const* cwd = "/"; 1459 if(info->cwd[0]) 1460 cwd = info->cwd; 1461 snprintf(bufr, FTPD_BUFSIZE, 1462 "\"%s\" is the current directory.", cwd); 1463 send_reply(info, 250, bufr); 1464 } 1465 else 1466 { 1467 send_reply(info, 500, "Unrecognized/unsupported command."); 1468 } 795 1469 } 796 1470 797 1471 798 1472 /************************************************************************** 799 * Function: rtems_ftpd_session *1473 * Function: session * 800 1474 ************************************************************************** 801 1475 * Description: * … … 817 1491 * none * 818 1492 * * 819 **************************************************************************820 * Change History: *821 * 12/01/97 - Creation (JWJ) *822 1493 *************************************************************************/ 823 1494 static void 824 rtems_ftpd_session(rtems_task_argument arg) 825 { 826 char cmd[256]; 827 rtems_status_code sc; 828 FTPD_SessionInfo_t *info = NULL; 829 830 831 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 832 (rtems_unsigned32 *)&info); 833 834 rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE); 835 836 /*********************************************************************** 837 * Set initial directory to "/". 838 **********************************************************************/ 839 strcpy(info->cwd, "/"); 840 info->xfer_mode = TYPE_A; 841 while (1) 842 { 843 if (fgets(cmd, 256, info->ctrl_fp) == NULL) 1495 session(rtems_task_argument arg) 1496 { 1497 char cmd[FTPD_BUFSIZE]; 1498 FTPD_SessionInfo_t *info = (FTPD_SessionInfo_t *)arg; 1499 rtems_event_set set; 1500 1501 while(1) { 1502 rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, 1503 &set); 1504 1505 send_reply(info, 220, FTPD_SERVER_MESSAGE); 1506 1507 info->cwd[0] = 0; 1508 info->xfer_mode = TYPE_I; 1509 1510 while (1) 1511 { 1512 if (fgets(cmd, FTPD_BUFSIZE, info->ctrl_fp) == NULL) 844 1513 { 845 846 1514 syslog(LOG_INFO, "ftpd: Connection aborted."); 1515 break; 847 1516 } 848 1517 849 1518 if (!strncmp("QUIT", cmd, 4)) 850 1519 { 851 rtems_ftpd_send_reply(221, "Goodbye.");852 1520 send_reply(info, 221, "Goodbye."); 1521 break; 853 1522 } 854 1523 else 855 1524 { 856 rtems_ftpd_parse_command(cmd);1525 parse_command(info, cmd); 857 1526 } 858 } 859 860 if (fclose(info->ctrl_fp) != 0) 861 { 862 syslog(LOG_ERR, "ftpd: Could not close session."); 863 } 864 865 866 /* Least we can do is put the CWD back to /. */ 867 chdir("/"); 868 869 /*********************************************************************** 870 * Free up the allocated SessionInfo struct and exit. 871 **********************************************************************/ 872 free(info); 873 sc = rtems_task_delete(RTEMS_SELF); 874 syslog(LOG_ERR, "ftpd: Task deletion failed: %s", 875 rtems_status_text(sc)); 1527 } 1528 1529 /* Close connection and put ourselves back into the task pool. */ 1530 close_stream(info); 1531 task_pool_release(info); 1532 } 876 1533 } 877 1534 878 1535 879 1536 /************************************************************************** 880 * Function: rtems_ftpd_daemon *1537 * Function: daemon * 881 1538 ************************************************************************** 882 1539 * Description: * … … 896 1553 * none * 897 1554 * * 898 **************************************************************************899 * Change History: *900 * 12/01/97 - Creation (JWJ) *901 1555 *************************************************************************/ 902 903 /* this is not prototyped in strict ansi mode */904 905 FILE *fdopen (int fildes, const char *mode);906 907 1556 static void 908 rtems_ftpd_daemon() 909 { 910 int s; 911 int s1; 912 int addrLen; 913 struct sockaddr_in remoteAddr; 914 struct sockaddr_in localAddr; 915 char sessionID; 916 rtems_task_priority priority; 917 rtems_status_code sc; 918 rtems_id tid; 919 FTPD_SessionInfo_t *info = NULL; 920 921 922 sessionID = 'a'; 923 924 s = socket(AF_INET, SOCK_STREAM, 0); 925 if (s < 0) 926 { 927 perror("Creating socket"); 928 } 929 930 localAddr.sin_family = AF_INET; 931 localAddr.sin_port = htons(rtems_ftpd_configuration.port); 932 localAddr.sin_addr.s_addr = INADDR_ANY; 933 memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero)); 934 if (bind(s, (struct sockaddr *)&localAddr, 935 sizeof(localAddr)) < 0) 936 { 937 perror("Binding control socket"); 938 } 939 940 if (listen(s, 2) < 0) 941 { 942 perror("Listening on control socket"); 943 } 944 945 while (1) 946 { 947 /******************************************************************** 948 * Allocate a SessionInfo structure for the session task. 949 *******************************************************************/ 950 info = (FTPD_SessionInfo_t *)malloc(sizeof(FTPD_SessionInfo_t)); 951 if (info == NULL) 1557 daemon() 1558 { 1559 int s; 1560 int addrLen; 1561 struct sockaddr_in remoteAddr; 1562 struct sockaddr_in localAddr; 1563 char sessionID; 1564 FTPD_SessionInfo_t *info = NULL; 1565 1566 1567 sessionID = 'a'; 1568 1569 s = socket(PF_INET, SOCK_STREAM, 0); 1570 if (s < 0) 1571 syslog(LOG_ERR, "ftpd: Error creating socket: %s", serr()); 1572 1573 localAddr.sin_family = AF_INET; 1574 localAddr.sin_port = htons(rtems_ftpd_configuration.port); 1575 localAddr.sin_addr.s_addr = htonl(INADDR_ANY); 1576 memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero)); 1577 1578 if (0 > bind(s, (struct sockaddr *)&localAddr, sizeof(localAddr))) 1579 syslog(LOG_ERR, "ftpd: Error binding control socket: %s", serr()); 1580 1581 if (0 > listen(s, 1)) 1582 syslog(LOG_ERR, "ftpd: Error listening on control socket: %s", serr()); 1583 1584 while (1) 1585 { 1586 int ss; 1587 addrLen = sizeof(remoteAddr); 1588 ss = accept(s, (struct sockaddr *)&remoteAddr, &addrLen); 1589 if (0 > ss) 1590 { 1591 syslog(LOG_ERR, "ftpd: Error accepting control connection: %s", serr()); 1592 } 1593 else 1594 { 1595 info = task_pool_obtain(); 1596 if (NULL == info) 952 1597 { 953 syslog(LOG_ERR, "ftpd: Could not allocate session info struct."); 954 rtems_panic("Malloc fail."); 955 } 956 957 /******************************************************************** 958 * Accept on the socket and start the session task. 959 *******************************************************************/ 960 addrLen = sizeof(remoteAddr); 961 s1 = accept(s, (struct sockaddr *)&remoteAddr, &addrLen); 962 if (s1 < 0) 963 { 964 perror("Accepting control connection"); 965 } 966 967 rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority); 968 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', sessionID), 969 priority, 8*1024, 970 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | 971 RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), 972 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 973 &tid); 974 if (sc != RTEMS_SUCCESSFUL) 975 { 976 syslog(LOG_ERR, "ftpd: Could not create FTPD session: %s", 977 rtems_status_text(sc)); 978 } 979 980 if (sessionID == 'z') 981 { 982 sessionID = 'a'; 1598 close_socket(ss); 983 1599 } 984 1600 else 985 1601 { 986 sessionID++; 1602 info->socket = ss; 1603 if ((info->ctrl_fp = fdopen(info->socket, "r+")) == NULL) 1604 { 1605 syslog(LOG_ERR, "ftpd: fdopen() on socket failed: %s", serr()); 1606 close_stream(info); 1607 task_pool_release(info); 1608 } 1609 else 1610 { 1611 /* Wakeup the session task. The task will call task_pool_release 1612 after it closes connection. */ 1613 rtems_event_send(info->tid, FTPD_RTEMS_EVENT); 1614 } 987 1615 } 988 989 /******************************************************************** 990 * Send the socket on to the new session. 991 *******************************************************************/ 992 if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL) 993 { 994 syslog(LOG_ERR, "ftpd: fdopen() on socket failed."); 995 close(s1); 996 } 997 else 998 { 999 sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0, 1000 (rtems_unsigned32)info); 1001 sc = rtems_task_start(tid, rtems_ftpd_session, 0); 1002 if (sc != RTEMS_SUCCESSFUL) 1003 { 1004 syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s", 1005 rtems_status_text(sc)); 1006 } 1007 } 1008 } 1616 } 1617 } 1009 1618 } 1010 1619 … … 1022 1631 * Inputs: * 1023 1632 * * 1024 * rtems_task_priority priority - Priority to assign to this task. *1025 * *1026 1633 * Output: * 1027 1634 * * 1028 1635 * int - RTEMS_SUCCESSFUL on successful start of the daemon. * 1029 1636 * * 1030 **************************************************************************1031 * Change History: *1032 * 12/01/97 - Creation (JWJ) *1033 1637 *************************************************************************/ 1034 1638 int 1035 1639 rtems_initialize_ftpd() 1036 1640 { 1037 rtems_status_code sc; 1038 rtems_id tid; 1039 1040 1041 if (rtems_ftpd_configuration.port == 0) 1042 { 1043 rtems_ftpd_configuration.port = FTPD_CONTROL_PORT; 1044 } 1045 1046 /*********************************************************************** 1047 * Default FTPD priority. 1048 **********************************************************************/ 1049 if (rtems_ftpd_configuration.priority == 0) 1050 { 1051 rtems_ftpd_configuration.priority = 40; 1052 } 1053 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), 1054 rtems_ftpd_configuration.priority, 8*1024, 1055 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | 1056 RTEMS_INTERRUPT_LEVEL(0), 1057 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 1058 &tid); 1059 if (sc != RTEMS_SUCCESSFUL) 1060 { 1061 syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s", 1062 rtems_status_text(sc)); 1063 return(RTEMS_UNSATISFIED); 1064 } 1065 1066 sc = rtems_task_start(tid, rtems_ftpd_daemon, 0); 1067 if (sc != RTEMS_SUCCESSFUL) 1068 { 1069 syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s", 1070 rtems_status_text(sc)); 1071 return(RTEMS_UNSATISFIED); 1072 } 1073 1074 syslog(LOG_INFO, "ftpd: FTP daemon started."); 1075 return(RTEMS_SUCCESSFUL); 1076 } 1077 1641 rtems_status_code sc; 1642 rtems_id tid; 1643 rtems_task_priority priority; 1644 int count; 1645 1646 if (rtems_ftpd_configuration.port == 0) 1647 { 1648 rtems_ftpd_configuration.port = FTPD_CONTROL_PORT; 1649 } 1650 1651 if (rtems_ftpd_configuration.priority == 0) 1652 { 1653 rtems_ftpd_configuration.priority = 40; 1654 } 1655 priority = rtems_ftpd_configuration.priority; 1656 1657 if (rtems_ftpd_configuration.tasks_count <= 0) 1658 rtems_ftpd_configuration.tasks_count = 1; 1659 count = rtems_ftpd_configuration.tasks_count; 1660 1661 if (!task_pool_init(count, priority)) 1662 { 1663 syslog(LOG_ERR, "ftpd: Could not initialize task pool."); 1664 return RTEMS_UNSATISFIED; 1665 } 1666 1667 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), 1668 priority, FTPD_STACKSIZE, 1669 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | 1670 RTEMS_INTERRUPT_LEVEL(0), 1671 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 1672 &tid); 1673 1674 if (sc == RTEMS_SUCCESSFUL) 1675 { 1676 sc = rtems_task_start(tid, daemon, 0); 1677 if (sc != RTEMS_SUCCESSFUL) 1678 rtems_task_delete(tid); 1679 } 1680 1681 if (sc != RTEMS_SUCCESSFUL) 1682 { 1683 task_pool_done(count); 1684 syslog(LOG_ERR, "ftpd: Could not create/start FTP daemon: %s", 1685 rtems_status_text(sc)); 1686 return RTEMS_UNSATISFIED; 1687 } 1688 1689 root[0] = '\0'; 1690 if ( 1691 rtems_ftpd_configuration.root && 1692 strlen(rtems_ftpd_configuration.root) < FTPD_BUFSIZE && 1693 rtems_ftpd_configuration.root[0] == '/') 1694 { 1695 strcpy(root, rtems_ftpd_configuration.root); 1696 squeeze_path(root); 1697 rtems_ftpd_configuration.root = root; 1698 } 1699 1700 syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)", 1701 count, ((count > 1) ? "s" : "")); 1702 return RTEMS_SUCCESSFUL; 1703 } -
c/src/libnetworking/rtems_servers/ftpd.h
rd1941587 r3f777d0e 26 26 int port; /* Well-known port */ 27 27 struct rtems_ftpd_hook *hooks; /* List of hooks */ 28 char const *root; /* Root for FTPD or 0 for / */ 29 int tasks_count; /* Max. connections */ 28 30 }; 29 31 -
cpukit/ftpd/ftpd.c
rd1941587 r3f777d0e 1 1 /* FIXME: 1. Parse command is a hack. We can do better. 2 * 2. chdir is a hack. We can do better. 3 * 3. PWD doesn't work. 4 * 4. Some sort of access control? 5 * 6 * FTP Server Daemon 2 * 2. Some sort of access control? 3 * 3. OSV: Timeouts on sockets. 4 * 4. OSV: hooks support seems to be a joke, as it requires storing of 5 * entire input file in memory. Seem to be better to change it to 6 * something more reasonable, like having 7 * 'hook_write(void const *buf, int count)' routine that will be 8 * called multiple times while file is being received. 9 * 5. OSV: Remove hack with "/dev/null"? 10 * 6. OSV: data_addr field of SessionInfo structure is not initialized. 11 * This will lead to undefined behavior if FTP client doesn't send 12 * PORT command. Seems we need to implement usage of default port 13 * (ftp port - 1). I didn't find any FTP client that doesn't send 14 * PORT command though. 15 * 7. OSV: while server claims TYPE ASCII command succeeds (to make 16 * happy some clients), ASCII mode isn't actually implemented. 17 * 8. Passive Mode? 18 * 19 * FTP Server Daemon 7 20 * 8 21 * Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu> 22 * 23 * Changed by: Sergei Organov <osv@javad.ru> (OSV) 24 * Changes: 25 * - use pool of pre-created threads to handle sessions 26 * - LIST output now similar to what "/bin/ls -al" would output, thus 27 * FTP clients could parse it. 28 * - LIST NAME now works (both for files and directories) 29 * - keep track of CWD for every session separately 30 * - ability to specify root directory name in configuration table 31 * - options sent in commands are ignored, thus LIST -al FILE works 32 * - added support for NLST, CDUP and MDTM commands 33 * - buffers are allocated on stack instead of heap where possible 34 * - drop using of task notepad to pass parameters - use function 35 * arguments instead 36 * - various bug-fixes, e.g., use of PF_INET in socket() instead of 37 * AF_INET, use snprintf() instead of sprintf() everywhere for safety, 38 * etc. 9 39 * 10 40 * $Id$ … … 25 55 * Organization: * 26 56 * * 27 * The FTP daemon is started upon boot. It runs all the time * 28 * and waits for connections on the known FTP port (21). When * 29 * a connection is made, it starts a 'session' task. That * 57 * The FTP daemon is started upon boot along with a (configurable) * 58 * number of tasks to handle sessions. It runs all the time and * 59 * waits for connections on the known FTP port (21). When * 60 * a connection is made, it wakeups a 'session' task. That * 30 61 * session then interacts with the remote host. When the session * 31 * is complete, the session task deletes itself. The daemon still*62 * is complete, the session task goes to sleep. The daemon still * 32 63 * runs, however. * 33 64 * * … … 38 69 * STOR xxx - Receives a file from the client. xxx = filename. * 39 70 * LIST xxx - Sends a file list to the client. * 40 * (LIST xxx isn't working yet...)*71 * NLST xxx - Sends a file list to the client. * 41 72 * USER - Does nothing. * 42 73 * PASS - Does nothing. * … … 47 78 * PWD - Print working directory. * 48 79 * CWD xxx - Change working directory. * 80 * CDUP - Change to upper directory. * 49 81 * SITE CHMOD xxx yyy - Change permissions on file yyy to xxx. * 50 82 * PORT a,b,c,d,x,y - Setup for a data port to IP address a.b.c.d * 51 83 * and port (x*256 + y). * 84 * MDTM xxx - Send date/time to the client. xxx = filename. * 52 85 * * 53 86 * * 54 87 * The public routines contained in this file are: * 55 88 * * 56 * rtems_initialize_ftpd_start - Starts the server daemon, then * 57 * returns to its caller. * 58 * * 59 * * 60 * The private routines contained in this file are: * 61 * * 62 * rtems_ftpd_send_reply - Sends a reply code and text through the * 63 * control port. * 64 * rtems_ftpd_command_retrieve - Performs to "RETR" command. * 65 * rtems_ftpd_command_store - Performs the "STOR" command. * 66 * rtems_ftpd_command_list - Performs the "LIST" command. * 67 * rtems_ftpd_command_port - Opens a data port (the "PORT" command). * 68 * rtems_ftpd_parse_command - Parses an incoming command. * 69 * rtmes_ftpd_session - Begins a service session. * 70 * rtems_ftpd_daemon - Listens on the FTP port for service * 71 * requests. * 89 * rtems_initialize_ftpd - Initializes and starts the server daemon, * 90 * then returns to its caller. * 91 * * 72 92 *------------------------------------------------------------------------* 73 93 * Jake Janovetz * … … 77 97 ************************************************************************** 78 98 * Change History: * 79 * 12/01/97 - Creation (JWJ) * 99 * 12/01/97 - Creation (JWJ) * 100 * 2001-01-08 - Changes by OSV * 80 101 *************************************************************************/ 81 82 #include <stdio.h>83 #include <stdlib.h>84 #include <string.h>85 #include <unistd.h>86 #include <fcntl.h>87 #include <dirent.h>88 89 #include <rtems.h>90 #include <rtems/rtems_bsdnet.h>91 #include <rtems/error.h>92 #include <syslog.h>93 94 #include <sys/types.h>95 #include <sys/socket.h>96 #include <arpa/ftp.h>97 #include <netinet/in.h>98 99 #include "ftpd.h"100 101 102 extern struct rtems_ftpd_configuration rtems_ftpd_configuration;103 102 104 103 /************************************************************************** … … 115 114 * not take place, but the error condition is temporary so the 116 115 * command can be reissued later. 117 * 5yz Permanent negative completion reply. The command was not 116 * 5yz Permanent negative completion reply. The command was not 118 117 * accepted and should not be retried. 119 118 *------------------------------------------------------------------------- … … 128 127 *************************************************************************/ 129 128 130 131 /************************************************************************** 132 * SessionInfo structure. 133 * 134 * The following structure is allocated for each session. The pointer 135 * to this structure is contained in the tasks notepad entry. 136 *************************************************************************/ 137 typedef struct 138 { 139 struct sockaddr_in data_addr; /* Data address for PORT commands */ 140 FILE *ctrl_fp; /* File pointer for control connection */ 141 char cwd[255]; /* Current working directory */ 142 /* Login -- future use -- */ 143 int xfer_mode; /* Transfer mode (ASCII/binary) */ 144 } FTPD_SessionInfo_t; 145 146 147 #define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.0-JWJ) ready." 129 #include <stdio.h> 130 #include <stdlib.h> 131 #include <string.h> 132 #include <unistd.h> 133 #include <fcntl.h> 134 #include <dirent.h> 135 #include <errno.h> 136 137 #include <rtems.h> 138 #include <rtems/rtems_bsdnet.h> 139 #include <rtems/error.h> 140 #include <syslog.h> 141 142 #include <sys/types.h> 143 #include <sys/socket.h> 144 #include <arpa/ftp.h> 145 #include <netinet/in.h> 146 147 #include "ftpd.h" 148 149 150 #ifdef __GNUC__ 151 /* change to #if 1 to disable syslog entirely */ 152 #if 0 153 #undef syslog 154 #define syslog(a, b, ...) while(0){} 155 #endif 156 #endif 157 158 #define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.1-JWJ) ready." 159 160 #define FTPD_SYSTYPE "RTEMS" 161 162 /* Seem to be unused */ 163 #if 0 148 164 #define FTPD_WELCOME_MESSAGE \ 149 165 "Welcome to the RTEMS FTP server.\n" \ 150 166 "\n" \ 151 167 "Login accepted.\n" 168 #endif 169 170 /* Various buffer sizes */ 171 enum 172 { 173 FTPD_BUFSIZE = 256, /* Size for temporary buffers */ 174 FTPD_DATASIZE = 1024, /* Size for file transfer buffers */ 175 FTPD_STACKSIZE = 8 * 1024, /* Tasks stack size */ 176 }; 177 178 /* Event to be used by session tasks for waiting */ 179 enum 180 { 181 FTPD_RTEMS_EVENT = RTEMS_EVENT_1 182 }; 183 184 /* Configuration table */ 185 extern struct rtems_ftpd_configuration rtems_ftpd_configuration; 186 187 /* this is not prototyped in strict ansi mode */ 188 FILE *fdopen (int fildes, const char *mode); 189 190 /* 191 * SessionInfo structure. 192 * 193 * The following structure is allocated for each session. 194 */ 195 typedef struct 196 { 197 struct sockaddr_in data_addr; /* Data address for PORT commands */ 198 FILE *ctrl_fp; /* File pointer for control connection */ 199 int socket; /* Socket descriptor for ctrl connection */ 200 char cwd[FTPD_BUFSIZE]; /* Current working directory */ 201 /* Login -- future use -- */ 202 int xfer_mode; /* Transfer mode (ASCII/binary) */ 203 rtems_id tid; /* Task id */ 204 } FTPD_SessionInfo_t; 205 206 207 /* 208 * TaskPool structure. 209 */ 210 typedef struct 211 { 212 FTPD_SessionInfo_t *info; 213 FTPD_SessionInfo_t **queue; 214 int count; 215 int head; 216 int tail; 217 rtems_id mutex; 218 rtems_id sem; 219 } FTPD_TaskPool_t; 220 221 /* 222 * Task pool instance. 223 */ 224 static FTPD_TaskPool_t task_pool; 225 226 /* 227 * Root node for FTPD without trailing slash. Even '/' node is denoted as 228 * empty string here. 229 */ 230 static char root[FTPD_BUFSIZE]; 231 232 233 /*PAGE 234 * 235 * serr 236 * 237 * Return errror string corresponding to current 'errno'. 238 * 239 */ 240 static char const* 241 serr(void) 242 { 243 return strerror(errno); 244 } 245 246 247 /* 248 * Utility routines to manage root directory and session local 249 * current working directory. 250 */ 251 252 253 /*PAGE 254 * 255 * squeeze_path 256 * 257 * Squeezes path according to OS rules, i.e., eliminates /./, /../, and // 258 * from the path. Does nothing if the path is relative, i.e. doesn't begin 259 * with '/'. The trailing slash is always removed, even when alone, i.e. "/" 260 * will be "" after squeeze. 261 * 262 * Input parameters: 263 * path - the path to be squeezed 264 * 265 * Output parameters: 266 * path - squeezed path 267 * 268 */ 269 static void 270 squeeze_path(char* path) 271 { 272 if(path[0] == '/') 273 { 274 char* e = path + 1; 275 int rest = strlen(e); 276 while(rest >= 0) 277 { 278 int len; 279 char* s = e; 280 e = strchr(s, '/'); 281 if(e) 282 ++e; 283 else 284 e = s + rest + 1; 285 len = e - s; 286 rest -= len; 287 if(len == 1 || (len == 2 && s[0] == '.')) 288 { 289 if(rest >= 0) 290 memmove(s, e, rest + 1); 291 else 292 *s++ = '\0'; 293 e = s; 294 } 295 else if(len == 3 && s[0] == '.' && s[1] == '.') 296 { 297 char* ps = s; 298 if(ps - 1 > path) { 299 do 300 --ps; 301 while(ps[-1] != '/'); 302 } 303 if(rest >= 0) 304 memmove(ps, e, rest + 1); 305 else 306 *ps++ = '\0'; 307 e = ps; 308 } 309 } 310 if(e[-2] == '/') 311 e[-2] = '\0'; 312 } 313 } 314 315 316 /*PAGE 317 * 318 * make_path 319 * 320 * Makes full path given file name, current working directory and root 321 * directory (file scope variable 'root'). 322 * 323 * Input parameters: 324 * cwd - current working directory 325 * name - file name 326 * root (file scope variable) - FTPD root directory 327 * 328 * Output parameters: 329 * buf - full path 330 * returns pointer to non-root part of the 'buf', i.e. to first character 331 * different from '/' after root part. 332 * 333 */ 334 static char const* 335 make_path(char* buf, char const* cwd, char const* name) 336 { 337 char* res = NULL; 338 339 int rlen = strlen(root); 340 int clen = strlen(cwd); 341 int nlen = strlen(name); 342 int len = rlen + nlen; 343 344 if (name[0] != '/') 345 { 346 ++len; 347 if (clen > 0) 348 len += clen + 1; 349 } 350 351 if (FTPD_BUFSIZE > len) 352 { 353 char* b = buf; 354 memcpy(b, root, rlen); b += rlen; 355 if (name[0] != '/') 356 { 357 *b++ = '/'; 358 if (clen > 0) 359 { 360 memcpy(b, cwd, clen); b += clen; 361 *b++ = '/'; 362 } 363 } 364 memcpy(b, name, nlen); b += nlen; 365 *b = '\0'; 366 367 res = buf + rlen; 368 while(rlen-- > 0 && res[-1] == '/') 369 --res; 370 squeeze_path(res); 371 } 372 373 return res; 374 } 375 376 /* 377 * Task pool management routines 378 */ 379 380 381 /*PAGE 382 * 383 * task_pool_done 384 * 385 * Cleanup task pool. 386 * 387 * Input parameters: 388 * count - number of entries in task pool to cleanup 389 * 390 * Output parameters: 391 * NONE 392 * 393 */ 394 static void 395 task_pool_done(int count) 396 { 397 int i; 398 for(i = 0; i < count; ++i) 399 rtems_task_delete(task_pool.info[i].tid); 400 if(task_pool.info) 401 free(task_pool.info); 402 if(task_pool.queue) 403 free(task_pool.queue); 404 if(task_pool.mutex != (rtems_id)-1) 405 rtems_semaphore_delete(task_pool.mutex); 406 if(task_pool.sem != (rtems_id)-1) 407 rtems_semaphore_delete(task_pool.sem); 408 task_pool.info = 0; 409 task_pool.queue = 0; 410 task_pool.count = 0; 411 task_pool.sem = -1; 412 task_pool.mutex = -1; 413 } 414 415 /* Forward declare */ 416 static void session(rtems_task_argument arg); 417 418 /*PAGE 419 * 420 * task_pool_init 421 * 422 * Initialize task pool. 423 * 424 * Input parameters: 425 * count - number of entries in task pool to create 426 * priority - priority tasks are started with 427 * 428 * Output parameters: 429 * returns 1 on success, 0 on failure. 430 * 431 */ 432 static int 433 task_pool_init(int count, rtems_task_priority priority) 434 { 435 int i; 436 rtems_status_code sc; 437 char id = 'a'; 438 439 task_pool.count = 0; 440 task_pool.head = task_pool.tail = 0; 441 task_pool.mutex = (rtems_id)-1; 442 task_pool.sem = (rtems_id)-1; 443 444 sc = rtems_semaphore_create( 445 rtems_build_name('F', 'T', 'P', 'M'), 446 1, 447 RTEMS_DEFAULT_ATTRIBUTES 448 | RTEMS_BINARY_SEMAPHORE 449 | RTEMS_INHERIT_PRIORITY 450 | RTEMS_PRIORITY, 451 RTEMS_NO_PRIORITY, 452 &task_pool.mutex); 453 454 if(sc == RTEMS_SUCCESSFUL) 455 sc = rtems_semaphore_create( 456 rtems_build_name('F', 'T', 'P', 'S'), 457 count, 458 RTEMS_DEFAULT_ATTRIBUTES, 459 RTEMS_NO_PRIORITY, 460 &task_pool.sem); 461 462 if(sc != RTEMS_SUCCESSFUL) { 463 task_pool_done(0); 464 syslog(LOG_ERR, "ftpd: Can not create semaphores"); 465 return 0; 466 } 467 468 task_pool.info = (FTPD_SessionInfo_t*) 469 malloc(sizeof(FTPD_SessionInfo_t) * count); 470 task_pool.queue = (FTPD_SessionInfo_t**) 471 malloc(sizeof(FTPD_SessionInfo_t*) * count); 472 if (NULL == task_pool.info || NULL == task_pool.queue) 473 { 474 task_pool_done(0); 475 syslog(LOG_ERR, "ftpd: Not enough memory"); 476 return 0; 477 } 478 479 for(i = 0; i < count; ++i) 480 { 481 FTPD_SessionInfo_t *info = &task_pool.info[i]; 482 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', id), 483 priority, FTPD_STACKSIZE, 484 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | 485 RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), 486 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 487 &info->tid); 488 if (sc == RTEMS_SUCCESSFUL) 489 { 490 sc = rtems_task_start( 491 info->tid, session, (rtems_task_argument)info); 492 if (sc != RTEMS_SUCCESSFUL) 493 task_pool_done(i); 494 } 495 else 496 task_pool_done(i + 1); 497 if (sc != RTEMS_SUCCESSFUL) 498 { 499 syslog(LOG_ERR, "ftpd: Could not create/start FTPD session: %s", 500 rtems_status_text(sc)); 501 return 0; 502 } 503 task_pool.queue[i] = task_pool.info + i; 504 info->ctrl_fp = NULL; 505 info->socket = -1; 506 if (++id > 'z') 507 id = 'a'; 508 } 509 task_pool.count = count; 510 return 1; 511 } 512 513 /*PAGE 514 * 515 * task_pool_obtain 516 * 517 * Obtain free task from task pool. 518 * 519 * Input parameters: 520 * NONE 521 * 522 * Output parameters: 523 * returns pointer to the corresponding SessionInfo structure on success, 524 * NULL if there are no free tasks in the pool. 525 * 526 */ 527 static FTPD_SessionInfo_t* 528 task_pool_obtain() 529 { 530 FTPD_SessionInfo_t* info = 0; 531 rtems_status_code sc; 532 sc = rtems_semaphore_obtain(task_pool.sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); 533 if (sc == RTEMS_SUCCESSFUL) 534 { 535 rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 536 info = task_pool.queue[task_pool.head]; 537 if(++task_pool.head >= task_pool.count) 538 task_pool.head = 0; 539 info->socket = -1; 540 info->ctrl_fp = NULL; 541 rtems_semaphore_release(task_pool.mutex); 542 } 543 return info; 544 } 545 546 /*PAGE 547 * 548 * task_pool_release 549 * 550 * Return task obtained by 'obtain()' back to the task pool. 551 * 552 * Input parameters: 553 * info - pointer to corresponding SessionInfo structure. 554 * 555 * Output parameters: 556 * NONE 557 * 558 */ 559 static void 560 task_pool_release(FTPD_SessionInfo_t* info) 561 { 562 rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 563 task_pool.queue[task_pool.tail] = info; 564 if(++task_pool.tail >= task_pool.count) 565 task_pool.tail = 0; 566 rtems_semaphore_release(task_pool.mutex); 567 rtems_semaphore_release(task_pool.sem); 568 } 569 570 /* 571 * End of task pool routines 572 */ 573 574 /*PAGE 575 * 576 * close_socket 577 * 578 * Close socket. 579 * 580 * Input parameters: 581 * s - socket descriptor to be closed. 582 * 583 * Output parameters: 584 * returns 1 on success, 0 on failure 585 * 586 */ 587 static int 588 close_socket(int s) 589 { 590 if (0 <= s) 591 { 592 if (0 != close(s)) 593 { 594 shutdown(s, 2); 595 if (0 != close(s)) 596 return 0; 597 } 598 } 599 return 1; 600 } 601 602 /*PAGE 603 * 604 * close_stream 605 * 606 * Close data stream of session. 607 * 608 * Input parameters: 609 * info - corresponding SessionInfo structure 610 * 611 * Output parameters: 612 * NONE 613 * 614 */ 615 static void 616 close_stream(FTPD_SessionInfo_t* info) 617 { 618 if (NULL != info->ctrl_fp) 619 { 620 if (0 != fclose(info->ctrl_fp)) 621 { 622 syslog(LOG_ERR, "ftpd: Could not close control stream: %s", serr()); 623 } 624 else 625 info->socket = -1; 626 } 627 628 if (!close_socket(info->socket)) 629 syslog(LOG_ERR, "ftpd: Could not close control socket: %s", serr()); 630 631 info->ctrl_fp = NULL; 632 info->socket = -1; 633 } 152 634 153 635 154 636 /************************************************************************** 155 * Function: rtems_ftpd_send_reply*637 * Function: send_reply * 156 638 ************************************************************************** 157 639 * Description: * … … 170 652 * none * 171 653 * * 172 **************************************************************************173 * Change History: *174 * 12/01/97 - Creation (JWJ) *175 654 *************************************************************************/ 176 655 static void 177 rtems_ftpd_send_reply(int code, char *text) 178 { 179 rtems_status_code sc; 180 FTPD_SessionInfo_t *info = NULL; 181 char str[80]; 182 183 184 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 185 (rtems_unsigned32 *)&info); 186 187 /*********************************************************************** 188 * code must be a 3-digit number. 189 **********************************************************************/ 190 if ((code < 100) || (code > 999)) 191 { 192 syslog(LOG_ERR, "ftpd: Code not 3-digits."); 193 return; 194 } 195 196 /*********************************************************************** 197 * If a text reply exists, add it to the reply data. 198 **********************************************************************/ 199 if (text != NULL) 200 { 201 sprintf(str, "%d %.70s\r\n", code, text); 202 fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text); 203 } 204 else 205 { 206 sprintf(str, "%d\r\n", code); 207 fprintf(info->ctrl_fp, "%d\r\n", code); 208 } 209 fflush(info->ctrl_fp); 210 } 211 656 send_reply(FTPD_SessionInfo_t *info, int code, char *text) 657 { 658 char const* s; 659 660 661 /*********************************************************************** 662 * code must be a 3-digit number. 663 **********************************************************************/ 664 if ((code < 100) || (code > 999)) 665 { 666 syslog(LOG_ERR, "ftpd: Code not 3-digits."); 667 return; 668 } 669 670 /*********************************************************************** 671 * If a text reply exists, add it to the reply data. 672 **********************************************************************/ 673 s = (info->xfer_mode == TYPE_A) ? "\r" : ""; 674 if (text != NULL) 675 fprintf(info->ctrl_fp, "%d %.70s%s\n", code, text, s); 676 else 677 fprintf(info->ctrl_fp, "%d%s\n", code, s); 678 fflush(info->ctrl_fp); 679 } 680 681 682 /*PAGE 683 * 684 * send_mode_reply 685 * 686 * Sends BINARY/ASCII reply string depending on current transfer mode. 687 * 688 * Input parameters: 689 * info - corresponding SessionInfo structure 690 * 691 * Output parameters: 692 * NONE 693 * 694 */ 695 static void 696 send_mode_reply(FTPD_SessionInfo_t *info) 697 { 698 if(info->xfer_mode == TYPE_I) 699 send_reply(info, 150, "Opening BINARY mode data connection."); 700 else 701 send_reply(info, 150, "Opening ASCII mode data connection."); 702 } 703 704 /*PAGE 705 * 706 * data_socket 707 * 708 * Create data socket for session. 709 * 710 * Input parameters: 711 * info - corresponding SessionInfo structure 712 * 713 * Output parameters: 714 * returns socket descriptor, or -1 if failure 715 * 716 */ 717 static int 718 data_socket(FTPD_SessionInfo_t *info) 719 { 720 int s = socket(PF_INET, SOCK_STREAM, 0); 721 if(0 > s) 722 send_reply(info, 420, "Server error - could not create socket."); 723 else if(0 > connect(s, (struct sockaddr *)&info->data_addr, 724 sizeof(struct sockaddr))) 725 { 726 send_reply(info, 420, "Server error - could not connect socket."); 727 close_socket(s); 728 s = -1; 729 } 730 return s; 731 } 212 732 213 733 /************************************************************************** 214 * Function: rtems_ftpd_command_retrieve*734 * Function: command_retrieve * 215 735 ************************************************************************** 216 736 * Description: * … … 230 750 * 1 for no reply sent. * 231 751 * * 232 **************************************************************************233 * Change History: *234 * 04/29/98 - Creation (JWJ) *235 752 *************************************************************************/ 236 753 static int 237 rtems_ftpd_command_retrieve(char *filename) 238 { 239 int s; 240 int n; 241 int fd; 242 unsigned char *bufr; 243 rtems_status_code sc; 244 FTPD_SessionInfo_t *info = NULL; 245 246 247 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 248 (rtems_unsigned32 *)&info); 249 250 if ((fd = open(filename, O_RDONLY)) == -1) 251 { 252 rtems_ftpd_send_reply(450, "Error opening file."); 253 return(0); 254 } 255 256 bufr = (unsigned char *)malloc(BUFSIZ); 257 if (bufr == NULL) 258 { 259 rtems_ftpd_send_reply(440, "Server error - malloc fail."); 260 close(fd); 261 return(0); 262 } 263 264 /*********************************************************************** 265 * Connect to the data connection (PORT made in an earlier PORT call). 266 **********************************************************************/ 267 rtems_ftpd_send_reply(150, "BINARY data connection."); 268 s = socket(AF_INET, SOCK_STREAM, 0); 269 if (connect(s, (struct sockaddr *)&info->data_addr, 270 sizeof(struct sockaddr)) < 0) 271 { 272 rtems_ftpd_send_reply(420, "Server error - could not connect socket."); 273 free(bufr); 274 close(fd); 275 close(s); 276 return(1); 277 } 278 279 /*********************************************************************** 280 * Send the data over the ether. 281 **********************************************************************/ 282 while ((n = read(fd, bufr, BUFSIZ)) > 0) 283 { 284 send(s, bufr, n, 0); 285 bufr[n-1] = '\0'; 286 } 287 288 if (n == 0) 289 { 290 rtems_ftpd_send_reply(210, "File sent successfully."); 291 } 292 else 293 { 294 rtems_ftpd_send_reply(450, "Retrieve failed."); 295 } 296 297 if (close(s) != 0) 298 { 299 syslog(LOG_ERR, "ftpd: Error closing data socket"); 300 } 301 302 free(bufr); 303 close(fd); 304 return(0); 754 command_retrieve(FTPD_SessionInfo_t *info, char *filename) 755 { 756 int s = -1; 757 int n; 758 int fd = -1; 759 char buf[FTPD_DATASIZE]; 760 int res = 0; 761 762 char const* r = make_path(buf, info->cwd, filename); 763 764 if (NULL == r || 0 > (fd = open(buf, O_RDONLY))) 765 { 766 send_reply(info, 450, "Error opening file."); 767 return(res); 768 } 769 770 send_mode_reply(info); 771 772 /*********************************************************************** 773 * Connect to the data connection (PORT made in an earlier PORT call). 774 **********************************************************************/ 775 s = data_socket(info); 776 if (0 <= s) 777 { 778 /*********************************************************************** 779 * Send the data over the ether. 780 **********************************************************************/ 781 while ((n = read(fd, buf, FTPD_DATASIZE)) > 0) 782 { 783 send(s, buf, n, 0); 784 } 785 786 if (0 == n) 787 { 788 if (0 == close(fd)) 789 { 790 fd = -1; 791 res = 1; 792 } 793 } 794 } 795 796 if (0 == res) 797 send_reply(info, 450, "Retrieve failed."); 798 else 799 send_reply(info, 210, "File sent successfully."); 800 801 if (-1 != fd) 802 close(fd); 803 804 if (!close_socket(s)) 805 syslog(LOG_ERR, "ftpd: Error closing data socket"); 806 807 return(res); 305 808 } 306 809 307 810 308 811 /************************************************************************** 309 * Function: rtems_ftpd_command_store*812 * Function: command_store * 310 813 ************************************************************************** 311 814 * Description: * … … 325 828 * 1 for failure. * 326 829 * * 327 **************************************************************************328 * Change History: *329 * 12/01/97 - Creation (JWJ) *330 830 *************************************************************************/ 331 831 static int 332 rtems_ftpd_command_store(char *filename) 333 { 334 char *bufr; 335 int s; 336 int n; 337 unsigned long size = 0; 338 rtems_status_code sc; 339 FTPD_SessionInfo_t *info = NULL; 340 struct rtems_ftpd_hook *usehook = NULL; 341 342 343 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 344 (rtems_unsigned32 *)&info); 345 346 bufr = (char *)malloc(BUFSIZ * sizeof(char)); 347 if (bufr == NULL) 348 { 349 rtems_ftpd_send_reply(440, "Server error - malloc fail."); 832 command_store(FTPD_SessionInfo_t *info, char *filename) 833 { 834 int s; 835 int n; 836 unsigned long size = 0; 837 struct rtems_ftpd_hook *usehook = NULL; 838 char buf[FTPD_DATASIZE]; 839 840 int null = !strcmp("/dev/null", filename); 841 842 if(!null) 843 { 844 if (NULL == make_path(buf, info->cwd, filename)) 845 { 846 send_reply(info, 450, "Error creating file."); 847 return(0); 848 } 849 } 850 851 send_mode_reply(info); 852 853 s = data_socket(info); 854 if(0 > s) 855 { 856 return(1); 857 } 858 859 860 /*********************************************************************** 861 * File: "/dev/null" just throws the data away. 862 * Otherwise, search our list of hooks to see if we need to do something 863 * special. 864 * OSV: FIXME: this is hack. Using /dev/null filesystem entry would be 865 * better. However, it's not clear how to handle root directory 866 * other than '/' then. 867 **********************************************************************/ 868 if (null) 869 { 870 while ((n = read(s, buf, FTPD_DATASIZE)) > 0); 871 } 872 else if (rtems_ftpd_configuration.hooks != NULL) 873 { 874 struct rtems_ftpd_hook *hook; 875 int i; 876 877 i = 0; 878 hook = &rtems_ftpd_configuration.hooks[i++]; 879 while (hook->filename != NULL) 880 { 881 if (!strcmp(hook->filename, buf)) 882 { 883 usehook = hook; 884 break; 885 } 886 hook = &rtems_ftpd_configuration.hooks[i++]; 887 } 888 } 889 890 if (usehook != NULL) 891 { 892 /* 893 * OSV: FIXME: Small buffer could be used and hook routine 894 * called multiple times instead. Alternatively, the support could be 895 * removed entirely in favor of configuring RTEMS pseudo-device with 896 * given name. 897 */ 898 899 char *bigBufr; 900 size_t filesize = rtems_ftpd_configuration.max_hook_filesize + 1; 901 902 /*********************************************************************** 903 * Allocate space for our "file". 904 **********************************************************************/ 905 bigBufr = (char *)malloc(filesize); 906 if (bigBufr == NULL) 907 { 908 send_reply(info, 440, "Server error - malloc fail."); 350 909 return(1); 351 } 352 353 rtems_ftpd_send_reply(150, "BINARY data connection."); 354 355 s = socket(AF_INET, SOCK_STREAM, 0); 356 if (connect(s, (struct sockaddr *)&info->data_addr, 357 sizeof(struct sockaddr)) < 0) 358 { 359 free(bufr); 360 close(s); 910 } 911 912 /*********************************************************************** 913 * Retrieve the file into our buffer space. 914 **********************************************************************/ 915 size = 0; 916 while ((n = read(s, bigBufr + size, filesize - size)) > 0) 917 { 918 size += n; 919 } 920 if (size >= filesize) 921 { 922 send_reply(info, 440, "Server error - Buffer size exceeded."); 923 free(bigBufr); 924 close_socket(s); 361 925 return(1); 362 } 363 364 365 /*********************************************************************** 366 * File: "/dev/null" just throws the data away. 367 * Otherwise, search our list of hooks to see if we need to do something 368 * special. 369 **********************************************************************/ 370 if (!strncmp("/dev/null", filename, 9)) 371 { 372 while ((n = read(s, bufr, BUFSIZ)) > 0); 373 } 374 else if (rtems_ftpd_configuration.hooks != NULL) 375 { 376 struct rtems_ftpd_hook *hook; 377 int i; 378 379 i = 0; 380 hook = &rtems_ftpd_configuration.hooks[i++]; 381 while (hook->filename != NULL) 926 } 927 close_socket(s); 928 929 /*********************************************************************** 930 * Call our hook. 931 **********************************************************************/ 932 if ((usehook->hook_function)(bigBufr, size) == 0) 933 { 934 send_reply(info, 210, "File transferred successfully."); 935 } 936 else 937 { 938 send_reply(info, 440, "File transfer failed."); 939 } 940 free(bigBufr); 941 } 942 else 943 { 944 int fd = 945 creat(buf, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 946 947 if (0 > fd) 948 { 949 send_reply(info, 450, "Error creating file."); 950 close_socket(s); 951 return(0); 952 } 953 954 while ((n = read(s, buf, FTPD_DATASIZE)) > 0) 955 { 956 if (0 > write(fd, buf, n)) 382 957 { 383 if (!strcmp(hook->filename, filename)) 384 { 385 usehook = hook; 386 break; 387 } 388 hook = &rtems_ftpd_configuration.hooks[i++]; 958 send_reply(info, 450, "Error during write."); 959 close(fd); 960 close_socket(s); 961 return(1); 389 962 } 390 } 391 392 if (usehook != NULL) 393 { 394 char *bigBufr; 395 396 /*********************************************************************** 397 * Allocate space for our "file". 398 **********************************************************************/ 399 bigBufr = (char *)malloc( 400 rtems_ftpd_configuration.max_hook_filesize * sizeof(char)); 401 if (bigBufr == NULL) 963 } 964 if (0 > close(fd)) 965 { 966 send_reply(info, 450, "Error during write."); 967 close_socket(s); 968 return(1); 969 } 970 close_socket(s); 971 send_reply(info, 226, "Transfer complete."); 972 } 973 974 return(0); 975 } 976 977 978 /*PAGE 979 * 980 * send_dirline 981 * 982 * Sends one line of LIST command reply corresponding to single file. 983 * 984 * Input parameters: 985 * s - socket descriptor to send data to 986 * wide - if 0, send only file name. If not 0, send 'stat' info as well in 987 * "ls -l" format. 988 * curTime - current time 989 * path - path to be prepended to what is given by 'add' 990 * add - path to be appended to what is given by 'path', the resulting path 991 * is then passed to 'stat()' routine 992 * name - file name to be reported in output 993 * buf - buffer for temporary data 994 * 995 * Output parameters: 996 * NONE 997 * 998 */ 999 static void 1000 send_dirline(int s, int wide, time_t curTime, char const* path, 1001 char const* add, char const* fname, char* buf) 1002 { 1003 if(wide) 1004 { 1005 struct stat stat_buf; 1006 1007 int plen = strlen(path); 1008 int alen = strlen(add); 1009 if(plen == 0) 1010 { 1011 buf[plen++] = '/'; 1012 buf[plen] = '\0'; 1013 } 1014 else 1015 { 1016 strcpy(buf, path); 1017 if(alen > 0 && buf[plen - 1] != '/') 402 1018 { 403 rtems_ftpd_send_reply(440, "Server error - malloc fail."); 404 free(bufr); 405 return(1); 1019 buf[plen++] = '/'; 1020 if(plen >= FTPD_BUFSIZE) 1021 return; 1022 buf[plen] = '\0'; 406 1023 } 407 408 /*********************************************************************** 409 * Retrieve the file into our buffer space. 410 **********************************************************************/ 411 size = 0; 412 while ((n = read(s, bufr, BUFSIZ)) > 0) 413 { 414 if (size + n > 415 rtems_ftpd_configuration.max_hook_filesize * sizeof(char)) 416 { 417 rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded."); 418 free(bufr); 419 free(bigBufr); 420 close(s); 421 return(1); 422 } 423 memcpy(&bigBufr[size], bufr, n); 424 size += n; 425 } 426 close(s); 427 428 /*********************************************************************** 429 * Call our hook. 430 **********************************************************************/ 431 if ((usehook->hook_function)(bigBufr, size) == 0) 432 { 433 rtems_ftpd_send_reply(210, "File transferred successfully."); 434 } 1024 } 1025 if(plen + alen >= FTPD_BUFSIZE) 1026 return; 1027 strcpy(buf + plen, add); 1028 1029 if (stat(buf, &stat_buf) == 0) 1030 { 1031 int len; 1032 struct tm bt; 1033 time_t tf = stat_buf.st_mtime; 1034 enum { SIZE = 80 }; 1035 enum { SIX_MONTHS = 365*24*60*60/2 }; 1036 char timeBuf[SIZE]; 1037 gmtime_r(&tf, &bt); 1038 if(curTime > tf + SIX_MONTHS || tf > curTime + SIX_MONTHS) 1039 strftime (timeBuf, SIZE, "%b %d %Y", &bt); 435 1040 else 436 { 437 rtems_ftpd_send_reply(440, "File transfer failed."); 438 } 439 free(bigBufr); 440 } 441 else 442 { 443 int fd; 444 size_t written; 445 446 fd = creat(filename, S_IRUSR | S_IWUSR | 447 S_IRGRP | S_IWGRP | 448 S_IROTH | S_IWOTH); 449 if (fd == -1) 450 { 451 rtems_ftpd_send_reply(450, "Could not open file."); 452 close(s); 453 free(bufr); 454 return(1); 455 } 456 while ((n = read(s, bufr, BUFSIZ)) > 0) 457 { 458 written = write(fd, bufr, n); 459 if (written == -1) 460 { 461 rtems_ftpd_send_reply(450, "Error during write."); 462 close(fd); 463 close(s); 464 free(bufr); 465 return(1); 466 } 467 } 468 close(fd); 469 close(s); 470 rtems_ftpd_send_reply(226, "Transfer complete."); 471 } 472 473 free(bufr); 474 return(0); 475 } 476 1041 strftime (timeBuf, SIZE, "%b %d %H:%M", &bt); 1042 1043 len = snprintf(buf, FTPD_BUFSIZE, 1044 "%c%c%c%c%c%c%c%c%c%c 1 %5d %5d %11u %s %s\r\n", 1045 (S_ISLNK(stat_buf.st_mode)?('l'): 1046 (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), 1047 (stat_buf.st_mode & S_IRUSR)?('r'):('-'), 1048 (stat_buf.st_mode & S_IWUSR)?('w'):('-'), 1049 (stat_buf.st_mode & S_IXUSR)?('x'):('-'), 1050 (stat_buf.st_mode & S_IRGRP)?('r'):('-'), 1051 (stat_buf.st_mode & S_IWGRP)?('w'):('-'), 1052 (stat_buf.st_mode & S_IXGRP)?('x'):('-'), 1053 (stat_buf.st_mode & S_IROTH)?('r'):('-'), 1054 (stat_buf.st_mode & S_IWOTH)?('w'):('-'), 1055 (stat_buf.st_mode & S_IXOTH)?('x'):('-'), 1056 (int)stat_buf.st_uid, 1057 (int)stat_buf.st_gid, 1058 (int)stat_buf.st_size, 1059 timeBuf, 1060 fname 1061 ); 1062 1063 send(s, buf, len, 0); 1064 } 1065 } 1066 else 1067 { 1068 int len = snprintf(buf, FTPD_BUFSIZE, "%s\r\n", fname); 1069 send(s, buf, len, 0); 1070 } 1071 } 477 1072 478 1073 /************************************************************************** 479 * Function: rtems_ftpd_command_list *1074 * Function: command_list * 480 1075 ************************************************************************** 481 1076 * Description: * … … 493 1088 * none * 494 1089 * * 495 **************************************************************************496 * Change History: *497 * 12/01/97 - Creation (JWJ) *498 1090 *************************************************************************/ 499 1091 static void 500 rtems_ftpd_command_list(char *fname) 501 { 502 int s; 503 rtems_status_code sc; 504 FTPD_SessionInfo_t *info = NULL; 505 DIR *dirp; 506 struct dirent *dp; 507 char dirline[255]; 508 struct stat stat_buf; 509 510 511 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 512 (rtems_unsigned32 *)&info); 513 514 rtems_ftpd_send_reply(150, "ASCII data connection for LIST."); 515 516 s = socket(AF_INET, SOCK_STREAM, 0); 517 if (connect(s, (struct sockaddr *)&info->data_addr, 518 sizeof(struct sockaddr)) < 0) 519 { 520 syslog(LOG_ERR, "ftpd: Error connecting to data socket."); 521 return; 522 } 523 524 if ((dirp = opendir(fname)) == NULL) 525 { 526 sprintf(dirline, "%s: No such file or directory.%s\n", 527 fname, (info->xfer_mode==TYPE_A)?("\r"):("")); 528 send(s, dirline, strlen(dirline), 0); 529 close(s); 530 rtems_ftpd_send_reply(226, "Transfer complete."); 531 return; 532 } 533 while ((dp = readdir(dirp)) != NULL) 534 { 535 if (stat(dp->d_name, &stat_buf) == 0) 536 { 537 sprintf(dirline, "%c%c%c%c%c%c%c%c%c%c %5d %5d %11d %s%s\n", 538 (S_ISLNK(stat_buf.st_mode)?('l'): 539 (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), 540 (stat_buf.st_mode & S_IRUSR)?('r'):('-'), 541 (stat_buf.st_mode & S_IWUSR)?('w'):('-'), 542 (stat_buf.st_mode & S_IXUSR)?('x'):('-'), 543 (stat_buf.st_mode & S_IRGRP)?('r'):('-'), 544 (stat_buf.st_mode & S_IWGRP)?('w'):('-'), 545 (stat_buf.st_mode & S_IXGRP)?('x'):('-'), 546 (stat_buf.st_mode & S_IROTH)?('r'):('-'), 547 (stat_buf.st_mode & S_IWOTH)?('w'):('-'), 548 (stat_buf.st_mode & S_IXOTH)?('x'):('-'), 549 (int)stat_buf.st_uid, 550 (int)stat_buf.st_gid, 551 (int)stat_buf.st_size, 552 dp->d_name, 553 (info->xfer_mode==TYPE_A)?("\r"):("")); 554 send(s, dirline, strlen(dirline), 0); 555 } 556 } 557 closedir(dirp); 558 559 close(s); 560 rtems_ftpd_send_reply(226, "Transfer complete."); 561 } 562 563 564 /* 565 * Cheesy way to change directories 1092 command_list(FTPD_SessionInfo_t *info, char const *fname, int wide) 1093 { 1094 int s; 1095 DIR *dirp = 0; 1096 struct dirent *dp = 0; 1097 struct stat stat_buf; 1098 char buf[FTPD_BUFSIZE]; 1099 char path[FTPD_BUFSIZE]; 1100 time_t curTime; 1101 char const* res; 1102 char const* cwd = info->cwd; 1103 1104 send_reply(info, 150, "Opening ASCII mode data connection for LIST."); 1105 1106 s = data_socket(info); 1107 if(0 > s) 1108 { 1109 syslog(LOG_ERR, "ftpd: Error connecting to data socket."); 1110 return; 1111 } 1112 1113 if(fname[0] == '\0') 1114 fname = "."; 1115 1116 res = make_path(path, cwd, fname); 1117 1118 if (NULL == res || 0 > stat(path, &stat_buf)) 1119 { 1120 snprintf(buf, FTPD_BUFSIZE, 1121 "%s: No such file or directory.\r\n", fname); 1122 send(s, buf, strlen(buf), 0); 1123 } 1124 else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(path)))) 1125 { 1126 snprintf(buf, FTPD_BUFSIZE, 1127 "%s: Can not open directory.\r\n", fname); 1128 send(s, buf, strlen(buf), 0); 1129 } 1130 else 1131 { 1132 time(&curTime); 1133 if(!dirp) 1134 send_dirline(s, wide, curTime, path, "", fname, buf); 1135 else { 1136 /* FIXME: need "." and ".." only when '-a' option is given */ 1137 send_dirline(s, wide, curTime, path, "", ".", buf); 1138 if(!strcmp(path, root)) 1139 send_dirline(s, wide, curTime, path, "", "..", buf); 1140 else 1141 send_dirline(s, wide, curTime, path, "..", "..", buf); 1142 while ((dp = readdir(dirp)) != NULL) 1143 send_dirline(s, wide, curTime, path, dp->d_name, dp->d_name, buf); 1144 } 1145 } 1146 1147 if(dirp) 1148 closedir(dirp); 1149 close_socket(s); 1150 send_reply(info, 226, "Transfer complete."); 1151 } 1152 1153 1154 /*PAGE 1155 * 1156 * rtems_ftpd_cwd 1157 * 1158 * Change current working directory. We use 'chdir' here only to validate the 1159 * new directory. We keep track of current working directory ourselves because 1160 * current working directory in RTEMS isn't thread local, but we need it to be 1161 * session local. 1162 * 1163 * Input parameters: 1164 * info - corresponding SessionInfo structure 1165 * dir - directory name passed in CWD command 1166 * 1167 * Output parameters: 1168 * info->cwd is set to new CWD value. 1169 * 566 1170 */ 567 1171 static void 568 rtems_ftpd_CWD(char *dir) 569 { 570 rtems_status_code sc; 571 FTPD_SessionInfo_t *info = NULL; 572 573 574 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 575 (rtems_unsigned32 *)&info); 576 577 if (chdir(dir) == 0) 578 { 579 rtems_ftpd_send_reply(250, "CWD command successful."); 580 } 581 else 582 { 583 rtems_ftpd_send_reply(550, "CWD command failed."); 584 } 585 } 586 1172 rtems_ftpd_cwd(FTPD_SessionInfo_t *info, char *dir) 1173 { 1174 char buf[FTPD_BUFSIZE]; 1175 char const* cwd = make_path(buf, info->cwd, dir); 1176 if(cwd && chdir(buf) == 0) 1177 { 1178 send_reply(info, 250, "CWD command successful."); 1179 strcpy(info->cwd, cwd); 1180 } 1181 else 1182 { 1183 send_reply(info, 550, "CWD command failed."); 1184 } 1185 } 1186 1187 1188 1189 /*PAGE 1190 * 1191 * command_mdtm 1192 * 1193 * Handle FTP MDTM command 1194 * 1195 * Input parameters: 1196 * info - corresponding SessionInfo structure 1197 * fname - file name passed in MDTM command 1198 * 1199 * Output parameters: 1200 * info->cwd is set to new CWD value. 1201 * 1202 */ 1203 static void 1204 command_mdtm(FTPD_SessionInfo_t *info, char const* fname) 1205 { 1206 struct stat stbuf; 1207 char buf[FTPD_BUFSIZE]; 1208 1209 if(*fname == '\0') 1210 fname = "."; 1211 1212 if (stat(fname, &stbuf) < 0) 1213 { 1214 snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr()); 1215 send_reply(info, 550, buf); 1216 } 1217 else 1218 { 1219 struct tm *t = gmtime(&stbuf.st_mtime); 1220 snprintf(buf, FTPD_BUFSIZE, "%04d%02d%02d%02d%02d%02d", 1221 1900 + t->tm_year, 1222 t->tm_mon+1, t->tm_mday, 1223 t->tm_hour, t->tm_min, t->tm_sec); 1224 send_reply(info, 213, buf); 1225 } 1226 } 587 1227 588 1228 /************************************************************************** 589 * Function: rtems_ftpd_command_port*1229 * Function: command_port * 590 1230 ************************************************************************** 591 1231 * Description: * … … 605 1245 * none * 606 1246 * * 607 **************************************************************************608 * Change History: *609 * 12/01/97 - Creation (JWJ) *610 1247 *************************************************************************/ 611 1248 static void 612 rtems_ftpd_command_port(char *bufr) 613 { 614 char *ip; 615 char *port; 616 int ip0, ip1, ip2, ip3, port0, port1; 617 rtems_status_code sc; 618 FTPD_SessionInfo_t *info = NULL; 619 620 621 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 622 (rtems_unsigned32 *)&info); 623 624 sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); 625 ip = (char *)&(info->data_addr.sin_addr); 626 ip[0] = ip0 & 0xff; 627 ip[1] = ip1 & 0xff; 628 ip[2] = ip2 & 0xff; 629 ip[3] = ip3 & 0xff; 630 port = (char *)&(info->data_addr.sin_port); 631 port[0] = port0 & 0xff; 632 port[1] = port1 & 0xff; 633 info->data_addr.sin_family = AF_INET; 634 } 635 1249 command_port(FTPD_SessionInfo_t *info, char *bufr) 1250 { 1251 char *ip; 1252 char *port; 1253 int ip0, ip1, ip2, ip3, port0, port1; 1254 1255 sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); 1256 ip = (char *)&(info->data_addr.sin_addr); 1257 ip[0] = ip0 & 0xff; 1258 ip[1] = ip1 & 0xff; 1259 ip[2] = ip2 & 0xff; 1260 ip[3] = ip3 & 0xff; 1261 port = (char *)&(info->data_addr.sin_port); 1262 port[0] = port0 & 0xff; 1263 port[1] = port1 & 0xff; 1264 info->data_addr.sin_family = AF_INET; 1265 } 1266 1267 1268 /*PAGE 1269 * 1270 * skip_options 1271 * 1272 * Utility routine to skip options (if any) from input command. 1273 * 1274 * Input parameters: 1275 * p - pointer to pointer to command 1276 * 1277 * Output parameters: 1278 * p - is changed to point to first non-option argument 1279 * 1280 */ 1281 static void 1282 skip_options(char **p) 1283 { 1284 char* buf = *p; 1285 while(1) { 1286 while(*buf == ' ') 1287 ++buf; 1288 if(*buf == '-') { 1289 if(*++buf == '-') { /* `--' should terminate options */ 1290 ++buf; 1291 while(*buf == ' ') 1292 ++buf; 1293 break; 1294 } 1295 while(*buf != ' ' && *buf != '\0') 1296 ++buf; 1297 } 1298 else 1299 break; 1300 } 1301 *p = buf; 1302 } 636 1303 637 1304 /************************************************************************** 638 * Function: rtems_ftpd_parse_command *1305 * Function: parse_command * 639 1306 ************************************************************************** 640 1307 * Description: * … … 655 1322 * none * 656 1323 * * 657 **************************************************************************658 * Change History: *659 * 12/01/97 - Creation (JWJ) *660 1324 *************************************************************************/ 661 1325 static void 662 rtems_ftpd_parse_command(char *bufr) 663 { 664 char fname[255]; 665 rtems_status_code sc; 666 FTPD_SessionInfo_t *info = NULL; 667 668 669 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 670 (rtems_unsigned32 *)&info); 671 672 if (!strncmp("PORT", bufr, 4)) 673 { 674 rtems_ftpd_send_reply(200, "PORT command successful."); 675 rtems_ftpd_command_port(&bufr[5]); 676 } 677 else if (!strncmp("RETR", bufr, 4)) 678 { 679 sscanf(&bufr[5], "%254s", fname); 680 rtems_ftpd_command_retrieve(fname); 681 } 682 else if (!strncmp("STOR", bufr, 4)) 683 { 684 sscanf(&bufr[5], "%254s", fname); 685 rtems_ftpd_command_store(fname); 686 } 687 else if (!strncmp("LIST", bufr, 4)) 688 { 689 if (bufr[5] == '\n') 690 { 691 rtems_ftpd_command_list("."); 692 } 693 else 694 { 695 sscanf(&bufr[5], "%254s", fname); 696 rtems_ftpd_command_list(fname); 697 } 698 } 699 else if (!strncmp("USER", bufr, 4)) 700 { 701 rtems_ftpd_send_reply(230, "User logged in."); 702 } 703 else if (!strncmp("SYST", bufr, 4)) 704 { 705 rtems_ftpd_send_reply(240, "RTEMS"); 706 } 707 else if (!strncmp("TYPE", bufr, 4)) 708 { 709 if (bufr[5] == 'I') 710 { 711 info->xfer_mode = TYPE_I; 712 rtems_ftpd_send_reply(200, "Type set to I."); 713 } 714 else if (bufr[5] == 'A') 715 { 716 info->xfer_mode = TYPE_A; 717 rtems_ftpd_send_reply(200, "Type set to A."); 718 } 719 else 720 { 721 info->xfer_mode = TYPE_I; 722 rtems_ftpd_send_reply(504, "Type not implemented. Set to I."); 723 } 724 } 725 else if (!strncmp("PASS", bufr, 4)) 726 { 727 rtems_ftpd_send_reply(230, "User logged in."); 728 } 729 else if (!strncmp("DELE", bufr, 4)) 730 { 731 sscanf(&bufr[4], "%254s", fname); 732 if (unlink(fname) == 0) 733 { 734 rtems_ftpd_send_reply(257, "DELE successful."); 735 } 736 else 737 { 738 rtems_ftpd_send_reply(550, "DELE failed."); 739 } 740 } 741 else if (!strncmp("SITE CHMOD", bufr, 10)) 742 { 743 int mask; 744 745 sscanf(&bufr[11], "%o %254s", &mask, fname); 746 if (chmod(fname, (mode_t)mask) == 0) 747 { 748 rtems_ftpd_send_reply(257, "CHMOD successful."); 749 } 750 else 751 { 752 rtems_ftpd_send_reply(550, "CHMOD failed."); 753 } 754 } 755 else if (!strncmp("RMD", bufr, 3)) 756 { 757 sscanf(&bufr[4], "%254s", fname); 758 if (rmdir(fname) == 0) 759 { 760 rtems_ftpd_send_reply(257, "RMD successful."); 761 } 762 else 763 { 764 rtems_ftpd_send_reply(550, "RMD failed."); 765 } 766 } 767 else if (!strncmp("MKD", bufr, 3)) 768 { 769 sscanf(&bufr[4], "%254s", fname); 770 if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 771 { 772 rtems_ftpd_send_reply(257, "MKD successful."); 773 } 774 else 775 { 776 rtems_ftpd_send_reply(550, "MKD failed."); 777 } 778 } 779 else if (!strncmp("CWD", bufr, 3)) 780 { 781 sscanf(&bufr[4], "%254s", fname); 782 rtems_ftpd_CWD(fname); 783 } 784 else if (!strncmp("PWD", bufr, 3)) 785 { 786 char *cwd = getcwd(0, 0); 787 sprintf(bufr, "\"%s\" is the current directory.", cwd); 788 rtems_ftpd_send_reply(250, bufr); 789 free(cwd); 790 } 791 else 792 { 793 rtems_ftpd_send_reply(500, "Unrecognized/unsupported command."); 794 } 1326 parse_command(FTPD_SessionInfo_t *info, char *bufr) 1327 { 1328 char fname[FTPD_BUFSIZE]; 1329 1330 if (!strncmp("PORT", bufr, 4)) 1331 { 1332 send_reply(info, 200, "PORT command successful."); 1333 command_port(info, &bufr[5]); 1334 } 1335 else if (!strncmp("RETR", bufr, 4)) 1336 { 1337 sscanf(&bufr[5], "%254s", fname); 1338 command_retrieve(info, fname); 1339 } 1340 else if (!strncmp("STOR", bufr, 4)) 1341 { 1342 sscanf(&bufr[5], "%254s", fname); 1343 command_store(info, fname); 1344 } 1345 else if (!strncmp("LIST", bufr, 4)) 1346 { 1347 bufr += 4; 1348 skip_options(&bufr); 1349 sscanf(bufr, "%254s", fname); 1350 command_list(info, fname, 1); 1351 } 1352 else if (!strncmp("NLST", bufr, 4)) 1353 { 1354 bufr += 4; 1355 skip_options(&bufr); 1356 sscanf(bufr, "%254s", fname); 1357 command_list(info, fname, 0); 1358 } 1359 else if (!strncmp("MDTM", bufr, 4)) 1360 { 1361 bufr += 4; 1362 skip_options(&bufr); 1363 sscanf(bufr, "%254s", fname); 1364 command_mdtm(info, fname); 1365 } 1366 else if (!strncmp("USER", bufr, 4)) 1367 { 1368 send_reply(info, 230, "User logged in."); 1369 } 1370 else if (!strncmp("SYST", bufr, 4)) 1371 { 1372 send_reply(info, 240, FTPD_SYSTYPE); 1373 } 1374 else if (!strncmp("TYPE", bufr, 4)) 1375 { 1376 if (bufr[5] == 'I') 1377 { 1378 info->xfer_mode = TYPE_I; 1379 send_reply(info, 200, "Type set to I."); 1380 } 1381 else if (bufr[5] == 'A') 1382 { 1383 /* FIXME: ASCII mode isn't actually supported yet. */ 1384 info->xfer_mode = TYPE_A; 1385 send_reply(info, 200, "Type set to A."); 1386 } 1387 else 1388 { 1389 info->xfer_mode = TYPE_I; 1390 send_reply(info, 504, "Type not implemented. Set to I."); 1391 } 1392 } 1393 else if (!strncmp("PASS", bufr, 4)) 1394 { 1395 send_reply(info, 230, "User logged in."); 1396 } 1397 else if (!strncmp("DELE", bufr, 4)) 1398 { 1399 sscanf(&bufr[4], "%254s", fname); 1400 if (unlink(fname) == 0) 1401 { 1402 send_reply(info, 257, "DELE successful."); 1403 } 1404 else 1405 { 1406 send_reply(info, 550, "DELE failed."); 1407 } 1408 } 1409 else if (!strncmp("SITE CHMOD", bufr, 10)) 1410 { 1411 int mask; 1412 1413 sscanf(&bufr[11], "%o %254s", &mask, fname); 1414 if (chmod(fname, (mode_t)mask) == 0) 1415 { 1416 send_reply(info, 257, "CHMOD successful."); 1417 } 1418 else 1419 { 1420 send_reply(info, 550, "CHMOD failed."); 1421 } 1422 } 1423 else if (!strncmp("RMD", bufr, 3)) 1424 { 1425 sscanf(&bufr[4], "%254s", fname); 1426 if (rmdir(fname) == 0) 1427 { 1428 send_reply(info, 257, "RMD successful."); 1429 } 1430 else 1431 { 1432 send_reply(info, 550, "RMD failed."); 1433 } 1434 } 1435 else if (!strncmp("MKD", bufr, 3)) 1436 { 1437 sscanf(&bufr[4], "%254s", fname); 1438 if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 1439 { 1440 send_reply(info, 257, "MKD successful."); 1441 } 1442 else 1443 { 1444 send_reply(info, 550, "MKD failed."); 1445 } 1446 } 1447 else if (!strncmp("CWD", bufr, 3)) 1448 { 1449 sscanf(&bufr[4], "%254s", fname); 1450 rtems_ftpd_cwd(info, fname); 1451 } 1452 else if (!strncmp("CDUP", bufr, 4)) 1453 { 1454 rtems_ftpd_cwd(info, ".."); 1455 } 1456 else if (!strncmp("PWD", bufr, 3)) 1457 { 1458 char const* cwd = "/"; 1459 if(info->cwd[0]) 1460 cwd = info->cwd; 1461 snprintf(bufr, FTPD_BUFSIZE, 1462 "\"%s\" is the current directory.", cwd); 1463 send_reply(info, 250, bufr); 1464 } 1465 else 1466 { 1467 send_reply(info, 500, "Unrecognized/unsupported command."); 1468 } 795 1469 } 796 1470 797 1471 798 1472 /************************************************************************** 799 * Function: rtems_ftpd_session *1473 * Function: session * 800 1474 ************************************************************************** 801 1475 * Description: * … … 817 1491 * none * 818 1492 * * 819 **************************************************************************820 * Change History: *821 * 12/01/97 - Creation (JWJ) *822 1493 *************************************************************************/ 823 1494 static void 824 rtems_ftpd_session(rtems_task_argument arg) 825 { 826 char cmd[256]; 827 rtems_status_code sc; 828 FTPD_SessionInfo_t *info = NULL; 829 830 831 sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0, 832 (rtems_unsigned32 *)&info); 833 834 rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE); 835 836 /*********************************************************************** 837 * Set initial directory to "/". 838 **********************************************************************/ 839 strcpy(info->cwd, "/"); 840 info->xfer_mode = TYPE_A; 841 while (1) 842 { 843 if (fgets(cmd, 256, info->ctrl_fp) == NULL) 1495 session(rtems_task_argument arg) 1496 { 1497 char cmd[FTPD_BUFSIZE]; 1498 FTPD_SessionInfo_t *info = (FTPD_SessionInfo_t *)arg; 1499 rtems_event_set set; 1500 1501 while(1) { 1502 rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, 1503 &set); 1504 1505 send_reply(info, 220, FTPD_SERVER_MESSAGE); 1506 1507 info->cwd[0] = 0; 1508 info->xfer_mode = TYPE_I; 1509 1510 while (1) 1511 { 1512 if (fgets(cmd, FTPD_BUFSIZE, info->ctrl_fp) == NULL) 844 1513 { 845 846 1514 syslog(LOG_INFO, "ftpd: Connection aborted."); 1515 break; 847 1516 } 848 1517 849 1518 if (!strncmp("QUIT", cmd, 4)) 850 1519 { 851 rtems_ftpd_send_reply(221, "Goodbye.");852 1520 send_reply(info, 221, "Goodbye."); 1521 break; 853 1522 } 854 1523 else 855 1524 { 856 rtems_ftpd_parse_command(cmd);1525 parse_command(info, cmd); 857 1526 } 858 } 859 860 if (fclose(info->ctrl_fp) != 0) 861 { 862 syslog(LOG_ERR, "ftpd: Could not close session."); 863 } 864 865 866 /* Least we can do is put the CWD back to /. */ 867 chdir("/"); 868 869 /*********************************************************************** 870 * Free up the allocated SessionInfo struct and exit. 871 **********************************************************************/ 872 free(info); 873 sc = rtems_task_delete(RTEMS_SELF); 874 syslog(LOG_ERR, "ftpd: Task deletion failed: %s", 875 rtems_status_text(sc)); 1527 } 1528 1529 /* Close connection and put ourselves back into the task pool. */ 1530 close_stream(info); 1531 task_pool_release(info); 1532 } 876 1533 } 877 1534 878 1535 879 1536 /************************************************************************** 880 * Function: rtems_ftpd_daemon *1537 * Function: daemon * 881 1538 ************************************************************************** 882 1539 * Description: * … … 896 1553 * none * 897 1554 * * 898 **************************************************************************899 * Change History: *900 * 12/01/97 - Creation (JWJ) *901 1555 *************************************************************************/ 902 903 /* this is not prototyped in strict ansi mode */904 905 FILE *fdopen (int fildes, const char *mode);906 907 1556 static void 908 rtems_ftpd_daemon() 909 { 910 int s; 911 int s1; 912 int addrLen; 913 struct sockaddr_in remoteAddr; 914 struct sockaddr_in localAddr; 915 char sessionID; 916 rtems_task_priority priority; 917 rtems_status_code sc; 918 rtems_id tid; 919 FTPD_SessionInfo_t *info = NULL; 920 921 922 sessionID = 'a'; 923 924 s = socket(AF_INET, SOCK_STREAM, 0); 925 if (s < 0) 926 { 927 perror("Creating socket"); 928 } 929 930 localAddr.sin_family = AF_INET; 931 localAddr.sin_port = htons(rtems_ftpd_configuration.port); 932 localAddr.sin_addr.s_addr = INADDR_ANY; 933 memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero)); 934 if (bind(s, (struct sockaddr *)&localAddr, 935 sizeof(localAddr)) < 0) 936 { 937 perror("Binding control socket"); 938 } 939 940 if (listen(s, 2) < 0) 941 { 942 perror("Listening on control socket"); 943 } 944 945 while (1) 946 { 947 /******************************************************************** 948 * Allocate a SessionInfo structure for the session task. 949 *******************************************************************/ 950 info = (FTPD_SessionInfo_t *)malloc(sizeof(FTPD_SessionInfo_t)); 951 if (info == NULL) 1557 daemon() 1558 { 1559 int s; 1560 int addrLen; 1561 struct sockaddr_in remoteAddr; 1562 struct sockaddr_in localAddr; 1563 char sessionID; 1564 FTPD_SessionInfo_t *info = NULL; 1565 1566 1567 sessionID = 'a'; 1568 1569 s = socket(PF_INET, SOCK_STREAM, 0); 1570 if (s < 0) 1571 syslog(LOG_ERR, "ftpd: Error creating socket: %s", serr()); 1572 1573 localAddr.sin_family = AF_INET; 1574 localAddr.sin_port = htons(rtems_ftpd_configuration.port); 1575 localAddr.sin_addr.s_addr = htonl(INADDR_ANY); 1576 memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero)); 1577 1578 if (0 > bind(s, (struct sockaddr *)&localAddr, sizeof(localAddr))) 1579 syslog(LOG_ERR, "ftpd: Error binding control socket: %s", serr()); 1580 1581 if (0 > listen(s, 1)) 1582 syslog(LOG_ERR, "ftpd: Error listening on control socket: %s", serr()); 1583 1584 while (1) 1585 { 1586 int ss; 1587 addrLen = sizeof(remoteAddr); 1588 ss = accept(s, (struct sockaddr *)&remoteAddr, &addrLen); 1589 if (0 > ss) 1590 { 1591 syslog(LOG_ERR, "ftpd: Error accepting control connection: %s", serr()); 1592 } 1593 else 1594 { 1595 info = task_pool_obtain(); 1596 if (NULL == info) 952 1597 { 953 syslog(LOG_ERR, "ftpd: Could not allocate session info struct."); 954 rtems_panic("Malloc fail."); 955 } 956 957 /******************************************************************** 958 * Accept on the socket and start the session task. 959 *******************************************************************/ 960 addrLen = sizeof(remoteAddr); 961 s1 = accept(s, (struct sockaddr *)&remoteAddr, &addrLen); 962 if (s1 < 0) 963 { 964 perror("Accepting control connection"); 965 } 966 967 rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority); 968 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', sessionID), 969 priority, 8*1024, 970 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | 971 RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), 972 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 973 &tid); 974 if (sc != RTEMS_SUCCESSFUL) 975 { 976 syslog(LOG_ERR, "ftpd: Could not create FTPD session: %s", 977 rtems_status_text(sc)); 978 } 979 980 if (sessionID == 'z') 981 { 982 sessionID = 'a'; 1598 close_socket(ss); 983 1599 } 984 1600 else 985 1601 { 986 sessionID++; 1602 info->socket = ss; 1603 if ((info->ctrl_fp = fdopen(info->socket, "r+")) == NULL) 1604 { 1605 syslog(LOG_ERR, "ftpd: fdopen() on socket failed: %s", serr()); 1606 close_stream(info); 1607 task_pool_release(info); 1608 } 1609 else 1610 { 1611 /* Wakeup the session task. The task will call task_pool_release 1612 after it closes connection. */ 1613 rtems_event_send(info->tid, FTPD_RTEMS_EVENT); 1614 } 987 1615 } 988 989 /******************************************************************** 990 * Send the socket on to the new session. 991 *******************************************************************/ 992 if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL) 993 { 994 syslog(LOG_ERR, "ftpd: fdopen() on socket failed."); 995 close(s1); 996 } 997 else 998 { 999 sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0, 1000 (rtems_unsigned32)info); 1001 sc = rtems_task_start(tid, rtems_ftpd_session, 0); 1002 if (sc != RTEMS_SUCCESSFUL) 1003 { 1004 syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s", 1005 rtems_status_text(sc)); 1006 } 1007 } 1008 } 1616 } 1617 } 1009 1618 } 1010 1619 … … 1022 1631 * Inputs: * 1023 1632 * * 1024 * rtems_task_priority priority - Priority to assign to this task. *1025 * *1026 1633 * Output: * 1027 1634 * * 1028 1635 * int - RTEMS_SUCCESSFUL on successful start of the daemon. * 1029 1636 * * 1030 **************************************************************************1031 * Change History: *1032 * 12/01/97 - Creation (JWJ) *1033 1637 *************************************************************************/ 1034 1638 int 1035 1639 rtems_initialize_ftpd() 1036 1640 { 1037 rtems_status_code sc; 1038 rtems_id tid; 1039 1040 1041 if (rtems_ftpd_configuration.port == 0) 1042 { 1043 rtems_ftpd_configuration.port = FTPD_CONTROL_PORT; 1044 } 1045 1046 /*********************************************************************** 1047 * Default FTPD priority. 1048 **********************************************************************/ 1049 if (rtems_ftpd_configuration.priority == 0) 1050 { 1051 rtems_ftpd_configuration.priority = 40; 1052 } 1053 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), 1054 rtems_ftpd_configuration.priority, 8*1024, 1055 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | 1056 RTEMS_INTERRUPT_LEVEL(0), 1057 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 1058 &tid); 1059 if (sc != RTEMS_SUCCESSFUL) 1060 { 1061 syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s", 1062 rtems_status_text(sc)); 1063 return(RTEMS_UNSATISFIED); 1064 } 1065 1066 sc = rtems_task_start(tid, rtems_ftpd_daemon, 0); 1067 if (sc != RTEMS_SUCCESSFUL) 1068 { 1069 syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s", 1070 rtems_status_text(sc)); 1071 return(RTEMS_UNSATISFIED); 1072 } 1073 1074 syslog(LOG_INFO, "ftpd: FTP daemon started."); 1075 return(RTEMS_SUCCESSFUL); 1076 } 1077 1641 rtems_status_code sc; 1642 rtems_id tid; 1643 rtems_task_priority priority; 1644 int count; 1645 1646 if (rtems_ftpd_configuration.port == 0) 1647 { 1648 rtems_ftpd_configuration.port = FTPD_CONTROL_PORT; 1649 } 1650 1651 if (rtems_ftpd_configuration.priority == 0) 1652 { 1653 rtems_ftpd_configuration.priority = 40; 1654 } 1655 priority = rtems_ftpd_configuration.priority; 1656 1657 if (rtems_ftpd_configuration.tasks_count <= 0) 1658 rtems_ftpd_configuration.tasks_count = 1; 1659 count = rtems_ftpd_configuration.tasks_count; 1660 1661 if (!task_pool_init(count, priority)) 1662 { 1663 syslog(LOG_ERR, "ftpd: Could not initialize task pool."); 1664 return RTEMS_UNSATISFIED; 1665 } 1666 1667 sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'), 1668 priority, FTPD_STACKSIZE, 1669 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | 1670 RTEMS_INTERRUPT_LEVEL(0), 1671 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, 1672 &tid); 1673 1674 if (sc == RTEMS_SUCCESSFUL) 1675 { 1676 sc = rtems_task_start(tid, daemon, 0); 1677 if (sc != RTEMS_SUCCESSFUL) 1678 rtems_task_delete(tid); 1679 } 1680 1681 if (sc != RTEMS_SUCCESSFUL) 1682 { 1683 task_pool_done(count); 1684 syslog(LOG_ERR, "ftpd: Could not create/start FTP daemon: %s", 1685 rtems_status_text(sc)); 1686 return RTEMS_UNSATISFIED; 1687 } 1688 1689 root[0] = '\0'; 1690 if ( 1691 rtems_ftpd_configuration.root && 1692 strlen(rtems_ftpd_configuration.root) < FTPD_BUFSIZE && 1693 rtems_ftpd_configuration.root[0] == '/') 1694 { 1695 strcpy(root, rtems_ftpd_configuration.root); 1696 squeeze_path(root); 1697 rtems_ftpd_configuration.root = root; 1698 } 1699 1700 syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)", 1701 count, ((count > 1) ? "s" : "")); 1702 return RTEMS_SUCCESSFUL; 1703 } -
cpukit/ftpd/ftpd.h
rd1941587 r3f777d0e 26 26 int port; /* Well-known port */ 27 27 struct rtems_ftpd_hook *hooks; /* List of hooks */ 28 char const *root; /* Root for FTPD or 0 for / */ 29 int tasks_count; /* Max. connections */ 28 30 }; 29 31 -
cpukit/libnetworking/ChangeLog
rd1941587 r3f777d0e 1 2001-01-12 Sergei Organov <osv@javad.ru> 2 3 * rtems_servers/ftpd.c, rtems_servers/ftpd.h: Major enhancements 4 as listed below: 5 - use pool of pre-created threads to handle sessions instead of 6 creating/deleting threads on the fly 7 - LIST output is now similar to what "/bin/ls -al" would output, 8 thus FTP clients such Netscape are happy with it. 9 - LIST NAME now works (both for files and directories) 10 - added support for NLST, CDUP, and MDTM FTP commands to make 11 more FTP clients happy 12 - keep track of CWD for every session separately 13 - ability to specify root directory name for FTPD in configuration 14 table. FTPD will then create illusion for FTP clients that this 15 is actually root directory. 16 - ignore options sent in commands, thus LIST -al FILE works and 17 doesn't try to list "-al" directory. 18 - buffers are allocated on stack instead of heap where possible to 19 eliminate malloc/free calls (avoid possible heap fragmentation 20 troubles). 21 - drop using of task notepad to pass parameters - use function 22 arguments instead 23 - use snprintf() instead of sprintf() as the latter is unsafe 24 - use of PF_INET in socket() instead of AF_INET 25 26 Here are ftp clients I've tried new FTPD with (all of them 27 running on Debian GNU/Linux 2.2): 28 29 Lftp 2.1.10 30 NcFTP 2.4.3 31 Netscape 4.75 32 ftp 33 mc 4.5.49 34 1 35 2001-01-02 Joel Sherrill <joel@OARcorp.com> 2 36
Note: See TracChangeset
for help on using the changeset viewer.