📄 ftpdlib.c
字号:
/* dirName doesn't start with a device name, prepend old path */ if (dirName == pTail) { (void) strcpy (curDirName, pSlot->curDirName); (void) pathCat (curDirName, dirName, newPath); } else /* it starts with a dev name */ (void) strcpy (newPath, dirName);/* use the whole thing */ pathCondense (newPath); /* condense ".." shit */ /* remember where we are */ (void) strcpy (pSlot->curDirName, newPath); /* notify successful chdir */ if (ftpdCmdSend (pSlot, sock, 250, messages [MSG_CHANGED_DIR], (int)newPath, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else if (strncmp (pBuf, "TYPE", 4) == 0) { /* we only support BINARY and ASCII representation types */ if (pBuf [5] == 'I' || pBuf [5] == 'i' || pBuf [5] == 'L' || pBuf [5] == 'l') { pSlot->status |= FTPD_BINARY_TYPE; pSlot->status &= ~FTPD_ASCII_TYPE; if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_TYPE_BINARY], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else if (pBuf [5] == 'A' || pBuf [5] == 'a') { pSlot->status |= FTPD_ASCII_TYPE; pSlot->status &= ~FTPD_BINARY_TYPE; if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_TYPE_ASCII], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else { if (ftpdCmdSend (pSlot, sock, 504, messages [MSG_PARAM_BAD], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } } else if (strncmp (pBuf, "PORT", 4) == 0) { /* client specifies the port to be used in setting up * active data connections later on (see ftpdDataConnGet ()). * format: first four decimal digits separated by commas * indicate the internet address; the last two decimal * digits separated by a comma represents hi and low * bytes of a port number. */ (void) sscanf (&pBuf [5], "%d,%d,%d,%d,%d,%d", &portNum [0], &portNum [1], &portNum [2], &portNum [3], &portNum [4], &portNum [5]); pSlot->dataAddr.sin_port = portNum [4] * 256 + portNum [5]; /* convert port number to network byte order */ pSlot->dataAddr.sin_port = htons (pSlot->dataAddr.sin_port); /* Set remote host to given value. */ value = (portNum [0] << 24) | (portNum [1] << 16) | (portNum [2] << 8) | portNum [3]; pSlot->dataAddr.sin_addr.s_addr = htonl (value); if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_PORT_SET], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else if (strncmp (pBuf, "PWD", 3) == 0) { /* get current working directory */ (void) strcpy (pBuf, pSlot->curDirName); if (ftpdCmdSend (pSlot, sock, 257, messages [MSG_CUR_DIR], (int)pBuf, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else if (strncmp (pBuf, "STRU", 4) == 0) { /* specify the file structure */ /* we only support normal byte stream oriented files; * we don't support IBM-ish record block oriented files */ if (pBuf [5] == 'F' || pBuf [5] == 'f') { if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_FILE_STRU], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else { if (ftpdCmdSend (pSlot, sock, 504, messages [MSG_PARAM_BAD], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } } else if (strncmp (pBuf, "MODE", 4) == 0) { /* specify transfer mode */ /* we only support stream mode -- no block or compressed mode */ if (pBuf [5] == 'S' || pBuf [5] == 's') { if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_STREAM_MODE], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else { if (ftpdCmdSend (pSlot, sock, 504, messages [MSG_PARAM_BAD], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } } else if (strncmp (pBuf, "ALLO", 4) == 0 || strncmp (pBuf, "ACCT", 4) == 0) { /* allocate and account commands are not need */ if (ftpdCmdSend (pSlot, sock, 202, messages [MSG_ALLOC_ACCOUNT], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else if (strncmp (pBuf, "PASV", 4) == 0) { /* client wants to connect to us instead of waiting * for us to make a connection to its data connection * socket */ ftpdSockFree (&pSlot->dataSock); /* we need to open a socket and start listening on it * to accommodate his request. */ if ((pSlot->dataSock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { if (ftpdCmdSend (pSlot, sock, 425, messages [MSG_PASSIVE_ERROR], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else { int outval1; int outval2; int outval3; int outval4; int outval5; int outval6; if (getsockname (pSlot->cmdSock, (struct sockaddr *) &pSlot->dataAddr, &addrLen) < 0) { /* Couldn't find address for local end of connection. */ if (ftpdCmdSend (pSlot, sock, 425, messages [MSG_PASSIVE_ERROR], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } /* * Find an ephemeral port for the expected connection * and initialize connection queue. */ pSlot->dataAddr.sin_port = htons (0); addrLen = sizeof (struct sockaddr_in); if (bind (pSlot->dataSock, (struct sockaddr *)&pSlot->dataAddr, sizeof (struct sockaddr_in)) < 0 || getsockname (pSlot->dataSock, (struct sockaddr *) &pSlot->dataAddr, &addrLen) < 0 || listen (pSlot->dataSock, 1) < 0) { ftpdSockFree (&pSlot->dataSock); if (ftpdCmdSend (pSlot, sock, 425, messages [MSG_PASSIVE_ERROR], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } continue; } /* we're passive, let us keep that in mind */ pSlot->status |= FTPD_PASSIVE; value = pSlot->dataAddr.sin_addr.s_addr; outval1 = ( (u_char *)&value)[0]; outval2 = ( (u_char *)&value)[1]; outval3 = ( (u_char *)&value)[2]; outval4 = ( (u_char *)&value)[3]; /* Separate port number into bytes. */ outval5 = ( (u_char *)&pSlot->dataAddr.sin_port)[0]; outval6 = ( (u_char *)&pSlot->dataAddr.sin_port)[1]; /* tell the client to which port to connect */ if (ftpdCmdSend (pSlot, pSlot->cmdSock, 227, messages [MSG_PASSIVE_MODE], outval1, outval2, outval3, outval4, outval5, outval6) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } } else if (strncmp (pBuf, "NOOP", 4) == 0) { /* don't do anything */ if (ftpdCmdSend (pSlot, sock, 200, messages [MSG_NOOP_OKAY], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } else if (strncmp (pBuf, "DELE", 4) == 0) { if (pBuf [5] != '/') { if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/') (void) sprintf (newPath, "%s%s", pSlot->curDirName, &pBuf [5]); else (void) sprintf (newPath, "%s/%s", pSlot->curDirName, &pBuf [5]); pFileName = newPath; } else pFileName = &pBuf [5]; ftpdDebugMsg ("DELE %s\n", (int)pFileName,0,0,0); if (remove (pFileName) != OK) { if (ftpdCmdSend (pSlot, sock, 550, messages [MSG_FILE_ERROR], (int) pFileName, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } continue; } else { if (ftpdCmdSend (pSlot, sock, 250, messages [MSG_DELE_OKAY], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } } else { /* unrecognized command or command not supported */ if (ftpdCmdSend (pSlot, sock, 500, messages [MSG_BAD_COMMAND], 0, 0, 0, 0, 0, 0) == ERROR) { ftpdSessionDelete (pSlot); return (ERROR); } } } /* * Processing halted due to pending server shutdown. * Remove all resources and exit. */ ftpdSessionDelete (pSlot); return (OK); }/********************************************************************************* ftpdDataConnGet - get a fresh data connection socket for FTP data transfer** FTP uses upto two connections per session (as described above) at any* time. The command connection (cmdSock) is maintained throughout the* FTP session to pass the request command strings and replies between* the client and the server. For commands that require bulk data transfer* such as contents of a file or a list of files in a directory, FTP* sets up dynamic data connections separate from the command connection.* This function, ftpdDataConnGet, is responsible for creating* such connections.** Setting up the data connection is performed in two ways. If the dataSock* is already initialized and we're in passive mode (as indicated by the* FTPD_PASSIVE bit of the status field in the FTPD_SESSION_SLOT) we need to* wait for our client to make a connection to us -- so we just do an accept* on this already initialized dataSock. If the dataSock is already* initialized and we're not in passive mode, we just use the already* existing connection. Otherwise, we need to initialize a new socket and* make a connection to the the port where client is accepting new* connections. This port number is in general set by "PORT" command (see* ftpdWorkTask()).*/LOCAL STATUS ftpdDataConnGet ( FTPD_SESSION_DATA *pSlot /* pointer to the work slot */ ) { FAST int newSock; /* new connection socket */ int addrLen; /* to be used with accept */ struct sockaddr_in addr; /* to be used with accept */ int on = 1; /* to be used to turn things on */ int retry = 0; /* retry counter initialized to zero */ /* command socket is invalid, return immediately */ if (pSlot->cmdSock == FTPD_SOCK_FREE) return (ERROR); pSlot->byteCount = 0; if (pSlot->dataSock != FTPD_SOCK_FREE) { /* data socket is already initialized */ /* are we being passive? (should we wait for client to connect * to us rather than connecting to the client?) */ if (pSlot->status & FTPD_PASSIVE) { /* we're being passive. wait for our client to connect to us. */ addrLen = sizeof (struct sockaddr); if ((newSock = accept (pSlot->dataSock, (struct sockaddr *) &addr, &addrLen)) < 0) { ftpdCmdSend (pSlot, pSlot->cmdSock, 425, "Can't open data connection", 0, 0, 0, 0, 0, 0); ftpdSockFree (&pSlot->dataSock); /* we can't be passive no more */ pSlot->status &= ~FTPD_PASSIVE; return (ERROR); } /* * Enable the keep alive option to prevent misbehaving clients * from locking the server. */ if (setsockopt (newSock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)) != 0) { ftpdSockFree (&pSlot->dataSock); return (ERROR); } /* Check for window size validity */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -