📄 ftp.c
字号:
if (!ftpState->user[0] && !ftpState->password[0]) return 1; /* no name or passwd */ if (ftpState->password[0]) return 1; /* passwd with no name? */ /* URL has name, but no passwd */ if (!(auth = httpHeaderGetAuth(req_hdr, HDR_AUTHORIZATION, "Basic"))) return 0; /* need auth header */ ftpState->flags.authenticated = 1; orig_user = xstrdup(ftpState->user); ftpLoginParser(auth, ftpState, FTP_LOGIN_NOT_ESCAPED); if (!strcmp(orig_user, ftpState->user)) { xfree(orig_user); return 1; /* same username */ } strcpy(ftpState->user, orig_user); xfree(orig_user); return 0; /* different username */}static voidftpCheckUrlpath(FtpStateData * ftpState){ request_t *request = ftpState->request; int l; const char *t; if ((t = strRChr(request->urlpath, ';')) != NULL) { if (strncasecmp(t + 1, "type=", 5) == 0) { ftpState->typecode = (char) toupper((int) *(t + 6)); strCutPtr(request->urlpath, t); } } l = strLen(request->urlpath); ftpState->flags.use_base = 1; /* check for null path */ if (!l) { stringReset(&request->urlpath, "/"); ftpState->flags.isdir = 1; ftpState->flags.root_dir = 1; } else if (!strCmp(request->urlpath, "/%2f/")) { /* UNIX root directory */ ftpState->flags.use_base = 0; ftpState->flags.isdir = 1; ftpState->flags.root_dir = 1; } else if ((l >= 1) && (*(strBuf(request->urlpath) + l - 1) == '/')) { /* Directory URL, ending in / */ ftpState->flags.isdir = 1; ftpState->flags.use_base = 0; if (l == 1) ftpState->flags.root_dir = 1; }}static voidftpBuildTitleUrl(FtpStateData * ftpState){ request_t *request = ftpState->request; size_t len; char *t; len = 64 + strlen(ftpState->user) + strlen(ftpState->password) + strlen(request->host) + strLen(request->urlpath); t = ftpState->title_url = xcalloc(len, 1); strcat(t, "ftp://"); if (strcmp(ftpState->user, "anonymous")) { strcat(t, ftpState->user); strcat(t, "@"); } strcat(t, request->host); if (request->port != urlDefaultPort(PROTO_FTP)) snprintf(&t[strlen(t)], len - strlen(t), ":%d", request->port); strcat(t, strBuf(request->urlpath));}voidftpStart(FwdState * fwd){ request_t *request = fwd->request; StoreEntry *entry = fwd->entry; int fd = fwd->server_fd; LOCAL_ARRAY(char, realm, 8192); const char *url = storeUrl(entry); FtpStateData *ftpState = xcalloc(1, sizeof(FtpStateData)); HttpReply *reply; StoreEntry *pe = NULL; const cache_key *key = NULL; cbdataAdd(ftpState, cbdataXfree, 0); debug(9, 3) ("ftpStart: '%s'\n", url); Counter.server.all.requests++; Counter.server.ftp.requests++; storeLockObject(entry); ftpState->entry = entry; ftpState->request = requestLink(request); ftpState->ctrl.fd = fd; ftpState->data.fd = -1; ftpState->size = -1; ftpState->mdtm = -1; ftpState->flags.pasv_supported = 1; ftpState->flags.rest_supported = 1; ftpState->fwd = fwd; comm_add_close_handler(fd, ftpStateFree, ftpState); if (ftpState->request->method == METHOD_PUT) ftpState->flags.put = 1; if (!ftpCheckAuth(ftpState, &request->header)) { /* This request is not fully authenticated */ if (request->port == 21) { snprintf(realm, 8192, "ftp %s", ftpState->user); } else { snprintf(realm, 8192, "ftp %s port %d", ftpState->user, request->port); } /* eject any old cached object */ key = storeKeyPublic(entry->mem_obj->url, entry->mem_obj->method); if ((pe = storeGet(key)) != NULL) storeRelease(pe); /* create reply */ reply = entry->mem_obj->reply; assert(reply != NULL); /* create appropriate reply */ ftpAuthRequired(reply, request, realm); httpReplySwapOut(reply, entry); fwdComplete(ftpState->fwd); comm_close(fd); return; } ftpCheckUrlpath(ftpState); ftpBuildTitleUrl(ftpState); debug(9, 5) ("ftpStart: host=%s, path=%s, user=%s, passwd=%s\n", ftpState->request->host, strBuf(ftpState->request->urlpath), ftpState->user, ftpState->password); ftpState->state = BEGIN; ftpState->ctrl.last_command = xstrdup("Connect to server"); ftpState->ctrl.buf = memAllocate(MEM_4K_BUF); ftpState->ctrl.freefunc = memFree4K; ftpState->ctrl.size = 4096; ftpState->ctrl.offset = 0; ftpState->data.buf = xmalloc(SQUID_TCP_SO_RCVBUF); ftpState->data.size = SQUID_TCP_SO_RCVBUF; ftpState->data.freefunc = xfree; ftpScheduleReadControlReply(ftpState, 0); commSetTimeout(fd, Config.Timeout.read, ftpTimeout, ftpState);}/* ====================================================================== */static voidftpWriteCommand(const char *buf, FtpStateData * ftpState){ debug(9, 5) ("ftpWriteCommand: %s\n", buf); safe_free(ftpState->ctrl.last_command); ftpState->ctrl.last_command = xstrdup(buf); comm_write(ftpState->ctrl.fd, xstrdup(buf), strlen(buf), ftpWriteCommandCallback, ftpState, xfree); ftpScheduleReadControlReply(ftpState, 0);}static voidftpWriteCommandCallback(int fd, char *bufnotused, size_t size, int errflag, void *data){ FtpStateData *ftpState = data; StoreEntry *entry = ftpState->entry; ErrorState *err; debug(9, 7) ("ftpWriteCommandCallback: wrote %d bytes\n", size); if (size > 0) { fd_bytes(fd, size, FD_WRITE); kb_incr(&Counter.server.all.kbytes_out, size); kb_incr(&Counter.server.ftp.kbytes_out, size); } if (errflag == COMM_ERR_CLOSING) return; if (errflag) { debug(50, 1) ("ftpWriteCommandCallback: FD %d: %s\n", fd, xstrerror()); if (entry->mem_obj->inmem_hi == 0) { err = errorCon(ERR_WRITE_ERROR, HTTP_SERVICE_UNAVAILABLE); err->xerrno = errno; err->request = requestLink(ftpState->request); errorAppendEntry(entry, err); } comm_close(ftpState->ctrl.fd); }}static wordlist *ftpParseControlReply(char *buf, size_t len, int *codep, int *used){ char *s; char *sbuf; char *end; int usable; int complete = 0; wordlist *head = NULL; wordlist *list; wordlist **tail = &head; off_t offset; size_t linelen; int code = -1; debug(9, 5) ("ftpParseControlReply\n"); /* * We need a NULL-terminated buffer for scanning, ick */ sbuf = xmalloc(len + 1); xstrncpy(sbuf, buf, len + 1); end = sbuf + len - 1; while (*end != '\r' && *end != '\n' && end > sbuf) end--; usable = end - sbuf; debug(9, 3) ("ftpParseControlReply: usable = %d\n", usable); if (usable == 0) { debug(9, 3) ("ftpParseControlReply: didn't find end of line\n"); safe_free(sbuf); return NULL; } debug(9, 3) ("ftpParseControlReply: %d bytes to play with\n", len); end++; s = sbuf; s += strspn(s, crlf); for (; s < end; s += strcspn(s, crlf), s += strspn(s, crlf)) { if (complete) break; debug(9, 3) ("ftpParseControlReply: s = {%s}\n", s); linelen = strcspn(s, crlf) + 1; if (linelen < 2) break; if (linelen > 3) complete = (*s >= '0' && *s <= '9' && *(s + 3) == ' '); if (complete) code = atoi(s); offset = 0; if (linelen > 3) if (*s >= '0' && *s <= '9' && (*(s + 3) == '-' || *(s + 3) == ' ')) offset = 4; list = memAllocate(MEM_WORDLIST); list->key = xmalloc(linelen - offset); xstrncpy(list->key, s + offset, linelen - offset); debug(9, 7) ("%d %s\n", code, list->key); *tail = list; tail = &list->next; } *used = (int) (s - sbuf); safe_free(sbuf); if (!complete) wordlistDestroy(&head); if (codep) *codep = code; return head;}static voidftpScheduleReadControlReply(FtpStateData * ftpState, int buffered_ok){ debug(9, 3) ("ftpScheduleReadControlReply: FD %d\n", ftpState->ctrl.fd); if (buffered_ok && ftpState->ctrl.offset > 0) { /* We've already read some reply data */ ftpHandleControlReply(ftpState); } else { commSetSelect(ftpState->ctrl.fd, COMM_SELECT_READ, ftpReadControlReply, ftpState, Config.Timeout.read); }}static voidftpReadControlReply(int fd, void *data){ FtpStateData *ftpState = data; StoreEntry *entry = ftpState->entry; int len; ErrorState *err; debug(9, 5) ("ftpReadControlReply\n"); assert(ftpState->ctrl.offset < ftpState->ctrl.size); Counter.syscalls.sock.reads++; len = read(fd, ftpState->ctrl.buf + ftpState->ctrl.offset, ftpState->ctrl.size - ftpState->ctrl.offset); if (len > 0) { fd_bytes(fd, len, FD_READ); kb_incr(&Counter.server.all.kbytes_in, len); kb_incr(&Counter.server.ftp.kbytes_in, len); } debug(9, 5) ("ftpReadControlReply: FD %d, Read %d bytes\n", fd, len); if (len < 0) { debug(50, 1) ("ftpReadControlReply: read error: %s\n", xstrerror()); if (ignoreErrno(errno)) { ftpScheduleReadControlReply(ftpState, 0); } else { if (entry->mem_obj->inmem_hi == 0) { err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = errno; err->request = requestLink(ftpState->request); errorAppendEntry(entry, err); } comm_close(ftpState->ctrl.fd); } return; } if (len == 0) { if (entry->store_status == STORE_PENDING) { storeReleaseRequest(entry); if (entry->mem_obj->inmem_hi == 0) { err = errorCon(ERR_FTP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = 0; err->request = requestLink(ftpState->request); err->ftp_server_msg = ftpState->ctrl.message; errorAppendEntry(entry, err); } } comm_close(ftpState->ctrl.fd); return; } len += ftpState->ctrl.offset; ftpState->ctrl.offset = len; assert(len <= ftpState->ctrl.size); ftpHandleControlReply(ftpState);}static voidftpHandleControlReply(FtpStateData * ftpState){ char *oldbuf; wordlist **W; int bytes_used = 0; wordlistDestroy(&ftpState->ctrl.message); ftpState->ctrl.message = ftpParseControlReply(ftpState->ctrl.buf, ftpState->ctrl.offset, &ftpState->ctrl.replycode, &bytes_used); if (ftpState->ctrl.message == NULL) { /* didn't get complete reply yet */ if (ftpState->ctrl.offset == ftpState->ctrl.size) { oldbuf = ftpState->ctrl.buf; ftpState->ctrl.buf = xcalloc(ftpState->ctrl.size << 1, 1); xmemcpy(ftpState->ctrl.buf, oldbuf, ftpState->ctrl.size); ftpState->ctrl.size <<= 1; ftpState->ctrl.freefunc(oldbuf); ftpState->ctrl.freefunc = xfree; } ftpScheduleReadControlReply(ftpState, 0); return; } else if (ftpState->ctrl.offset == bytes_used) { /* used it all up */ ftpState->ctrl.offset = 0; } else { /* Got some data past the complete reply */ assert(bytes_used < ftpState->ctrl.offset); ftpState->ctrl.offset -= bytes_used; xmemmove(ftpState->ctrl.buf, ftpState->ctrl.buf + bytes_used, ftpState->ctrl.offset); } /* Find the last line of the reply message */ for (W = &ftpState->ctrl.message; (*W)->next; W = &(*W)->next); safe_free(ftpState->ctrl.last_reply); ftpState->ctrl.last_reply = (*W)->key; safe_free(*W); debug(9, 8) ("ftpReadControlReply: state=%d, code=%d\n", ftpState->state, ftpState->ctrl.replycode); FTP_SM_FUNCS[ftpState->state] (ftpState);}/* ====================================================================== */static voidftpReadWelcome(FtpStateData * ftpState){ int code = ftpState->ctrl.replycode; debug(9, 3) ("ftpReadWelcome\n"); if (ftpState->flags.pasv_only) ftpState->login_att++; if (code == 220) { if (ftpState->ctrl.message) { if (strstr(ftpState->ctrl.message->key, "NetWare")) ftpState->flags.skip_whitespace = 1; if (ftpState->cwd_message) wordlistDestroy(&ftpState->cwd_message); ftpState->cwd_message = ftpState->ctrl.message; ftpState->ctrl.message = NULL; } ftpSendUser(ftpState); } else if (code == 120) { if (NULL != ftpState->ctrl.message) debug(9, 3) ("FTP server is busy: %s\n", ftpState->ctrl.message->key); return; } else { ftpFail(ftpState); }}static voidftpSendUser(FtpStateData * ftpState){ if (ftpState->proxy_host != NULL) snprintf(cbuf, 1024, "USER %s@%s\r\n", ftpState->user, ftpState->request->host); else snprintf(cbuf, 1024, "USER %s\r\n", ftpState->user); ftpWriteCommand(cbuf, ftpState); ftpState->state = SENT_USER;}static voidftpReadUser(FtpStateData * ftpState){ int code = ftpState->ctrl.replycode; debug(9, 3) ("ftpReadUser\n"); if (code == 230) { ftpReadPass(ftpState); } else if (code == 331) { ftpSendPass(ftpState); } else { ftpFail(ftpState); }}static voidftpSendPass(FtpStateData * ftpState){ snprintf(cbuf, 1024, "PASS %s\r\n", ftpState->password); ftpWriteCommand(cbuf, ftpState); ftpState->state = SENT_PASS;}static voidftpReadPass(FtpStateData * ftpState){ int code = ftpState->ctrl.replycode; debug(9, 3) ("ftpReadPass\n"); if (ftpState->ctrl.message) { if (ftpState->cwd_message) wordlistDestroy(&ftpState->cwd_message); ftpState->cwd_message = ftpState->ctrl.message; ftpState->ctrl.message = NULL; } if (code == 230) { ftpSendType(ftpState); } else { ftpFail(ftpState); }}static voidftpSendType(FtpStateData * ftpState){ const char *t; const char *filename; char mode; /* * Ref section 3.2.2 of RFC 1738 */ switch (mode = ftpState->typecode) { case 'D': mode = 'A'; break; case 'A': case 'I': break; default: if (ftpState->flags.isdir) { mode = 'A'; } else { t = strRChr(ftpState->request->urlpath, '/'); filename = t ? t + 1 : strBuf(ftpState->request->urlpath);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -