Changeset 07fbfced in rtems
- Timestamp:
- 03/05/01 23:01:43 (23 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- 2e549dad
- Parents:
- 1fc16ff
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/exec/libnetworking/ChangeLog
r1fc16ff r07fbfced 1 2001-01-31 Sergei Organov <osv@javad.ru> 2 3 * rtems_servers/ftp.d: Following changes: 4 - Hacks with current dir and root dir removed in favor of new libio 5 support for task-local current and root directories. 6 - Bug in `close_data_socket()' introduced by previous change fixed. 7 - `command_pasv()' changed to set timeout on socket we are listening 8 on and code fixed to don't close socket twice on error. 9 - `serr()' changed to clear `errno'. 10 - `data_socket()' changed to clear `errno' before `bind()'. 11 - `session()' changed to clear `errno' before processing session. 12 - `close_data_socket()' fixed to close both active and passive sockets 13 - Initialize info->data_socket to -1 in `daemon()' 14 - Initialize `fname' to empty string in `exec_command()' 15 1 16 2001-02-03 Ralf Corsepius <corsepiu@faw.uni-ulm.de> 2 17 -
c/src/libnetworking/ChangeLog
r1fc16ff r07fbfced 1 2001-01-31 Sergei Organov <osv@javad.ru> 2 3 * rtems_servers/ftp.d: Following changes: 4 - Hacks with current dir and root dir removed in favor of new libio 5 support for task-local current and root directories. 6 - Bug in `close_data_socket()' introduced by previous change fixed. 7 - `command_pasv()' changed to set timeout on socket we are listening 8 on and code fixed to don't close socket twice on error. 9 - `serr()' changed to clear `errno'. 10 - `data_socket()' changed to clear `errno' before `bind()'. 11 - `session()' changed to clear `errno' before processing session. 12 - `close_data_socket()' fixed to close both active and passive sockets 13 - Initialize info->data_socket to -1 in `daemon()' 14 - Initialize `fname' to empty string in `exec_command()' 15 1 16 2001-02-03 Ralf Corsepius <corsepiu@faw.uni-ulm.de> 2 17 -
c/src/libnetworking/rtems_servers/ftpd.c
r1fc16ff r07fbfced 15 15 * 16 16 * Changes: 17 * 18 * 2001-01-31 Sergei Organov <osv@javad.ru> 19 * 20 * * Hacks with current dir and root dir removed in favor of new libio 21 * support for task-local current and root directories. 22 * 23 * 2001-01-30 Sergei Organov <osv@javad.ru> 24 * 25 * * Bug in `close_data_socket()' introduced by previous change fixed. 26 * * `command_pasv()' changed to set timeout on socket we are listening on 27 * and code fixed to don't close socket twice on error. 28 * * `serr()' changed to clear `errno'. 29 * * `data_socket()' changed to clear `errno' before `bind()'. 30 * * `session()' changed to clear `errno' before processing session. 31 * 32 * 2001-01-29 Sergei Organov <osv@javad.ru> 33 * 34 * * `close_data_socket()' fixed to close both active and passive sockets 35 * * Initialize info->data_socket to -1 in `daemon()' 36 * * Initialize `fname' to empty string in `exec_command()' 17 37 * 18 38 * 2001-01-22 Sergei Organov <osv@javad.ru> … … 170 190 #include <rtems/rtems_bsdnet.h> 171 191 #include <rtems/error.h> 192 #include <rtems/libio.h> 172 193 #include <syslog.h> 173 194 … … 236 257 int data_socket; /* Socket for data connection */ 237 258 int idle; /* Timeout in seconds */ 238 char cwd[FTPD_BUFSIZE]; /* Current working directory */239 259 int xfer_mode; /* Transfer mode (ASCII/binary) */ 240 260 rtems_id tid; /* Task id */ … … 262 282 263 283 /* 264 * Root node for FTPD without trailing slash. Even '/' node is denoted as265 * empty string here.266 */ 267 static char ftpd_root[FTPD_BUFSIZE];284 * Root directory 285 */ 286 287 static char const* ftpd_root = "/"; 268 288 269 289 /* … … 287 307 serr(void) 288 308 { 289 return strerror(errno); 309 int err = errno; 310 errno = 0; 311 return strerror(err); 290 312 } 291 313 … … 306 328 { 307 329 return (ftpd_access & FTPD_NO_WRITE) == 0; 308 }309 310 /*PAGE311 *312 * Utility routines to manage root directory and session local313 * current working directory.314 *315 */316 317 318 /*PAGE319 *320 * is_dir321 *322 * Return 1 if file with given 'name' exists and is directory, 0 otherwise.323 *324 */325 static int326 is_dir(char const* name)327 {328 struct stat s;329 int res = stat(name, &s) == 0 && S_ISDIR(s.st_mode);330 return res;331 }332 333 /*PAGE334 *335 * squeeze_path336 *337 * Squeezes path according to OS rules, i.e., eliminates /./, /../, and //338 * from the path. Does nothing if the path is relative, i.e. doesn't begin339 * with '/'. The trailing slash is always removed, even when alone, i.e. "/"340 * will be "" after squeeze.341 *342 * Input parameters:343 * path - the path to be squeezed344 * full - full file name or NULL (assumed that it points to the beginning of345 * buffer, and 'path' also points somewhere into the same buffer). Is346 * used to check if intermediate names are directories.347 *348 * Output parameters:349 * path - squeezed path350 * returns 1 on success, 0 on failure (if any name that supposed to denote351 * directory is not a directory).352 *353 */354 static int355 squeeze_path(char* path, char* full)356 {357 if(path[0] == '/')358 {359 char* e = path + 1;360 int rest = strlen(e);361 while(rest >= 0)362 {363 int len;364 char* s = e;365 e = strchr(s, '/');366 if(e)367 {368 char c = *e;369 *e = '\0';370 if(full && !is_dir(full))371 {372 *e = c;373 return 0;374 }375 *e++ = c;376 }377 else378 e = s + rest + 1;379 len = e - s;380 rest -= len;381 if(len == 1 || (len == 2 && s[0] == '.'))382 {383 if(rest >= 0)384 memmove(s, e, rest + 1);385 else386 *s++ = '\0';387 e = s;388 }389 else if(len == 3 && s[0] == '.' && s[1] == '.')390 {391 char* ps = s;392 if(ps - 1 > path) {393 do394 --ps;395 while(ps[-1] != '/');396 }397 if(rest >= 0)398 memmove(ps, e, rest + 1);399 else400 *ps++ = '\0';401 e = ps;402 }403 }404 if(e[-2] == '/')405 {406 e[-2] = '\0';407 if(full && !is_dir(full))408 return 0;409 }410 }411 return 1;412 }413 414 415 /*PAGE416 *417 * make_path418 *419 * Makes full path given file name, current working directory and root420 * directory (file scope variable 'root').421 *422 * Input parameters:423 * cwd - current working directory424 * name - file name425 * root (file scope variable) - FTPD root directory426 *427 * Output parameters:428 * buf - full path429 * returns pointer to non-root part of the 'buf', i.e. to first character430 * different from '/' after root part.431 *432 */433 static char const*434 make_path(char* buf, char const* cwd, char const* name)435 {436 char* res = NULL;437 438 int rlen = strlen(ftpd_root);439 int clen = strlen(cwd);440 int nlen = strlen(name);441 int len = rlen + nlen;442 443 if (name[0] != '/')444 {445 ++len;446 if (clen > 0)447 len += clen + 1;448 }449 450 if (FTPD_BUFSIZE > len)451 {452 char* b = buf;453 memcpy(b, ftpd_root, rlen); b += rlen;454 if (name[0] != '/')455 {456 *b++ = '/';457 if (clen > 0)458 {459 memcpy(b, cwd, clen); b += clen;460 *b++ = '/';461 }462 }463 memcpy(b, name, nlen); b += nlen;464 *b = '\0';465 466 res = buf + rlen;467 while(rlen-- > 0 && res[-1] == '/')468 --res;469 if(!squeeze_path(res, buf))470 res = NULL;471 }472 473 return res;474 330 } 475 331 … … 603 459 } 604 460 task_pool.queue[i] = task_pool.info + i; 605 info->ctrl_fp = NULL;606 info->ctrl_socket = -1;607 461 if (++id > 'z') 608 462 id = 'a'; … … 638 492 if(++task_pool.head >= task_pool.count) 639 493 task_pool.head = 0; 640 info->ctrl_socket = -1;641 info->ctrl_fp = NULL;642 494 rtems_semaphore_release(task_pool.mutex); 643 495 } … … 801 653 for(tries = 1; tries < 10; ++tries) 802 654 { 655 errno = 0; 803 656 if(bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0) 804 657 break; … … 850 703 close_data_socket(FTPD_SessionInfo_t *info) 851 704 { 852 int s = info->pasv_socket; 705 /* As at most one data socket could be open simultaneously and in some cases 706 data_socket == pasv_socket, we select socket to close, then close it. */ 707 int s = info->data_socket; 853 708 if(0 > s) 854 s = info-> data_socket;709 s = info->pasv_socket; 855 710 if(!close_socket(s)) 856 711 syslog(LOG_ERR, "ftpd: Error closing data socket."); … … 937 792 char buf[FTPD_DATASIZE]; 938 793 int res = 0; 939 char const* r = NULL;940 794 941 795 if(!can_read()) … … 945 799 } 946 800 947 r = make_path(buf, info->cwd, filename); 948 949 if (NULL == r || 0 > (fd = open(buf, O_RDONLY))) 801 if (0 > (fd = open(filename, O_RDONLY))) 950 802 { 951 803 send_reply(info, 550, "Error opening file."); … … 1031 883 /*PAGE 1032 884 * 885 * discard 886 * 887 * Analog of `write' routine that just discards passed data 888 * 889 * Input parameters: 890 * fd - file descriptor (ignored) 891 * buf - data to write (ignored) 892 * count - number of bytes in `buf' 893 * 894 * Output parameters: 895 * returns `count' 896 * 897 */ 898 static ssize_t 899 discard(int fd, void const* buf, size_t count) 900 { 901 (void)fd; 902 (void)buf; 903 return count; 904 } 905 906 /*PAGE 907 * 1033 908 * command_store 1034 909 * … … 1052 927 int res = 1; 1053 928 int bare_lfs = 0; 1054 1055 int null = !strcmp("/dev/null", filename); 929 int null = 0; 930 typedef ssize_t (*WriteProc)(int, void const*, size_t); 931 WriteProc wrt = &write; 1056 932 1057 933 if(!can_write()) … … 1059 935 send_reply(info, 550, "Access denied."); 1060 936 return; 1061 }1062 1063 if(!null)1064 {1065 if (NULL == make_path(buf, info->cwd, filename))1066 {1067 send_reply(info, 550, "Error creating file.");1068 return;1069 }1070 937 } 1071 938 … … 1076 943 return; 1077 944 1078 945 null = !strcmp("/dev/null", filename); 1079 946 if (null) 1080 947 { 1081 948 /* File "/dev/null" just throws data away. 1082 * FIXME: this is hack. Using /dev/null filesystem entry would be 1083 * better. However, it's not clear how to handle root directory other 1084 * than '/' then. 949 * FIXME: this is hack. Using `/dev/null' filesystem entry would be 950 * better. 1085 951 */ 1086 w hile ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0)1087 ;1088 } 1089 else if (rtems_ftpd_configuration.hooks != NULL)952 wrt = &discard; 953 } 954 955 if (!null && rtems_ftpd_configuration.hooks != NULL) 1090 956 { 1091 957 … … 1160 1026 else 1161 1027 { 1162 /* Data transfer to regular file. */ 1163 int fd = 1164 creat(buf, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 1028 /* Data transfer to regular file or /dev/null. */ 1029 int fd = 0; 1030 1031 if(!null) 1032 fd = creat(filename, 1033 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 1165 1034 1166 1035 if (0 > fd) … … 1175 1044 while ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0) 1176 1045 { 1177 if (wr ite(fd, buf, n) != n)1046 if (wrt(fd, buf, n) != n) 1178 1047 { 1179 1048 res = 0; … … 1197 1066 char const lf = '\r'; 1198 1067 pended_cr = 0; 1199 if(wr ite(fd, &lf, 1) != 1)1068 if(wrt(fd, &lf, 1) != 1) 1200 1069 { 1201 1070 res = 0; … … 1232 1101 break; 1233 1102 count = i - sub - pended_cr; 1234 if(count > 0 && wr ite(fd, b, count) != count)1103 if(count > 0 && wrt(fd, b, count) != count) 1235 1104 { 1236 1105 res = 0; 1237 1106 break; 1238 1107 } 1239 if(sub == 2 && wr ite(fd, e - 1, 1) != 1)1108 if(sub == 2 && wrt(fd, e - 1, 1) != 1) 1240 1109 res = 0; 1241 1110 } … … 1385 1254 struct stat stat_buf; 1386 1255 char buf[FTPD_BUFSIZE]; 1387 char path[FTPD_BUFSIZE];1388 1256 time_t curTime; 1389 char const* res;1390 char const* cwd = info->cwd;1391 1257 int sc = 1; 1392 1258 … … 1403 1269 fname = "."; 1404 1270 1405 res = make_path(path, cwd, fname); 1406 1407 if (NULL == res || 0 > stat(path, &stat_buf)) 1271 if (0 > stat(fname, &stat_buf)) 1408 1272 { 1409 1273 snprintf(buf, FTPD_BUFSIZE, … … 1411 1275 send(s, buf, strlen(buf), 0); 1412 1276 } 1413 else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir( path))))1277 else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(fname)))) 1414 1278 { 1415 1279 snprintf(buf, FTPD_BUFSIZE, … … 1421 1285 time(&curTime); 1422 1286 if(!dirp && *fname) 1423 sc = sc && send_dirline(s, wide, curTime, path, "", fname, buf);1287 sc = sc && send_dirline(s, wide, curTime, fname, "", fname, buf); 1424 1288 else { 1425 1289 /* FIXME: need "." and ".." only when '-a' option is given */ 1426 sc = sc && send_dirline(s, wide, curTime, path, "", ".", buf);1427 sc = sc && send_dirline(s, wide, curTime, path,1428 (strcmp( path, ftpd_root) ? ".." : ""), "..", buf);1290 sc = sc && send_dirline(s, wide, curTime, fname, "", ".", buf); 1291 sc = sc && send_dirline(s, wide, curTime, fname, 1292 (strcmp(fname, ftpd_root) ? ".." : ""), "..", buf); 1429 1293 while (sc && (dp = readdir(dirp)) != NULL) 1430 1294 sc = sc && 1431 send_dirline(s, wide, curTime, path, dp->d_name, dp->d_name, buf);1295 send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf); 1432 1296 } 1433 1297 } … … 1446 1310 /*PAGE 1447 1311 * 1448 * rtems_ftpd_cwd 1449 * 1450 * Change current working directory. We use 'chdir' here only to validate the 1451 * new directory. We keep track of current working directory ourselves because 1452 * current working directory in RTEMS isn't thread local, but we need it to be 1453 * session local. 1312 * command_cwd 1313 * 1314 * Change current working directory. 1454 1315 * 1455 1316 * Input parameters: … … 1458 1319 * 1459 1320 * Output parameters: 1460 * info->cwd is set to new CWD value.1321 * NONE 1461 1322 * 1462 1323 */ 1463 1324 static void 1464 rtems_ftpd_cwd(FTPD_SessionInfo_t *info, char *dir) 1325 command_cwd(FTPD_SessionInfo_t *info, char *dir) 1326 { 1327 if(chdir(dir) == 0) 1328 send_reply(info, 250, "CWD command successful."); 1329 else 1330 send_reply(info, 550, "CWD command failed."); 1331 } 1332 1333 1334 /*PAGE 1335 * 1336 * command_pwd 1337 * 1338 * Send current working directory to client. 1339 * 1340 * Input parameters: 1341 * info - corresponding SessionInfo structure 1342 * 1343 * Output parameters: 1344 * NONE 1345 */ 1346 static void 1347 command_pwd(FTPD_SessionInfo_t *info) 1465 1348 { 1466 1349 char buf[FTPD_BUFSIZE]; 1467 char const* cwd = make_path(buf, info->cwd, dir); 1468 if(cwd && chdir(buf) == 0) 1469 { 1470 send_reply(info, 250, "CWD command successful."); 1471 strcpy(info->cwd, cwd); 1472 } 1473 else 1474 { 1475 send_reply(info, 550, "CWD command failed."); 1476 } 1477 } 1478 1479 1350 char const* cwd; 1351 errno = 0; 1352 buf[0] = '"'; 1353 cwd = getcwd(buf + 1, FTPD_BUFSIZE - 4); 1354 if(cwd) 1355 { 1356 int len = strlen(cwd); 1357 static char const txt[] = "\" is the current directory."; 1358 int size = sizeof(txt); 1359 if(len + size + 1 >= FTPD_BUFSIZE) 1360 size = FTPD_BUFSIZE - len - 2; 1361 memcpy(buf + len + 1, txt, size); 1362 buf[len + size] = '\0'; 1363 send_reply(info, 250, buf); 1364 } 1365 else { 1366 snprintf(buf, FTPD_BUFSIZE, "Error: %s.", serr()); 1367 send_reply(info, 452, buf); 1368 } 1369 } 1480 1370 1481 1371 /*PAGE … … 1498 1388 char buf[FTPD_BUFSIZE]; 1499 1389 1500 if ( NULL == make_path(buf, info->cwd, fname) || 0 > stat(buf, &stbuf))1390 if (0 > stat(fname, &stbuf)) 1501 1391 { 1502 1392 snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr()); … … 1615 1505 else if (0 > listen(s, 1)) 1616 1506 syslog(LOG_ERR, "ftpd: Error listening on PASV socket: %s", serr()); 1617 else 1507 else if(set_socket_timeout(s, info->idle)) 1618 1508 { 1619 1509 char buf[FTPD_BUFSIZE]; … … 1628 1518 1629 1519 info->pasv_socket = accept(s, (struct sockaddr *)&addr, &addrLen); 1630 close_socket(s);1631 1520 if (0 > info->pasv_socket) 1632 1521 syslog(LOG_ERR, "ftpd: Error accepting PASV connection: %s", serr()); 1633 1522 else 1523 { 1524 close_socket(s); 1525 s = -1; 1634 1526 err = 0; 1527 } 1635 1528 } 1636 1529 } … … 1747 1640 * cmd - command to be executed (upper-case) 1748 1641 * args - arguments of the command 1749 * buf - beginning of buffer where 'cmd' and 'args' reside.1750 1642 * 1751 1643 * Output parameters: … … 1753 1645 */ 1754 1646 static void 1755 exec_command(FTPD_SessionInfo_t *info, char* cmd, char* args , char* buf)1647 exec_command(FTPD_SessionInfo_t *info, char* cmd, char* args) 1756 1648 { 1757 1649 char fname[FTPD_BUFSIZE]; 1758 1650 int wrong_command = 0; 1759 1651 1652 fname[0] = '\0'; 1653 1760 1654 if (!strcmp("PORT", cmd)) 1761 1655 { … … 1825 1719 else if ( 1826 1720 1 == sscanf(args, "%254s", fname) && 1827 NULL != make_path(buf, info->cwd, fname) && 1828 unlink(buf) == 0) 1721 unlink(fname) == 0) 1829 1722 { 1830 1723 send_reply(info, 257, "DELE successful."); … … 1849 1742 else if( 1850 1743 2 == sscanf(args, "%o %254s", &mask, fname) && 1851 NULL != make_path(buf, info->cwd, fname) && 1852 chmod(buf, (mode_t)mask) == 0) 1744 chmod(fname, (mode_t)mask) == 0) 1853 1745 { 1854 1746 send_reply(info, 257, "CHMOD successful."); … … 1870 1762 else if ( 1871 1763 1 == sscanf(args, "%254s", fname) && 1872 NULL != make_path(buf, info->cwd, fname) && 1873 rmdir(buf) == 0) 1764 rmdir(fname) == 0) 1874 1765 { 1875 1766 send_reply(info, 257, "RMD successful."); … … 1888 1779 else if ( 1889 1780 1 == sscanf(args, "%254s", fname) && 1890 NULL != make_path(buf, info->cwd, fname) && 1891 mkdir(buf, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 1781 mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 1892 1782 { 1893 1783 send_reply(info, 257, "MKD successful."); … … 1901 1791 { 1902 1792 sscanf(args, "%254s", fname); 1903 rtems_ftpd_cwd(info, fname);1793 command_cwd(info, fname); 1904 1794 } 1905 1795 else if (!strcmp("CDUP", cmd)) 1906 1796 { 1907 rtems_ftpd_cwd(info, "..");1797 command_cwd(info, ".."); 1908 1798 } 1909 1799 else if (!strcmp("PWD", cmd)) 1910 1800 { 1911 char const* cwd = "/"; 1912 if(info->cwd[0]) 1913 cwd = info->cwd; 1914 snprintf(buf, FTPD_BUFSIZE, 1915 "\"%s\" is the current directory.", cwd); 1916 send_reply(info, 250, buf); 1801 command_pwd(info); 1917 1802 } 1918 1803 else … … 1944 1829 { 1945 1830 FTPD_SessionInfo_t *const info = (FTPD_SessionInfo_t *)arg; 1831 int chroot_made = 0; 1832 1833 rtems_libio_set_private_env(); 1834 1835 /* chroot() can fail here because the directory may not exist yet. */ 1836 chroot_made = chroot(ftpd_root) == 0; 1946 1837 1947 1838 while(1) 1948 1839 { 1949 1840 rtems_event_set set; 1841 char buf[128]; 1950 1842 1951 1843 rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, 1952 1844 &set); 1845 1846 chroot_made = chroot_made || chroot(ftpd_root) == 0; 1847 chdir("/"); 1848 1849 errno = 0; 1953 1850 1954 1851 send_reply(info, 220, FTPD_SERVER_MESSAGE); … … 1974 1871 else 1975 1872 { 1976 exec_command(info, cmd, args , buf);1873 exec_command(info, cmd, args); 1977 1874 } 1978 1875 } … … 2062 1959 info->ctrl_addr = addr; 2063 1960 info->pasv_socket = -1; 2064 info-> xfer_mode = TYPE_A;2065 info-> cwd[0] = '\0';1961 info->data_socket = -1; 1962 info->xfer_mode = TYPE_A; 2066 1963 info->data_addr.sin_port = 2067 1964 htons(ntohs(info->ctrl_addr.sin_port) - 1); … … 2150 2047 } 2151 2048 2152 ftpd_root [0] = '\0';2049 ftpd_root = "/"; 2153 2050 if ( 2154 2051 rtems_ftpd_configuration.root && 2155 strlen(rtems_ftpd_configuration.root) < FTPD_BUFSIZE && 2156 rtems_ftpd_configuration.root[0] == '/') 2157 { 2158 strcpy(ftpd_root, rtems_ftpd_configuration.root); 2159 squeeze_path(ftpd_root, NULL); 2160 rtems_ftpd_configuration.root = ftpd_root; 2161 } 2052 rtems_ftpd_configuration.root[0] == '/' 2053 ) 2054 ftpd_root = rtems_ftpd_configuration.root; 2055 2056 rtems_ftpd_configuration.root = ftpd_root; 2162 2057 2163 2058 syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)", 2164 2059 count, ((count > 1) ? "s" : "")); 2060 2165 2061 return RTEMS_SUCCESSFUL; 2166 2062 } -
cpukit/ftpd/ftpd.c
r1fc16ff r07fbfced 15 15 * 16 16 * Changes: 17 * 18 * 2001-01-31 Sergei Organov <osv@javad.ru> 19 * 20 * * Hacks with current dir and root dir removed in favor of new libio 21 * support for task-local current and root directories. 22 * 23 * 2001-01-30 Sergei Organov <osv@javad.ru> 24 * 25 * * Bug in `close_data_socket()' introduced by previous change fixed. 26 * * `command_pasv()' changed to set timeout on socket we are listening on 27 * and code fixed to don't close socket twice on error. 28 * * `serr()' changed to clear `errno'. 29 * * `data_socket()' changed to clear `errno' before `bind()'. 30 * * `session()' changed to clear `errno' before processing session. 31 * 32 * 2001-01-29 Sergei Organov <osv@javad.ru> 33 * 34 * * `close_data_socket()' fixed to close both active and passive sockets 35 * * Initialize info->data_socket to -1 in `daemon()' 36 * * Initialize `fname' to empty string in `exec_command()' 17 37 * 18 38 * 2001-01-22 Sergei Organov <osv@javad.ru> … … 170 190 #include <rtems/rtems_bsdnet.h> 171 191 #include <rtems/error.h> 192 #include <rtems/libio.h> 172 193 #include <syslog.h> 173 194 … … 236 257 int data_socket; /* Socket for data connection */ 237 258 int idle; /* Timeout in seconds */ 238 char cwd[FTPD_BUFSIZE]; /* Current working directory */239 259 int xfer_mode; /* Transfer mode (ASCII/binary) */ 240 260 rtems_id tid; /* Task id */ … … 262 282 263 283 /* 264 * Root node for FTPD without trailing slash. Even '/' node is denoted as265 * empty string here.266 */ 267 static char ftpd_root[FTPD_BUFSIZE];284 * Root directory 285 */ 286 287 static char const* ftpd_root = "/"; 268 288 269 289 /* … … 287 307 serr(void) 288 308 { 289 return strerror(errno); 309 int err = errno; 310 errno = 0; 311 return strerror(err); 290 312 } 291 313 … … 306 328 { 307 329 return (ftpd_access & FTPD_NO_WRITE) == 0; 308 }309 310 /*PAGE311 *312 * Utility routines to manage root directory and session local313 * current working directory.314 *315 */316 317 318 /*PAGE319 *320 * is_dir321 *322 * Return 1 if file with given 'name' exists and is directory, 0 otherwise.323 *324 */325 static int326 is_dir(char const* name)327 {328 struct stat s;329 int res = stat(name, &s) == 0 && S_ISDIR(s.st_mode);330 return res;331 }332 333 /*PAGE334 *335 * squeeze_path336 *337 * Squeezes path according to OS rules, i.e., eliminates /./, /../, and //338 * from the path. Does nothing if the path is relative, i.e. doesn't begin339 * with '/'. The trailing slash is always removed, even when alone, i.e. "/"340 * will be "" after squeeze.341 *342 * Input parameters:343 * path - the path to be squeezed344 * full - full file name or NULL (assumed that it points to the beginning of345 * buffer, and 'path' also points somewhere into the same buffer). Is346 * used to check if intermediate names are directories.347 *348 * Output parameters:349 * path - squeezed path350 * returns 1 on success, 0 on failure (if any name that supposed to denote351 * directory is not a directory).352 *353 */354 static int355 squeeze_path(char* path, char* full)356 {357 if(path[0] == '/')358 {359 char* e = path + 1;360 int rest = strlen(e);361 while(rest >= 0)362 {363 int len;364 char* s = e;365 e = strchr(s, '/');366 if(e)367 {368 char c = *e;369 *e = '\0';370 if(full && !is_dir(full))371 {372 *e = c;373 return 0;374 }375 *e++ = c;376 }377 else378 e = s + rest + 1;379 len = e - s;380 rest -= len;381 if(len == 1 || (len == 2 && s[0] == '.'))382 {383 if(rest >= 0)384 memmove(s, e, rest + 1);385 else386 *s++ = '\0';387 e = s;388 }389 else if(len == 3 && s[0] == '.' && s[1] == '.')390 {391 char* ps = s;392 if(ps - 1 > path) {393 do394 --ps;395 while(ps[-1] != '/');396 }397 if(rest >= 0)398 memmove(ps, e, rest + 1);399 else400 *ps++ = '\0';401 e = ps;402 }403 }404 if(e[-2] == '/')405 {406 e[-2] = '\0';407 if(full && !is_dir(full))408 return 0;409 }410 }411 return 1;412 }413 414 415 /*PAGE416 *417 * make_path418 *419 * Makes full path given file name, current working directory and root420 * directory (file scope variable 'root').421 *422 * Input parameters:423 * cwd - current working directory424 * name - file name425 * root (file scope variable) - FTPD root directory426 *427 * Output parameters:428 * buf - full path429 * returns pointer to non-root part of the 'buf', i.e. to first character430 * different from '/' after root part.431 *432 */433 static char const*434 make_path(char* buf, char const* cwd, char const* name)435 {436 char* res = NULL;437 438 int rlen = strlen(ftpd_root);439 int clen = strlen(cwd);440 int nlen = strlen(name);441 int len = rlen + nlen;442 443 if (name[0] != '/')444 {445 ++len;446 if (clen > 0)447 len += clen + 1;448 }449 450 if (FTPD_BUFSIZE > len)451 {452 char* b = buf;453 memcpy(b, ftpd_root, rlen); b += rlen;454 if (name[0] != '/')455 {456 *b++ = '/';457 if (clen > 0)458 {459 memcpy(b, cwd, clen); b += clen;460 *b++ = '/';461 }462 }463 memcpy(b, name, nlen); b += nlen;464 *b = '\0';465 466 res = buf + rlen;467 while(rlen-- > 0 && res[-1] == '/')468 --res;469 if(!squeeze_path(res, buf))470 res = NULL;471 }472 473 return res;474 330 } 475 331 … … 603 459 } 604 460 task_pool.queue[i] = task_pool.info + i; 605 info->ctrl_fp = NULL;606 info->ctrl_socket = -1;607 461 if (++id > 'z') 608 462 id = 'a'; … … 638 492 if(++task_pool.head >= task_pool.count) 639 493 task_pool.head = 0; 640 info->ctrl_socket = -1;641 info->ctrl_fp = NULL;642 494 rtems_semaphore_release(task_pool.mutex); 643 495 } … … 801 653 for(tries = 1; tries < 10; ++tries) 802 654 { 655 errno = 0; 803 656 if(bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0) 804 657 break; … … 850 703 close_data_socket(FTPD_SessionInfo_t *info) 851 704 { 852 int s = info->pasv_socket; 705 /* As at most one data socket could be open simultaneously and in some cases 706 data_socket == pasv_socket, we select socket to close, then close it. */ 707 int s = info->data_socket; 853 708 if(0 > s) 854 s = info-> data_socket;709 s = info->pasv_socket; 855 710 if(!close_socket(s)) 856 711 syslog(LOG_ERR, "ftpd: Error closing data socket."); … … 937 792 char buf[FTPD_DATASIZE]; 938 793 int res = 0; 939 char const* r = NULL;940 794 941 795 if(!can_read()) … … 945 799 } 946 800 947 r = make_path(buf, info->cwd, filename); 948 949 if (NULL == r || 0 > (fd = open(buf, O_RDONLY))) 801 if (0 > (fd = open(filename, O_RDONLY))) 950 802 { 951 803 send_reply(info, 550, "Error opening file."); … … 1031 883 /*PAGE 1032 884 * 885 * discard 886 * 887 * Analog of `write' routine that just discards passed data 888 * 889 * Input parameters: 890 * fd - file descriptor (ignored) 891 * buf - data to write (ignored) 892 * count - number of bytes in `buf' 893 * 894 * Output parameters: 895 * returns `count' 896 * 897 */ 898 static ssize_t 899 discard(int fd, void const* buf, size_t count) 900 { 901 (void)fd; 902 (void)buf; 903 return count; 904 } 905 906 /*PAGE 907 * 1033 908 * command_store 1034 909 * … … 1052 927 int res = 1; 1053 928 int bare_lfs = 0; 1054 1055 int null = !strcmp("/dev/null", filename); 929 int null = 0; 930 typedef ssize_t (*WriteProc)(int, void const*, size_t); 931 WriteProc wrt = &write; 1056 932 1057 933 if(!can_write()) … … 1059 935 send_reply(info, 550, "Access denied."); 1060 936 return; 1061 }1062 1063 if(!null)1064 {1065 if (NULL == make_path(buf, info->cwd, filename))1066 {1067 send_reply(info, 550, "Error creating file.");1068 return;1069 }1070 937 } 1071 938 … … 1076 943 return; 1077 944 1078 945 null = !strcmp("/dev/null", filename); 1079 946 if (null) 1080 947 { 1081 948 /* File "/dev/null" just throws data away. 1082 * FIXME: this is hack. Using /dev/null filesystem entry would be 1083 * better. However, it's not clear how to handle root directory other 1084 * than '/' then. 949 * FIXME: this is hack. Using `/dev/null' filesystem entry would be 950 * better. 1085 951 */ 1086 w hile ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0)1087 ;1088 } 1089 else if (rtems_ftpd_configuration.hooks != NULL)952 wrt = &discard; 953 } 954 955 if (!null && rtems_ftpd_configuration.hooks != NULL) 1090 956 { 1091 957 … … 1160 1026 else 1161 1027 { 1162 /* Data transfer to regular file. */ 1163 int fd = 1164 creat(buf, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 1028 /* Data transfer to regular file or /dev/null. */ 1029 int fd = 0; 1030 1031 if(!null) 1032 fd = creat(filename, 1033 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 1165 1034 1166 1035 if (0 > fd) … … 1175 1044 while ((n = recv(s, buf, FTPD_DATASIZE, 0)) > 0) 1176 1045 { 1177 if (wr ite(fd, buf, n) != n)1046 if (wrt(fd, buf, n) != n) 1178 1047 { 1179 1048 res = 0; … … 1197 1066 char const lf = '\r'; 1198 1067 pended_cr = 0; 1199 if(wr ite(fd, &lf, 1) != 1)1068 if(wrt(fd, &lf, 1) != 1) 1200 1069 { 1201 1070 res = 0; … … 1232 1101 break; 1233 1102 count = i - sub - pended_cr; 1234 if(count > 0 && wr ite(fd, b, count) != count)1103 if(count > 0 && wrt(fd, b, count) != count) 1235 1104 { 1236 1105 res = 0; 1237 1106 break; 1238 1107 } 1239 if(sub == 2 && wr ite(fd, e - 1, 1) != 1)1108 if(sub == 2 && wrt(fd, e - 1, 1) != 1) 1240 1109 res = 0; 1241 1110 } … … 1385 1254 struct stat stat_buf; 1386 1255 char buf[FTPD_BUFSIZE]; 1387 char path[FTPD_BUFSIZE];1388 1256 time_t curTime; 1389 char const* res;1390 char const* cwd = info->cwd;1391 1257 int sc = 1; 1392 1258 … … 1403 1269 fname = "."; 1404 1270 1405 res = make_path(path, cwd, fname); 1406 1407 if (NULL == res || 0 > stat(path, &stat_buf)) 1271 if (0 > stat(fname, &stat_buf)) 1408 1272 { 1409 1273 snprintf(buf, FTPD_BUFSIZE, … … 1411 1275 send(s, buf, strlen(buf), 0); 1412 1276 } 1413 else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir( path))))1277 else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(fname)))) 1414 1278 { 1415 1279 snprintf(buf, FTPD_BUFSIZE, … … 1421 1285 time(&curTime); 1422 1286 if(!dirp && *fname) 1423 sc = sc && send_dirline(s, wide, curTime, path, "", fname, buf);1287 sc = sc && send_dirline(s, wide, curTime, fname, "", fname, buf); 1424 1288 else { 1425 1289 /* FIXME: need "." and ".." only when '-a' option is given */ 1426 sc = sc && send_dirline(s, wide, curTime, path, "", ".", buf);1427 sc = sc && send_dirline(s, wide, curTime, path,1428 (strcmp( path, ftpd_root) ? ".." : ""), "..", buf);1290 sc = sc && send_dirline(s, wide, curTime, fname, "", ".", buf); 1291 sc = sc && send_dirline(s, wide, curTime, fname, 1292 (strcmp(fname, ftpd_root) ? ".." : ""), "..", buf); 1429 1293 while (sc && (dp = readdir(dirp)) != NULL) 1430 1294 sc = sc && 1431 send_dirline(s, wide, curTime, path, dp->d_name, dp->d_name, buf);1295 send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf); 1432 1296 } 1433 1297 } … … 1446 1310 /*PAGE 1447 1311 * 1448 * rtems_ftpd_cwd 1449 * 1450 * Change current working directory. We use 'chdir' here only to validate the 1451 * new directory. We keep track of current working directory ourselves because 1452 * current working directory in RTEMS isn't thread local, but we need it to be 1453 * session local. 1312 * command_cwd 1313 * 1314 * Change current working directory. 1454 1315 * 1455 1316 * Input parameters: … … 1458 1319 * 1459 1320 * Output parameters: 1460 * info->cwd is set to new CWD value.1321 * NONE 1461 1322 * 1462 1323 */ 1463 1324 static void 1464 rtems_ftpd_cwd(FTPD_SessionInfo_t *info, char *dir) 1325 command_cwd(FTPD_SessionInfo_t *info, char *dir) 1326 { 1327 if(chdir(dir) == 0) 1328 send_reply(info, 250, "CWD command successful."); 1329 else 1330 send_reply(info, 550, "CWD command failed."); 1331 } 1332 1333 1334 /*PAGE 1335 * 1336 * command_pwd 1337 * 1338 * Send current working directory to client. 1339 * 1340 * Input parameters: 1341 * info - corresponding SessionInfo structure 1342 * 1343 * Output parameters: 1344 * NONE 1345 */ 1346 static void 1347 command_pwd(FTPD_SessionInfo_t *info) 1465 1348 { 1466 1349 char buf[FTPD_BUFSIZE]; 1467 char const* cwd = make_path(buf, info->cwd, dir); 1468 if(cwd && chdir(buf) == 0) 1469 { 1470 send_reply(info, 250, "CWD command successful."); 1471 strcpy(info->cwd, cwd); 1472 } 1473 else 1474 { 1475 send_reply(info, 550, "CWD command failed."); 1476 } 1477 } 1478 1479 1350 char const* cwd; 1351 errno = 0; 1352 buf[0] = '"'; 1353 cwd = getcwd(buf + 1, FTPD_BUFSIZE - 4); 1354 if(cwd) 1355 { 1356 int len = strlen(cwd); 1357 static char const txt[] = "\" is the current directory."; 1358 int size = sizeof(txt); 1359 if(len + size + 1 >= FTPD_BUFSIZE) 1360 size = FTPD_BUFSIZE - len - 2; 1361 memcpy(buf + len + 1, txt, size); 1362 buf[len + size] = '\0'; 1363 send_reply(info, 250, buf); 1364 } 1365 else { 1366 snprintf(buf, FTPD_BUFSIZE, "Error: %s.", serr()); 1367 send_reply(info, 452, buf); 1368 } 1369 } 1480 1370 1481 1371 /*PAGE … … 1498 1388 char buf[FTPD_BUFSIZE]; 1499 1389 1500 if ( NULL == make_path(buf, info->cwd, fname) || 0 > stat(buf, &stbuf))1390 if (0 > stat(fname, &stbuf)) 1501 1391 { 1502 1392 snprintf(buf, FTPD_BUFSIZE, "%s: %s.", fname, serr()); … … 1615 1505 else if (0 > listen(s, 1)) 1616 1506 syslog(LOG_ERR, "ftpd: Error listening on PASV socket: %s", serr()); 1617 else 1507 else if(set_socket_timeout(s, info->idle)) 1618 1508 { 1619 1509 char buf[FTPD_BUFSIZE]; … … 1628 1518 1629 1519 info->pasv_socket = accept(s, (struct sockaddr *)&addr, &addrLen); 1630 close_socket(s);1631 1520 if (0 > info->pasv_socket) 1632 1521 syslog(LOG_ERR, "ftpd: Error accepting PASV connection: %s", serr()); 1633 1522 else 1523 { 1524 close_socket(s); 1525 s = -1; 1634 1526 err = 0; 1527 } 1635 1528 } 1636 1529 } … … 1747 1640 * cmd - command to be executed (upper-case) 1748 1641 * args - arguments of the command 1749 * buf - beginning of buffer where 'cmd' and 'args' reside.1750 1642 * 1751 1643 * Output parameters: … … 1753 1645 */ 1754 1646 static void 1755 exec_command(FTPD_SessionInfo_t *info, char* cmd, char* args , char* buf)1647 exec_command(FTPD_SessionInfo_t *info, char* cmd, char* args) 1756 1648 { 1757 1649 char fname[FTPD_BUFSIZE]; 1758 1650 int wrong_command = 0; 1759 1651 1652 fname[0] = '\0'; 1653 1760 1654 if (!strcmp("PORT", cmd)) 1761 1655 { … … 1825 1719 else if ( 1826 1720 1 == sscanf(args, "%254s", fname) && 1827 NULL != make_path(buf, info->cwd, fname) && 1828 unlink(buf) == 0) 1721 unlink(fname) == 0) 1829 1722 { 1830 1723 send_reply(info, 257, "DELE successful."); … … 1849 1742 else if( 1850 1743 2 == sscanf(args, "%o %254s", &mask, fname) && 1851 NULL != make_path(buf, info->cwd, fname) && 1852 chmod(buf, (mode_t)mask) == 0) 1744 chmod(fname, (mode_t)mask) == 0) 1853 1745 { 1854 1746 send_reply(info, 257, "CHMOD successful."); … … 1870 1762 else if ( 1871 1763 1 == sscanf(args, "%254s", fname) && 1872 NULL != make_path(buf, info->cwd, fname) && 1873 rmdir(buf) == 0) 1764 rmdir(fname) == 0) 1874 1765 { 1875 1766 send_reply(info, 257, "RMD successful."); … … 1888 1779 else if ( 1889 1780 1 == sscanf(args, "%254s", fname) && 1890 NULL != make_path(buf, info->cwd, fname) && 1891 mkdir(buf, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 1781 mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0) 1892 1782 { 1893 1783 send_reply(info, 257, "MKD successful."); … … 1901 1791 { 1902 1792 sscanf(args, "%254s", fname); 1903 rtems_ftpd_cwd(info, fname);1793 command_cwd(info, fname); 1904 1794 } 1905 1795 else if (!strcmp("CDUP", cmd)) 1906 1796 { 1907 rtems_ftpd_cwd(info, "..");1797 command_cwd(info, ".."); 1908 1798 } 1909 1799 else if (!strcmp("PWD", cmd)) 1910 1800 { 1911 char const* cwd = "/"; 1912 if(info->cwd[0]) 1913 cwd = info->cwd; 1914 snprintf(buf, FTPD_BUFSIZE, 1915 "\"%s\" is the current directory.", cwd); 1916 send_reply(info, 250, buf); 1801 command_pwd(info); 1917 1802 } 1918 1803 else … … 1944 1829 { 1945 1830 FTPD_SessionInfo_t *const info = (FTPD_SessionInfo_t *)arg; 1831 int chroot_made = 0; 1832 1833 rtems_libio_set_private_env(); 1834 1835 /* chroot() can fail here because the directory may not exist yet. */ 1836 chroot_made = chroot(ftpd_root) == 0; 1946 1837 1947 1838 while(1) 1948 1839 { 1949 1840 rtems_event_set set; 1841 char buf[128]; 1950 1842 1951 1843 rtems_event_receive(FTPD_RTEMS_EVENT, RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, 1952 1844 &set); 1845 1846 chroot_made = chroot_made || chroot(ftpd_root) == 0; 1847 chdir("/"); 1848 1849 errno = 0; 1953 1850 1954 1851 send_reply(info, 220, FTPD_SERVER_MESSAGE); … … 1974 1871 else 1975 1872 { 1976 exec_command(info, cmd, args , buf);1873 exec_command(info, cmd, args); 1977 1874 } 1978 1875 } … … 2062 1959 info->ctrl_addr = addr; 2063 1960 info->pasv_socket = -1; 2064 info-> xfer_mode = TYPE_A;2065 info-> cwd[0] = '\0';1961 info->data_socket = -1; 1962 info->xfer_mode = TYPE_A; 2066 1963 info->data_addr.sin_port = 2067 1964 htons(ntohs(info->ctrl_addr.sin_port) - 1); … … 2150 2047 } 2151 2048 2152 ftpd_root [0] = '\0';2049 ftpd_root = "/"; 2153 2050 if ( 2154 2051 rtems_ftpd_configuration.root && 2155 strlen(rtems_ftpd_configuration.root) < FTPD_BUFSIZE && 2156 rtems_ftpd_configuration.root[0] == '/') 2157 { 2158 strcpy(ftpd_root, rtems_ftpd_configuration.root); 2159 squeeze_path(ftpd_root, NULL); 2160 rtems_ftpd_configuration.root = ftpd_root; 2161 } 2052 rtems_ftpd_configuration.root[0] == '/' 2053 ) 2054 ftpd_root = rtems_ftpd_configuration.root; 2055 2056 rtems_ftpd_configuration.root = ftpd_root; 2162 2057 2163 2058 syslog(LOG_INFO, "ftpd: FTP daemon started (%d session%s max)", 2164 2059 count, ((count > 1) ? "s" : "")); 2060 2165 2061 return RTEMS_SUCCESSFUL; 2166 2062 } -
cpukit/libnetworking/ChangeLog
r1fc16ff r07fbfced 1 2001-01-31 Sergei Organov <osv@javad.ru> 2 3 * rtems_servers/ftp.d: Following changes: 4 - Hacks with current dir and root dir removed in favor of new libio 5 support for task-local current and root directories. 6 - Bug in `close_data_socket()' introduced by previous change fixed. 7 - `command_pasv()' changed to set timeout on socket we are listening 8 on and code fixed to don't close socket twice on error. 9 - `serr()' changed to clear `errno'. 10 - `data_socket()' changed to clear `errno' before `bind()'. 11 - `session()' changed to clear `errno' before processing session. 12 - `close_data_socket()' fixed to close both active and passive sockets 13 - Initialize info->data_socket to -1 in `daemon()' 14 - Initialize `fname' to empty string in `exec_command()' 15 1 16 2001-02-03 Ralf Corsepius <corsepiu@faw.uni-ulm.de> 2 17
Note: See TracChangeset
for help on using the changeset viewer.