📄 nanoftp.c
字号:
* @ctx: an FTP context * * Check if there is a response from the FTP server after a command. * Returns the code number, or 0 */intxmlNanoFTPCheckResponse(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[1024 + 1]; fd_set rfd; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&rfd); FD_SET(ctxt->controlFd, &rfd); switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) { case 0: return(0); case -1:#ifdef DEBUG_FTP perror("select");#endif return(-1); } return(xmlNanoFTPReadResponse(ctx, buf, 1024));}/** * Send the user authentification */static intxmlNanoFTPSendUser(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200]; int len; int res; if (ctxt->user == NULL)#ifndef HAVE_SNPRINTF len = sprintf(buf, "USER anonymous\r\n");#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "USER anonymous\r\n");#endif /* HAVE_SNPRINTF */ else#ifndef HAVE_SNPRINTF len = sprintf(buf, "USER %s\r\n", ctxt->user);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) return(res); return(0);}/** * Send the password authentification */static intxmlNanoFTPSendPasswd(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200]; int len; int res; if (ctxt->passwd == NULL)#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASS libxml@%s\r\n", hostname);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", hostname);#endif /* HAVE_SNPRINTF */ else#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASS %s\r\n", ctxt->passwd);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) return(res); return(0);}/** * xmlNanoFTPQuit: * @ctx: an FTP context * * Send a QUIT command to the server * * Returns -1 in case of error, 0 otherwise */intxmlNanoFTPQuit(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200]; int len; int res;#ifndef HAVE_SNPRINTF len = sprintf(buf, "QUIT\r\n");#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "QUIT\r\n");#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); return(0);}/** * xmlNanoFTPConnect: * @ctx: an FTP context * * Tries to open a control connection * * Returns -1 in case of error, 0 otherwise */intxmlNanoFTPConnect(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; struct hostent *hp; int port; int res; if (ctxt == NULL) return(-1); if (ctxt->hostname == NULL) return(-1); /* * do the blocking DNS query. */ if (proxy) hp = gethostbyname(proxy); else hp = gethostbyname(ctxt->hostname); if (hp == NULL) return(-1); /* * Prepare the socket */ memset(&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr)); ctxt->ftpAddr.sin_family = AF_INET; memcpy(&ctxt->ftpAddr.sin_addr, hp->h_addr_list[0], hp->h_length); if (proxy) { port = proxyPort; } else { port = ctxt->port; } if (port == 0) port = 21; ctxt->ftpAddr.sin_port = htons(port); ctxt->controlFd = socket(AF_INET, SOCK_STREAM, 0); if (ctxt->controlFd < 0) return(-1); /* * Do the connect. */ if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr, sizeof(struct sockaddr_in)) < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } /* * Wait for the HELLO from the server. */ res = xmlNanoFTPGetResponse(ctxt); if (res != 2) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } /* * State diagram for the login operation on the FTP server * * Reference: RFC 959 * * 1 * +---+ USER +---+------------->+---+ * | B |---------->| W | 2 ---->| E | * +---+ +---+------ | -->+---+ * | | | | | * 3 | | 4,5 | | | * -------------- ----- | | | * | | | | | * | | | | | * | --------- | * | 1| | | | * V | | | | * +---+ PASS +---+ 2 | ------>+---+ * | |---------->| W |------------->| S | * +---+ +---+ ---------->+---+ * | | | | | * 3 | |4,5| | | * -------------- -------- | * | | | | | * | | | | | * | ----------- * | 1,3| | | | * V | 2| | | * +---+ ACCT +---+-- | ----->+---+ * | |---------->| W | 4,5 -------->| F | * +---+ +---+------------->+---+ * * Of course in case of using a proxy this get really nasty and is not * standardized at all :-( */ if (proxy) { int len; char buf[400]; if (proxyUser != NULL) { /* * We need proxy auth */#ifndef HAVE_SNPRINTF len = sprintf(buf, "USER %s\r\n", proxyUser);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; return(res); } res = xmlNanoFTPGetResponse(ctxt); switch (res) { case 2: if (proxyPasswd == NULL) break; case 3: if (proxyPasswd != NULL)#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASS %s\r\n", proxyPasswd);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);#endif /* HAVE_SNPRINTF */ else#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASS libxml@%s\r\n", hostname);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", hostname);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; return(res); } res = xmlNanoFTPGetResponse(ctxt); if (res > 3) { close(ctxt->controlFd); ctxt->controlFd = -1; return(-1); } break; case 1: break; case 4: case 5: case -1: default: close(ctxt->controlFd); ctxt->controlFd = -1; return(-1); } } /* * We assume we don't need more authentication to the proxy * and that it succeeded :-\ */ switch (proxyType) { case 0: /* we will try in seqence */ case 1: /* Using SITE command */#ifndef HAVE_SNPRINTF len = sprintf(buf, "SITE %s\r\n", ctxt->hostname);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(res); } res = xmlNanoFTPGetResponse(ctxt); if (res == 2) { /* we assume it worked :-\ 1 is error for SITE command */ proxyType = 1; break; } if (proxyType == 1) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } case 2: /* USER user@host command */ if (ctxt->user == NULL)#ifndef HAVE_SNPRINTF len = sprintf(buf, "USER anonymous@%s\r\n",#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",#endif /* HAVE_SNPRINTF */ ctxt->hostname); else#ifndef HAVE_SNPRINTF len = sprintf(buf, "USER %s@%s\r\n",#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "USER %s@%s\r\n",#endif /* HAVE_SNPRINTF */ ctxt->user, ctxt->hostname);#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(res); } res = xmlNanoFTPGetResponse(ctxt); if ((res == 1) || (res == 2)) { /* we assume it worked :-\ */ proxyType = 2; return(0); } if (ctxt->passwd == NULL)#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASS libxml@%s\r\n", hostname);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", hostname);#endif /* HAVE_SNPRINTF */ else#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASS %s\r\n", ctxt->passwd);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(res); } res = xmlNanoFTPGetResponse(ctxt); if ((res == 1) || (res == 2)) { /* we assume it worked :-\ */ proxyType = 2; return(0); } if (proxyType == 2) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } case 3: /* * If you need support for other Proxy authentication scheme * send the code or at least the sequence in use. */ default: close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } } /* * Non-proxy handling. */ res = xmlNanoFTPSendUser(ctxt); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } res = xmlNanoFTPGetResponse(ctxt); switch (res) { case 2: return(0); case 3: break; case 1: case 4: case 5: case -1: default: close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } res = xmlNanoFTPSendPasswd(ctxt); if (res < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } res = xmlNanoFTPGetResponse(ctxt); switch (res) { case 2: break; case 3: fprintf(stderr, "FTP server asking for ACCNT on anonymous\n"); case 1: case 4: case 5: case -1: default: close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } return(0);}/** * xmlNanoFTPConnectTo: * @server: an FTP server name * @directory: the port (use 21 if 0) * * Tries to open a control connection to the given server/port * * Returns and fTP context or NULL if it failed */void *xmlNanoFTPConnectTo(const char *server, int port) { xmlNanoFTPCtxtPtr ctxt; int res; xmlNanoFTPInit(); if (server == NULL) return(NULL); ctxt = xmlNanoFTPNewCtxt(NULL); ctxt->hostname = xmlMemStrdup(server); if (port != 0) ctxt->port = port; res = xmlNanoFTPConnect(ctxt); if (res < 0) { xmlNanoFTPFreeCtxt(ctxt); return(NULL); } return(ctxt);}/** * xmlNanoFTPGetConnection: * @ctx: an FTP context * @directory: a directory on the server * * Tries to change the remote directory * * Returns -1 incase of error, 1 if CWD worked, 0 if it failed */intxmlNanoFTPCwd(void *ctx, char *directory) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[400]; int len; int res; /* * Expected response code for CWD: * * CWD * 250 * 500, 501, 502, 421, 530, 550 */#ifndef HAVE_SNPRINTF len = sprintf(buf, "CWD %s\r\n", directory);#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) return(res); res = xmlNanoFTPGetResponse(ctxt); if (res == 4) { return(-1); } if (res == 2) return(1); if (res == 5) { return(0); } return(0);}/** * xmlNanoFTPGetConnection: * @ctx: an FTP context * * Try to open a data connection to the server. Currently only * passive mode is supported. * * Returns -1 incase of error, 0 otherwise */intxmlNanoFTPGetConnection(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200], *cur; int len, i; int res; unsigned char ad[6], *adp, *portp; unsigned int temp[6]; struct sockaddr_in dataAddr; size_t dataAddrLen; ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ctxt->dataFd < 0) { fprintf(stderr, "xmlNanoFTPGetConnection: failed to create socket\n"); } dataAddrLen = sizeof(dataAddr); memset(&dataAddr, 0, dataAddrLen); dataAddr.sin_family = AF_INET; if (ctxt->passive) {#ifndef HAVE_SNPRINTF len = sprintf(buf, "PASV\r\n");#else /* HAVE_SNPRINTF */ len = snprintf(buf, sizeof(buf), "PASV\r\n");#endif /* HAVE_SNPRINTF */#ifdef DEBUG_FTP printf(buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { close(ctxt->dataFd); ctxt->dataFd = -1; return(res); } res = xmlNanoFTPReadResponse(ctx, buf, sizeof(buf) -1); if (res != 2) { if (res == 5) { close(ctxt->dataFd); ctxt->dataFd = -1; return(-1); } else { /* * retry with an active connection */ close(ctxt->dataFd); ctxt->dataFd = -1; ctxt->passive = 0; } } cur = &buf[4]; while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++; if (sscanf(cur, "%d,%d,%d,%d,%d,%d", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5]) != 6) { fprintf(stderr, "Invalid answer to PASV\n"); close(ctxt->dataFd); ctxt->dataFd = -1; return(-1); } for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff); memcpy(&dataAddr.sin_addr, &ad[0], 4); memcpy(&dataAddr.sin_port, &ad[4], 2); if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) { fprintf(stderr, "Failed to create a data connection\n"); close(ctxt->dataFd); ctxt->dataFd = -1; return (-1); } } else { getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen); dataAddr.sin_port = 0; if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) { fprintf(stderr, "Failed to bind a port\n"); close(ctxt->dataFd); ctxt->dataFd = -1; return (-1); } getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -