cc3e7ee422bb2ad40ba43ca332558a59f3d77114 galt Fri May 13 11:48:55 2011 -0700 require FTP to check for return code of 331 before sending the PASS command. diff --git src/lib/net.c src/lib/net.c index 3e00091..a57d9c6 100644 --- src/lib/net.c +++ src/lib/net.c @@ -507,31 +507,31 @@ else { return readyCount > 0; /* Zero readyCount indicates time out */ } } } static void sendFtpCommandOnly(int sd, char *cmd) /* send command to ftp server */ { mustWriteFd(sd, cmd, strlen(cmd)); } #define NET_FTP_TIMEOUT 1000000 -static boolean receiveFtpReply(int sd, char *cmd, struct dyString **retReply) +static boolean receiveFtpReply(int sd, char *cmd, struct dyString **retReply, int *retCode) /* send command to ftp server and check resulting reply code, * warn and return FALSE if not desired reply. If retReply is non-NULL, store reply text there. */ { char *startLastLine = NULL; struct dyString *rs = newDyString(4*1024); while (1) { int readSize = 0; while (1) { char buf[4*1024]; if (!readReadyWait(sd, NET_FTP_TIMEOUT)) { warn("ftp server response timed out > %d microsec", NET_FTP_TIMEOUT); return FALSE; @@ -565,39 +565,41 @@ break; // EOF /* must be some text info we can't use, ignore it till we get status code */ } int reply = atoi(startLastLine); if ((reply < 200) || (reply > 399)) { warn("ftp server error on cmd=[%s] response=[%s]\n",cmd,rs->string); return FALSE; } if (retReply) *retReply = rs; else dyStringFree(&rs); +if (retCode) + *retCode = reply; return TRUE; } -static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply) +static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply, int *retCode) /* send command to ftp server and check resulting reply code, * warn and return FALSE if not desired reply. If retReply is non-NULL, store reply text there. */ { sendFtpCommandOnly(sd, cmd); -return receiveFtpReply(sd, cmd, retReply); +return receiveFtpReply(sd, cmd, retReply, retCode); } static int parsePasvPort(char *rs) /* parse PASV reply to get the port and return it */ { char *words[7]; int wordCount; char *rsStart = strchr(rs,'('); char *rsEnd = strchr(rs,')'); int result = 0; rsStart++; *rsEnd=0; wordCount = chopString(rsStart, ",", words, ArraySize(words)); if (wordCount != 6) errAbort("PASV reply does not parse correctly"); @@ -668,48 +670,52 @@ errAbort("mktime failed while parsing strptime'd MDTM string [%s]", words[1]); return t; } static int openFtpControlSocket(char *host, int port, char *user, char *password) /* Open a socket to host,port; authenticate anonymous ftp; set type to I; * return socket desc or -1 if there was an error. */ { int sd = netConnect(host, port); if (sd < 0) return -1; /* First read the welcome msg */ if (readReadyWait(sd, NET_FTP_TIMEOUT)) - sendFtpCommand(sd, "", NULL); + sendFtpCommand(sd, "", NULL, NULL); char cmd[256]; +int retCode = 0; safef(cmd,sizeof(cmd),"USER %s\r\n", user); -if (!sendFtpCommand(sd, cmd, NULL)) +if (!sendFtpCommand(sd, cmd, NULL, &retCode)) { close(sd); return -1; } +if (retCode == 331) + { safef(cmd,sizeof(cmd),"PASS %s\r\n", password); -if (!sendFtpCommand(sd, cmd, NULL)) + if (!sendFtpCommand(sd, cmd, NULL, NULL)) { close(sd); return -1; } + } -if (!sendFtpCommand(sd, "TYPE I\r\n", NULL)) +if (!sendFtpCommand(sd, "TYPE I\r\n", NULL, NULL)) { close(sd); return -1; } /* 200 Type set to I */ /* (send the data as binary, so can support compressed files) */ return sd; } boolean netGetFtpInfo(char *url, long long *retSize, time_t *retTime) /* Return date in UTC and size of ftp url file */ { /* Parse the URL and connect. */ struct netParsedUrl npu; netParseUrl(url, &npu); @@ -718,41 +724,41 @@ // TODO maybe remove this workaround where udc cache wants info on URL "/" ? if (sameString(npu.file,"/")) { *retSize = 0; *retTime = time(NULL); return TRUE; } int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password); if (sd < 0) return FALSE; char cmd[256]; safef(cmd,sizeof(cmd),"SIZE %s\r\n", npu.file); struct dyString *rs = NULL; -if (!sendFtpCommand(sd, cmd, &rs)) +if (!sendFtpCommand(sd, cmd, &rs, NULL)) { close(sd); return FALSE; } *retSize = parseFtpSIZE(rs->string); /* 200 12345 */ dyStringFree(&rs); safef(cmd,sizeof(cmd),"MDTM %s\r\n", npu.file); -if (!sendFtpCommand(sd, cmd, &rs)) +if (!sendFtpCommand(sd, cmd, &rs, NULL)) { close(sd); return FALSE; } *retTime = parseFtpMDTM(rs->string); /* 200 YYYYMMDDhhmmss */ dyStringFree(&rs); close(sd); return TRUE; } static void sendFtpDataToPipe(int pipefd[2], int sd, int sdata, struct netParsedUrl npu) /* This is to be executed by the child process after the fork in netGetOpenFtpSockets. * It keeps the ftp control socket alive while reading from the ftp data socket * and writing to the pipe to the parent process, which closes the ftp sockets @@ -804,41 +810,41 @@ * Otherwise, create a pipe and fork to keep control socket alive in the child * process until we are done fetching data. */ { char cmd[256]; /* Parse the URL and connect. */ struct netParsedUrl npu; netParseUrl(url, &npu); if (!sameString(npu.protocol, "ftp")) errAbort("netGetOpenFtpSockets: url (%s) is not for ftp.", url); int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password); if (sd == -1) return -1; struct dyString *rs = NULL; -if (!sendFtpCommand(sd, "PASV\r\n", &rs)) +if (!sendFtpCommand(sd, "PASV\r\n", &rs, NULL)) { close(sd); return -1; } /* 227 Entering Passive Mode (128,231,210,81,222,250) */ if (npu.byteRangeStart != -1) { safef(cmd,sizeof(cmd),"REST %lld\r\n", (long long) npu.byteRangeStart); - if (!sendFtpCommand(sd, cmd, NULL)) + if (!sendFtpCommand(sd, cmd, NULL, NULL)) { close(sd); return -1; } } /* RETR for files, LIST for directories ending in / */ safef(cmd,sizeof(cmd),"%s %s\r\n",((npu.file[strlen(npu.file)-1]) == '/') ? "LIST" : "RETR", npu.file); sendFtpCommandOnly(sd, cmd); int sdata = netConnect(npu.host, parsePasvPort(rs->string)); dyStringFree(&rs); if (sdata < 0) { close(sd); @@ -848,31 +854,31 @@ int secondsWaited = 0; while (TRUE) { if (secondsWaited >= 10) { warn("ftp server error on cmd=[%s] timed-out waiting for data or error\n", cmd); close(sd); close(sdata); return -1; } if (readReadyWait(sdata, NET_FTP_TIMEOUT)) break; // we have some data if (readReadyWait(sd, 0)) /* wait in microsec */ { // this can see an error like bad filename - if (!receiveFtpReply(sd, cmd, NULL)) + if (!receiveFtpReply(sd, cmd, NULL, NULL)) { close(sd); close(sdata); return -1; } } ++secondsWaited; } if (retCtrlSd != NULL) { *retCtrlSd = sd; return sdata; } else