[BACK]Return to ftpcmd.y CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / ftpd

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/libexec/ftpd/ftpcmd.y between version 1.48.2.2 and 1.92

version 1.48.2.2, 2001/03/29 14:14:17 version 1.92, 2011/07/01 02:46:15
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   
 /*-  /*-
  * Copyright (c) 1997-2000 The NetBSD Foundation, Inc.   * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
  * This code is derived from software contributed to The NetBSD Foundation   * This code is derived from software contributed to The NetBSD Foundation
Line 15 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software  
  *    must display the following acknowledgement:  
  *        This product includes software developed by the NetBSD  
  *        Foundation, Inc. and its contributors.  
  * 4. Neither the name of The NetBSD Foundation nor the names of its  
  *    contributors may be used to endorse or promote products derived  
  *    from this software without specific prior written permission.  
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
Line 48 
Line 41 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software   * 3. Neither the name of the University nor the names of its contributors
  *    must display the following acknowledgement:  
  *      This product includes software developed by the University of  
  *      California, Berkeley and its contributors.  
  * 4. Neither the name of the University nor the names of its contributors  
  *    may be used to endorse or promote products derived from this software   *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.   *    without specific prior written permission.
  *   *
Line 97  __RCSID("$NetBSD$");
Line 86  __RCSID("$NetBSD$");
   
 #include <ctype.h>  #include <ctype.h>
 #include <errno.h>  #include <errno.h>
 #include <glob.h>  
 #include <pwd.h>  #include <pwd.h>
 #include <setjmp.h>  
 #include <signal.h>  
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
Line 121  static int cmd_type;
Line 107  static int cmd_type;
 static  int cmd_form;  static  int cmd_form;
 static  int cmd_bytesz;  static  int cmd_bytesz;
   
 char    cbuf[512];  char    cbuf[FTP_BUFLEN];
   char    *cmdp;
 char    *fromname;  char    *fromname;
   
   extern int      epsvall;
   struct tab      sitetab[];
   
   static  int     check_write(const char *, int);
   static  void    help(struct tab *, const char *);
   static  void    port_check(const char *, int);
           int     yylex(void);
   
 %}  %}
   
 %union {  %union {
         int     i;          struct {
         char   *s;                  LLT     ll;
                   int     i;
           } u;
           char *s;
           const char *cs;
 }  }
   
 %token  %token
         A       B       C       E       F       I          A       B       C       E       F       I
         L       N       P       R       S       T          L       N       P       R       S       T
   
         SP      CRLF    COMMA          SP      CRLF    COMMA   ALL
   
         USER    PASS    ACCT    CWD     CDUP    SMNT          USER    PASS    ACCT    CWD     CDUP    SMNT
         QUIT    REIN    PORT    PASV    TYPE    STRU          QUIT    REIN    PORT    PASV    TYPE    STRU
Line 161  char *fromname;
Line 160  char *fromname;
         LEXERR          LEXERR
   
 %token  <s> STRING  %token  <s> STRING
 %token  <s> ALL  %token  <u> NUMBER
 %token  <i> NUMBER  
   
 %type   <i> check_login octal_number byte_size  %type   <u.i> check_login octal_number byte_size
 %type   <i> struct_code mode_code type_code form_code decimal_integer  %type   <u.i> struct_code mode_code type_code form_code decimal_integer
 %type   <s> pathstring pathname password username  %type   <s> pathstring pathname password username
 %type   <s> mechanism_name base64data prot_code  %type   <s> mechanism_name base64data prot_code
   
 %start  cmd_list  %start  cmd_sel
   
 %%  %%
   
 cmd_list  cmd_sel
         : /* empty */          : cmd
   
         | cmd_list cmd  
                 {                  {
                         fromname = NULL;                          REASSIGN(fromname, NULL);
                         restart_point = (off_t) 0;                          restart_point = (off_t) 0;
                 }                  }
   
         | cmd_list rcmd          | rcmd
   
         ;          ;
   
Line 295  cmd
Line 291  cmd
         | LPSV check_login CRLF          | LPSV check_login CRLF
                 {                  {
                         if ($2) {                          if ($2) {
                                 if (epsvall)                                  if (CURCLASS_FLAGS_ISSET(passive)) {
                                         reply(501,                                          if (epsvall)
                                             "LPSV disallowed after EPSV ALL");                                                  reply(501,
                                 else                                                      "LPSV disallowed after EPSV ALL");
                                         long_passive("LPSV", PF_UNSPEC);                                          else
                                                   long_passive("LPSV", PF_UNSPEC);
                                   } else
                                           reply(500, "LPSV mode not available.");
                         }                          }
                 }                  }
   
         | EPSV check_login SP NUMBER CRLF          | EPSV check_login SP NUMBER CRLF
                 {                  {
                         if ($2)                          if ($2) {
                                 long_passive("EPSV", epsvproto2af($4));                                  if (CURCLASS_FLAGS_ISSET(passive))
                                           long_passive("EPSV",
                                               epsvproto2af($4.i));
                                   else
                                           reply(500, "EPSV mode not available.");
                           }
                 }                  }
   
         | EPSV check_login SP ALL CRLF          | EPSV check_login SP ALL CRLF
                 {                  {
                         if ($2) {                          if ($2) {
                                 reply(200, "EPSV ALL command successful.");                                  if (CURCLASS_FLAGS_ISSET(passive)) {
                                 epsvall++;                                          reply(200,
                                               "EPSV ALL command successful.");
                                           epsvall++;
                                   } else
                                           reply(500, "EPSV mode not available.");
                         }                          }
                 }                  }
   
         | EPSV check_login CRLF          | EPSV check_login CRLF
                 {                  {
                         if ($2)                          if ($2) {
                                 long_passive("EPSV", PF_UNSPEC);                                  if (CURCLASS_FLAGS_ISSET(passive))
                                           long_passive("EPSV", PF_UNSPEC);
                                   else
                                           reply(500, "EPSV mode not available.");
                           }
                 }                  }
   
         | TYPE check_login SP type_code CRLF          | TYPE check_login SP type_code CRLF
Line 442  cmd
Line 454  cmd
                         if (check_write($3, 0)) {                          if (check_write($3, 0)) {
                                 if (fromname) {                                  if (fromname) {
                                         renamecmd(fromname, $3);                                          renamecmd(fromname, $3);
                                         free(fromname);                                          REASSIGN(fromname, NULL);
                                         fromname = NULL;  
                                 } else {                                  } else {
                                         reply(503, "Bad sequence of commands.");                                          reply(503, "Bad sequence of commands.");
                                 }                                  }
Line 454  cmd
Line 465  cmd
   
         | ABOR check_login CRLF          | ABOR check_login CRLF
                 {                  {
                         if ($2)                          if (is_oob)
                                   abor();
                           else if ($2)
                                 reply(225, "ABOR command successful.");                                  reply(225, "ABOR command successful.");
                 }                  }
   
Line 490  cmd
Line 503  cmd
   
         | LIST check_login CRLF          | LIST check_login CRLF
                 {                  {
                         char *argv[] = { INTERNAL_LS, "-lgA", NULL };                          const char *argv[] = { INTERNAL_LS, "-lgA", NULL };
   
                           if (CURCLASS_FLAGS_ISSET(hidesymlinks))
                                   argv[1] = "-LlgA";
                         if ($2)                          if ($2)
                                 retrieve(argv, "");                                  retrieve(argv, "");
                 }                  }
   
         | LIST check_login SP pathname CRLF          | LIST check_login SP pathname CRLF
                 {                  {
                         char *argv[] = { INTERNAL_LS, "-lgA", NULL, NULL };                          const char *argv[] = { INTERNAL_LS, "-lgA", NULL, NULL };
   
                           if (CURCLASS_FLAGS_ISSET(hidesymlinks))
                                   argv[1] = "-LlgA";
                         if ($2 && $4 != NULL) {                          if ($2 && $4 != NULL) {
                                 argv[2] = $4;                                  argv[2] = $4;
                                 retrieve(argv, $4);                                  retrieve(argv, $4);
Line 529  cmd
Line 546  cmd
         | SITE SP CHMOD SP octal_number SP pathname CRLF          | SITE SP CHMOD SP octal_number SP pathname CRLF
                 {                  {
                         if (check_write($7, 0)) {                          if (check_write($7, 0)) {
                                 if ($5 > 0777)                                  if (($5 == -1) || ($5 > 0777))
                                         reply(501,                                          reply(501,
                                 "CHMOD: Mode value must be between 0 and 0777");                                  "CHMOD: Mode value must be between 0 and 0777");
                                 else if (chmod($7, $5) < 0)                                  else if (chmod($7, $5) < 0)
Line 551  cmd
Line 568  cmd
                 {                  {
                         if ($4) {                          if ($4) {
                                 reply(200,                                  reply(200,
                             "Current IDLE time limit is %d seconds; max %d",                                      "Current IDLE time limit is " LLF
                                     curclass.timeout, curclass.maxtimeout);                                      " seconds; max " LLF,
                                       (LLT)curclass.timeout,
                                       (LLT)curclass.maxtimeout);
                         }                          }
                 }                  }
   
         | SITE SP IDLE check_login SP NUMBER CRLF          | SITE SP IDLE check_login SP NUMBER CRLF
                 {                  {
                         if ($4) {                          if ($4) {
                                 if ($6 < 30 || $6 > curclass.maxtimeout) {                                  if ($6.i < 30 || $6.i > curclass.maxtimeout) {
                                         reply(501,                                          reply(501,
                             "IDLE time limit must be between 30 and %d seconds",                                  "IDLE time limit must be between 30 and "
                                             curclass.maxtimeout);                                              LLF " seconds",
                                               (LLT)curclass.maxtimeout);
                                 } else {                                  } else {
                                         curclass.timeout = $6;                                          curclass.timeout = $6.i;
                                         (void) alarm(curclass.timeout);                                          (void) alarm(curclass.timeout);
                                         reply(200,                                          reply(200,
                                             "IDLE time limit set to %d seconds",                                              "IDLE time limit set to "
                                             curclass.timeout);                                              LLF " seconds",
                                               (LLT)curclass.timeout);
                                 }                                  }
                         }                          }
                 }                  }
Line 584  cmd
Line 605  cmd
   
         | SITE SP RATEGET check_login SP STRING CRLF          | SITE SP RATEGET check_login SP STRING CRLF
                 {                  {
                           char errbuf[100];
                         char *p = $6;                          char *p = $6;
                         LLT rate;                          LLT rate;
   
                         if ($4) {                          if ($4) {
                                 rate = strsuftoll(p);                                  rate = strsuftollx("RATEGET", p, 0,
                                 if (rate == -1)                                      curclass.maxrateget
                                         reply(501, "Invalid RATEGET %s", p);                                      ? curclass.maxrateget
                                 else if (curclass.maxrateget &&                                      : LLTMAX, errbuf, sizeof(errbuf));
                                     rate > curclass.maxrateget)                                  if (errbuf[0])
                                         reply(501,                                          reply(501, "%s", errbuf);
                         "RATEGET " LLF " is larger than maximum RATEGET " LLF,  
                                             (LLT)rate,  
                                             (LLT)curclass.maxrateget);  
                                 else {                                  else {
                                         curclass.rateget = rate;                                          curclass.rateget = rate;
                                         reply(200,                                          reply(200,
Line 618  cmd
Line 637  cmd
   
         | SITE SP RATEPUT check_login SP STRING CRLF          | SITE SP RATEPUT check_login SP STRING CRLF
                 {                  {
                           char errbuf[100];
                         char *p = $6;                          char *p = $6;
                         LLT rate;                          LLT rate;
   
                         if ($4) {                          if ($4) {
                                 rate = strsuftoll(p);                                  rate = strsuftollx("RATEPUT", p, 0,
                                 if (rate == -1)                                      curclass.maxrateput
                                         reply(501, "Invalid RATEPUT %s", p);                                      ? curclass.maxrateput
                                 else if (curclass.maxrateput &&                                      : LLTMAX, errbuf, sizeof(errbuf));
                                     rate > curclass.maxrateput)                                  if (errbuf[0])
                                         reply(501,                                          reply(501, "%s", errbuf);
                         "RATEPUT " LLF " is larger than maximum RATEPUT " LLF,  
                                             (LLT)rate,  
                                             (LLT)curclass.maxrateput);  
                                 else {                                  else {
                                         curclass.rateput = rate;                                          curclass.rateput = rate;
                                         reply(200,                                          reply(200,
Line 656  cmd
Line 673  cmd
                 {                  {
                         int oldmask;                          int oldmask;
   
                         if ($4 && CURCLASS_FLAGS_ISSET(modify)) {                          if ($4 && check_write("", 0)) {
                                 if (($6 == -1) || ($6 > 0777)) {                                  if (($6 == -1) || ($6 > 0777)) {
                                         reply(501, "Bad UMASK value");                                          reply(501, "Bad UMASK value");
                                 } else {                                  } else {
Line 687  cmd
Line 704  cmd
   
         | STAT CRLF          | STAT CRLF
                 {                  {
                         statcmd();                          if (is_oob)
                                   statxfer();
                           else
                                   statcmd();
                 }                  }
   
         | HELP CRLF          | HELP CRLF
Line 782  cmd
Line 802  cmd
                 }                  }
   
   
                                 /* extensions from draft-ietf-ftpext-mlst-11 */                                                  /* RFC 3659 */
   
                 /*                  /*
                  * Return size of file in a format suitable for                   * Return size of file in a format suitable for
Line 858  cmd
Line 878  cmd
         ;          ;
   
 rcmd  rcmd
         : REST check_login SP byte_size CRLF          : REST check_login SP NUMBER CRLF
                 {                  {
                         if ($2) {                          if ($2) {
                                 fromname = NULL;                                  REASSIGN(fromname, NULL);
                                 restart_point = $4; /* XXX: $4 is only "int" */                                  restart_point = (off_t)$4.ll;
                                 reply(350,                                  reply(350,
     "Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.",      "Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.",
                                     (LLT)restart_point);                                      (LLT)restart_point);
Line 872  rcmd
Line 892  rcmd
         | RNFR SP pathname CRLF          | RNFR SP pathname CRLF
                 {                  {
                         restart_point = (off_t) 0;                          restart_point = (off_t) 0;
                         if (check_write($3, 0))                          if (check_write($3, 0)) {
                                   REASSIGN(fromname, NULL);
                                 fromname = renamefrom($3);                                  fromname = renamefrom($3);
                           }
                         if ($3 != NULL)                          if ($3 != NULL)
                                 free($3);                                  free($3);
                 }                  }
Line 894  password
Line 916  password
   
 byte_size  byte_size
         : NUMBER          : NUMBER
                   {
                           $$ = $1.i;
                   }
         ;          ;
   
 host_port  host_port
Line 906  host_port
Line 931  host_port
                         data_dest.su_len = sizeof(struct sockaddr_in);                          data_dest.su_len = sizeof(struct sockaddr_in);
                         data_dest.su_family = AF_INET;                          data_dest.su_family = AF_INET;
                         p = (char *)&data_dest.su_port;                          p = (char *)&data_dest.su_port;
                         p[0] = $9; p[1] = $11;                          p[0] = $9.i; p[1] = $11.i;
                         a = (char *)&data_dest.su_addr;                          a = (char *)&data_dest.su_addr;
                         a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;                          a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i;
                 }                  }
         ;          ;
   
Line 923  host_long_port4
Line 948  host_long_port4
                         data_dest.su_len = sizeof(struct sockaddr_in);                          data_dest.su_len = sizeof(struct sockaddr_in);
                         data_dest.su_family = AF_INET;                          data_dest.su_family = AF_INET;
                         p = (char *)&data_dest.su_port;                          p = (char *)&data_dest.su_port;
                         p[0] = $15; p[1] = $17;                          p[0] = $15.i; p[1] = $17.i;
                         a = (char *)&data_dest.su_addr;                          a = (char *)&data_dest.su_addr;
                         a[0] =  $5;  a[1] =  $7;  a[2] =  $9;  a[3] = $11;                          a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i;
   
                         /* reject invalid LPRT command */                          /* reject invalid LPRT command */
                         if ($1 != 4 || $3 != 4 || $13 != 2)                          if ($1.i != 4 || $3.i != 4 || $13.i != 2)
                                 memset(&data_dest, 0, sizeof(data_dest));                                  memset(&data_dest, 0, sizeof(data_dest));
                 }                  }
         ;          ;
Line 942  host_long_port6
Line 967  host_long_port6
                 NUMBER                  NUMBER
                 {                  {
 #ifdef INET6  #ifdef INET6
                         char *a, *p;                          unsigned char buf[16];
   
                         memset(&data_dest, 0, sizeof(data_dest));                          (void)memset(&data_dest, 0, sizeof(data_dest));
                         data_dest.su_len = sizeof(struct sockaddr_in6);                          data_dest.su_len = sizeof(struct sockaddr_in6);
                         data_dest.su_family = AF_INET6;                          data_dest.su_family = AF_INET6;
                         p = (char *)&data_dest.su_port;                          buf[0] = $39.i; buf[1] = $41.i;
                         p[0] = $39; p[1] = $41;                          (void)memcpy(&data_dest.su_port, buf,
                         a = (char *)&data_dest.si_su.su_sin6.sin6_addr;                              sizeof(data_dest.su_port));
                          a[0] =  $5;  a[1] =  $7;  a[2] =  $9;  a[3] = $11;                          buf[0] = $5.i; buf[1] = $7.i;
                          a[4] = $13;  a[5] = $15;  a[6] = $17;  a[7] = $19;                          buf[2] = $9.i; buf[3] = $11.i;
                          a[8] = $21;  a[9] = $23; a[10] = $25; a[11] = $27;                          buf[4] = $13.i; buf[5] = $15.i;
                         a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;                          buf[6] = $17.i; buf[7] = $19.i;
                           buf[8] = $21.i; buf[9] = $23.i;
                           buf[10] = $25.i; buf[11] = $27.i;
                           buf[12] = $29.i; buf[13] = $31.i;
                           buf[14] = $33.i; buf[15] = $35.i;
                           (void)memcpy(&data_dest.si_su.su_sin6.sin6_addr,
                               buf, sizeof(data_dest.si_su.su_sin6.sin6_addr));
                         if (his_addr.su_family == AF_INET6) {                          if (his_addr.su_family == AF_INET6) {
                                 /* XXX: more sanity checks! */                                  /* XXX: more sanity checks! */
                                 data_dest.su_scope_id = his_addr.su_scope_id;                                  data_dest.su_scope_id = his_addr.su_scope_id;
Line 962  host_long_port6
Line 993  host_long_port6
                         memset(&data_dest, 0, sizeof(data_dest));                          memset(&data_dest, 0, sizeof(data_dest));
 #endif /* INET6 */  #endif /* INET6 */
                         /* reject invalid LPRT command */                          /* reject invalid LPRT command */
                         if ($1 != 6 || $3 != 16 || $37 != 2)                          if ($1.i != 6 || $3.i != 16 || $37.i != 2)
                                 memset(&data_dest, 0, sizeof(data_dest));                                  memset(&data_dest, 0, sizeof(data_dest));
                 }                  }
         ;          ;
Line 1078  pathname
Line 1109  pathname
                          * others.                           * others.
                          */                           */
                         if (logged_in && $1 && *$1 == '~') {                          if (logged_in && $1 && *$1 == '~') {
                                 glob_t gl;                                  char    *path, *home, *result;
                                 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;                                  size_t  len;
   
                                   path = strchr($1 + 1, '/');
                                   if (path != NULL)
                                           *path++ = '\0';
                                 if ($1[1] == '\0')                                  if ($1[1] == '\0')
                                         $$ = xstrdup(homedir);                                          home = homedir;
                                 else {                                  else {
                                         memset(&gl, 0, sizeof(gl));                                          struct passwd   *hpw;
                                         if (glob($1, flags, NULL, &gl) ||  
                                             gl.gl_pathc == 0) {                                          if ((hpw = getpwnam($1 + 1)) != NULL)
                                                 reply(550, "not found");                                                  home = hpw->pw_dir;
                                                 $$ = NULL;                                          else
                                         } else                                                  home = $1;
                                                 $$ = xstrdup(gl.gl_pathv[0]);                                  }
                                         globfree(&gl);                                  len = strlen(home) + 1;
                                   if (path != NULL)
                                           len += strlen(path) + 1;
                                   if ((result = malloc(len)) == NULL)
                                           fatal("Local resource failure: malloc");
                                   strlcpy(result, home, len);
                                   if (path != NULL) {
                                           strlcat(result, "/", len);
                                           strlcat(result, path, len);
                                 }                                  }
                                   $$ = result;
                                 free($1);                                  free($1);
                         } else                          } else
                                 $$ = $1;                                  $$ = $1;
Line 1112  octal_number
Line 1155  octal_number
                          * Convert a number that was read as decimal number                           * Convert a number that was read as decimal number
                          * to what it would be if it had been read as octal.                           * to what it would be if it had been read as octal.
                          */                           */
                         dec = $1;                          dec = $1.i;
                         multby = 1;                          multby = 1;
                         ret = 0;                          ret = 0;
                         while (dec) {                          while (dec) {
Line 1143  prot_code
Line 1186  prot_code
   
 decimal_integer  decimal_integer
         : NUMBER          : NUMBER
                   {
                           $$ = $1.i;
                   }
         ;          ;
   
 check_login  check_login
Line 1170  check_login
Line 1216  check_login
 #define SITECMD 7       /* SITE command */  #define SITECMD 7       /* SITE command */
 #define NSTR    8       /* Number followed by a string */  #define NSTR    8       /* Number followed by a string */
 #define NOARGS  9       /* No arguments allowed */  #define NOARGS  9       /* No arguments allowed */
   #define EOLN    10      /* End of line */
   
 struct tab cmdtab[] = {  struct tab cmdtab[] = {
                                 /* From RFC 959, in order defined (5.3.1) */                                  /* From RFC 959, in order defined (5.3.1) */
         { "USER", USER, STR1,   1,      "<sp> username" },          { "USER", USER, STR1,   1,      "<sp> username", 0, },
         { "PASS", PASS, ZSTR1,  1,      "<sp> password" },          { "PASS", PASS, ZSTR1,  1,      "<sp> password", 0, },
         { "ACCT", ACCT, STR1,   0,      "(specify account)" },          { "ACCT", ACCT, STR1,   0,      "(specify account)", 0, },
         { "CWD",  CWD,  OSTR,   1,      "[ <sp> directory-name ]" },          { "CWD",  CWD,  OSTR,   1,      "[ <sp> directory-name ]", 0, },
         { "CDUP", CDUP, NOARGS, 1,      "(change to parent directory)" },          { "CDUP", CDUP, NOARGS, 1,      "(change to parent directory)", 0, },
         { "SMNT", SMNT, ARGS,   0,      "(structure mount)" },          { "SMNT", SMNT, ARGS,   0,      "(structure mount)", 0, },
         { "QUIT", QUIT, NOARGS, 1,      "(terminate service)" },          { "QUIT", QUIT, NOARGS, 1,      "(terminate service)", 0, },
         { "REIN", REIN, NOARGS, 0,      "(reinitialize server state)" },          { "REIN", REIN, NOARGS, 0,      "(reinitialize server state)", 0, },
         { "PORT", PORT, ARGS,   1,      "<sp> b0, b1, b2, b3, b4" },          { "PORT", PORT, ARGS,   1,      "<sp> b0, b1, b2, b3, b4, b5", 0, },
         { "LPRT", LPRT, ARGS,   1,      "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },          { "LPRT", LPRT, ARGS,   1,      "<sp> af, hal, h1, h2, h3,..., pal, p1, p2...", 0, },
         { "EPRT", EPRT, STR1,   1,      "<sp> |af|addr|port|" },          { "EPRT", EPRT, STR1,   1,      "<sp> |af|addr|port|", 0, },
         { "PASV", PASV, NOARGS, 1,      "(set server in passive mode)" },          { "PASV", PASV, NOARGS, 1,      "(set server in passive mode)", 0, },
         { "LPSV", LPSV, ARGS,   1,      "(set server in passive mode)" },          { "LPSV", LPSV, ARGS,   1,      "(set server in passive mode)", 0, },
         { "EPSV", EPSV, ARGS,   1,      "[<sp> af|ALL]" },          { "EPSV", EPSV, ARGS,   1,      "[<sp> af|ALL]", 0, },
         { "TYPE", TYPE, ARGS,   1,      "<sp> [ A | E | I | L ]" },          { "TYPE", TYPE, ARGS,   1,      "<sp> [ A | E | I | L ]", 0, },
         { "STRU", STRU, ARGS,   1,      "(specify file structure)" },          { "STRU", STRU, ARGS,   1,      "(specify file structure)", 0, },
         { "MODE", MODE, ARGS,   1,      "(specify transfer mode)" },          { "MODE", MODE, ARGS,   1,      "(specify transfer mode)", 0, },
         { "RETR", RETR, STR1,   1,      "<sp> file-name" },          { "RETR", RETR, STR1,   1,      "<sp> file-name", 0, },
         { "STOR", STOR, STR1,   1,      "<sp> file-name" },          { "STOR", STOR, STR1,   1,      "<sp> file-name", 0, },
         { "STOU", STOU, STR1,   1,      "<sp> file-name" },          { "STOU", STOU, STR1,   1,      "<sp> file-name", 0, },
         { "APPE", APPE, STR1,   1,      "<sp> file-name" },          { "APPE", APPE, STR1,   1,      "<sp> file-name", 0, },
         { "ALLO", ALLO, ARGS,   1,      "allocate storage (vacuously)" },          { "ALLO", ALLO, ARGS,   1,      "allocate storage (vacuously)", 0, },
         { "REST", REST, ARGS,   1,      "<sp> offset (restart command)" },          { "REST", REST, ARGS,   1,      "<sp> offset (restart command)", 0, },
         { "RNFR", RNFR, STR1,   1,      "<sp> file-name" },          { "RNFR", RNFR, STR1,   1,      "<sp> file-name", 0, },
         { "RNTO", RNTO, STR1,   1,      "<sp> file-name" },          { "RNTO", RNTO, STR1,   1,      "<sp> file-name", 0, },
         { "ABOR", ABOR, NOARGS, 1,      "(abort operation)" },          { "ABOR", ABOR, NOARGS, 4,      "(abort operation)", 0, },
         { "DELE", DELE, STR1,   1,      "<sp> file-name" },          { "DELE", DELE, STR1,   1,      "<sp> file-name", 0, },
         { "RMD",  RMD,  STR1,   1,      "<sp> path-name" },          { "RMD",  RMD,  STR1,   1,      "<sp> path-name", 0, },
         { "MKD",  MKD,  STR1,   1,      "<sp> path-name" },          { "MKD",  MKD,  STR1,   1,      "<sp> path-name", 0, },
         { "PWD",  PWD,  NOARGS, 1,      "(return current directory)" },          { "PWD",  PWD,  NOARGS, 1,      "(return current directory)", 0, },
         { "LIST", LIST, OSTR,   1,      "[ <sp> path-name ]" },          { "LIST", LIST, OSTR,   1,      "[ <sp> path-name ]", 0, },
         { "NLST", NLST, OSTR,   1,      "[ <sp> path-name ]" },          { "NLST", NLST, OSTR,   1,      "[ <sp> path-name ]", 0, },
         { "SITE", SITE, SITECMD, 1,     "site-cmd [ <sp> arguments ]" },          { "SITE", SITE, SITECMD, 1,     "site-cmd [ <sp> arguments ]", 0, },
         { "SYST", SYST, NOARGS, 1,      "(get type of operating system)" },          { "SYST", SYST, NOARGS, 1,      "(get type of operating system)", 0, },
         { "STAT", STAT, OSTR,   1,      "[ <sp> path-name ]" },          { "STAT", STAT, OSTR,   4,      "[ <sp> path-name ]", 0, },
         { "HELP", HELP, OSTR,   1,      "[ <sp> <string> ]" },          { "HELP", HELP, OSTR,   1,      "[ <sp> <string> ]", 0, },
         { "NOOP", NOOP, NOARGS, 2,      "" },          { "NOOP", NOOP, NOARGS, 2,      "", 0, },
   
                                 /* From RFC 2228, in order defined */                                  /* From RFC 2228, in order defined */
         { "AUTH", AUTH, STR1,   1,      "<sp> mechanism-name" },          { "AUTH", AUTH, STR1,   1,      "<sp> mechanism-name", 0, },
         { "ADAT", ADAT, STR1,   1,      "<sp> base-64-data" },          { "ADAT", ADAT, STR1,   1,      "<sp> base-64-data", 0, },
         { "PROT", PROT, STR1,   1,      "<sp> prot-code" },          { "PROT", PROT, STR1,   1,      "<sp> prot-code", 0, },
         { "PBSZ", PBSZ, ARGS,   1,      "<sp> decimal-integer" },          { "PBSZ", PBSZ, ARGS,   1,      "<sp> decimal-integer", 0, },
         { "CCC",  CCC,  NOARGS, 1,      "(Disable data protection)" },          { "CCC",  CCC,  NOARGS, 1,      "(Disable data protection)", 0, },
         { "MIC",  MIC,  STR1,   1,      "<sp> base64data" },          { "MIC",  MIC,  STR1,   4,      "<sp> base64data", 0, },
         { "CONF", CONF, STR1,   1,      "<sp> base64data" },          { "CONF", CONF, STR1,   4,      "<sp> base64data", 0, },
         { "ENC",  ENC,  STR1,   1,      "<sp> base64data" },          { "ENC",  ENC,  STR1,   4,      "<sp> base64data", 0, },
   
                                 /* From RFC 2389, in order defined */                                  /* From RFC 2389, in order defined */
         { "FEAT", FEAT, NOARGS, 1,      "(display extended features)" },          { "FEAT", FEAT, NOARGS, 1,      "(display extended features)", 0, },
         { "OPTS", OPTS, STR1,   1,      "<sp> command [ <sp> options ]" },          { "OPTS", OPTS, STR1,   1,      "<sp> command [ <sp> options ]", 0, },
   
                                 /* from draft-ietf-ftpext-mlst-11 */                                  /* From RFC 3659, in order defined */
         { "MDTM", MDTM, OSTR,   1,      "<sp> path-name" },          { "MDTM", MDTM, OSTR,   1,      "<sp> path-name", 0, },
         { "SIZE", SIZE, OSTR,   1,      "<sp> path-name" },          { "SIZE", SIZE, OSTR,   1,      "<sp> path-name", 0, },
         { "MLST", MLST, OSTR,   2,      "[ <sp> path-name ]" },          { "MLST", MLST, OSTR,   2,      "[ <sp> path-name ]", 0, },
         { "MLSD", MLSD, OSTR,   1,      "[ <sp> directory-name ]" },          { "MLSD", MLSD, OSTR,   1,      "[ <sp> directory-name ]", 0, },
   
                                 /* obsolete commands */                                  /* obsolete commands */
         { "MAIL", MAIL, OSTR,   0,      "(mail to user)" },          { "MAIL", MAIL, OSTR,   0,      "(mail to user)", 0, },
         { "MLFL", MLFL, OSTR,   0,      "(mail file)" },          { "MLFL", MLFL, OSTR,   0,      "(mail file)", 0, },
         { "MRCP", MRCP, STR1,   0,      "(mail recipient)" },          { "MRCP", MRCP, STR1,   0,      "(mail recipient)", 0, },
         { "MRSQ", MRSQ, OSTR,   0,      "(mail recipient scheme question)" },          { "MRSQ", MRSQ, OSTR,   0,      "(mail recipient scheme question)", 0, },
         { "MSAM", MSAM, OSTR,   0,      "(mail send to terminal and mailbox)" },          { "MSAM", MSAM, OSTR,   0,      "(mail send to terminal and mailbox)", 0, },
         { "MSND", MSND, OSTR,   0,      "(mail send to terminal)" },          { "MSND", MSND, OSTR,   0,      "(mail send to terminal)", 0, },
         { "MSOM", MSOM, OSTR,   0,      "(mail send to terminal or mailbox)" },          { "MSOM", MSOM, OSTR,   0,      "(mail send to terminal or mailbox)", 0, },
         { "XCUP", CDUP, NOARGS, 1,      "(change to parent directory)" },          { "XCUP", CDUP, NOARGS, 1,      "(change to parent directory)", 0, },
         { "XCWD", CWD,  OSTR,   1,      "[ <sp> directory-name ]" },          { "XCWD", CWD,  OSTR,   1,      "[ <sp> directory-name ]", 0, },
         { "XMKD", MKD,  STR1,   1,      "<sp> path-name" },          { "XMKD", MKD,  STR1,   1,      "<sp> path-name", 0, },
         { "XPWD", PWD,  NOARGS, 1,      "(return current directory)" },          { "XPWD", PWD,  NOARGS, 1,      "(return current directory)", 0, },
         { "XRMD", RMD,  STR1,   1,      "<sp> path-name" },          { "XRMD", RMD,  STR1,   1,      "<sp> path-name", 0, },
   
         {  NULL,  0,    0,      0,      0 }          {  NULL,  0,    0,      0,      0, 0, }
 };  };
   
 struct tab sitetab[] = {  struct tab sitetab[] = {
         { "CHMOD",      CHMOD,  NSTR, 1,        "<sp> mode <sp> file-name" },          { "CHMOD",      CHMOD,  NSTR,   1,      "<sp> mode <sp> file-name", 0, },
         { "HELP",       HELP,   OSTR, 1,        "[ <sp> <string> ]" },          { "HELP",       HELP,   OSTR,   1,      "[ <sp> <string> ]", 0, },
         { "IDLE",       IDLE,   ARGS, 1,        "[ <sp> maximum-idle-time ]" },          { "IDLE",       IDLE,   ARGS,   1,      "[ <sp> maximum-idle-time ]", 0, },
         { "RATEGET",    RATEGET,OSTR, 1,        "[ <sp> get-throttle-rate ]" },          { "RATEGET",    RATEGET,OSTR,   1,      "[ <sp> get-throttle-rate ]", 0, },
         { "RATEPUT",    RATEPUT,OSTR, 1,        "[ <sp> put-throttle-rate ]" },          { "RATEPUT",    RATEPUT,OSTR,   1,      "[ <sp> put-throttle-rate ]", 0, },
         { "UMASK",      UMASK,  ARGS, 1,        "[ <sp> umask ]" },          { "UMASK",      UMASK,  ARGS,   1,      "[ <sp> umask ]", 0, },
         { NULL,         0,     0,     0,        NULL }          { NULL,         0,      0,      0,      0, 0, }
 };  };
   
 static  int     check_write(const char *, int);  
 static  void    help(struct tab *, const char *);  
 static  void    port_check(const char *, int);  
 static  void    toolong(int);  
 static  int     yylex(void);  
   
 extern int epsvall;  
   
 /*  /*
  * Check if a filename is allowed to be modified (isupload == 0) or   * Check if a filename is allowed to be modified (isupload == 0) or
  * uploaded (isupload == 1), and if necessary, check the filename is `sane'.   * uploaded (isupload == 1), and if necessary, check the filename is `sane'.
    * If the filename is NULL, fail.
    * If the filename is "", don't do the sane name check.
  */   */
 static int  static int
 check_write(const char *file, int isupload)  check_write(const char *file, int isupload)
Line 1289  check_write(const char *file, int isuplo
Line 1330  check_write(const char *file, int isuplo
                 reply(502, "No permission to use this command.");                  reply(502, "No permission to use this command.");
                 return (0);                  return (0);
         }          }
   
                 /* checking sanenames */                  /* checking sanenames */
         if (CURCLASS_FLAGS_ISSET(sanenames)) {          if (file[0] != '\0' && CURCLASS_FLAGS_ISSET(sanenames)) {
                 const char *p;                  const char *p;
   
                 if (file[0] == '.')                  if (file[0] == '.')
                         goto insane_name;                          goto insane_name;
                 for (p = file; *p; p++) {                  for (p = file; *p; p++) {
                         if (isalnum(*p) || *p == '-' || *p == '+' ||                          if (isalnum((unsigned char)*p) || *p == '-' || *p == '+' ||
                             *p == ',' || *p == '.' || *p == '_')                              *p == ',' || *p == '.' || *p == '_')
                                 continue;                                  continue;
  insane_name:   insane_name:
Line 1320  lookup(struct tab *p, const char *cmd)
Line 1362  lookup(struct tab *p, const char *cmd)
 #include <arpa/telnet.h>  #include <arpa/telnet.h>
   
 /*  /*
  * getline - a hacked up version of fgets to ignore TELNET escape codes.   * get_line - a hacked up version of fgets to ignore TELNET escape codes.
    *      `s' is the buffer to read into.
    *      `n' is the 1 less than the size of the buffer, to allow trailing NUL
    *      `iop' is the FILE to read from.
    *      Returns 0 on success, -1 on EOF, -2 if the command was too long.
  */   */
 char *  int
 getline(char *s, int n, FILE *iop)  get_line(char *s, int n, FILE *iop)
 {  {
         int c;          int c;
         char *cs;          char *cs;
Line 1334  getline(char *s, int n, FILE *iop)
Line 1380  getline(char *s, int n, FILE *iop)
                 *cs++ = tmpline[c];                  *cs++ = tmpline[c];
                 if (tmpline[c] == '\n') {                  if (tmpline[c] == '\n') {
                         *cs++ = '\0';                          *cs++ = '\0';
                         if (debug)                          if (ftpd_debug)
                                 syslog(LOG_DEBUG, "command: %s", s);                                  syslog(LOG_DEBUG, "command: %s", s);
                         tmpline[0] = '\0';                          tmpline[0] = '\0';
                         return(s);                          return(0);
                 }                  }
                 if (c == 0)                  if (c == 0)
                         tmpline[0] = '\0';                          tmpline[0] = '\0';
Line 1376  getline(char *s, int n, FILE *iop)
Line 1422  getline(char *s, int n, FILE *iop)
                     }                      }
                 }                  }
                 *cs++ = c;                  *cs++ = c;
                 if (--n <= 0 || c == '\n')                  if (--n <= 0) {
                           /*
                            * If command doesn't fit into buffer, discard the
                            * rest of the command and indicate truncation.
                            * This prevents the command to be split up into
                            * multiple commands.
                            */
                           if (ftpd_debug)
                                   syslog(LOG_DEBUG,
                                       "command too long, last char: %d", c);
                           while (c != '\n' && (c = getc(iop)) != EOF)
                                   continue;
                           return (-2);
                   }
                   if (c == '\n')
                         break;                          break;
         }          }
         if (c == EOF && cs == s)          if (c == EOF && cs == s)
                 return (NULL);                  return (-1);
         *cs++ = '\0';          *cs++ = '\0';
         if (debug) {          if (ftpd_debug) {
                 if ((curclass.type != CLASS_GUEST &&                  if ((curclass.type != CLASS_GUEST &&
                     strncasecmp(s, "PASS ", 5) == 0) ||                      strncasecmp(s, "PASS ", 5) == 0) ||
                     strncasecmp(s, "ACCT ", 5) == 0) {                      strncasecmp(s, "ACCT ", 5) == 0) {
Line 1402  getline(char *s, int n, FILE *iop)
Line 1462  getline(char *s, int n, FILE *iop)
                         syslog(LOG_DEBUG, "command: %.*s", len, s);                          syslog(LOG_DEBUG, "command: %.*s", len, s);
                 }                  }
         }          }
         return (s);          return (0);
 }  }
   
 static void  void
 toolong(int signo)  ftp_handle_line(char *cp)
 {  {
   
         reply(421,          cmdp = cp;
             "Timeout (%d seconds): closing control connection.",          yyparse();
             curclass.timeout);  
         if (logging)  
                 syslog(LOG_INFO, "User %s timed out after %d seconds",  
                     (pw ? pw->pw_name : "unknown"), curclass.timeout);  
         dologout(1);  
 }  }
   
 static int  void
   ftp_loop(void)
   {
           int ret;
   
           while (1) {
                   (void) alarm(curclass.timeout);
                   ret = get_line(cbuf, sizeof(cbuf)-1, stdin);
                   (void) alarm(0);
                   if (ret == -1) {
                           reply(221, "You could at least say goodbye.");
                           dologout(0);
                   } else if (ret == -2) {
                           reply(500, "Command too long.");
                   } else {
                           ftp_handle_line(cbuf);
                   }
           }
           /*NOTREACHED*/
   }
   
   int
 yylex(void)  yylex(void)
 {  {
         static int cpos, state;          static int cpos, state;
Line 1431  yylex(void)
Line 1507  yylex(void)
   
         case CMD:          case CMD:
                 hasyyerrored = 0;                  hasyyerrored = 0;
                 (void) signal(SIGALRM, toolong);                  if ((cp = strchr(cmdp, '\r'))) {
                 (void) alarm(curclass.timeout);  
                 if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {  
                         reply(221, "You could at least say goodbye.");  
                         dologout(0);  
                 }  
                 (void) alarm(0);  
                 if ((cp = strchr(cbuf, '\r'))) {  
                         *cp = '\0';                          *cp = '\0';
 #if HAVE_SETPROCTITLE  #if defined(HAVE_SETPROCTITLE)
                         if (strncasecmp(cbuf, "PASS", 4) != 0 &&                          if (strncasecmp(cmdp, "PASS", 4) != 0 &&
                             strncasecmp(cbuf, "ACCT", 4) != 0)                              strncasecmp(cmdp, "ACCT", 4) != 0)
                                 setproctitle("%s: %s", proctitle, cbuf);                                  setproctitle("%s: %s", proctitle, cmdp);
 #endif /* HAVE_SETPROCTITLE */  #endif /* defined(HAVE_SETPROCTITLE) */
                         *cp++ = '\n';                          *cp++ = '\n';
                         *cp = '\0';                          *cp = '\0';
                 }                  }
                 if ((cp = strpbrk(cbuf, " \n")))                  if ((cp = strpbrk(cmdp, " \n")))
                         cpos = cp - cbuf;                          cpos = cp - cmdp;
                 if (cpos == 0)                  if (cpos == 0)
                         cpos = 4;                          cpos = 4;
                 c = cbuf[cpos];                  c = cmdp[cpos];
                 cbuf[cpos] = '\0';                  cmdp[cpos] = '\0';
                 p = lookup(cmdtab, cbuf);                  p = lookup(cmdtab, cmdp);
                 cbuf[cpos] = c;                  cmdp[cpos] = c;
                 if (p != NULL) {                  if (p != NULL) {
                         if (! CMD_IMPLEMENTED(p)) {                          if (is_oob && ! CMD_OOB(p)) {
                                   /* command will be handled in-band */
                                   return (0);
                           } else if (! CMD_IMPLEMENTED(p)) {
                                 reply(502, "%s command not implemented.",                                  reply(502, "%s command not implemented.",
                                     p->name);                                      p->name);
                                 hasyyerrored = 1;                                  hasyyerrored = 1;
                                 break;                                  break;
                         }                          }
                         state = p->state;                          state = p->state;
                         yylval.s = p->name;                          yylval.cs = p->name;
                         return (p->token);                          return (p->token);
                 }                  }
                 break;                  break;
   
         case SITECMD:          case SITECMD:
                 if (cbuf[cpos] == ' ') {                  if (cmdp[cpos] == ' ') {
                         cpos++;                          cpos++;
                         return (SP);                          return (SP);
                 }                  }
                 cp = &cbuf[cpos];                  cp = &cmdp[cpos];
                 if ((cp2 = strpbrk(cp, " \n")))                  if ((cp2 = strpbrk(cp, " \n")))
                         cpos = cp2 - cbuf;                          cpos = cp2 - cmdp;
                 c = cbuf[cpos];                  c = cmdp[cpos];
                 cbuf[cpos] = '\0';                  cmdp[cpos] = '\0';
                 p = lookup(sitetab, cp);                  p = lookup(sitetab, cp);
                 cbuf[cpos] = c;                  cmdp[cpos] = c;
                 if (p != NULL) {                  if (p != NULL) {
                         if (!CMD_IMPLEMENTED(p)) {                          if (!CMD_IMPLEMENTED(p)) {
                                 reply(502, "SITE %s command not implemented.",                                  reply(502, "SITE %s command not implemented.",
Line 1489  yylex(void)
Line 1561  yylex(void)
                                 break;                                  break;
                         }                          }
                         state = p->state;                          state = p->state;
                         yylval.s = p->name;                          yylval.cs = p->name;
                         return (p->token);                          return (p->token);
                 }                  }
                 break;                  break;
   
         case OSTR:          case OSTR:
                 if (cbuf[cpos] == '\n') {                  if (cmdp[cpos] == '\n') {
                         state = CMD;                          state = EOLN;
                         return (CRLF);                          return (CRLF);
                 }                  }
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
Line 1504  yylex(void)
Line 1576  yylex(void)
         case STR1:          case STR1:
         case ZSTR1:          case ZSTR1:
         dostr1:          dostr1:
                 if (cbuf[cpos] == ' ') {                  if (cmdp[cpos] == ' ') {
                         cpos++;                          cpos++;
                         state = state == OSTR ? STR2 : state+1;                          state = state == OSTR ? STR2 : state+1;
                         return (SP);                          return (SP);
Line 1512  yylex(void)
Line 1584  yylex(void)
                 break;                  break;
   
         case ZSTR2:          case ZSTR2:
                 if (cbuf[cpos] == '\n') {                  if (cmdp[cpos] == '\n') {
                         state = CMD;                          state = EOLN;
                         return (CRLF);                          return (CRLF);
                 }                  }
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
   
         case STR2:          case STR2:
                 cp = &cbuf[cpos];                  cp = &cmdp[cpos];
                 n = strlen(cp);                  n = strlen(cp);
                 cpos += n - 1;                  cpos += n - 1;
                 /*                  /*
                  * Make sure the string is nonempty and \n terminated.                   * Make sure the string is nonempty and \n terminated.
                  */                   */
                 if (n > 1 && cbuf[cpos] == '\n') {                  if (n > 1 && cmdp[cpos] == '\n') {
                         cbuf[cpos] = '\0';                          cmdp[cpos] = '\0';
                         yylval.s = xstrdup(cp);                          yylval.s = ftpd_strdup(cp);
                         cbuf[cpos] = '\n';                          cmdp[cpos] = '\n';
                         state = ARGS;                          state = ARGS;
                         return (STRING);                          return (STRING);
                 }                  }
                 break;                  break;
   
         case NSTR:          case NSTR:
                 if (cbuf[cpos] == ' ') {                  if (cmdp[cpos] == ' ') {
                         cpos++;                          cpos++;
                         return (SP);                          return (SP);
                 }                  }
                 if (isdigit(cbuf[cpos])) {                  if (isdigit((unsigned char)cmdp[cpos])) {
                         cp = &cbuf[cpos];                          cp = &cmdp[cpos];
                         while (isdigit(cbuf[++cpos]))                          while (isdigit((unsigned char)cmdp[++cpos]))
                                 ;                                  ;
                         c = cbuf[cpos];                          c = cmdp[cpos];
                         cbuf[cpos] = '\0';                          cmdp[cpos] = '\0';
                         yylval.i = atoi(cp);                          yylval.u.i = atoi(cp);
                         cbuf[cpos] = c;                          cmdp[cpos] = c;
                         state = STR1;                          state = STR1;
                         return (NUMBER);                          return (NUMBER);
                 }                  }
Line 1554  yylex(void)
Line 1626  yylex(void)
                 goto dostr1;                  goto dostr1;
   
         case ARGS:          case ARGS:
                 if (isdigit(cbuf[cpos])) {                  if (isdigit((unsigned char)cmdp[cpos])) {
                         cp = &cbuf[cpos];                          cp = &cmdp[cpos];
                         while (isdigit(cbuf[++cpos]))                          while (isdigit((unsigned char)cmdp[++cpos]))
                                 ;                                  ;
                         c = cbuf[cpos];                          c = cmdp[cpos];
                         cbuf[cpos] = '\0';                          cmdp[cpos] = '\0';
                         yylval.i = atoi(cp);                          yylval.u.i = atoi(cp);
                         cbuf[cpos] = c;                          yylval.u.ll = STRTOLL(cp, (char **)NULL, 10);
                           cmdp[cpos] = c;
                         return (NUMBER);                          return (NUMBER);
                 }                  }
                 if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0                  if (strncasecmp(&cmdp[cpos], "ALL", 3) == 0
                  && !isalnum(cbuf[cpos + 3])) {                      && !isalnum((unsigned char)cmdp[cpos + 3])) {
                         yylval.s = xstrdup("ALL");  
                         cpos += 3;                          cpos += 3;
                         return ALL;                          return (ALL);
                 }                  }
                 switch (cbuf[cpos++]) {                  switch (cmdp[cpos++]) {
   
                 case '\n':                  case '\n':
                         state = CMD;                          state = EOLN;
                         return (CRLF);                          return (CRLF);
   
                 case ' ':                  case ' ':
Line 1634  yylex(void)
Line 1706  yylex(void)
                 break;                  break;
   
         case NOARGS:          case NOARGS:
                 if (cbuf[cpos] == '\n') {                  if (cmdp[cpos] == '\n') {
                         state = CMD;                          state = EOLN;
                         return (CRLF);                          return (CRLF);
                 }                  }
                 c = cbuf[cpos];                  c = cmdp[cpos];
                 cbuf[cpos] = '\0';                  cmdp[cpos] = '\0';
                 reply(501, "'%s' command does not take any arguments.", cbuf);                  reply(501, "'%s' command does not take any arguments.", cmdp);
                 hasyyerrored = 1;                  hasyyerrored = 1;
                 cbuf[cpos] = c;                  cmdp[cpos] = c;
                 break;                  break;
   
           case EOLN:
                   state = CMD;
                   return (0);
   
         default:          default:
                 fatal("Unknown state in scanner.");                  fatal("Unknown state in scanner.");
         }          }
         yyerror(NULL);          yyerror(NULL);
         state = CMD;          state = CMD;
         longjmp(errcatch, 0);          return (0);
         /* NOTREACHED */  
 }  }
   
 /* ARGSUSED */  /* ARGSUSED */
 void  void
 yyerror(char *s)  yyerror(const char *s)
 {  {
         char *cp;          char *cp;
   
         if (hasyyerrored)          if (hasyyerrored || is_oob)
                 return;                  return;
         if ((cp = strchr(cbuf,'\n')) != NULL)          if ((cp = strchr(cmdp,'\n')) != NULL)
                 *cp = '\0';                  *cp = '\0';
         reply(500, "'%s': command not understood.", cbuf);          reply(500, "'%s': command not understood.", cmdp);
         hasyyerrored = 1;          hasyyerrored = 1;
 }  }
   
Line 1673  help(struct tab *ctab, const char *s)
Line 1748  help(struct tab *ctab, const char *s)
 {  {
         struct tab *c;          struct tab *c;
         int width, NCMDS;          int width, NCMDS;
         char *type;          const char *htype;
   
         if (ctab == sitetab)          if (ctab == sitetab)
                 type = "SITE ";                  htype = "SITE ";
         else          else
                 type = "";                  htype = "";
         width = 0, NCMDS = 0;          width = 0, NCMDS = 0;
         for (c = ctab; c->name != NULL; c++) {          for (c = ctab; c->name != NULL; c++) {
                 int len = strlen(c->name);                  int len = strlen(c->name);
Line 1693  help(struct tab *ctab, const char *s)
Line 1768  help(struct tab *ctab, const char *s)
                 int columns, lines;                  int columns, lines;
   
                 reply(-214, "%s", "");                  reply(-214, "%s", "");
                 reply(0, "The following %scommands are recognized.", type);                  reply(0, "The following %scommands are recognized.", htype);
                 reply(0, "(`-' = not implemented, `+' = supports options)");                  reply(0, "(`-' = not implemented, `+' = supports options)");
                 columns = 76 / width;                  columns = 76 / width;
                 if (columns == 0)                  if (columns == 0)
Line 1728  help(struct tab *ctab, const char *s)
Line 1803  help(struct tab *ctab, const char *s)
         }          }
         c = lookup(ctab, s);          c = lookup(ctab, s);
         if (c == (struct tab *)0) {          if (c == (struct tab *)0) {
                 reply(502, "Unknown command %s.", s);                  reply(502, "Unknown command '%s'.", s);
                 return;                  return;
         }          }
         if (CMD_IMPLEMENTED(c))          if (CMD_IMPLEMENTED(c))
                 reply(214, "Syntax: %s%s %s", type, c->name, c->help);                  reply(214, "Syntax: %s%s %s", htype, c->name, c->help);
         else          else
                 reply(214, "%s%-*s\t%s; not implemented.", type, width,                  reply(504, "%s%-*s\t%s; not implemented.", htype, width,
                     c->name, c->help);                      c->name, c->help);
 }  }
   
Line 1746  help(struct tab *ctab, const char *s)
Line 1821  help(struct tab *ctab, const char *s)
 static void  static void
 port_check(const char *cmd, int family)  port_check(const char *cmd, int family)
 {  {
           char h1[NI_MAXHOST], h2[NI_MAXHOST];
           char s1[NI_MAXHOST], s2[NI_MAXHOST];
   #ifdef NI_WITHSCOPEID
           const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
   #else
           const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
   #endif
   
         if (epsvall) {          if (epsvall) {
                 reply(501, "%s disallowed after EPSV ALL", cmd);                  reply(501, "%s disallowed after EPSV ALL", cmd);
Line 1763  port_check(const char *cmd, int family)
Line 1845  port_check(const char *cmd, int family)
   
                         /* be paranoid, if told so */                          /* be paranoid, if told so */
         if (CURCLASS_FLAGS_ISSET(checkportcmd)) {          if (CURCLASS_FLAGS_ISSET(checkportcmd)) {
                 if ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||  
                     (data_dest.su_len != his_addr.su_len))  
                         goto port_check_fail;  
                 switch (data_dest.su_family) {  
                 case AF_INET:  
                         if (memcmp(&data_dest.su_addr, &his_addr.su_addr,  
                             data_dest.su_len) != 0)  
                                 goto port_check_fail;  
                         break;  
 #ifdef INET6  #ifdef INET6
                 case AF_INET6:                  /*
                         if (memcmp(&data_dest.su_6addr, &his_addr.su_6addr,                   * be paranoid, there are getnameinfo implementation that does
                             sizeof(data_dest.su_6addr)) != 0)                   * not present scopeid portion
                                 goto port_check_fail;                   */
                         if (data_dest.su_scope_id != his_addr.su_scope_id)                  if (data_dest.su_family == AF_INET6 &&
                                 goto port_check_fail;                      data_dest.su_scope_id != his_addr.su_scope_id)
                         break;                          goto port_check_fail;
 #endif  #endif
                 default:  
                   if (getnameinfo((struct sockaddr *)&data_dest, data_dest.su_len,
                       h1, sizeof(h1), s1, sizeof(s1), niflags))
                           goto port_check_fail;
                   if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
                       h2, sizeof(h2), s2, sizeof(s2), niflags))
                           goto port_check_fail;
   
                   if (atoi(s1) < IPPORT_RESERVED || strcmp(h1, h2) != 0)
                         goto port_check_fail;                          goto port_check_fail;
                 }  
         }          }
   
         usedefault = 0;          usedefault = 0;

Legend:
Removed from v.1.48.2.2  
changed lines
  Added in v.1.92

CVSweb <webmaster@jp.NetBSD.org>