Пример #1
0
/* send the initial data to a basic authenticator module */
static void
authenticateBasicStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
{
    authenticateStateData *r = NULL;
    char buf[8192];
    char user[1024], pass[1024];
    basic_data *basic_auth;
    assert(auth_user_request);
    assert(handler);
    assert(auth_user_request->auth_user->auth_type == AUTH_BASIC);
    assert(auth_user_request->auth_user->scheme_data != NULL);
    basic_auth = auth_user_request->auth_user->scheme_data;
    debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username,
	basic_auth->passwd);
    if (basicConfig->authenticate == NULL) {
	handler(data, NULL);
	return;
    }
    /* check to see if the auth_user already has a request outstanding */
    if (basic_auth->flags.credentials_ok == 2) {
	/* there is a request with the same credentials already being verified */
	auth_basic_queue_node *node;
	node = xmalloc(sizeof(auth_basic_queue_node));
	assert(node);
	/* save the details */
	node->next = basic_auth->auth_queue;
	basic_auth->auth_queue = node;
	node->handler = handler;
	node->data = data;
	cbdataLock(data);
	return;
    } else {
	r = cbdataAlloc(authenticateStateData);
	r->handler = handler;
	cbdataLock(data);
	r->data = data;
	r->auth_user_request = auth_user_request;
	authenticateAuthUserRequestLock(r->auth_user_request);
	/* mark the user as haveing verification in progress */
	basic_auth->flags.credentials_ok = 2;
	if (basicConfig->utf8) {
	    latin1_to_utf8(user, sizeof(user), basic_auth->username);
	    latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd);
	    xstrncpy(user, rfc1738_escape(user), sizeof(user));
	    xstrncpy(pass, rfc1738_escape(pass), sizeof(pass));
	} else {
	    xstrncpy(user, rfc1738_escape(basic_auth->username), sizeof(user));
	    xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
	}
	snprintf(buf, sizeof(buf), "%s %s\n", user, pass);
	helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r);
    }
}
Пример #2
0
static char *
makeRefreshCheckRequest(StoreEntry * entry, refresh_check_format * format)
{
    static MemBuf mb = MemBufNULL;
    int first = 1;
    HttpReply *reply;
    String sb = StringNull;

    if (!entry->mem_obj)
	return NULL;

    reply = entry->mem_obj->reply;
    memBufReset(&mb);
    for (; format; format = format->next) {
	char buf[256];
	const char *str = NULL;
	const char *quoted;
	switch (format->type) {
	case REFRESH_CHECK_URI:
	    str = entry->mem_obj->url;
	    break;
	case REFRESH_CHECK_AGE:
	    snprintf(buf, sizeof(buf), "%ld", (long int) (squid_curtime - entry->timestamp));
	    str = buf;
	    break;
	case REFRESH_CHECK_RESP_HEADER:
	    sb = httpHeaderGetByName(&reply->header, format->header);
	    str = strBuf(sb);
	    break;
	case REFRESH_CHECK_RESP_HEADER_ID:
	    sb = httpHeaderGetStrOrList(&reply->header, format->header_id);
	    str = strBuf(sb);
	    break;
	case REFRESH_CHECK_RESP_HEADER_MEMBER:
	    sb = httpHeaderGetByNameListMember(&reply->header, format->header, format->member, format->separator);
	    str = strBuf(sb);
	    break;
	case REFRESH_CHECK_RESP_HEADER_ID_MEMBER:
	    sb = httpHeaderGetListMember(&reply->header, format->header_id, format->member, format->separator);
	    str = strBuf(sb);
	    break;

	case REFRESH_CHECK_UNKNOWN:
	case REFRESH_CHECK_END:
	    fatal("unknown refresh_check_program format error");
	    break;
	}
	if (!str || !*str)
	    str = "-";
	if (!first)
	    memBufAppend(&mb, " ", 1);
	quoted = rfc1738_escape(str);
	memBufAppend(&mb, quoted, strlen(quoted));
	stringClean(&sb);
	first = 0;
    }
    return mb.buf;
}
Пример #3
0
void
redirectStart(clientHttpRequest * http, RH * handler, void *data)
{
    ConnStateData *conn = http->conn;
    redirectStateData *r = NULL;
    const char *fqdn;
    char *urlgroup = conn->port->urlgroup;
    char buf[8192];
    char claddr[20];
    char myaddr[20];
    assert(http);
    assert(handler);
    debug(61, 5) ("redirectStart: '%s'\n", http->uri);
    if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) {
	/* Skip redirector if there is one request queued */
	n_bypassed++;
	handler(data, NULL);
	return;
    }
    r = cbdataAlloc(redirectStateData);
    r->orig_url = xstrdup(http->uri);
    r->client_addr = conn->log_addr;
    r->client_ident = NULL;
    if (http->request->auth_user_request)
	r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
    else if (http->request->extacl_user) {
	r->client_ident = http->request->extacl_user;
    }
    if (!r->client_ident && conn->rfc931[0])
	r->client_ident = conn->rfc931;
#if USE_SSL
    if (!r->client_ident)
	r->client_ident = sslGetUserEmail(fd_table[conn->fd].ssl);
#endif
    if (!r->client_ident)
	r->client_ident = dash_str;
    r->method_s = http->request->method->string;
    r->handler = handler;
    r->data = data;
    cbdataLock(r->data);
    if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
	fqdn = dash_str;
    xstrncpy(claddr, inet_ntoa(r->client_addr), 20);
    xstrncpy(myaddr, inet_ntoa(http->request->my_addr), 20);
    snprintf(buf, 8191, "%s %s/%s %s %s %s myip=%s myport=%d",
	r->orig_url,
	claddr,
	fqdn,
	r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
	r->method_s,
	urlgroup ? urlgroup : "-",
	myaddr,
	http->request->my_port);
    debug(61, 6) ("redirectStart: sending '%s' to the helper\n", buf);
    strcat(buf, "\n");
    helperSubmit(redirectors, buf, redirectHandleReply, r);
}
void
redirectStart(clientHttpRequest * http, RH * handler, void *data)
{
    ConnStateData *conn = http->conn;
    redirectStateData *r = NULL;
    const char *fqdn;
    char buf[8192];
    assert(http);
    assert(handler);
    debug(61, 5) ("redirectStart: '%s'\n", http->uri);
    if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) {
        /* Skip redirector if there is one request queued */
        n_bypassed++;
        handler(data, NULL);
        return;
    }
    r = cbdataAlloc(redirectStateData);
    r->orig_url = xstrdup(http->uri);
    r->client_addr = conn->log_addr;
    if (http->request->auth_user_request)
        r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
    else if (conn->rfc931[0]) {
        r->client_ident = conn->rfc931;
    } else {
        r->client_ident = dash_str;
    }
    r->method_s = RequestMethodStr[http->request->method];
    r->handler = handler;
    r->data = data;
    cbdataLock(r->data);
    if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
        fqdn = dash_str;
    snprintf(buf, 8192, "%s %s/%s %s %s\n",
             r->orig_url,
             inet_ntoa(r->client_addr),
             fqdn,
             r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
             r->method_s);
    helperSubmit(redirectors, buf, redirectHandleReply, r);
}
Пример #5
0
pid_t
ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc)
{
    unsigned long thread;
    struct ipc_params params;
    int opt;
    int optlen = sizeof(opt);
    DWORD ecode = 0;
    pid_t pid;
    struct sockaddr_in CS;
    struct sockaddr_in PS;
    int crfd = -1;
    int prfd = -1;
    int cwfd = -1;
    int pwfd = -1;
    socklen_t len;
    int x;

    requirePathnameExists(name, prog);

    if (rfd)
	*rfd = -1;
    if (wfd)
	*wfd = -1;
    if (hIpc)
	*hIpc = NULL;

    if (WIN32_OS_version != _WIN_OS_WINNT) {
	getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
	opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT);
	setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt));
    }
    if (type == IPC_TCP_SOCKET) {
	crfd = cwfd = comm_open(SOCK_STREAM,
	    IPPROTO_TCP,
	    local_addr,
	    0,
	    COMM_NOCLOEXEC,
	    name);
	prfd = pwfd = comm_open(SOCK_STREAM,
	    IPPROTO_TCP,	/* protocol */
	    local_addr,
	    0,			/* port */
	    0,			/* blocking */
	    name);
    } else if (type == IPC_UDP_SOCKET) {
	crfd = cwfd = comm_open(SOCK_DGRAM,
	    IPPROTO_UDP,
	    local_addr,
	    0,
	    COMM_NOCLOEXEC,
	    name);
	prfd = pwfd = comm_open(SOCK_DGRAM,
	    IPPROTO_UDP,
	    local_addr,
	    0,
	    0,
	    name);
    } else if (type == IPC_FIFO) {
	debug(54, 0)
	    ("ipcCreate: %s: use IPC_TCP_SOCKET instead of IP_FIFO on Windows\n",
	    prog);
	assert(0);
    } else {
	assert(IPC_NONE);
    }
    debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
    debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
    debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
    debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);

    if (WIN32_OS_version != _WIN_OS_WINNT) {
	getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
	opt = opt | SO_SYNCHRONOUS_NONALERT;
	setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen);
    }
    if (crfd < 0) {
	debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
	return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (pwfd < 0) {
	debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
	return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
	len = sizeof(PS);
	memset(&PS, '\0', len);
	if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) {
	    debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    pwfd, inet_ntoa(PS.sin_addr), ntohs(PS.sin_port));
	len = sizeof(CS);
	memset(&CS, '\0', len);
	if (getsockname(crfd, (struct sockaddr *) &CS, &len) < 0) {
	    debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    crfd, inet_ntoa(CS.sin_addr), ntohs(CS.sin_port));
    }
    if (type == IPC_TCP_SOCKET) {
	if (listen(crfd, 1) < 0) {
	    debug(54, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
    }
    /* flush or else we get dup data if unbuffered_logs is set */
    logsFlush();
    params.type = type;
    params.crfd = crfd;
    params.cwfd = cwfd;
    params.PS = PS;
    params.prog = prog;
    params.args = (char **) args;

    thread = _beginthreadex(NULL, 0, ipc_thread_1, &params, 0, NULL);

    if (thread == 0) {
	debug(54, 1) ("ipcCreate: _beginthread: %s\n", xstrerror());
	return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) {
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    memset(hello_buf, '\0', HELLO_BUF_SZ);
    x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);

    if (x < 0) {
	debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
	debug(54, 0) ("--> read: %s\n", xstrerror());
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    } else if (strcmp(hello_buf, hello_string)) {
	debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
	debug(54, 0) ("--> read returned %d\n", x);
	debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    x = send(pwfd, ok_string, strlen(ok_string), 0);

    if (x < 0) {
	debug(54, 0) ("ipcCreate: PARENT: OK write test failed\n");
	debug(54, 0) ("--> read: %s\n", xstrerror());
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    memset(hello_buf, '\0', HELLO_BUF_SZ);
    x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);

    if (x < 0) {
	debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
	debug(54, 0) ("--> read: %s\n", xstrerror());
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    } else if (!strcmp(hello_buf, err_string)) {
	debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
	debug(54, 0) ("--> read returned %d\n", x);
	debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    hello_buf[x] = '\0';
    pid = atol(hello_buf);
    commSetTimeout(prfd, -1, NULL, NULL);
    commSetNonBlocking(prfd);
    commSetNonBlocking(pwfd);
    commSetCloseOnExec(prfd);
    commSetCloseOnExec(pwfd);

    if (rfd)
	*rfd = prfd;
    if (wfd)
	*wfd = pwfd;

    fd_table[prfd].flags.ipc = 1;
    fd_table[pwfd].flags.ipc = 1;
    fd_table[crfd].flags.ipc = 1;
    fd_table[cwfd].flags.ipc = 1;

    if (Config.sleep_after_fork) {
	/* XXX emulation of usleep() */
	DWORD sl;
	sl = Config.sleep_after_fork / 1000;
	if (sl == 0)
	    sl = 1;
	Sleep(sl);
    }
    if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) {
	if (hIpc)
	    *hIpc = (HANDLE) thread;
	return pid;
    } else {
	CloseHandle((HANDLE) thread);
	return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
}
Пример #6
0
static unsigned int __stdcall
ipc_thread_1(void *in_params)
{
    int t1, t2, t3, retval = -1;
    int p2c[2] =
    {-1, -1};
    int c2p[2] =
    {-1, -1};
    HANDLE hProcess = NULL, thread = NULL;
    pid_t pid = -1;
    struct thread_params thread_params;
    int x, tmp_s, fd = -1;
    char *str;
#if HAVE_PUTENV
    char *env_str = NULL;
#endif
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    long F;
    int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1;
    char *prog = NULL, *buf1 = NULL;
    struct sockaddr_in CS_ipc, PS_ipc;

    struct ipc_params *params = (struct ipc_params *) in_params;
    int type = params->type;
    int crfd = params->crfd;
    int cwfd = params->cwfd;
    char **args = params->args;
    struct sockaddr_in PS = params->PS;


    buf1 = xcalloc(1, 8192);
    strcpy(buf1, params->prog);
    prog = strtok(buf1, w_space);

    if ((str = strrchr(prog, '/')))
	prog = ++str;
    if ((str = strrchr(prog, '\\')))
	prog = ++str;

    prog = xstrdup(prog);

    if (type == IPC_TCP_SOCKET) {
	debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
	if ((fd = accept(crfd, NULL, NULL)) < 0) {
	    debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
	    goto cleanup;
	}
	debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
	comm_close(crfd);
	snprintf(buf1, 8191, "%s CHILD socket", prog);
	fd_open(fd, FD_SOCKET, buf1);
	fd_table[fd].flags.ipc = 1;
	cwfd = crfd = fd;
    } else if (type == IPC_UDP_SOCKET) {
	if (comm_connect_addr(crfd, &PS) == COMM_ERROR)
	    goto cleanup;
    }
    x = send(cwfd, hello_string, strlen(hello_string) + 1, 0);

    if (x < 0) {
	debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
	debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
	goto cleanup;
    }
#if HAVE_PUTENV
    env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
    putenv(env_str);
#endif
    memset(buf1, '\0', sizeof(buf1));
    x = recv(crfd, buf1, 8191, 0);

    if (x < 0) {
	debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
	debug(54, 0) ("--> read: %s\n", xstrerror());
	goto cleanup;
    } else if (strcmp(buf1, ok_string)) {
	debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
	debug(54, 0) ("--> read returned %d\n", x);
	debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
	goto cleanup;
    }
    /* assign file descriptors to child process */
    if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
	debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
	debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    if (type == IPC_UDP_SOCKET) {
	snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L);
	crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);

	if (crfd_ipc < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L);
	prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
	if (pwfd_ipc < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	tmp_s = sizeof(PS_ipc);
	memset(&PS_ipc, '\0', tmp_s);
	if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) {
	    debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port));
	tmp_s = sizeof(CS_ipc);
	memset(&CS_ipc, '\0', tmp_s);
	if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) {
	    debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port));

	if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) {
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	fd = crfd;

	if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) {
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
    }				/* IPC_UDP_SOCKET */
    t1 = dup(0);
    t2 = dup(1);
    t3 = dup(2);
    dup2(c2p[0], 0);
    dup2(p2c[1], 1);
    dup2(fileno(debug_log), 2);
    close(c2p[0]);
    close(p2c[1]);

    commUnsetNonBlocking(fd);

    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.hStdInput = (HANDLE) _get_osfhandle(0);
    si.hStdOutput = (HANDLE) _get_osfhandle(1);
    si.hStdError = (HANDLE) _get_osfhandle(2);
    si.dwFlags = STARTF_USESTDHANDLES;

    /* Make sure all other valid handles are not inerithable */
    for (x = 3; x < Squid_MaxFD; x++) {
	if ((F = _get_osfhandle(x)) == -1)
	    continue;
	SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0);
    }

    *buf1 = '\0';
    strcpy(buf1 + 4096, params->prog);
    str = strtok(buf1 + 4096, w_space);

    do {
	strcat(buf1, str);
	strcat(buf1, " ");
    } while ((str = strtok(NULL, w_space)));

    x = 1;

    while (args[x]) {
	strcat(buf1, args[x++]);
	strcat(buf1, " ");
    }

    if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
	    NULL, NULL, &si, &pi)) {
	pid = pi.dwProcessId;
	hProcess = pi.hProcess;
    } else {
	pid = -1;
	WIN32_maperror(GetLastError());
	x = errno;
    }

    dup2(t1, 0);
    dup2(t2, 1);
    dup2(t3, 2);
    close(t1);
    close(t2);
    close(t3);

    if (pid == -1) {
	errno = x;
	debug(54, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    if (type == IPC_UDP_SOCKET) {
	WSAPROTOCOL_INFO wpi;

	memset(&wpi, 0, sizeof(wpi));
	if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
	    debug(54, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n",
		xstrerror());
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = write(c2p[1], (const char *) &wpi, sizeof(wpi));
	if (x < sizeof(wpi)) {
	    debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = read(p2c[0], buf1, 8192);
	if (x < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	} else if (strncmp(buf1, ok_string, strlen(ok_string))) {
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    debug(54, 0) ("--> read returned %d\n", x);
	    buf1[x] = '\0';
	    debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
	if (x < sizeof(PS_ipc)) {
	    debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = read(p2c[0], buf1, 8192);
	if (x < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	} else if (strncmp(buf1, ok_string, strlen(ok_string))) {
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    debug(54, 0) ("--> read returned %d\n", x);
	    buf1[x] = '\0';
	    debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = send(pwfd_ipc, ok_string, strlen(ok_string), 0);
	x = recv(prfd_ipc, buf1 + 200, 8191 - 200, 0);
	assert((size_t) x == strlen(ok_string)
	    && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
    }				/* IPC_UDP_SOCKET */
    snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid);
    fd_note(fd, buf1);

    if (prfd_ipc != -1) {
	snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
	fd_note(crfd_ipc, buf1);
	snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
	fd_note(prfd_ipc, buf1);
    }
    /* else {                       IPC_TCP_SOCKET */
    /*     commSetNoLinger(fd); */
    /*  } */
    thread_params.prog = prog;
    thread_params.send_fd = cwfd;
    thread_params.pid = pid;

    if ((thread_params.type = type) == IPC_TCP_SOCKET)
	thread_params.rfd = p2c[0];
    else
	thread_params.rfd = prfd_ipc;

    thread =
	(HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);

    if (!thread) {
	debug(54, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    snprintf(buf1, 8191, "%ld\n", (long int) pid);

    if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
	goto cleanup;

    debug(54, 2) ("ipc(%s,%ld): started successfully\n", prog, (long int) pid);

    /* cycle */
    for (;;) {
	x = recv(crfd, buf1, 8192, 0);
	if (x <= 0) {
	    debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n",
		prog, pid, x);
	    break;
	}
	buf1[x] = '\0';
	if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
	    debug(54, 3)
		("ipc(%s,%d): request for shutdown received from parent. Exiting...\n",
		prog, pid);
	    TerminateProcess(hProcess, 0);
	    break;
	}
	debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid,
	    rfc1738_escape_unescaped(buf1));
	if (type == IPC_TCP_SOCKET)
	    x = write(c2p[1], buf1, x);
	else
	    x = send(pwfd_ipc, buf1, x, 0);
	if (x <= 0) {
	    debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n",
		prog, pid, x, prog);
	    break;
	}
    }

    retval = 0;

  cleanup:
    if (c2p[1] != -1)
	close(c2p[1]);

    if (fd_table[crfd].flags.open)
	ipcCloseAllFD(-1, -1, crfd, cwfd);

    if (prfd_ipc != -1) {
	send(crfd_ipc, shutdown_string, strlen(shutdown_string), 0);
	shutdown(crfd_ipc, SD_BOTH);
	shutdown(prfd_ipc, SD_BOTH);
    }
    ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);

    if (hProcess && WAIT_OBJECT_0 !=
	WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {

	getCurrentTime();
	debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n",
	    prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5);
    }
    if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
	getCurrentTime();
	debug(54, 0)
	    ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n",
	    prog, pid);
    }
    getCurrentTime();

    if (!retval)
	debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid);

    if (buf1)
	xfree(buf1);

    if (prog)
	xfree(prog);

    if (env_str)
	xfree(env_str);

    if (thread)
	CloseHandle(thread);

    if (hProcess)
	CloseHandle(hProcess);

    if (p2c[0] != -1)
	close(p2c[0]);

    return retval;
}
Пример #7
0
int
ipcCreate(int type, const char *prog, char *const args[], const char *name, int *rfd, int *wfd)
{
    pid_t pid;
    struct sockaddr_in CS;
    struct sockaddr_in PS;
    int crfd = -1;
    int prfd = -1;
    int cwfd = -1;
    int pwfd = -1;
    int fd;
    int t1, t2, t3;
    socklen_t len;
    int tmp_s;
#if HAVE_PUTENV
    char *env_str;
#endif
    int x;

#if HAVE_POLL && defined(_SQUID_OSF_)
    assert(type != IPC_FIFO);
#endif

    if (rfd)
	*rfd = -1;
    if (wfd)
	*wfd = -1;
    if (type == IPC_TCP_SOCKET) {
	crfd = cwfd = comm_open(SOCK_STREAM,
	    0,
	    local_addr,
	    0,
	    COMM_NOCLOEXEC,
	    name);
	prfd = pwfd = comm_open(SOCK_STREAM,
	    0,			/* protocol */
	    local_addr,
	    0,			/* port */
	    0,			/* blocking */
	    name);
    } else if (type == IPC_UDP_SOCKET) {
	crfd = cwfd = comm_open(SOCK_DGRAM,
	    0,
	    local_addr,
	    0,
	    COMM_NOCLOEXEC,
	    name);
	prfd = pwfd = comm_open(SOCK_DGRAM,
	    0,
	    local_addr,
	    0,
	    0,
	    name);
    } else if (type == IPC_FIFO) {
	int p2c[2];
	int c2p[2];
	if (pipe(p2c) < 0) {
	    debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror());
	    return -1;
	}
	if (pipe(c2p) < 0) {
	    debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror());
	    return -1;
	}
	fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
	fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
	fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
	fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
    } else {
	assert(IPC_NONE);
    }
    debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
    debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
    debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
    debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);

    if (crfd < 0) {
	debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
	return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (pwfd < 0) {
	debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
	return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
	len = sizeof(PS);
	memset(&PS, '\0', len);
	if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) {
	    debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    pwfd, inet_ntoa(PS.sin_addr), ntohs(PS.sin_port));
	len = sizeof(CS);
	memset(&CS, '\0', len);
	if (getsockname(crfd, (struct sockaddr *) &CS, &len) < 0) {
	    debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    crfd, inet_ntoa(CS.sin_addr), ntohs(CS.sin_port));
    }
    if (type == IPC_TCP_SOCKET) {
	if (listen(crfd, 1) < 0) {
	    debug(50, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
    }
    /* flush or else we get dup data if unbuffered_logs is set */
    logsFlush();
    if ((pid = fork()) < 0) {
	debug(50, 1) ("ipcCreate: fork: %s\n", xstrerror());
	return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (pid > 0) {		/* parent */
	/* close shared socket with child */
	comm_close(crfd);
	if (cwfd != crfd)
	    comm_close(cwfd);
	cwfd = crfd = -1;
	if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
	    if (comm_connect_addr(pwfd, &CS) == COMM_ERROR)
		return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	memset(hello_buf, '\0', HELLO_BUF_SZ);
	if (type == IPC_UDP_SOCKET)
	    x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);
	else
	    x = read(prfd, hello_buf, HELLO_BUF_SZ - 1);
	if (x < 0) {
	    debug(50, 0) ("ipcCreate: PARENT: hello read test failed\n");
	    debug(50, 0) ("--> read: %s\n", xstrerror());
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	} else if (strcmp(hello_buf, hello_string)) {
	    debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
	    debug(54, 0) ("--> read returned %d\n", x);
	    debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
	}
	commSetTimeout(prfd, -1, NULL, NULL);
	commSetNonBlocking(prfd);
	commSetNonBlocking(pwfd);
	if (rfd)
	    *rfd = prfd;
	if (wfd)
	    *wfd = pwfd;
	fd_table[prfd].flags.ipc = 1;
	fd_table[pwfd].flags.ipc = 1;
	return pwfd;
    }
    /* child */
    no_suid();			/* give up extra priviliges */
    /* close shared socket with parent */
    close(prfd);
    if (pwfd != prfd)
	close(pwfd);
    pwfd = prfd = -1;

    if (type == IPC_TCP_SOCKET) {
	debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
	if ((fd = accept(crfd, NULL, NULL)) < 0) {
	    debug(50, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
	    _exit(1);
	}
	debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
	close(crfd);
	cwfd = crfd = fd;
    } else if (type == IPC_UDP_SOCKET) {
	if (comm_connect_addr(crfd, &PS) == COMM_ERROR)
	    return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (type == IPC_UDP_SOCKET) {
	x = send(cwfd, hello_string, strlen(hello_string), 0);
	if (x < 0) {
	    debug(50, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
	    debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n");
	    _exit(1);
	}
    } else {
	if (write(cwfd, hello_string, strlen(hello_string)) < 0) {
	    debug(50, 0) ("write FD %d: %s\n", cwfd, xstrerror());
	    debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n");
	    _exit(1);
	}
    }
#if HAVE_PUTENV
    env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
    putenv(env_str);
#endif
    /*
     * This double-dup stuff avoids problems when one of 
     *  crfd, cwfd, or debug_log are in the rage 0-2.
     */
    do {
	x = open(_PATH_DEVNULL, 0, 0444);
	if (x > -1)
	    commSetCloseOnExec(x);
    } while (x < 3);
    t1 = dup(crfd);
    t2 = dup(cwfd);
    t3 = dup(fileno(debug_log));
    assert(t1 > 2 && t2 > 2 && t3 > 2);
    close(crfd);
    close(cwfd);
    close(fileno(debug_log));
    dup2(t1, 0);
    dup2(t2, 1);
    dup2(t3, 2);
    close(t1);
    close(t2);
    close(t3);
#if HAVE_SETSID
    setsid();
#endif
    execvp(prog, args);
    debug(50, 0) ("ipcCreate: %s: %s\n", prog, xstrerror());
    _exit(1);
    return 0;
}
/* Borrow part of code from libwww2 came with Mosaic distribution */
static void
gopherToHTML(GopherStateData * gopherState, char *inbuf, int len)
{
    char *pos = inbuf;
    char *lpos = NULL;
    char *tline = NULL;
    LOCAL_ARRAY(char, line, TEMP_BUF_SIZE);
    LOCAL_ARRAY(char, tmpbuf, TEMP_BUF_SIZE);
    String outbuf = StringNull;
    char *name = NULL;
    char *selector = NULL;
    char *host = NULL;
    char *port = NULL;
    char *escaped_selector = NULL;
    const char *icon_url = NULL;
    char gtype;
    StoreEntry *entry = NULL;

    memset(tmpbuf, '\0', TEMP_BUF_SIZE);
    memset(line, '\0', TEMP_BUF_SIZE);

    entry = gopherState->entry;

    if (gopherState->conversion == HTML_INDEX_PAGE) {
	char *html_url = html_quote(storeUrl(entry));
	gopherHTMLHeader(entry, "Gopher Index %s", html_url);
	storeAppendPrintf(entry,
	    "<p>This is a searchable Gopher index. Use the search\n"
	    "function of your browser to enter search terms.\n"
	    "<ISINDEX>\n");
	gopherHTMLFooter(entry);
	/* now let start sending stuff to client */
	storeBufferFlush(entry);
	gopherState->HTML_header_added = 1;
	return;
    }
    if (gopherState->conversion == HTML_CSO_PAGE) {
	char *html_url = html_quote(storeUrl(entry));
	gopherHTMLHeader(entry, "CSO Search of %s", html_url);
	storeAppendPrintf(entry,
	    "<P>A CSO database usually contains a phonebook or\n"
	    "directory.  Use the search function of your browser to enter\n"
	    "search terms.</P><ISINDEX>\n");
	gopherHTMLFooter(entry);
	/* now let start sending stuff to client */
	storeBufferFlush(entry);
	gopherState->HTML_header_added = 1;
	return;
    }
    inbuf[len] = '\0';

    if (!gopherState->HTML_header_added) {
	if (gopherState->conversion == HTML_CSO_RESULT)
	    gopherHTMLHeader(entry, "CSO Search Result", NULL);
	else
	    gopherHTMLHeader(entry, "Gopher Menu", NULL);
	strCat(outbuf, "<PRE>");
	gopherState->HTML_header_added = 1;
	gopherState->HTML_pre = 1;
    }
    while ((pos != NULL) && (pos < inbuf + len)) {

	if (gopherState->len != 0) {
	    /* there is something left from last tx. */
	    xstrncpy(line, gopherState->buf, gopherState->len + 1);
	    if (gopherState->len + len > TEMP_BUF_SIZE) {
		debug(10, 1) ("GopherHTML: Buffer overflow. Lost some data on URL: %s\n",
		    storeUrl(entry));
		len = TEMP_BUF_SIZE - gopherState->len;
	    }
	    lpos = (char *) memccpy(line + gopherState->len, inbuf, '\n', len);
	    if (lpos)
		*lpos = '\0';
	    else {
		/* there is no complete line in inbuf */
		/* copy it to temp buffer */
		if (gopherState->len + len > TEMP_BUF_SIZE) {
		    debug(10, 1) ("GopherHTML: Buffer overflow. Lost some data on URL: %s\n",
			storeUrl(entry));
		    len = TEMP_BUF_SIZE - gopherState->len;
		}
		xmemcpy(gopherState->buf + gopherState->len, inbuf, len);
		gopherState->len += len;
		return;
	    }

	    /* skip one line */
	    pos = (char *) memchr(pos, '\n', len);
	    if (pos)
		pos++;

	    /* we're done with the remain from last tx. */
	    gopherState->len = 0;
	    *(gopherState->buf) = '\0';
	} else {

	    lpos = (char *) memccpy(line, pos, '\n', len - (pos - inbuf));
	    if (lpos)
		*lpos = '\0';
	    else {
		/* there is no complete line in inbuf */
		/* copy it to temp buffer */
		if ((len - (pos - inbuf)) > TEMP_BUF_SIZE) {
		    debug(10, 1) ("GopherHTML: Buffer overflow. Lost some data on URL: %s\n",
			storeUrl(entry));
		    len = TEMP_BUF_SIZE;
		}
		if (len > (pos - inbuf)) {
		    xmemcpy(gopherState->buf, pos, len - (pos - inbuf));
		    gopherState->len = len - (pos - inbuf);
		}
		break;
	    }

	    /* skip one line */
	    pos = (char *) memchr(pos, '\n', len);
	    if (pos)
		pos++;

	}

	/* at this point. We should have one line in buffer to process */

	if (*line == '.') {
	    /* skip it */
	    memset(line, '\0', TEMP_BUF_SIZE);
	    continue;
	}
	switch (gopherState->conversion) {

	case HTML_INDEX_RESULT:
	case HTML_DIR:{
		tline = line;
		gtype = *tline++;
		name = tline;
		selector = strchr(tline, TAB);
		if (selector) {
		    *selector++ = '\0';
		    host = strchr(selector, TAB);
		    if (host) {
			*host++ = '\0';
			port = strchr(host, TAB);
			if (port) {
			    char *junk;
			    port[0] = ':';
			    junk = strchr(host, TAB);
			    if (junk)
				*junk++ = 0;	/* Chop port */
			    else {
				junk = strchr(host, '\r');
				if (junk)
				    *junk++ = 0;	/* Chop port */
				else {
				    junk = strchr(host, '\n');
				    if (junk)
					*junk++ = 0;	/* Chop port */
				}
			    }
			    if ((port[1] == '0') && (!port[2]))
				port[0] = 0;	/* 0 means none */
			}
			/* escape a selector here */
			escaped_selector = xstrdup(rfc1738_escape_part(selector));

			switch (gtype) {
			case GOPHER_DIRECTORY:
			    icon_url = mimeGetIconURL("internal-menu");
			    break;
			case GOPHER_HTML:
			case GOPHER_FILE:
			    icon_url = mimeGetIconURL("internal-text");
			    break;
			case GOPHER_INDEX:
			case GOPHER_CSO:
			    icon_url = mimeGetIconURL("internal-index");
			    break;
			case GOPHER_IMAGE:
			case GOPHER_GIF:
			case GOPHER_PLUS_IMAGE:
			    icon_url = mimeGetIconURL("internal-image");
			    break;
			case GOPHER_SOUND:
			case GOPHER_PLUS_SOUND:
			    icon_url = mimeGetIconURL("internal-sound");
			    break;
			case GOPHER_PLUS_MOVIE:
			    icon_url = mimeGetIconURL("internal-movie");
			    break;
			case GOPHER_TELNET:
			case GOPHER_3270:
			    icon_url = mimeGetIconURL("internal-telnet");
			    break;
			case GOPHER_BIN:
			case GOPHER_MACBINHEX:
			case GOPHER_DOSBIN:
			case GOPHER_UUENCODED:
			    icon_url = mimeGetIconURL("internal-binary");
			    break;
			case GOPHER_INFO:
			    icon_url = NULL;
			    break;
			default:
			    icon_url = mimeGetIconURL("internal-unknown");
			    break;
			}

			memset(tmpbuf, '\0', TEMP_BUF_SIZE);
			if ((gtype == GOPHER_TELNET) || (gtype == GOPHER_3270)) {
			    if (strlen(escaped_selector) != 0)
				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG border=\"0\" SRC=\"%s\"> <A HREF=\"telnet://%s@%s%s%s/\">%s</A>\n",
				    icon_url, escaped_selector, rfc1738_escape_part(host),
				    *port ? ":" : "", port, html_quote(name));
			    else
				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG border=\"0\" SRC=\"%s\"> <A HREF=\"telnet://%s%s%s/\">%s</A>\n",
				    icon_url, rfc1738_escape_part(host), *port ? ":" : "",
				    port, html_quote(name));

			} else if (gtype == GOPHER_INFO) {
			    snprintf(tmpbuf, TEMP_BUF_SIZE, "\t%s\n", html_quote(name));
			} else {
			    if (strncmp(selector, "GET /", 5) == 0) {
				/* WWW link */
				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG border=\"0\" SRC=\"%s\"> <A HREF=\"http://%s/%s\">%s</A>\n",
				    icon_url, host, rfc1738_escape_unescaped(selector + 5), html_quote(name));
			    } else {
				/* Standard link */
				snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG border=\"0\" SRC=\"%s\"> <A HREF=\"gopher://%s/%c%s\">%s</A>\n",
				    icon_url, host, gtype, rfc1738_escape(selector), html_quote(name));
			    }
			}
			safe_free(escaped_selector);
			strCat(outbuf, tmpbuf);
		    } else {
			memset(line, '\0', TEMP_BUF_SIZE);
			continue;
		    }
		} else {
		    memset(line, '\0', TEMP_BUF_SIZE);
		    continue;
		}
		break;
	    }			/* HTML_DIR, HTML_INDEX_RESULT */


	case HTML_CSO_RESULT:{
		if (line[0] == '-') {
		    int code, recno;
		    char *s_code, *s_recno, *result;

		    s_code = strtok(line + 1, ":\n");
		    s_recno = strtok(NULL, ":\n");
		    result = strtok(NULL, "\n");

		    if (!result)
			break;

		    code = atoi(s_code);
		    recno = atoi(s_recno);

		    if (code != 200)
			break;

		    if (gopherState->cso_recno != recno) {
			snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR noshade size=\"1px\"><H2>Record# %d<br><i>%s</i></H2>\n<PRE>", recno, html_quote(result));
			gopherState->cso_recno = recno;
		    } else {
			snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", html_quote(result));
		    }
		    strCat(outbuf, tmpbuf);
		    break;
		} else {
		    int code;
		    char *s_code, *result;

		    s_code = strtok(line, ":");
		    result = strtok(NULL, "\n");

		    if (!result)
			break;

		    code = atoi(s_code);
		    switch (code) {

		    case 200:{
			    /* OK */
			    /* Do nothing here */
			    break;
			}

		    case 102:	/* Number of matches */
		    case 501:	/* No Match */
		    case 502:	/* Too Many Matches */
			{
			    /* Print the message the server returns */
			    snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR noshade size=\"1px\"><H2>%s</H2>\n<PRE>", html_quote(result));
			    strCat(outbuf, tmpbuf);
			    break;
			}


		    }
		}

	    }			/* HTML_CSO_RESULT */
	default:
	    break;		/* do nothing */

	}			/* switch */

    }				/* while loop */

    if (strLen(outbuf) > 0) {
	storeAppend(entry, strBuf(outbuf), strLen(outbuf));
	/* now let start sending stuff to client */
	storeBufferFlush(entry);
    }
    stringClean(&outbuf);
    return;
}
Пример #9
0
static void
icpHandleIcpV2(int fd, struct sockaddr_in from, char *buf, int len)
{
    icp_common_t header;
    StoreEntry *entry = NULL;
    char *url = NULL;
    const cache_key *key;
    request_t *icp_request = NULL;
    int allow = 0;
    aclCheck_t checklist;
    icp_common_t *reply;
    int src_rtt = 0;
    u_num32 flags = 0;
    int rtt = 0;
    int hops = 0;
    xmemcpy(&header, buf, sizeof(icp_common_t));
    /*
     * Only these fields need to be converted
     */
    header.length = ntohs(header.length);
    header.reqnum = ntohl(header.reqnum);
    header.flags = ntohl(header.flags);
    header.pad = ntohl(header.pad);
    /*
     * Length field should match the number of bytes read
     */
    if (len != header.length) {
	debug(12, 3) ("icpHandleIcpV2: ICP message is too small\n");
	return;
    }
    switch (header.opcode) {
    case ICP_QUERY:
	/* We have a valid packet */
	url = buf + sizeof(icp_common_t) + sizeof(u_num32);
	if (strpbrk(url, w_space)) {
	    url = rfc1738_escape(url);
	    reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0);
	    icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, 0);
	    break;
	}
	if ((icp_request = urlParse(METHOD_GET, url)) == NULL) {
	    reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0);
	    icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, 0);
	    break;
	}
	memset(&checklist, '\0', sizeof(checklist));
	checklist.src_addr = from.sin_addr;
	checklist.my_addr = no_addr;
	checklist.request = icp_request;
	allow = aclCheckFast(Config.accessList.icp, &checklist);
	if (!allow) {
	    debug(12, 2) ("icpHandleIcpV2: Access Denied for %s by %s.\n",
		inet_ntoa(from.sin_addr), AclMatchedName);
	    if (clientdbCutoffDenied(from.sin_addr)) {
		/*
		 * count this DENIED query in the clientdb, even though
		 * we're not sending an ICP reply...
		 */
		clientdbUpdate(from.sin_addr, LOG_UDP_DENIED, PROTO_ICP, 0);
	    } else {
		reply = icpCreateMessage(ICP_DENIED, 0, url, header.reqnum, 0);
		icpUdpSend(fd, &from, reply, LOG_UDP_DENIED, 0);
	    }
	    break;
	}
	if (header.flags & ICP_FLAG_SRC_RTT) {
	    rtt = netdbHostRtt(icp_request->host);
	    hops = netdbHostHops(icp_request->host);
	    src_rtt = ((hops & 0xFFFF) << 16) | (rtt & 0xFFFF);
	    if (rtt)
		flags |= ICP_FLAG_SRC_RTT;
	}
	/* The peer is allowed to use this cache */
	entry = storeGetPublic(url, METHOD_GET);
	debug(12, 5) ("icpHandleIcpV2: OPCODE %s\n", icp_opcode_str[header.opcode]);
	if (icpCheckUdpHit(entry, icp_request)) {
	    reply = icpCreateMessage(ICP_HIT, flags, url, header.reqnum, src_rtt);
	    icpUdpSend(fd, &from, reply, LOG_UDP_HIT, 0);
	    break;
	}
	if (Config.onoff.test_reachability && rtt == 0) {
	    if ((rtt = netdbHostRtt(icp_request->host)) == 0)
		netdbPingSite(icp_request->host);
	}
	/* if store is rebuilding, return a UDP_HIT, but not a MISS */
	if (store_dirs_rebuilding && opt_reload_hit_only) {
	    reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
	    icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0);
	} else if (hit_only_mode_until > squid_curtime) {
	    reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
	    icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0);
	} else if (Config.onoff.test_reachability && rtt == 0) {
	    reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
	    icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0);
	} else {
	    reply = icpCreateMessage(ICP_MISS, flags, url, header.reqnum, src_rtt);
	    icpUdpSend(fd, &from, reply, LOG_UDP_MISS, 0);
	}
	break;

    case ICP_HIT:
#if ALLOW_SOURCE_PING
    case ICP_SECHO:
#endif
    case ICP_DECHO:
    case ICP_MISS:
    case ICP_DENIED:
    case ICP_MISS_NOFETCH:
	if (neighbors_do_private_keys && header.reqnum == 0) {
	    debug(12, 0) ("icpHandleIcpV2: Neighbor %s returned reqnum = 0\n",
		inet_ntoa(from.sin_addr));
	    debug(12, 0) ("icpHandleIcpV2: Disabling use of private keys\n");
	    neighbors_do_private_keys = 0;
	}
	url = buf + sizeof(icp_common_t);
	debug(12, 3) ("icpHandleIcpV2: %s from %s for '%s'\n",
	    icp_opcode_str[header.opcode],
	    inet_ntoa(from.sin_addr),
	    url);
	key = icpGetCacheKey(url, (int) header.reqnum);
	/* call neighborsUdpAck even if ping_status != PING_WAITING */
	neighborsUdpAck(key, &header, &from);
	break;

    case ICP_INVALID:
    case ICP_ERR:
	break;

    default:
	debug(12, 0) ("icpHandleIcpV2: UNKNOWN OPCODE: %d from %s\n",
	    header.opcode, inet_ntoa(from.sin_addr));
	break;
    }
    if (icp_request)
	requestDestroy(icp_request);
}