⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpd.c

📁 picoos源码。The RTOS and the TCP/IP stack will be built automatically.
💻 C
📖 第 1 页 / 共 4 页
字号:
    }
  }
  else
  if (conn->auth == 1)
  {
    conn->auth = (i > 0) ? 3 : 0;
  }

  if (conn->auth == 0)
  {
    ft_reply(conn, 530, "Login incorrect.");
  }
  else
  {
    ft_reply(conn, 230, "User logged in.");
  }
}


/* This code is shared by ftcmd_pasv and ftcmd_port.
 */
static transfer_t* ft_setupNewTransfer(connection_t *conn)
{
  unsigned long one = 1;
  int s;

  if ((conn->transfer != NULL) &&
      (conn->transfer->state >= TSTATE_WAITFORPORT))
  {
    ft_reply(conn, 500, "Sorry, only one transfer allowed per connection.");
  }

  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s < 0)
  {
    ft_reply(conn, 500, "Socket error.");
    return NULL;
  }

  ft_destroyTransfer(conn->transfer);

  conn->transfer = ft_newTransfer(s, conn);
  if (conn->transfer == NULL)
  {
    ft_reply(conn, 500, "Out of memory error.");
    closesocket(s);
    return NULL;
  }

  /* set nonblocking transfer */
  ioctlsocket(s, FIONBIO, (void*) &one);

  return conn->transfer;
}


/* Handle the PASV command.
 */
static void ftcmd_pasv(connection_t *conn, char *param)
{
  transfer_t *tran;
  struct sockaddr_in addr;
  unsigned long ip, port;
  int len;

  tran = ft_setupNewTransfer(conn);
  if (tran == NULL)
    return;

  ft_addSocket(tran->sock);

  /* setup socket */
  sysMemSet(&addr, 0, sizeof(addr));
  len = sizeof(addr);
  if (getsockname(conn->sock, (struct sockaddr*)&addr, &len))
  {
    ft_reply(conn, 500, "Socket error.");
    return;
  }

  addr.sin_port = 0;
  if (bind(tran->sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0)
  {
    ft_reply(conn, 500, "Socket error.");
    return;
  }

  len = sizeof(addr);
  if (getsockname(tran->sock, (struct sockaddr *)&addr, &len) < 0)
  {
    ft_reply(conn, 500, "Socket error.");
    return;
  }

  if (listen(tran->sock, 1) < 0)
  {
    ft_reply(conn, 500, "Socket error.");
    return;
  }

  tran->state = TSTATE_GOTPASV;
  ip = (unsigned long) htonl(addr.sin_addr.s_addr);
  port = (unsigned long) htons(addr.sin_port);

  ft_reply(conn, 227, "Entering passive mode (%u,%u,%u,%u,%u,%u)",
           (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF,
           (port >> 8) & 0xFF, port & 0xFF);
}


/* Handle the PORT command.
 */
static void ftcmd_port(connection_t *conn, char *param)
{
  unsigned long one = 1;
  transfer_t *tran;
  struct sockaddr_in sin;
  short unsigned int a0, a1, a2, a3, p0, p1;
  int   len;

  if (sscanf(param, "%3hu,%3hu,%3hu,%3hu,%3hu,%3hu", 
      &a0, &a1, &a2, &a3, &p0, &p1) < 6)
  {
    ft_reply(conn, 501, "Parse error.");
    return;
  }

  tran = ft_setupNewTransfer(conn);
  if (tran == NULL)
    return;

  /* bind socket to our FTP data port, port 20. */

  len = sizeof(sin);
  sysMemSet(&sin, 0, sizeof(sin));
  if (getsockname(conn->sock, (struct sockaddr*)&sin, &len) < 0)
  {
    ft_reply(conn, 500, "Socket error.");
    return;
  }

  setsockopt(tran->sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));

  sin.sin_port = FTP_PORT - 1;
  bind(tran->sock, (struct sockaddr*)&sin, sizeof(sin));

  tran->sin.sin_family = AF_INET;
  tran->sin.sin_addr.s_addr = htonl(
    ((a0 & 0xFF) << 24) + ((a1 & 0xFF) << 16) +
    ((a2 & 0xFF) <<  8) + ((a3 & 0xFF)) );
  tran->sin.sin_port = htons((unsigned short)
    (((p0 & 0xFF) << 8) + (p1 & 0xFF)) );
  tran->state = TSTATE_GOTPORT;

  ft_reply(conn, 200, "PORT command OK.");
}


/* Handle PWD command (print current path).
 * Paths are not supported by us, so we are always in the root dir.
 */
static void ftcmd_pwd(connection_t *conn, char *param)
{
  (void) param;
#if FS_SUBDIRECTORIES
  ft_reply(conn, 257, "\"/%s\" is current working directory.", conn->curpath);
#else
  ft_reply(conn, 257, "\"/\" is current working directory.");
#endif
}


/* Handles the QUIT command
 * (shut down the control and data connection)
 */
static void ftcmd_quit(connection_t *conn, char *param)
{
  (void) param;
  if (conn->transfer != NULL)
  {
    ft_abortTransfer(conn);
  }
  ft_reply(conn, 221, "Have a nice day!");
  ft_destroyConnection(conn);
}


/* Handle the REIN command
 * (do nearly a full reset of the connection)
 */
static void ftcmd_rein(connection_t *conn, char *param)
{
  if (conn->transfer != NULL)
  {
    /* Note: This is not compliant to RFC959 */
    ft_abortTransfer(conn);
  }

  conn->buflen    = 0;
  conn->auth      = 0;
  conn->resumePos = 0;
#if FS_SUBDIRECTORIES
  conn->curpath[0]  = 0;
#endif
  conn->lastTrans = COUNTERVAR;
  ft_reply(conn, 220, "FTPD ready.");
}


/* Handle a REST command.
 */
static void ftcmd_rest(connection_t *conn, char *param)
{
  if (sscanf(param, "%u", &conn->resumePos) != 1)
  {
    ft_reply(conn, 501, "Parse error.");
  }
  else
  {
    ft_reply(conn, 350, "Setting resume at %u bytes.", conn->resumePos);
  }
}


/* Handle the RETR command.
 * This function simply opens the source file,
 * the download is done by the global state machine.
 */
static void ftcmd_retr(connection_t *conn, char *param)
{
  transfer_t *tran = conn->transfer;
  char *c;

  if ((tran == NULL) ||
      ((tran->state != TSTATE_GOTPASV) &&
       (tran->state != TSTATE_GOTPORT)))
  {
    ft_reply(conn, 425, "No data connection.");
    return;
  }

  tran->filehandle = -1;
  ft_getFilename(conn, param, tran->filename);

  if (conn->auth < 4)
  {
    c = tran->filename;
    while ((*c == '/') || (*c == '\\')) c++;
    if (sysStrnicmp(c, "public/", 7) != 0)
    {
      ft_reply(conn, 503, "Please login with USER and PASS.");
      return;
    }
  }

  if (*tran->filename != 0)
  {
    tran->filehandle = fsys_open(tran->filename, FSO_RDONLY);
  }
  if (tran->filehandle < 0)
  {
    ft_reply(tran->owner, 550, "File unavailable.");
    ft_destroyTransfer(tran);
  }
  else
  {
    tran->upload = 0;
    tran->dirlisting = 0;
    ft_prepTransfer(tran);
  }
}


/* Handle the RMD command.
 */
static void ftcmd_rmd(connection_t *conn, char *param)
{
#if FS_SUBDIRECTORIES

  if (fsys_buildPathName(fnamebuf_g, conn->curpath, param) >= 0)
  {
    if (fsys_rmdir(fnamebuf_g) == 0)
    {
      ft_reply(conn, 250, "Directory successfully removed.");
      return;
    }
  }
  ft_reply(conn, 550, "Failed to remove directory.");

#else /* FS_SUBDIRECTORIES */

  (void) param;
  ft_reply(conn, 502, "Command not implemented.");

#endif /* FS_SUBDIRECTORIES */
}


/* Handle the RNFR command.
 * (get the filename of the file to rename)
 */
static void ftcmd_rnfr(connection_t *conn, char *param)
{
  struct fsys_stat st;

  ft_getFilename(conn, param, conn->renfrom);
  if ((*conn->renfrom == 0) || (fsys_stat(conn->renfrom, &st) < 0))
  {
    conn->renfrom[0] = 0;
    ft_reply(conn, 550, "File unavailable.");
  }
  else
  {
    ft_reply(conn, 350, "File exists, send RNTO.");
  }
}


/* Handle the RNTO command.
 * (get filename to rename to and do the work)
 */
static void ftcmd_rnto(connection_t *conn, char *param)
{
  if (conn->renfrom[0] == 0)
  {
    ft_reply(conn, 503, "Need to send RNFR first.");
    return;
  }
  ft_getFilename(conn, param, tempbuf_g);
  if (*tempbuf_g == 0)
  {
    ft_reply(conn, 550, "New file name is illegal.");
  }
  else
  if (fsys_rename(conn->renfrom, tempbuf_g) < 0)
  {
    ft_reply(conn, 550, "Failed to rename file.");
  }
  else
  {
    ft_reply(conn, 250, "File renamed.");
  }
  conn->renfrom[0] = 0;
}


/* Handle the SIZE command. This is a FTP extension.
 */
static void ftcmd_size(connection_t *conn, char *param)
{
  struct fsys_stat st;

  ft_getFilename(conn, param, tempbuf_g);
  if ((*tempbuf_g == 0) || (fsys_stat(tempbuf_g, &st) < 0))
  {
    ft_reply(conn, 550, "File unavailable.");
  }
  else
  {
    ft_reply(conn, 213, "%lu", (unsigned long)(st.st_size));
  }
}


/* Handle the STAT command.
 * This is a bit too complex for us, so we
 * reply with a 'disabled' message, because
 * we won't confess the command is not implemented...
 */
static void ftcmd_stat(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 502, "STAT command disabled.");
}


/* Handle the STOR command.
 * Note that the function ft_execStore() does the rest.
 */
static void ftcmd_stor(connection_t *conn, char *param)
{
  (void) param;
  ft_execStore(conn, param, 0);
}


/* Handle the STRU command.
 * (we support only the file mode)
 */
static void ftcmd_stru(connection_t *conn, char *param)
{
  (void) param;
  if ((*param == 'F') || (*param == 'f'))
  {
    ft_reply(conn, 200, "Structure is FILE.");
  }
  else
  {
    ft_reply(conn, 504, "Unknown structure.");
  }
}


/* Handle the SYST command.
 * (we do not return a system identification)
 */
static void ftcmd_syst(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 502, "Command disabled for security reason.");
}


/* Handle the TYPE command.
 */
static void ftcmd_type(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 200, "TYPE ignored (always I)");
}


/* Handle the USER command, get user name.
 */
static void ftcmd_user(connection_t *conn, char *param)
{
  sysStrncpy(conn->username, param, MAX_NAMESIZE);
  conn->username[MAX_NAMESIZE] = 0;

  if (sysStrcmp(conn->username, "anonymous") == 0)
  {
    ft_reply(conn, 331, "Login OK, send password (your e-mail).");
    conn->auth = 1;
  }
  else
  {
    ft_reply(conn, 331, "Password required for %s.", conn->username);
    conn->auth = 2;
  }
}



/*---------------------------------------------------------------------------
 *  COMMAND LINE PARSER + TOOLS
 *-------------------------------------------------------------------------*/


/* Parse and execute a FTP command.
 */
static void ft_execCommand(connection_t *conn)
{
  const CMDINFO_t *cmd;
  sint_t p, w, e;
  u16_t i, len;

  /* remove all illegal characters
     from the beginning of the buffer */
  for (i = 0;
       ((i < conn->buflen) &&
       !((conn->rxbuffer[i] >= 'a') && (conn->rxbuffer[i] <= 'z')) &&
       !((conn->rxbuffer[i] >= 'A') && (conn->rxbuffer[i] <= 'Z')));
       i++);

  if (i > 0)
  {
    ft_removeRxbufBytes(conn, i);
  }

  /* test if parameters are following and
     find end of command (marked by LF or CR/LF) */
  for (w = 0, p = 0, e = 0, i = 0;
       i < conn->buflen;  i++)
  {
    if (conn->rxbuffer[i] != ' ')
    {
      p = w;
    }
    else
    {
      w = 1;
    }
    if ((conn->rxbuffer[i] == '\r') || (conn->rxbuffer[i] == '\n'))
    {
      e = 1;
      break;
    }
  }

  if (e == 0)
  {
    /* no valid command in the buffer */
    return;
  }

  for (cmd = cmdtable_g; cmd->cmdfunc != NULL; cmd++)
  {
    len = (u16_t) sysStrlen(cmd->name);
    if ((i < len) ||
        (sysStrnicmp(conn->rxbuffer, cmd->name, len) != 0) ||
        ((cmd->arg != 0) && (p == 0)))
    {
      continue;
    }

    if (conn->auth < cmd->auth)
    {
      ft_removeRxbufBytes(conn, i);
      ft_reply(conn, 503, "Please login with USER and PASS.");
      return;
    }

    while ((len < conn->buflen) && (conn->rxbuffer[len] == ' ')) len++;
    ft_removeRxbufBytes(conn, len);
    i -= len;

    sysStrncpy(parambuf_g, conn->rxbuffer, i);
    parambuf_g[i] = 0;
    ft_removeRxbufBytes(conn, i);
    (cmd->cmdfunc)(conn, parambuf_g);
    return;
  }

  ft_reply(conn, 500, "Syntax error, command unrecognized.");
  ft_removeRxbufBytes(conn, i); 
}


/* abort an active transfer and delete the broken file.
 */
static void ft_abortTransfer(connection_t *conn)
{
  transfer_t *tran = conn->transfer;

  ft_reply(conn, 426, "File transfer aborted.");

  if (tran->filehandle != -1)
  {
    fsys_close(tran->filehandle);
    tran->filehandle = -1;
  }
  if (tran->upload)
  {
    fsys_remove(tran->filename);
  }
  ft_destroyTransfer(conn->transfer);
}


/* Execute the STOR or APPE command.
 */
static void ft_execStore(connection_t *conn, char *param, sint_t appflag)
{
  transfer_t *tran = conn->transfer;

  if ((tran == NULL) ||
      ((tran->state != TSTATE_GOTPASV) && (tran->state != TSTATE_GOTPORT)))
  {
    ft_reply(conn, 425, "No data connection.");
    return;
  }
  ft_getFilename(conn, param, tran->filename);
  if (*tran->filename == 0)
  {
    ft_reply(conn, 553, "File name not allowed.");
    return;
  }
  tran->filehandle = fsys_open(tran->filename,
                               FSO_WRONLY | FSO_CREAT |
                               (((appflag != 0) ||
                               (conn->resumePos > 0)) ? 0 : FSO_TRUNC));
  if (tran->filehandle < 0)
  {
    ft_reply(tran->owner, 550, "Failed to create file.");
  }
  else
  {
    tran->upload = 1;
    tran->append = appflag;
    ft_prepTransfer(tran);
  }
}


/* Initialize a file transfer (up- or download).
 * Retrieves the current file size, connects the socket, etc.
 */
static void ft_prepTransfer(transfer_t *tran)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -