ftpd.c
上传用户:lukesailor
上传日期:2007-01-04
资源大小:27k
文件大小:41k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /* $Id: ftpd.c,v 1.73 1999/02/13 15:23:41 agulbra Exp $ */
  2. #define _GNU_SOURCE
  3. #include <time.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <stdarg.h>
  7. #include <unistd.h>
  8. #include <signal.h>
  9. #include <ctype.h>
  10. #include <sys/time.h>
  11. #include <errno.h>
  12. #include <string.h>
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <netinet/ip.h>
  17. #include <sys/stat.h>
  18. #include <fcntl.h>
  19. #include <sys/mman.h>
  20. #include <sys/param.h>
  21. #include <sys/ioctl.h>
  22. #include <pwd.h>
  23. #include <grp.h>
  24. #include <arpa/inet.h>
  25. #include <netdb.h>
  26. #include <sys/resource.h>
  27. #include <sys/vfs.h>
  28. #ifndef _GNU_SOURCE
  29. #define _GNU_SOURCE /* for GLOB_ABEND in newer glibcs */
  30. #endif
  31. #include <glob.h>
  32. #if defined(GLOB_ABORTED) && !defined(GLOB_ABEND)
  33. #define GLOB_ABEND GLOB_ABORTED
  34. #endif
  35. #define SYSLOG_NAMES /* for -f */
  36. #include <syslog.h>
  37. #ifdef USE_SHADOW
  38. #include <shadow.h>
  39. #endif
  40. #include "ftpd.h"
  41. #if PATH_MAX < 1024
  42. #error "troll-ftpd requres that PATH_MAX be at least 1024"
  43. #endif
  44. /* include files, *sigh* */
  45. int wildmat( const char *, const char * );
  46. /* then mine */
  47. int sfgets( void );
  48. void *aborttransfer( int );
  49. void parser( void );
  50. void dobanner( void );
  51. void douser( const char *name );
  52. void dopass( const char *password );
  53. void docwd( const char *dir );
  54. void doretr( const char *name );
  55. void dorest (const char *name );
  56. void dodele( const char *name );
  57. void dostor( const char *name );
  58. void domkd( const char *name );
  59. void dormd( const char *name );
  60. void domdtm( const char *name );
  61. void dosize( const char *name );
  62. void doport( unsigned int ip, unsigned int port );
  63. void dopasv( void );
  64. void error( int n, const char *msg );
  65. void domode( const char *arg );
  66. void dostru( const char *arg );
  67. void dotype( const char *arg );
  68. void dornfr( const char *name );
  69. void dornto( const char *name );
  70. jmp_buf appropriately;
  71. int logging = 0;
  72. void sighandler( int sig )
  73. {
  74.     if ( sig == SIGUSR1 && logging < 2 )
  75. logging++;
  76.     else if ( sig == SIGUSR2 && logging > 0 )
  77. logging--;
  78. }
  79. const int window = 51200; /* window size */
  80. unsigned int downloaded = 0; /* bytes downloaded */
  81. unsigned int uploaded = 0; /* bytes uploaded */
  82. int passive;
  83. int datafd = 0; /* data connection file descriptor */
  84. struct sockaddr_in ctrlconn; /* stdin/stdout, for using the same ip number */
  85. const int cmdsize = PATH_MAX + 32;
  86. char cmd[PATH_MAX + 32]; /* command line - about 30 chars for command */
  87. char wd[PATH_MAX + 1]; /* current working directory */
  88. char *rd = NULL; /* root directory, for chroot'd environments */
  89. char * cpwd = NULL; /* crypted password of the user one logs in as */
  90. int loggedin = 0;
  91. char account[9];
  92. char * renamefrom = 0;
  93. int warez = 0; /* don't guard against warez */
  94. int debug = 0; /* don't give debug output */
  95. int guest = 0; /* if non-zero, it's a guest user */
  96. uid_t useruid = 0; /* smallest uid which can ftp */
  97. int candownload = 0; /* if non-zero, don't let the user download */
  98. double load; /* for reporting what the load was */
  99. int firstport = 0; /* first and last ports to use, if we're */
  100. int lastport = 0; /* packet filter friendly. */
  101. int type = 1; /* type - 0 = error, 1 = ascii, 2 = binary */
  102. int restartat;
  103. unsigned long int idletime = 1800;
  104. struct reply {
  105.     struct reply *prev;
  106.     char line[1];
  107. };
  108. struct reply *lastreply = 0;
  109. int replycode = 0;
  110. struct sockaddr_in peer;
  111. unsigned short int peerdataport;
  112. void addreply( int code, const char *line,... )
  113. {
  114.     struct reply *p;
  115.     struct reply *q;
  116.     char buf[PATH_MAX + 50];
  117.     va_list ap;
  118.     int offs;
  119.     if ( code )
  120. replycode = code;
  121.     q = NULL;
  122.     va_start( ap, line );
  123.     vsnprintf( buf, PATH_MAX + 50, line, ap );
  124.     va_end( ap );
  125.     offs = strlen( buf );
  126.     while ( offs-- && isspace( buf[offs] ) )
  127. buf[offs] = '';
  128.     if ( !offs && buf[0] )
  129. offs++;
  130.     while ( offs ) {
  131. while ( offs && buf[offs] != 'n' && isspace( buf[offs] ) )
  132.     buf[offs--] = '';
  133. while ( offs && buf[offs] != 'n' )
  134.     offs--;
  135. if ( offs )
  136.     offs++;
  137. p = (struct reply *)malloc( sizeof(struct reply) + strlen(buf+offs) );
  138. if ( !p ) {
  139.     printf( "421 Out of memoryrn" );
  140.     fflush( stdout );
  141.     syslog( LOG_ERR, "out of memory" );
  142.     exit( 6 );
  143. }
  144. strcpy( p->line, buf + offs );
  145. if ( q ) {
  146.     p->prev = q->prev;
  147.     q->prev = p;
  148. } else {
  149.     p->prev = lastreply;
  150.     lastreply = p;
  151. }
  152. q = p;
  153. if ( offs )
  154.     buf[--offs] = 'r';
  155.     }
  156. }
  157. void replycont( struct reply * ); /* ick */
  158. void replycont( struct reply *p )
  159. {
  160.     if ( p ) {
  161. replycont( p->prev );
  162. printf( "%3d-%srn", replycode, p->line );
  163. if ( logging > 1 )
  164.     syslog( LOG_DEBUG,  "%3d-%sn", replycode, p->line );
  165. free( (char * ) p );
  166.     }
  167. }
  168. void doreply( void )
  169. {
  170.     if ( lastreply ) {
  171. replycont( lastreply->prev );
  172. printf( "%3d %srn", replycode, lastreply->line );
  173. if ( logging > 1 )
  174.     syslog( LOG_DEBUG,  "%3d %sn", replycode, lastreply->line );
  175. free( (char * ) lastreply );
  176. lastreply = NULL;
  177. fflush( stdout );
  178.     }
  179. }
  180. /* this is dog-slow.  but now it's 100% in compliance with the protocol. */
  181. int sfgets( void )
  182. {
  183.     int l;
  184.     int nread;
  185.     fd_set rs;
  186.     struct timeval tv;
  187.     FD_ZERO( &rs );
  188.     tv.tv_sec = idletime;
  189.     tv.tv_usec = 0;
  190.     nread = 0;
  191.     l = 0;
  192.     do {
  193. if ( nread == 0 ) {
  194.     FD_SET( 0, &rs );
  195.     select( 1, &rs, NULL, NULL, &tv );
  196.     if ( ioctl( 0, FIONREAD, &nread ) < 0 )
  197. nread = 0;
  198. }
  199. if ( FD_ISSET( 0, &rs ) ) {
  200.     int i;
  201.     i = read( 0, cmd+l, 1 );
  202.     if ( i == 0 ) {
  203. syslog( LOG_INFO, "exiting due to EOF from client" );
  204. exit( 21 );
  205.     } else if ( i < 0 ) {
  206. syslog( LOG_INFO,
  207. "exiting due to read error from client: %m" );
  208. exit( 22 );
  209.     }
  210.     if ( nread )
  211. nread--;
  212.     if ( cmd[l] == 'n' ) {
  213. /* if you need to debug ftpd, you can (e.g.) connect
  214.                    to it using an ordinary client, connect to the
  215.                    process using gdb or another ptrace()-aware
  216.                    debugger, and set a breakpoint on the next
  217.                    line. ftpd will hit the breakpoint immediately
  218.                    after the next command or whever the timeout hits. */
  219. cmd[l+1] = '';
  220. return 1;
  221.     }
  222.     if ( l < cmdsize - 2 )
  223. l++;
  224. } else {
  225.     return 0;
  226. }
  227.     } while( 1 );
  228. }
  229. void parser( void )
  230. {
  231.     char *arg;
  232.     int n;
  233.     while ( 1 ) {
  234. doreply();
  235. if ( !sfgets() ) {
  236.     addreply( 421,
  237.       "Timeout - try typing a little faster next time." );
  238.     syslog( LOG_INFO, "exiting due to timeout (idle time %d)",
  239.     idletime );
  240.     return;
  241. }
  242. if ( debug )
  243.     addreply( 0, "%s", cmd );
  244. n = 0;
  245. while ( isalpha( cmd[n] ) && n < cmdsize ) {
  246.     cmd[n] = tolower( cmd[n] );
  247.     n++;
  248. }
  249. if ( n >= cmdsize ) {
  250.     addreply( 421,
  251.       "Command line maximum length exceeded." );
  252.     syslog( LOG_INFO, "found line over 1000 characters" );
  253.     return;
  254. }
  255. if ( !n ) {
  256.     addreply( 221,
  257.       "Goodbye.  You uploaded %d and downloaded %d kbytes.",
  258.       (uploaded+1023)/1024, (downloaded+1023)/1024 );
  259.     continue;
  260. }
  261. while ( isspace( cmd[n] ) && n < cmdsize )
  262.     cmd[n++] = '';
  263. arg = cmd + n;
  264. while ( cmd[n] && n < cmdsize )
  265.     n++;
  266. n--;
  267. while ( isspace( cmd[n] ) )
  268.     cmd[n--] = '';
  269. if ( logging )
  270.     syslog( LOG_DEBUG, "command %s %s",
  271.     cmd, strcasecmp( cmd, "pass" ) ? arg : "<password>" );
  272. if ( !strcasecmp( cmd, "user" ) ) {
  273.     douser( arg );
  274. } else if ( !strcasecmp( cmd, "pass" ) ) {
  275.     dopass( arg );
  276. } else if ( !strcasecmp( cmd, "quit" ) ) {
  277.     addreply( 221,
  278.       "Goodbye.  You uploaded %d and downloaded %d kbytes.",
  279.       (uploaded+1023)/1024, (downloaded+1023)/1024 );
  280.     return;
  281. } else if ( !strcasecmp( cmd, "noop" ) ) {
  282.     addreply( 200, "NOOP command successful" );
  283. } else if ( !strcasecmp( cmd, "syst" ) ) {
  284.     printf( "215 UNIX Type: L8rn" );
  285.     fflush( stdout );
  286. } else if ( !strcasecmp( cmd, "port" ) ) {
  287.     /* don't auto-login for PORT or PASV, but do auto-login
  288.        for the command which _uses_ the data connection */
  289.     unsigned int a1, a2, a3, a4, p1, p2;
  290.     if ( arg &&
  291.  6 == sscanf( arg, "%d,%d,%d,%d,%d,%d",
  292.       &a1, &a2, &a3, &a4, &p1, &p2 ) &&
  293.  a1 < 256 && a2 < 256 && a3 < 256 && a4 < 256 &&
  294.  p1 < 256 && p2 < 256 ) {
  295. doport( (a1 << 24) + (a2 << 16) + (a3 << 8) + a4,
  296. ( (p1 << 8 ) + p2 ) );
  297.     } else {
  298. addreply( 501, "Syntax error." );
  299.     }
  300. } else if ( !strcasecmp( cmd, "pasv" ) ) {
  301.     dopasv();
  302. } else if ( !strcasecmp( cmd, "pwd" ) ||
  303.     !strcasecmp( cmd, "xpwd" ) ) {
  304.     if ( loggedin )
  305. addreply( 257, ""%s"rn", wd );
  306.     else
  307. addreply( 550, "Not logged in" );
  308. } else if( !strcasecmp( cmd, "auth" ) ) {
  309.     /* RFC 2228 Page 5 Authentication/Security mechanism (AUTH) */
  310.     addreply( 502, "Security extensions not implemented" );
  311. } else {
  312.     /* from this point, all commands trigger an automatic login */
  313.     douser( NULL );
  314.     if ( !strcasecmp( cmd, "cwd" ) ) {
  315. docwd( arg );
  316.     } else if ( !strcasecmp( cmd, "cdup" ) ) {
  317. docwd( ".." );
  318.     } else if ( !strcasecmp( cmd, "retr" ) ) {
  319. if ( arg && *arg )
  320.     doretr( arg );
  321. else
  322.     printf( "501 No file namern" );
  323.     } else if ( !strcasecmp( cmd, "rest" ) ) {
  324. if (arg && *arg)
  325.     dorest(arg);
  326. else
  327.     addreply (501, "No restart point");
  328.     } else if ( !strcasecmp( cmd, "dele" ) ) {
  329. if ( arg && *arg )
  330.     dodele( arg );
  331. else
  332.     addreply( 501, "No file namern" );
  333.     } else if ( !strcasecmp( cmd, "stor" ) ) {
  334. if ( arg && *arg )
  335.     dostor( arg );
  336. else
  337.     addreply( 501, "No file name." );
  338.     } else if ( !strcasecmp( cmd, "mkd" ) ||
  339. !strcasecmp( cmd, "xmkd" ) ) {
  340. if ( arg && *arg )
  341.     domkd( arg );
  342. else
  343.     addreply( 501, "No directory name." );
  344.     } else if ( !strcasecmp( cmd, "rmd" ) ||
  345. !strcasecmp( cmd, "xrmd" ) ) {
  346. if ( arg && *arg )
  347.     dormd( arg );
  348. else
  349.     addreply( 550, "No directory name." );
  350.     } else if ( !strcasecmp( cmd, "list" ) ) {
  351. opt_l = 1;
  352. donlist( (arg && *arg ) ? arg :  "" );
  353.     } else if ( !strcasecmp( cmd, "nlst" ) ) {
  354. opt_l = 0;
  355. donlist( (arg && *arg ) ? arg :  "" );
  356.     } else if ( !strcasecmp( cmd, "type" ) ) {
  357. dotype( arg );
  358.     } else if ( !strcasecmp( cmd, "mode" ) ) {
  359. domode( arg );
  360.     } else if ( !strcasecmp( cmd, "stru" ) ) {
  361. dostru( arg );
  362.     } else if ( !strcasecmp( cmd, "abor" ) ) {
  363. addreply( 226, "Since you see this ABOR must've succeeded." );
  364.     } else if ( !strcasecmp( cmd, "site" ) ) {
  365. char *sitearg;
  366. sitearg = arg;
  367. while ( sitearg && *sitearg && !isspace( *sitearg ) )
  368.     sitearg++;
  369. if ( sitearg )
  370.     *sitearg++ = '';
  371. if ( !strcasecmp( arg, "idle" ) ) {
  372.     if ( !*sitearg ) {
  373. addreply( 501, "SITE IDLE: need argument" );
  374.     } else {
  375. unsigned long int i = 0;
  376. i = strtoul( sitearg, &sitearg, 10 );
  377. if ( sitearg && *sitearg )
  378.     addreply( 501, "Garbage ( %s ) after value ( %d )",
  379.       sitearg, i );
  380. else if ( i > 7200 )
  381.     addreply( 501, "Too large ( >7200 seconds )" );
  382. else
  383.     addreply( 200, "Idle time set to %u seconds",
  384.       ( idletime = i ) );
  385.     }
  386. } else if ( arg && *arg ) {
  387.     addreply( 500, "SITE %s unknown", arg );
  388. } else {
  389.     addreply( 500, "SITE: argument needed" );
  390. }
  391.     } else if ( !strcasecmp( cmd, "xdbg" ) ) {
  392. debug++;
  393. addreply( 200,
  394.   "XDBG command succeeded, debug level is now %d.",
  395.   debug );
  396.     } else if ( !strcasecmp( cmd, "mdtm" ) ) {
  397. domdtm( (arg && *arg ) ? arg : "" );
  398.     } else if ( !strcasecmp( cmd, "size" ) ) {
  399. dosize( (arg && *arg ) ? arg : "" );
  400.     } else if ( !strcasecmp( cmd, "rnfr" ) ) {
  401. if ( arg && *arg )
  402.     dornfr( arg );
  403. else
  404.     addreply( 550, "No file name given." );
  405.     } else if ( !strcasecmp( cmd, "rnto" ) ) {
  406. if ( arg && *arg )
  407.     dornto( arg );
  408. else
  409.     addreply( 550, "No file name given." );
  410.     } else {
  411. addreply( 500, "Unknown command." );
  412.     }
  413. }
  414.     }
  415. }
  416. /* small help routine to display a banner */
  417. void dobanner( void )
  418. {
  419.     int m;
  420.     FILE *msg;
  421.     m = 0;
  422.     if ( (msg = fopen( ".banner", "r" ) ) != NULL ) {
  423. /* if you think this is too small, send me mail.  NOTE: It should
  424.    not be unlimited.  Take a look at e.g. ftp.3com.com to see why:
  425.    at the time of writing the logon banner is 250-odd lines */
  426. char buffer[1025];
  427. int len = fread( (void * ) buffer, 1, 1024, msg );
  428. fclose( msg );
  429. if ( len > 0 && len < 1024 ) {
  430.     buffer[len] = '';
  431.     addreply( 0, "%s", buffer );
  432. }
  433.     }
  434. }
  435. void douser( const char *username )
  436. {
  437.     struct passwd *pw;
  438.     if ( loggedin ) {
  439. if ( username ) {
  440.     if ( guest )
  441. addreply( 230, "Anonymous user logged in, no "
  442.   "need for a password." );
  443.     else
  444. addreply( 530, "You're already logged in." );
  445. }
  446. return;
  447.     }
  448.     if ( username &&
  449.  strcasecmp( username, "ftp" ) &&
  450.  strcasecmp( username, "anonymous" ) ) {
  451. char *shell;
  452. if ( cpwd ) {
  453.     free( (void*) cpwd );
  454.     cpwd = NULL;
  455. }
  456. pw = getpwnam( username );
  457. setusershell();
  458. while ( (shell = getusershell() ) != NULL &&
  459. pw && strcmp( pw->pw_shell, shell ) ) ;
  460. endusershell();
  461. if ( shell && pw &&
  462.      ( pw->pw_uid >= useruid ) &&
  463.      chdir( pw->pw_dir ) == 0 ) {
  464. #ifdef USE_SHADOW
  465.     struct spwd *spw;
  466.     if ( !strcmp(pw->pw_passwd, "x") &&
  467.  (spw = getspnam( username ) ) )
  468. cpwd = strdup( spw->sp_pwdp[0] == '@' ? "*" : spw->sp_pwdp );
  469.     else
  470. #endif
  471. cpwd = strdup( pw->pw_passwd );
  472.     setfsuid( pw->pw_uid );
  473.     setregid( pw->pw_gid, pw->pw_gid );
  474.     setgroups( sizeof( pw->pw_gid ), &( pw->pw_gid ) );
  475.     initgroups( pw->pw_name, pw->pw_gid );
  476. } else {
  477.     cpwd = strdup("*");
  478. }
  479. strncpy( account, username, 8 );
  480. account[8] = '';
  481. addreply( 331, "User %s OK.  Password required.", account );
  482. loggedin = 0;
  483.     } else {
  484. if ( (pw = getpwnam( "ftp" ) ) == NULL ||
  485.      pw->pw_uid == 0 || pw->pw_gid == 0 ||
  486.      setregid( pw->pw_gid, pw->pw_gid ) ||
  487.      setgroups( sizeof( pw->pw_gid ), &( pw->pw_gid ) ) ||
  488.      chroot( pw->pw_dir ) ||
  489.      !( rd = strdup( pw->pw_dir ) ) ||
  490.      chdir( "/" ) ) {
  491.     syslog( LOG_ERR, "unable to set up secure anonymous FTP" );
  492.     printf( "421 can't set up secure anonymous FTP, abortingrn" );
  493.     fflush( stdout );
  494.     sleep( 1 );
  495.     exit( 4 );
  496. }
  497. setfsuid( pw->pw_uid );
  498. dobanner();
  499. /* the 230 will be overwritten if this is an implicit login */
  500. addreply( 230, "Anonymous user logged in." );
  501. strcpy( account, "ftp" );
  502. rd = strdup( pw->pw_dir );
  503. loggedin = guest = 1;
  504. syslog( LOG_INFO, "guest logged in" );
  505.     }
  506.     (void)getcwd( wd, PATH_MAX );
  507. }
  508. void dopass( const char *password )
  509. {
  510.     if ( loggedin ||
  511.  ( cpwd && !strcmp( cpwd, (const char *)crypt( password, cpwd ) ) ) ) {
  512. gid_t g[NGROUPS_MAX];
  513. int ngroups;
  514. /* note that the password stays around for a short while, so
  515.  root is able to find out what the user's password is */
  516. if ( !loggedin )
  517.     candownload = 1; /* real users can always download */
  518. ngroups = getgroups( NGROUPS_MAX, g );
  519. if ( ngroups > 0 ) {
  520.     char reply[80];
  521.     int p;
  522.     char *q;
  523.     sprintf( reply, "User %s has group access to:", account );
  524.     p = strlen( reply );
  525.     do {
  526. ngroups--;
  527. q = getgroup( g[ngroups] );
  528. if ( p + strlen(q) > 75 ) {
  529.     reply[p] = '';
  530.     addreply( 0, "%s", reply );
  531.     *reply = '';
  532.     p = 0;
  533. }
  534. reply[p++] = ' ';
  535. while ( q && *q && !isspace( *q ) )
  536.     reply[p++] = *q++;
  537.     } while ( ngroups > 0 );
  538.     reply[p] = '';
  539.     addreply( 0, "%s", reply );
  540. }
  541. addreply( 230, "OK.  Current directory is %s", wd );
  542. syslog( LOG_INFO, "%s logged in", account );
  543. loggedin = 1;
  544.     } else {
  545. addreply( 530, "Sorry" );
  546.     }
  547. }
  548. void docwd( const char *dir )
  549. {
  550.     char buffer[PATH_MAX + 256]; /* let's hope... */
  551.     if ( loggedin && !guest && dir && *dir == '~' ) {
  552. struct passwd *pw;
  553. int i;
  554. const char *p;
  555. i = 0;
  556. p = dir;
  557. p++;
  558. while ( *p && *p != '/' )
  559.     buffer[i++] = *p++;
  560. buffer[i] = '';
  561. if ( (pw = getpwnam( i ? buffer : account ) ) )
  562.     snprintf( buffer, PATH_MAX+255, "%s%s", pw->pw_dir, p );
  563. else
  564.     *buffer = '';
  565.     } else {
  566. *buffer = '';
  567.     }
  568.     if ( chdir( *buffer ? buffer : ( dir && *dir ? dir :  "/" ) ) ) {
  569. snprintf( buffer, PATH_MAX+255, "Can't change directory to %s: %s",
  570.   dir, strerror( errno ) );
  571. syslog( LOG_INFO, "%s", buffer );
  572. addreply( 530, "%s", buffer );
  573.     } else {
  574. int m;
  575. FILE *msg;
  576. m = 0;
  577. if ( (msg = fopen( ".message", "r" ) ) != NULL ) {
  578.     int len = fread( (void *)buffer, 1, 1024, msg );
  579.     fclose( msg );
  580.     if ( len > 0 && len < 1024 ) {
  581. buffer[len] = '';
  582. addreply( 0, "%s", buffer );
  583.     }
  584. }
  585. if ( !getcwd( wd, PATH_MAX ) ) {
  586.     if ( *dir == '/' ) {
  587. snprintf( wd, PATH_MAX, "%s", dir ); /* already checked */
  588.     } else {
  589. if ( snprintf( wd, PATH_MAX, "%s/%s", wd, dir ) < 0 ) {
  590.     printf( "421 Path too longrn" );
  591.     fflush( stdout );
  592.     syslog( LOG_ERR, "path too long" );
  593.     exit( 14 );
  594. }
  595.     }
  596. }
  597. addreply( 250, "Changed to %s", wd );
  598.     }
  599. }
  600. void dopasv( void )
  601. {
  602.     unsigned int fodder;
  603.     unsigned int a;
  604.     unsigned int p;
  605.     unsigned int on;
  606.     struct sockaddr_in dataconn; /* my data connection endpoint */
  607.     int firstporttried;
  608.     if ( datafd ) { /* for buggy clients */
  609. close( datafd );
  610. datafd = 0;
  611.     }
  612.     datafd = socket( AF_INET, SOCK_STREAM, 0 );
  613.     if ( datafd < 0 ) {
  614. error( 425, "Can't open passive connection" );
  615. datafd = 0;
  616. return;
  617.     }
  618.     on = 1;
  619.     if ( setsockopt( datafd, SOL_SOCKET, SO_REUSEADDR,
  620.      &on, sizeof(on) ) < 0 ) {
  621. error( 421, "setsockopt" );
  622. return;
  623.     }
  624.     dataconn = ctrlconn;
  625.     if ( firstport && lastport )
  626. firstporttried = firstport + ( getpid() % (lastport-firstport+1) );
  627.     else
  628. firstporttried = 0;
  629.     p = firstporttried;;
  630.     dataconn.sin_port = ntohs( p );
  631.     while ( bind( datafd,
  632.   (struct sockaddr *)&dataconn, sizeof(dataconn) ) < 0 ) {
  633. if ( firstporttried ) {
  634.     p--;
  635.     if ( p < firstport )
  636. p = lastport;
  637. }
  638. if ( firstporttried == 0 || firstporttried == p ) {
  639.     if ( firstporttried )
  640. addreply( 0, "TCP ports %d to %d inclusive are all busy",
  641.   firstport, lastport );
  642.     error( 425, "Can't bind to socket" );
  643.     close( datafd );
  644.     datafd = 0;
  645.     return;
  646. }
  647. dataconn.sin_port = ntohs( p );
  648.     }
  649.     (void)listen( datafd, 1 ); /* maybe 0 on some unices? */
  650.     fodder = sizeof( dataconn );
  651.     if ( getsockname( datafd, (struct sockaddr *)&dataconn, &fodder ) < 0 ) {
  652. error( 425, "Can't getsockname( dataconn )" );
  653. close( datafd );
  654. datafd = 0;
  655. return;
  656.     }
  657.     a = ntohl( dataconn.sin_addr.s_addr );
  658.     p = ntohs( (unsigned short int ) ( dataconn.sin_port ) );
  659.     addreply( 227, "Passive mode OK (%d,%d,%d,%d,%d,%d)",
  660.       (a >> 24) & 255, (a >> 16) & 255, (a >> 8) & 255, a & 255,
  661.       (p >> 8) & 255, p & 255 );
  662.     passive = 1;
  663.     return;
  664. }
  665. void doport( unsigned int a, unsigned int p )
  666. {
  667.     struct sockaddr_in dataconn; /* his endpoint */
  668.     int on;
  669.     if ( datafd ) { /* for buggy clients saying PORT over and over */
  670. close( datafd );
  671. datafd = 0;
  672.     }
  673.     datafd = socket( AF_INET, SOCK_STREAM, 0 );
  674.     if ( datafd < 0 ) {
  675. error( 425, "Can't make data socket" );
  676. datafd = 0;
  677. return;
  678.     }
  679.     on = 1;
  680.     if ( setsockopt( datafd, SOL_SOCKET, SO_REUSEADDR,
  681.      &on, sizeof(on) ) < 0 ) {
  682. error( 421, "setsockopt" );
  683. return;
  684.     }
  685.     dataconn = ctrlconn;
  686.     dataconn.sin_port = htons( (short ) 20 ); /* FTP data connection port */
  687.     if ( bind( datafd, (struct sockaddr *)&dataconn, sizeof(dataconn) ) < 0 ) {
  688. error( -220, "bind" );
  689. close( datafd );
  690. datafd = 0;
  691. return;
  692.     }
  693.     if ( debug )
  694. addreply( 0, "My data connection endpoint is %s:%d",
  695.   inet_ntoa( *(struct in_addr *)&dataconn.sin_addr.s_addr ),
  696.   ntohs( dataconn.sin_port ) );
  697.     peerdataport = p;
  698.     if ( htonl( a ) != peer.sin_addr.s_addr ) {
  699. addreply( 425, "Will not open connection to %d.%d.%d.%d (only to %s)",
  700.   (a >> 24) & 255, (a >> 16) & 255, (a >> 8) & 255, a & 255,
  701.   inet_ntoa( peer.sin_addr ) );
  702. close( datafd );
  703. datafd = 0;
  704. return;
  705.     }
  706.     passive = 0;
  707.     addreply( 200, "PORT command successful" );
  708.     return;
  709. }
  710. int opendata( void )
  711. {
  712.     struct sockaddr_in dataconn; /* his data connection endpoint */
  713.     int fd;
  714.     int fodder;
  715.     if ( !datafd ) {
  716. error( 425, "No data connection" );
  717. return 0;
  718.     }
  719.     if ( passive ) {
  720. fodder = sizeof( dataconn );
  721. fd = accept( datafd, (struct sockaddr *)&dataconn, &fodder );
  722. if ( fd < 0 ) {
  723.     error( 421, "accept failed" );
  724.     return 0;
  725. }
  726. addreply( 150, "Accepted data connection from %s:%d",
  727.   inet_ntoa( dataconn.sin_addr ),
  728.   ntohs((unsigned short int)dataconn.sin_port) );
  729.     } else {
  730. dataconn.sin_addr.s_addr = peer.sin_addr.s_addr;
  731. dataconn.sin_port = htons( peerdataport );
  732. dataconn.sin_family = AF_INET;
  733. if (connect(datafd, (struct sockaddr *)&dataconn, sizeof(dataconn))) {
  734.     addreply( 425, "Could not open data connection to %s port %d: %s",
  735.       inet_ntoa( dataconn.sin_addr ), peerdataport,
  736.       strerror( errno ) );
  737.     close( datafd );
  738.     datafd = 0;
  739.     return 0;
  740. }
  741. fd = datafd;
  742. datafd = 0;
  743. addreply( 150, "Connecting to %s:%d",
  744.   inet_ntoa( dataconn.sin_addr ), peerdataport );
  745.     }
  746.     fodder = IPTOS_THROUGHPUT;
  747.     if ( setsockopt( fd, SOL_IP, IP_TOS, (char *)&fodder, sizeof(int) ) < 0 )
  748.   syslog( LOG_WARNING, "setsockopt( IP_TOS ): %m" );
  749.     fodder = window;
  750.     if ( setsockopt( fd, SOL_SOCKET, SO_SNDBUF,
  751.      (char *)&fodder, sizeof(int) ) < 0 )
  752. syslog( LOG_WARNING, "setsockopt( SO_SNDBUF, %d ): %m", window );
  753.     fodder = window; /* not that important, but... */
  754.     if ( setsockopt( fd, SOL_SOCKET, SO_RCVBUF,
  755.      (char *)&fodder, sizeof(int) ) < 0 )
  756. syslog( LOG_WARNING, "setsockopt( SO_RCVBUF, %d ): %m", window );
  757.     return fd;
  758. }
  759. void dodele( const char *name )
  760. {
  761.     if ( guest ) {
  762. addreply( 550, "Anonymous users can not delete files." );
  763.     } else if ( !name || !*name ) {
  764. addreply( 501, "No file name supplied." );
  765.     } else {
  766. int successes = 0;
  767. glob_t g;
  768. int a;
  769. a = glob( name, 0, NULL, &g );
  770. if ( a == GLOB_NOSPACE ) {
  771.     addreply( 550, "Out of memory during globbing of %s", name );
  772.     addreply( 0, "(This probably means "Permission denied")" );
  773. } else if ( a == GLOB_ABEND ) {
  774.     addreply( 550, "Read error during globbing of %s", name );
  775. } else if ( a == GLOB_NOMATCH ) {
  776.     addreply( 550, "No match for %s in %s", name, wd );
  777. } else if ( a == 0 ) {
  778.     char **path;
  779.     path = g.gl_pathv;
  780.     while ( path && *path ) {
  781. if ( unlink( *path ) ) {
  782.     addreply( 0, "Could not delete %s: %s",
  783.       *path, strerror( errno ) );
  784. } else {
  785.     addreply( 250, "Deleted %s", *path );
  786.     successes++;
  787. }
  788. path++;
  789.     }
  790. }
  791. globfree( &g );
  792. /* set the reply code in case there were no successes */
  793. if ( successes == 0 )
  794.     addreply( 550, "No files deleted." );
  795.     }
  796. }
  797. void doretr( const char *name )
  798. {
  799.     int c, f, o, s, skip;
  800.     struct stat st;
  801.     char *p, *buf;
  802.     int left;
  803.     struct timeval started, ended;
  804.     double t;
  805.     double speed;
  806.     char speedstring[30];
  807.     if ( !candownload ) {
  808. addreply( 550, "The load was %3.2f when you connected.  We do not "
  809.   "allow downloadsnby anonymous users when the load is "
  810.   "that high.  Uploads are alwaysnallowed.", load );
  811. return;
  812.     }
  813.     f = open( name, O_RDONLY );
  814.     if ( f < 0 ) {
  815. char buffer[PATH_MAX + 40];
  816. snprintf( buffer, PATH_MAX+39, "Can't open %s", name );
  817. error( 550, buffer );
  818. return;
  819.     }
  820.     if ( fstat( f, &st ) ) {
  821. close( f );
  822. error( 451, "can't find file size" );
  823. return;
  824.     }
  825.     if ( restartat && ( restartat > st.st_size ) ) {
  826. addreply( 451, "Restart offset %d is too large for file size %d.n"
  827.   "Restart offset reset to 0.",
  828.   restartat, st.st_size );
  829. restartat = 0;
  830. return;
  831.     }
  832.     if ( !S_ISREG( st.st_mode ) ) {
  833. close( f );
  834. addreply( 450, "Not a regular file" );
  835. return;
  836.     }
  837.     if ( warez && ( st.st_uid == warez ) && guest ) {
  838. close( f );
  839. addreply( 550, "This file has been uploaded by an anonymous user.  "
  840.   "It has notnyet been approved for downloading by "
  841.   "the site administrators.n" );
  842. return;
  843.     }
  844.     c = opendata();
  845.     if ( !c ) {
  846. close( f );
  847. return;
  848.     }
  849.     if ( (s = fcntl( c, F_GETFL, 0 ) ) < 0 ) {
  850. error( 451, "fcntl failed" );
  851. close( f );
  852. close( c );
  853. return;
  854.     }
  855.     s |= FNDELAY;
  856.     fcntl( c, F_SETFL, s );
  857.     if ( type == 1 ) {
  858. addreply( 0,
  859.   "NOTE: ASCII mode requested, but binary mode used" );
  860. if ( (time( 0 ) % 1000000 ) == 0 )
  861.     addreply( 0, "The computer is your friend. Trust the computer" );
  862.     }
  863.     if ( st.st_size - restartat > 4096 )
  864. addreply( 0, "%.1f kbytes to download",
  865.   (st.st_size - restartat) / 1024.0 );
  866.     doreply();
  867.     (void)gettimeofday( &started, NULL );
  868.     o = restartat & ~262143;
  869.     skip = restartat - o;
  870.     while ( o < st.st_size ) {
  871. left = st.st_size - o;
  872. if ( left > 262144 )
  873.     left = 262144;
  874. buf = mmap( 0, left, PROT_READ, MAP_FILE | MAP_SHARED, f, o );
  875. if ( buf == (char *)-1 ) {
  876.     error( 451, "mmap of file failed" );
  877.     close( f );
  878.     close( c );
  879.     return;
  880. }
  881. p = buf;
  882. o += left;
  883. s = left;
  884. while ( left > skip ) {
  885.     size_t w;
  886.     w = write( c, p+skip, (size_t) (left - skip) );
  887.     if ( (int ) w < 0 ) {
  888. if ( errno == EAGAIN ) {
  889.     /* wait idletime seconds for progress */
  890.     fd_set rs;
  891.     fd_set ws;
  892.     struct timeval tv;
  893.     FD_ZERO( &rs );
  894.     FD_ZERO( &ws );
  895.     FD_SET( 0, &rs );
  896.     FD_SET( c, &ws );
  897.     tv.tv_sec = idletime;
  898.     tv.tv_usec = 0;
  899.     select( c + 1, &rs, &ws, NULL, &tv );
  900.     if ( FD_ISSET( 0, &rs ) ) {
  901. /* we assume is is ABRT since nothing else is legal */
  902. addreply( 426, "Transfer aborted" );
  903. munmap( buf, s );
  904. close( f );
  905. close( c );
  906. return;
  907.     } else if ( !( FD_ISSET( c, &ws ) ) ) {
  908. /* client presumably gone away */
  909. syslog( LOG_INFO,
  910. "died: %ld seconds without download progress",
  911. idletime );
  912. exit( 11 );
  913.     }
  914.     w = 0;
  915. } else {
  916.     error( 450, "Error during write to data connection" );
  917.     close( f );
  918.     close( c );
  919.     return;
  920. }
  921.     }
  922.     left -= w;
  923.     p += w;
  924. }
  925. skip = 0;
  926. munmap( buf, s );
  927.     }
  928.     (void)gettimeofday( &ended, NULL );
  929.     t = ( ended.tv_sec + ended.tv_usec / 1000000.0 ) -
  930. ( started.tv_sec + started.tv_usec / 1000000.0 );
  931.     addreply( 226, "File written successfully" );
  932.     if ( t && ( st.st_size - restartat ) > 2*window )
  933. speed = ( st.st_size - restartat - window ) / t;
  934.     else
  935. speed = 0.0;
  936.     if ( speed > 524288 )
  937. addreply( 0, "%.3f seconds (measured here), %.2f Mbytes per second",
  938.   t, speed / 1048576 );
  939.     else if ( speed > 512 )
  940. addreply( 0, "%.3f seconds (measured here), %.2f Kbytes per second",
  941.   t, speed / 1024 );
  942.     else if ( speed > 0.1 )
  943. addreply( 0, "%.3f seconds (measured here), %.2f bytes per second",
  944.   t, speed );
  945.     close( f );
  946.     close( c );
  947.     downloaded = downloaded + st.st_size - restartat;
  948.     if ( restartat ) {
  949. addreply( 0, "Restart offset reset to 0." );
  950. restartat = 0;
  951.     }
  952.     sprintf( speedstring, " (%.2fKB/sec)", speed/1024 );
  953.     syslog( LOG_INFO, "%s%s%s%s downloaded%s",
  954.     rd ? rd :  "",
  955.     *name == '/' ? "" : wd,
  956.     ( *name != '/' && ( !*wd || wd[strlen( wd ) - 1] != '/' ) )
  957.     ? "/" : "",
  958.     name,
  959.     speed > 0.1 ? speedstring : "" );
  960. }
  961. void dorest (const char *name)
  962. {
  963.     char *endptr;
  964.     restartat = strtoul( name, &endptr, 10 );
  965.     if ( *endptr ) {
  966. restartat = 0;
  967. addreply( 501, "RESTART needs numeric parameter." );
  968.     } else {
  969. syslog( LOG_NOTICE, "info: restart %d", restartat );
  970. addreply( 350,
  971.   "Restarting at %ld. Send STOR or RETR to initiate transfer.",
  972.   restartat );
  973.     }
  974. }
  975. /* next two functions contributed by Patrick Michael Kane <modus@asimov.net> */
  976. void domkd( const char *name )
  977. {
  978.     if ( guest )
  979. addreply( 550, "Sorry, anonymous users are not allowed to "
  980.   "make directories." );
  981.     else if ( (mkdir( name, 0755 ) ) < 0 )
  982. error( 550, "Can't create directory" );
  983.     else
  984. addreply( 257, "MKD command successful." );
  985. }
  986. void dormd( const char *name )
  987. {
  988.     if ( guest )
  989. addreply( 550, "Sorry, anonymous users are not allowed to "
  990.   "remove directories." );
  991.     else if ( (rmdir( name ) ) < 0 )
  992. error( 550, "Can't remove directory" );
  993.     else
  994. addreply( 250, "RMD command successful." );
  995. }
  996. void dostor( const char *name )
  997. {
  998.     int c, f;
  999.     char *p;
  1000.     char buf[16384];
  1001.     int r;
  1002.     static int filesize; /* static to avoid longjmp warning */
  1003.     struct statfs statfsbuf;
  1004.     struct stat st;
  1005.     // Added for ascii upload
  1006.     int i,j,k;
  1007.     char cpy[16384];
  1008.     char *q;
  1009.     filesize = 0;
  1010.     if ( type < 1 ) {
  1011. addreply( 503, "Only ASCII and binary modes are supported" );
  1012. return;
  1013.     }
  1014.     if ( !stat( name, &st ) )  {
  1015. if ( guest ) {
  1016.     addreply( 553,
  1017.       "Anonymous users may not overwrite existing files" );
  1018.     return;
  1019. }
  1020.     } else if ( errno != ENOENT ) {
  1021. error( 553, "Can't check for file presence" );
  1022. return;
  1023.     }
  1024.     f = open( name, O_CREAT | O_TRUNC | O_WRONLY, 0600 );
  1025.     if ( f < 0 ) {
  1026. error( 553, "Can't open file" );
  1027. return;
  1028.     }
  1029.     if ( restartat && lseek(f, restartat, SEEK_SET) < 0) {
  1030. error (451, "can't seek" );
  1031. return;
  1032.     }
  1033.     c = opendata();
  1034.     if ( !c ) {
  1035. close( f );
  1036. return;
  1037.     }
  1038.     doreply();
  1039.     k=0;
  1040.     do {
  1041. /* wait idletime seconds for data to be available */
  1042. fd_set rs;
  1043. struct timeval tv;
  1044. FD_ZERO( &rs );
  1045. FD_SET( 0, &rs );
  1046. FD_SET( c, &rs );
  1047. tv.tv_sec = idletime;
  1048. tv.tv_usec = 0;
  1049. select( c + 1, &rs, NULL, NULL, &tv );
  1050. if ( FD_ISSET( 0, &rs ) ) {
  1051.     addreply( 0, "ABRT is the only legal command while uploading" );
  1052.     addreply( 426, "Transfer aborted" );
  1053.     close( f );
  1054.     close( c );
  1055.     addreply( 0, "%s %s", name,
  1056.       unlink( name ) ? "partially uploaded" : "removed" );
  1057.     return;
  1058. } else if ( !( FD_ISSET( c, &rs ) ) ) {
  1059.     /* client presumably gone away */
  1060.     unlink( name );
  1061.     syslog( LOG_INFO, "died: %ld seconds without upload progress",
  1062.     idletime );
  1063.     exit( 20 );
  1064. }
  1065. r = read( c, &buf, 16384 );
  1066. if ( r > 0 ) {
  1067.     p = buf;
  1068.     filesize += r;
  1069.     while ( r ) {
  1070. size_t w;
  1071. if ( type == 1 ) {
  1072.     for (i=0,j=0;i < ( size_t ) r;i++,j++) {
  1073. if ( p[i] == 'r' ) {
  1074.     i++;
  1075.     k++;
  1076.   }
  1077. cpy[j] = buf[i];
  1078.     }
  1079.     q = cpy;
  1080.     r -= k;
  1081.     w = write( f, q, ( size_t ) r );
  1082. } else {
  1083.     w = write( f, p, ( size_t ) r );
  1084. }
  1085. if ( (signed int)w < 0 ) {
  1086.     error( -450, "Error during write to file" );
  1087.     close( f );
  1088.     close( c );
  1089.     addreply( 450, "%s %s", name,
  1090.       unlink(name)?"partially uploaded":"removed" );
  1091.     return;
  1092. }
  1093. r -= w;
  1094. p += w;
  1095.     }
  1096.     r = 1;
  1097. } else if ( r < 0 ) {
  1098.     error( -451, "Error during read from data connection" );
  1099.     close( f );
  1100.     close( c );
  1101.     addreply( 451, "%s %s", name,
  1102.       unlink( name ) ? "partially uploaded" : "removed" );
  1103.     return;
  1104. }
  1105.     } while ( r > 0 );
  1106.     fchmod( f, 0644 );
  1107.     addreply( 226, "File written successfully" );
  1108.     if ( fstatfs( f, &statfsbuf ) == 0 ) {
  1109. double space;
  1110. space = (double)statfsbuf.f_bsize * (double)statfsbuf.f_bavail;
  1111. if ( space > 524288 )
  1112.     addreply( 0, "%.1f Mbytes free disk space", space / 1048576 );
  1113. else
  1114.     addreply( 0, "%f Kbytes free disk space", space / 1024 );
  1115.     }
  1116.     close( f );
  1117.     close( c );
  1118.     uploaded += filesize;
  1119.     syslog( LOG_INFO, "%s%s%s%s uploaded",
  1120.     rd ? rd :  "",
  1121.     *name == '/' ? "" : wd,
  1122.     ( *name != '/' && ( !*wd || wd[strlen( wd ) - 1] != '/' ) )
  1123.     ? "/" : "",
  1124.     name );
  1125.     return;
  1126. }
  1127. void domdtm( const char *name )
  1128. {
  1129.     struct stat st;
  1130.     struct tm *t;
  1131.     if ( !name || !*name ) {
  1132. addreply( 500, "Command not understood" );
  1133.     } else if ( lstat( name, &st ) ) {
  1134. if ( debug )
  1135.     addreply( 0, "arg is %s, wd is %s", name, wd );
  1136. addreply( 550, "Unable to stat()" );
  1137.     } else if ( !S_ISREG( st.st_mode ) ) {
  1138. addreply( 550, "Not a regular file" );
  1139.     } else {
  1140. t = gmtime( (time_t * ) & st.st_mtime );
  1141. if ( !t ) {
  1142.     addreply( 550, "gmtime() returned NULL" );
  1143. } else {
  1144.     addreply( 213, "%04d%02d%02d%02d%02d%02d",
  1145.      t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1146.      t->tm_hour, t->tm_min, t->tm_sec );
  1147. }
  1148.     }
  1149.     return;
  1150. }
  1151. void dosize( const char *name )
  1152. {
  1153.     struct stat st;
  1154.     if ( !name || !*name ) {
  1155. addreply( 500, "Command not understood" );
  1156.     } else if ( lstat( name, &st ) ) {
  1157. if ( debug )
  1158.     addreply( 0, "arg is %s, wd is %s", name, wd );
  1159. addreply( 550, "Unable to stat()" );
  1160.     } else if ( !S_ISREG( st.st_mode ) ) {
  1161. addreply( 550, "Not a regular file" );
  1162.     } else {
  1163. addreply( 213, "%ld ", (long)st.st_size );
  1164.     }
  1165.     return;
  1166. }
  1167. void dotype( const char *arg )
  1168. {
  1169.     replycode = 200; /* bloody awful hack */
  1170.     if ( !arg || !*arg ) {
  1171. addreply( 501, "TYPE needs an argumentn"
  1172.  "Only A(scii), I(mage) and L(ocal) are supported" );
  1173.     } else if ( tolower(*arg) == 'a' )
  1174. type = 1;
  1175.     else if ( tolower(*arg) == 'i' )
  1176. type = 2;
  1177.     else if ( tolower(*arg) == 'l' ) {
  1178. if ( arg[1] == '8' ) {
  1179.     type = 2;
  1180. } else if ( isdigit( arg[1] ) ) {
  1181.     addreply( 504, "Only 8-bit bytes are supported" );
  1182. } else {
  1183.     addreply( 0, "Byte size not specified" );
  1184.     type = 2;
  1185. }
  1186.     } else {
  1187. addreply( 504, "Unknown TYPE: %s", arg );
  1188.     }
  1189.     addreply( 0, "TYPE is now %s", ( type > 1 ) ? "8-bit binary" : "ASCII" );
  1190. }
  1191. void dostru( const char *arg )
  1192. {
  1193.     if ( !arg || !*arg )
  1194. addreply( 500, "No argumentsn"
  1195.  "Not that it matters, only STRU F is supported" );
  1196.     else if ( strcasecmp( arg, "F" ) )
  1197. addreply( 504, "STRU %s is not supportednOnly F(ile) is supported",
  1198.  arg );
  1199.     else
  1200. addreply( 200, "F OK" );
  1201. }
  1202. void domode( const char *arg )
  1203. {
  1204.     if ( !arg || !*arg )
  1205. addreply( 500, "No argumentsn"
  1206.  "Not that it matters, only MODE S is supported" );
  1207.     else if ( strcasecmp( arg, "S" ) )
  1208. addreply( 504, "MODE %s is not supportedn"
  1209.  "Only S(tream) is supported", arg );
  1210.     else
  1211. addreply( 200, "S OK" );
  1212. }
  1213. void dornfr( const char *name )
  1214. {
  1215.     struct stat st;
  1216.     if ( guest ) {
  1217. addreply( 550,
  1218.   "Sorry, anonymous users are not allowed to rename files." );
  1219.     } else if ( ( stat( name, &st ) ) == 0 ) {
  1220. if ( renamefrom ) {
  1221.     addreply( 0, "Aborting previous rename operation." );
  1222.     (void) free( renamefrom );
  1223. }
  1224. renamefrom = strdup( name );
  1225. addreply( 350, "RNFR accepted - file exists, ready for destination." );
  1226.     } else {
  1227. addreply( 550, "File does not exist!" );
  1228.     }
  1229.     return;
  1230. }
  1231. /* rnto can return 550, which is not strictly allowed */
  1232. void dornto( const char *name )
  1233. {
  1234.     struct stat st;
  1235.     if ( guest )
  1236. addreply( 550,
  1237.   "Sorry, anonymous users are not allowed to rename files." );
  1238.     else if ( ( stat( name, &st ) ) == 0 )
  1239. addreply( 550, "RENAME Failed - destination file already exists." );
  1240.     else if ( !renamefrom )
  1241. addreply( 503, "Need RNFR before RNTO" );
  1242.     else if ( (rename( renamefrom, name ) ) < 0 )
  1243. addreply( 550, "Rename failed: %s", strerror( errno ) );
  1244.     else
  1245. addreply( 250, "File renamed." );
  1246.     if ( renamefrom )
  1247. (void) free( renamefrom );
  1248.     renamefrom = 0;
  1249.     return;
  1250. }
  1251. // end of addition
  1252. void error( int n, const char *msg )
  1253. {
  1254.     syslog( LOG_ERR, "%s: %m", msg );
  1255.     addreply( n, "%s: %s", msg, strerror( errno ) );
  1256. }
  1257. int main( int argc, char **argv )
  1258. {
  1259.     int fodder;
  1260.     struct hostent *he;
  1261.     struct passwd *pw;
  1262.     FILE *f;
  1263.     double maxload;
  1264.     time_t tmt;
  1265.     struct tm *t;
  1266.     struct rusage ru;
  1267.     int dowarez;
  1268.     unsigned long maxusers;
  1269.     struct sigaction sa;
  1270.     /* logging stuff.  use sigaction so they're not reset */
  1271.     sa.sa_handler = sighandler;
  1272.     sa.sa_mask = 0;
  1273.     sa.sa_flags = SA_RESTART;
  1274.     (void)sigaction( SIGUSR1, &sa, NULL );
  1275.     (void)sigaction( SIGUSR2, &sa, NULL );
  1276.     /* we pretend urgent data doesn't exist */
  1277.     sa.sa_handler = SIG_IGN;
  1278.     (void)sigaction( SIGURG, &sa, NULL );
  1279.     maxload = 0.0;
  1280.     maxusers = 0;
  1281.     openlog( "in.ftpd", LOG_CONS | LOG_PID, LOG_LOCAL2 );
  1282.     while ( (fodder = getopt( argc, argv, "c:df:m:p:su:" ) ) != -1 ) {
  1283. if ( fodder == 's' ) {
  1284.     if ( (pw = getpwnam( "ftp" ) ) )
  1285. warez = pw->pw_uid;
  1286.     else
  1287. syslog( LOG_ERR, "can't find ftp uid" );
  1288. } else if ( fodder == 'd' ) {
  1289.     if ( logging < 2 )
  1290. logging++;
  1291. } else if ( fodder == 'c' ) {
  1292.     char *nptr, *endptr;
  1293.     nptr = optarg;
  1294.     endptr = NULL;
  1295.     maxusers = strtoul( nptr, &endptr, 0 );
  1296.     if ( !nptr || !*nptr || !endptr || *endptr || !maxusers ) {
  1297. printf( "421 Configuration error: Illegal user limit: %srn",
  1298. optarg );
  1299. syslog( LOG_ERR, "Illegal user limit: %s", optarg );
  1300. sleep( 1 );
  1301. exit( 8 );
  1302.     }
  1303. } else if ( fodder == 'f' ) {
  1304.     int n;
  1305.     n=0;
  1306.     while( facilitynames[n].c_name &&
  1307.    strcasecmp( facilitynames[n].c_name, optarg ) )
  1308. n++;
  1309.     if ( facilitynames[n].c_name ) {
  1310. closelog();
  1311. openlog( "in.ftpd", LOG_CONS | LOG_PID,
  1312.  facilitynames[n].c_val );
  1313.     } else {
  1314. syslog( LOG_ERR, "Unknown facility name %s", optarg );
  1315.     }
  1316. } else if ( fodder == 'm' ) {
  1317.     char *nptr,
  1318. *endptr;
  1319.     nptr = optarg;
  1320.     endptr = NULL;
  1321.     maxload = strtod( nptr, &endptr );
  1322.     if ( !nptr || !*nptr || !endptr || *endptr || maxload <= 0.0 ) {
  1323. printf( "421 Configuration error: Illegal load limit: %srn",
  1324. optarg );
  1325. syslog( LOG_ERR, "Illegal load limit: %s", optarg );
  1326. sleep( 1 );
  1327. exit( 15 );
  1328.     }
  1329. } else if ( fodder == 'p' ) {
  1330.     int ret;
  1331.     ret = sscanf(optarg, "%d:%d", &firstport, &lastport);
  1332.     if ( ret != 2 ||
  1333.  firstport < 1024 ||
  1334.  lastport > 65535 ||
  1335.  lastport <= firstport ) {
  1336. printf( "421 Configuration error: Illegal port range: %srn",
  1337. optarg );
  1338. syslog( LOG_ERR, "Illegal port range: %s", optarg );
  1339. sleep( 1 );
  1340. exit( 17 );
  1341.     }
  1342. } else if ( fodder == 'u' ) {
  1343.     char *nptr, *endptr;
  1344.     long tmp;
  1345.     nptr = optarg;
  1346.     endptr = NULL;
  1347.     tmp = strtol( nptr, &endptr, 10 );
  1348.     if ( !nptr || !*nptr || !endptr || *endptr ||
  1349.  tmp > 65535 || tmp < 0 ) {
  1350. printf( "421 Configuration error: Illegal uid limit: %srn",
  1351. optarg );
  1352. syslog( LOG_ERR, "Illegal uid limit: %s", optarg );
  1353. sleep( 1 );
  1354. exit( 16 );
  1355.     }
  1356.     useruid = (uid_t) tmp;
  1357. } else if ( fodder == '?' ) {
  1358.     syslog( LOG_WARNING, "unknown option" );
  1359. }
  1360.     }
  1361.     if ( firstport || maxusers ) {
  1362. int users;
  1363. if ( firstport ) {
  1364.     int portmax;
  1365.     portmax = (lastport-firstport+1)/2;
  1366.     if ( !maxusers || maxusers > portmax )
  1367. maxusers = portmax; /* ... so we don't run out of ports */
  1368. }
  1369. users = daemons();
  1370. if ( users > maxusers ) {
  1371.     printf( "421 %d users (the maximum) are already logged inrn",
  1372.     maxusers );
  1373.     sleep( 1 );
  1374.     exit( 5 );
  1375. }
  1376. addreply( 0, "You are user number %d of %d allowed.",
  1377.   users, maxusers );
  1378.     }
  1379.     load = -1.0;
  1380.     if ( (f = fopen( "/proc/loadavg", "r" ) ) != NULL &&
  1381.  fscanf( f, "%lf", &load ) == 1 )
  1382. fclose( f );
  1383.     fodder = sizeof(struct sockaddr_in);
  1384.     if ( getsockname( 0, (struct sockaddr *)&ctrlconn, &fodder ) ) {
  1385. printf( "421 Cannot getsockname( STDIN ), errno=%drn", errno );
  1386. syslog( LOG_ERR, "Cannot getsockname( STDIN ): %s", strerror(errno) );
  1387. exit( 3 );
  1388.     }
  1389.     getnames();
  1390.     loggedin = 0;
  1391.     if ( getpeername( 0, (struct sockaddr *)&peer, &fodder ) ) {
  1392. printf( "421 Cannot getpeername( STDIN ), errno=%drn", errno );
  1393. syslog( LOG_ERR, "Cannot getpeername( STDIN ): %s", strerror(errno) );
  1394. sleep( 1 );
  1395. exit( 9 );
  1396.     }
  1397.     he = gethostbyaddr( (char *)&peer.sin_addr.s_addr,
  1398. sizeof(peer.sin_addr.s_addr),
  1399. AF_INET );
  1400.     syslog( LOG_INFO, "connection from %s",
  1401.     he && strlen( he->h_name )
  1402.     ? he->h_name : inet_ntoa( peer.sin_addr ) );
  1403.     he = gethostbyaddr( (char *)&ctrlconn.sin_addr.s_addr,
  1404. sizeof(ctrlconn.sin_addr.s_addr),
  1405. AF_INET );
  1406.     if ( he && he->h_name ) {
  1407. char name[PATH_MAX];
  1408. FILE * config;
  1409. if ( snprintf( name, PATH_MAX, "/var/adm/ftp/%s/.", he->h_name ) < 0 ){
  1410.     syslog( LOG_ERR, "host name far too long for %s",
  1411.     inet_ntoa( ctrlconn.sin_addr ) );
  1412.     exit( 15 );
  1413. }
  1414. if ( !chdir( name ) ) {
  1415.     rd = malloc( strlen( he->h_name ) + 3 );
  1416.     /* it'd be much better with a separate name here */
  1417.     if ( !rd ||
  1418.  ( pw = getpwnam( "ftp" ) ) == NULL ||
  1419.  setregid( pw->pw_gid, pw->pw_gid ) ||
  1420.  setgroups( sizeof( pw->pw_gid ), &( pw->pw_gid ) ) ||
  1421.  chroot( name ) ||
  1422.  chdir( "/" ) ) {
  1423. printf( "421 Unable to cage in anonymous user, abortingrn" );
  1424. syslog( LOG_INFO, "Unable to cage in anonymous user" );
  1425. fflush( stdout );
  1426. sleep( 1 );
  1427. exit( 10 );
  1428.     }
  1429.     sprintf( rd, "%s:", he->h_name );
  1430.     setfsuid( pw->pw_uid );
  1431.     dobanner();
  1432.     loggedin = guest = 1;
  1433.     syslog( LOG_INFO, "logged in guest of %s", he->h_name );
  1434. } else if ( (config=fopen( name, "r" )) != NULL ) {
  1435.     char line[1024];
  1436.     do {
  1437. fgets( line, 1024, config );
  1438.     } while( 0 );
  1439.     printf( "421 %s: configuration errorrn", name );
  1440.     syslog( LOG_ERR, "%s: configuration error", name );
  1441.     fflush( stdout );
  1442.     sleep( 1 );
  1443.     exit( 19 );
  1444. }
  1445. cpwd = strdup( "*" );
  1446.     }
  1447.     chdir( "/" );
  1448.     strcpy( wd, "/" );
  1449.     fodder = IPTOS_LOWDELAY;
  1450.     if ( setsockopt( 0, SOL_IP, IP_TOS, (char *)&fodder, sizeof(int) ) < 0 )
  1451. syslog( LOG_WARNING, "setsockopt ( IP_TOS ): %m" );
  1452.     fodder = 1;
  1453.     if ( setsockopt( 0, SOL_SOCKET, SO_OOBINLINE,
  1454.      (char *)&fodder, sizeof(int) ) < 0 )
  1455. syslog( LOG_WARNING, "setsockopt: %m" );
  1456.     tmt = time( NULL );
  1457.     t = localtime( (time_t *) &tmt );
  1458.     if ( t != 0 && load >= 0.0 )
  1459. addreply( 220,
  1460.   "Local time is now %02d:%02d and the load is %3.2f.",
  1461.   t->tm_hour, t->tm_min, load );
  1462.     else
  1463. syslog( LOG_ERR, "unable to read load average or current time" );
  1464.     if ( loggedin )
  1465. addreply( 220,
  1466.   "Only anonymous FTP is allowed at %s.", he->h_name );
  1467.     addreply( 220, "You will be disconnected after %d seconds of inactivity.",
  1468.       idletime );
  1469.     candownload = maxload <= 0.0 || load < maxload;
  1470.     parser();
  1471.     if ( getrusage( RUSAGE_SELF, &ru ) == 0 ) {
  1472. unsigned long s, u;
  1473. u = ( ru.ru_utime.tv_usec + ru.ru_stime.tv_usec + 500 ) / 1000;
  1474. s = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
  1475. if ( u > 999 ) {
  1476.     u -= 1000;
  1477.     s++;
  1478. }
  1479. addreply( 0, "CPU time spent on you: %ld.%03ld seconds.", s, u );
  1480.     }
  1481.     doreply();
  1482.     sleep( 1 );
  1483.     exit( 0 );
  1484. }