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

📄 ftp.c

📁 -
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -