varnish-cache/lib/libvarnish/vcli_proto.c
1
/*-
2
 * Copyright (c) 2010-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <sys/types.h>
34
#include <sys/uio.h>
35
36
#include <poll.h>
37
#include <stdint.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "vdef.h"
44
45
#include "vas.h"        // XXX Flexelint "not used" - but req'ed for assert()
46
#include "vcli.h"
47
#include "vsha256.h"
48
49
void
50 67080
VCLI_AuthResponse(int S_fd, const char *challenge,
51
    char response[CLI_AUTH_RESPONSE_LEN + 1])
52
{
53
        VSHA256_CTX ctx;
54
        uint8_t buf[VSHA256_LEN];
55
        int i;
56
57 67080
        assert(CLI_AUTH_RESPONSE_LEN == (VSHA256_LEN * 2));
58
59 67080
        VSHA256_Init(&ctx);
60 67080
        VSHA256_Update(&ctx, challenge, 32);
61 67080
        VSHA256_Update(&ctx, "\n", 1);
62 67080
        do {
63 17239560
                i = read(S_fd, buf, 1);
64 17239560
                if (i == 1)
65 17172480
                        VSHA256_Update(&ctx, buf, i);
66 17239560
        } while (i > 0);
67 67080
        VSHA256_Update(&ctx, challenge, 32);
68 67080
        VSHA256_Update(&ctx, "\n", 1);
69 67080
        VSHA256_Final(buf, &ctx);
70 2213640
        for (i = 0; i < VSHA256_LEN; i++)
71 2146560
                assert(snprintf(response + 2 * i, 3, "%02x", buf[i]) == 2);
72 67080
}
73
74
int
75 789470
VCLI_WriteResult(int fd, unsigned status, const char *result)
76
{
77
        int i, l;
78
        struct iovec iov[3];
79 789470
        char nl[2] = "\n";
80
        size_t len;
81
        char res[CLI_LINE0_LEN + 2];    /*
82
                                         * NUL + one more so we can catch
83
                                         * any misformats by snprintf
84
                                         */
85
86 789470
        assert(status >= 100);
87 789470
        assert(status <= 999);          /*lint !e650 const out of range */
88
89 789470
        len = strlen(result);
90
91 1578940
        i = snprintf(res, sizeof res,
92 789470
            "%-3d %-8zd\n", status, len);
93 789470
        assert(i == CLI_LINE0_LEN);
94 789470
        assert(strtoul(res + 3, NULL, 10) == len);
95
96 789470
        iov[0].iov_base = res;
97 789470
        iov[0].iov_len = CLI_LINE0_LEN;
98
99 789470
        iov[1].iov_base = (void*)(uintptr_t)result;     /* TRUST ME */
100 789470
        iov[1].iov_len = len;
101
102 789470
        iov[2].iov_base = nl;
103 789470
        iov[2].iov_len = 1;
104
105 3157880
        for (l = i = 0; i < 3; i++)
106 2368410
                l += iov[i].iov_len;
107 789470
        i = writev(fd, iov, 3);
108 789470
        return (i != l);
109
}
110
111
static int
112 1514700
read_tmo(int fd, char *ptr, unsigned len, double tmo)
113
{
114
        int i, j, to;
115
        struct pollfd pfd;
116
117 1514700
        if (tmo > 0)
118 1514700
                to = (int)(tmo * 1e3);
119
        else
120 0
                to = -1;
121 1514700
        pfd.fd = fd;
122 1514700
        pfd.events = POLLIN;
123 3029329
        for (j = 0; len > 0; ) {
124 1514869
                i = poll(&pfd, 1, to);
125 1514869
                if (i < 0) {
126 0
                        errno = EINTR;
127 0
                        return (-1);
128
                }
129 1514869
                if (i == 0) {
130 0
                        errno = ETIMEDOUT;
131 0
                        return (-1);
132
                }
133 1514869
                i = read(fd, ptr, len);
134 1514869
                if (i < 0)
135 0
                        return (i);
136 1514869
                if (i == 0)
137 240
                        break;
138 1514629
                len -= i;
139 1514629
                ptr += i;
140 1514629
                j += i;
141
        }
142 1514700
        return (j);
143 1514700
}
144
145
int
146 757470
VCLI_ReadResult(int fd, unsigned *status, char **ptr, double tmo)
147
{
148
        char res[CLI_LINE0_LEN];        /* For NUL */
149
        int i, j;
150
        unsigned u, v, s;
151 757470
        char *p = NULL;
152 757470
        const char *err = "CLI communication error (hdr)";
153
154 757470
        if (status == NULL)
155 0
                status = &s;
156 757470
        if (ptr != NULL)
157 757470
                *ptr = NULL;
158 757470
        do {
159 757470
                i = read_tmo(fd, res, CLI_LINE0_LEN, tmo);
160 757470
                if (i != CLI_LINE0_LEN)
161 240
                        break;
162
163 757230
                if (res[3] != ' ')
164 0
                        break;
165
166 757230
                if (res[CLI_LINE0_LEN - 1] != '\n')
167 0
                        break;
168
169 757230
                res[CLI_LINE0_LEN - 1] = '\0';
170 757230
                j = sscanf(res, "%u %u\n", &u, &v);
171 757230
                if (j != 2)
172 0
                        break;
173
174 757230
                err = "CLI communication error (body)";
175
176 757230
                *status = u;
177 757230
                p = malloc(v + 1L);
178 757230
                if (p == NULL)
179 0
                        break;
180
181 757230
                i = read_tmo(fd, p, v + 1, tmo);
182 757230
                if (i < 0)
183 0
                        break;
184 757230
                if (i != v + 1)
185 0
                        break;
186 757230
                if (p[v] != '\n')
187 0
                        break;
188
189 757230
                p[v] = '\0';
190 757230
                if (ptr == NULL)
191 0
                        free(p);
192
                else
193 757230
                        *ptr = p;
194 757230
                return (0);
195
        } while (0);
196
197 240
        free(p);
198 240
        *status = CLIS_COMMS;
199 240
        if (ptr != NULL)
200 240
                *ptr = strdup(err);
201 240
        return (*status);
202 757470
}