common.c revision 1.2.2.2 1 1.2.2.2 matt /*-
2 1.2.2.2 matt * Copyright (c) 1998-2004 Dag-Erling Codan Smrgrav
3 1.2.2.2 matt * All rights reserved.
4 1.2.2.2 matt *
5 1.2.2.2 matt * Redistribution and use in source and binary forms, with or without
6 1.2.2.2 matt * modification, are permitted provided that the following conditions
7 1.2.2.2 matt * are met:
8 1.2.2.2 matt * 1. Redistributions of source code must retain the above copyright
9 1.2.2.2 matt * notice, this list of conditions and the following disclaimer
10 1.2.2.2 matt * in this position and unchanged.
11 1.2.2.2 matt * 2. Redistributions in binary form must reproduce the above copyright
12 1.2.2.2 matt * notice, this list of conditions and the following disclaimer in the
13 1.2.2.2 matt * documentation and/or other materials provided with the distribution.
14 1.2.2.2 matt * 3. The name of the author may not be used to endorse or promote products
15 1.2.2.2 matt * derived from this software without specific prior written permission
16 1.2.2.2 matt *
17 1.2.2.2 matt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1.2.2.2 matt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1.2.2.2 matt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.2.2.2 matt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1.2.2.2 matt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 1.2.2.2 matt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1.2.2.2 matt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1.2.2.2 matt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1.2.2.2 matt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 1.2.2.2 matt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.2.2.2 matt */
28 1.2.2.2 matt
29 1.2.2.2 matt #include "free2net.h"
30 1.2.2.2 matt
31 1.2.2.2 matt #include <sys/cdefs.h>
32 1.2.2.2 matt __FBSDID("$FreeBSD: src/lib/libfetch/common.c,v 1.48.4.2 2006/11/11 00:16:07 des Exp $");
33 1.2.2.2 matt
34 1.2.2.2 matt #include <sys/param.h>
35 1.2.2.2 matt #include <sys/socket.h>
36 1.2.2.2 matt #include <sys/time.h>
37 1.2.2.2 matt #include <sys/uio.h>
38 1.2.2.2 matt #include <netinet/in.h>
39 1.2.2.2 matt
40 1.2.2.2 matt #include <errno.h>
41 1.2.2.2 matt #include <netdb.h>
42 1.2.2.2 matt #include <pwd.h>
43 1.2.2.2 matt #include <stdarg.h>
44 1.2.2.2 matt #include <stdlib.h>
45 1.2.2.2 matt #include <stdio.h>
46 1.2.2.2 matt #include <string.h>
47 1.2.2.2 matt #include <unistd.h>
48 1.2.2.2 matt
49 1.2.2.2 matt #include "fetch.h"
50 1.2.2.2 matt #include "common.h"
51 1.2.2.2 matt
52 1.2.2.2 matt
53 1.2.2.2 matt /*** Local data **************************************************************/
54 1.2.2.2 matt
55 1.2.2.2 matt /*
56 1.2.2.2 matt * Error messages for resolver errors
57 1.2.2.2 matt */
58 1.2.2.2 matt static struct fetcherr _netdb_errlist[] = {
59 1.2.2.2 matt #ifdef EAI_NODATA
60 1.2.2.2 matt { EAI_NODATA, FETCH_RESOLV, "Host not found" },
61 1.2.2.2 matt #endif
62 1.2.2.2 matt { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" },
63 1.2.2.2 matt { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" },
64 1.2.2.2 matt { EAI_NONAME, FETCH_RESOLV, "No address record" },
65 1.2.2.2 matt { -1, FETCH_UNKNOWN, "Unknown resolver error" }
66 1.2.2.2 matt };
67 1.2.2.2 matt
68 1.2.2.2 matt /* End-of-Line */
69 1.2.2.2 matt static const char ENDL[2] = "\r\n";
70 1.2.2.2 matt
71 1.2.2.2 matt
72 1.2.2.2 matt /*** Error-reporting functions ***********************************************/
73 1.2.2.2 matt
74 1.2.2.2 matt /*
75 1.2.2.2 matt * Map error code to string
76 1.2.2.2 matt */
77 1.2.2.2 matt static struct fetcherr *
78 1.2.2.2 matt _fetch_finderr(struct fetcherr *p, int e)
79 1.2.2.2 matt {
80 1.2.2.2 matt while (p->num != -1 && p->num != e)
81 1.2.2.2 matt p++;
82 1.2.2.2 matt return (p);
83 1.2.2.2 matt }
84 1.2.2.2 matt
85 1.2.2.2 matt /*
86 1.2.2.2 matt * Set error code
87 1.2.2.2 matt */
88 1.2.2.2 matt void
89 1.2.2.2 matt _fetch_seterr(struct fetcherr *p, int e)
90 1.2.2.2 matt {
91 1.2.2.2 matt p = _fetch_finderr(p, e);
92 1.2.2.2 matt fetchLastErrCode = p->cat;
93 1.2.2.2 matt snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
94 1.2.2.2 matt }
95 1.2.2.2 matt
96 1.2.2.2 matt /*
97 1.2.2.2 matt * Set error code according to errno
98 1.2.2.2 matt */
99 1.2.2.2 matt void
100 1.2.2.2 matt _fetch_syserr(void)
101 1.2.2.2 matt {
102 1.2.2.2 matt switch (errno) {
103 1.2.2.2 matt case 0:
104 1.2.2.2 matt fetchLastErrCode = FETCH_OK;
105 1.2.2.2 matt break;
106 1.2.2.2 matt case EPERM:
107 1.2.2.2 matt case EACCES:
108 1.2.2.2 matt case EROFS:
109 1.2.2.2 matt case EAUTH:
110 1.2.2.2 matt case ENEEDAUTH:
111 1.2.2.2 matt fetchLastErrCode = FETCH_AUTH;
112 1.2.2.2 matt break;
113 1.2.2.2 matt case ENOENT:
114 1.2.2.2 matt case EISDIR: /* XXX */
115 1.2.2.2 matt fetchLastErrCode = FETCH_UNAVAIL;
116 1.2.2.2 matt break;
117 1.2.2.2 matt case ENOMEM:
118 1.2.2.2 matt fetchLastErrCode = FETCH_MEMORY;
119 1.2.2.2 matt break;
120 1.2.2.2 matt case EBUSY:
121 1.2.2.2 matt case EAGAIN:
122 1.2.2.2 matt fetchLastErrCode = FETCH_TEMP;
123 1.2.2.2 matt break;
124 1.2.2.2 matt case EEXIST:
125 1.2.2.2 matt fetchLastErrCode = FETCH_EXISTS;
126 1.2.2.2 matt break;
127 1.2.2.2 matt case ENOSPC:
128 1.2.2.2 matt fetchLastErrCode = FETCH_FULL;
129 1.2.2.2 matt break;
130 1.2.2.2 matt case EADDRINUSE:
131 1.2.2.2 matt case EADDRNOTAVAIL:
132 1.2.2.2 matt case ENETDOWN:
133 1.2.2.2 matt case ENETUNREACH:
134 1.2.2.2 matt case ENETRESET:
135 1.2.2.2 matt case EHOSTUNREACH:
136 1.2.2.2 matt fetchLastErrCode = FETCH_NETWORK;
137 1.2.2.2 matt break;
138 1.2.2.2 matt case ECONNABORTED:
139 1.2.2.2 matt case ECONNRESET:
140 1.2.2.2 matt fetchLastErrCode = FETCH_ABORT;
141 1.2.2.2 matt break;
142 1.2.2.2 matt case ETIMEDOUT:
143 1.2.2.2 matt fetchLastErrCode = FETCH_TIMEOUT;
144 1.2.2.2 matt break;
145 1.2.2.2 matt case ECONNREFUSED:
146 1.2.2.2 matt case EHOSTDOWN:
147 1.2.2.2 matt fetchLastErrCode = FETCH_DOWN;
148 1.2.2.2 matt break;
149 1.2.2.2 matt default:
150 1.2.2.2 matt fetchLastErrCode = FETCH_UNKNOWN;
151 1.2.2.2 matt }
152 1.2.2.2 matt snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
153 1.2.2.2 matt }
154 1.2.2.2 matt
155 1.2.2.2 matt
156 1.2.2.2 matt /*
157 1.2.2.2 matt * Emit status message
158 1.2.2.2 matt */
159 1.2.2.2 matt void
160 1.2.2.2 matt _fetch_info(const char *fmt, ...)
161 1.2.2.2 matt {
162 1.2.2.2 matt va_list ap;
163 1.2.2.2 matt
164 1.2.2.2 matt va_start(ap, fmt);
165 1.2.2.2 matt vfprintf(stderr, fmt, ap);
166 1.2.2.2 matt va_end(ap);
167 1.2.2.2 matt fputc('\n', stderr);
168 1.2.2.2 matt }
169 1.2.2.2 matt
170 1.2.2.2 matt
171 1.2.2.2 matt /*** Network-related utility functions ***************************************/
172 1.2.2.2 matt
173 1.2.2.2 matt /*
174 1.2.2.2 matt * Return the default port for a scheme
175 1.2.2.2 matt */
176 1.2.2.2 matt int
177 1.2.2.2 matt _fetch_default_port(const char *scheme)
178 1.2.2.2 matt {
179 1.2.2.2 matt struct servent *se;
180 1.2.2.2 matt
181 1.2.2.2 matt if ((se = getservbyname(scheme, "tcp")) != NULL)
182 1.2.2.2 matt return (ntohs(se->s_port));
183 1.2.2.2 matt if (strcasecmp(scheme, SCHEME_FTP) == 0)
184 1.2.2.2 matt return (FTP_DEFAULT_PORT);
185 1.2.2.2 matt if (strcasecmp(scheme, SCHEME_HTTP) == 0)
186 1.2.2.2 matt return (HTTP_DEFAULT_PORT);
187 1.2.2.2 matt return (0);
188 1.2.2.2 matt }
189 1.2.2.2 matt
190 1.2.2.2 matt /*
191 1.2.2.2 matt * Return the default proxy port for a scheme
192 1.2.2.2 matt */
193 1.2.2.2 matt int
194 1.2.2.2 matt _fetch_default_proxy_port(const char *scheme)
195 1.2.2.2 matt {
196 1.2.2.2 matt if (strcasecmp(scheme, SCHEME_FTP) == 0)
197 1.2.2.2 matt return (FTP_DEFAULT_PROXY_PORT);
198 1.2.2.2 matt if (strcasecmp(scheme, SCHEME_HTTP) == 0)
199 1.2.2.2 matt return (HTTP_DEFAULT_PROXY_PORT);
200 1.2.2.2 matt return (0);
201 1.2.2.2 matt }
202 1.2.2.2 matt
203 1.2.2.2 matt
204 1.2.2.2 matt /*
205 1.2.2.2 matt * Create a connection for an existing descriptor.
206 1.2.2.2 matt */
207 1.2.2.2 matt conn_t *
208 1.2.2.2 matt _fetch_reopen(int sd)
209 1.2.2.2 matt {
210 1.2.2.2 matt conn_t *conn;
211 1.2.2.2 matt
212 1.2.2.2 matt /* allocate and fill connection structure */
213 1.2.2.2 matt if ((conn = calloc(1, sizeof(*conn))) == NULL)
214 1.2.2.2 matt return (NULL);
215 1.2.2.2 matt conn->sd = sd;
216 1.2.2.2 matt ++conn->ref;
217 1.2.2.2 matt return (conn);
218 1.2.2.2 matt }
219 1.2.2.2 matt
220 1.2.2.2 matt
221 1.2.2.2 matt /*
222 1.2.2.2 matt * Bump a connection's reference count.
223 1.2.2.2 matt */
224 1.2.2.2 matt conn_t *
225 1.2.2.2 matt _fetch_ref(conn_t *conn)
226 1.2.2.2 matt {
227 1.2.2.2 matt
228 1.2.2.2 matt ++conn->ref;
229 1.2.2.2 matt return (conn);
230 1.2.2.2 matt }
231 1.2.2.2 matt
232 1.2.2.2 matt
233 1.2.2.2 matt /*
234 1.2.2.2 matt * Bind a socket to a specific local address
235 1.2.2.2 matt */
236 1.2.2.2 matt int
237 1.2.2.2 matt _fetch_bind(int sd, int af, const char *addr)
238 1.2.2.2 matt {
239 1.2.2.2 matt struct addrinfo hints, *res, *res0;
240 1.2.2.2 matt
241 1.2.2.2 matt memset(&hints, 0, sizeof(hints));
242 1.2.2.2 matt hints.ai_family = af;
243 1.2.2.2 matt hints.ai_socktype = SOCK_STREAM;
244 1.2.2.2 matt hints.ai_protocol = 0;
245 1.2.2.2 matt if (getaddrinfo(addr, NULL, &hints, &res0) != 0)
246 1.2.2.2 matt return (-1);
247 1.2.2.2 matt for (res = res0; res; res = res->ai_next)
248 1.2.2.2 matt if (bind(sd, res->ai_addr, res->ai_addrlen) == 0)
249 1.2.2.2 matt return (0);
250 1.2.2.2 matt return (-1);
251 1.2.2.2 matt }
252 1.2.2.2 matt
253 1.2.2.2 matt
254 1.2.2.2 matt /*
255 1.2.2.2 matt * Establish a TCP connection to the specified port on the specified host.
256 1.2.2.2 matt */
257 1.2.2.2 matt conn_t *
258 1.2.2.2 matt _fetch_connect(const char *host, int port, int af, int verbose)
259 1.2.2.2 matt {
260 1.2.2.2 matt conn_t *conn;
261 1.2.2.2 matt char pbuf[10];
262 1.2.2.2 matt const char *bindaddr;
263 1.2.2.2 matt struct addrinfo hints, *res, *res0;
264 1.2.2.2 matt int sd, err;
265 1.2.2.2 matt
266 1.2.2.2 matt DEBUG(fprintf(stderr, "---> %s:%d\n", host, port));
267 1.2.2.2 matt
268 1.2.2.2 matt if (verbose)
269 1.2.2.2 matt _fetch_info("looking up %s", host);
270 1.2.2.2 matt
271 1.2.2.2 matt /* look up host name and set up socket address structure */
272 1.2.2.2 matt snprintf(pbuf, sizeof(pbuf), "%d", port);
273 1.2.2.2 matt memset(&hints, 0, sizeof(hints));
274 1.2.2.2 matt hints.ai_family = af;
275 1.2.2.2 matt hints.ai_socktype = SOCK_STREAM;
276 1.2.2.2 matt hints.ai_protocol = 0;
277 1.2.2.2 matt if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
278 1.2.2.2 matt _netdb_seterr(err);
279 1.2.2.2 matt return (NULL);
280 1.2.2.2 matt }
281 1.2.2.2 matt bindaddr = getenv("FETCH_BIND_ADDRESS");
282 1.2.2.2 matt
283 1.2.2.2 matt if (verbose)
284 1.2.2.2 matt _fetch_info("connecting to %s:%d", host, port);
285 1.2.2.2 matt
286 1.2.2.2 matt /* try to connect */
287 1.2.2.2 matt for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) {
288 1.2.2.2 matt if ((sd = socket(res->ai_family, res->ai_socktype,
289 1.2.2.2 matt res->ai_protocol)) == -1)
290 1.2.2.2 matt continue;
291 1.2.2.2 matt if (bindaddr != NULL && *bindaddr != '\0' &&
292 1.2.2.2 matt _fetch_bind(sd, res->ai_family, bindaddr) != 0) {
293 1.2.2.2 matt _fetch_info("failed to bind to '%s'", bindaddr);
294 1.2.2.2 matt close(sd);
295 1.2.2.2 matt continue;
296 1.2.2.2 matt }
297 1.2.2.2 matt if (connect(sd, res->ai_addr, res->ai_addrlen) == 0)
298 1.2.2.2 matt break;
299 1.2.2.2 matt close(sd);
300 1.2.2.2 matt }
301 1.2.2.2 matt freeaddrinfo(res0);
302 1.2.2.2 matt if (sd == -1) {
303 1.2.2.2 matt _fetch_syserr();
304 1.2.2.2 matt return (NULL);
305 1.2.2.2 matt }
306 1.2.2.2 matt
307 1.2.2.2 matt if ((conn = _fetch_reopen(sd)) == NULL) {
308 1.2.2.2 matt _fetch_syserr();
309 1.2.2.2 matt close(sd);
310 1.2.2.2 matt }
311 1.2.2.2 matt return (conn);
312 1.2.2.2 matt }
313 1.2.2.2 matt
314 1.2.2.2 matt
315 1.2.2.2 matt /*
316 1.2.2.2 matt * Enable SSL on a connection.
317 1.2.2.2 matt */
318 1.2.2.2 matt int
319 1.2.2.2 matt _fetch_ssl(conn_t *conn, int verbose)
320 1.2.2.2 matt {
321 1.2.2.2 matt
322 1.2.2.2 matt #ifdef WITH_SSL
323 1.2.2.2 matt /* Init the SSL library and context */
324 1.2.2.2 matt if (!SSL_library_init()){
325 1.2.2.2 matt fprintf(stderr, "SSL library init failed\n");
326 1.2.2.2 matt return (-1);
327 1.2.2.2 matt }
328 1.2.2.2 matt
329 1.2.2.2 matt SSL_load_error_strings();
330 1.2.2.2 matt
331 1.2.2.2 matt conn->ssl_meth = SSLv23_client_method();
332 1.2.2.2 matt conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
333 1.2.2.2 matt SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
334 1.2.2.2 matt
335 1.2.2.2 matt conn->ssl = SSL_new(conn->ssl_ctx);
336 1.2.2.2 matt if (conn->ssl == NULL){
337 1.2.2.2 matt fprintf(stderr, "SSL context creation failed\n");
338 1.2.2.2 matt return (-1);
339 1.2.2.2 matt }
340 1.2.2.2 matt SSL_set_fd(conn->ssl, conn->sd);
341 1.2.2.2 matt if (SSL_connect(conn->ssl) == -1){
342 1.2.2.2 matt ERR_print_errors_fp(stderr);
343 1.2.2.2 matt return (-1);
344 1.2.2.2 matt }
345 1.2.2.2 matt
346 1.2.2.2 matt if (verbose) {
347 1.2.2.2 matt X509_NAME *name;
348 1.2.2.2 matt char *str;
349 1.2.2.2 matt
350 1.2.2.2 matt fprintf(stderr, "SSL connection established using %s\n",
351 1.2.2.2 matt SSL_get_cipher(conn->ssl));
352 1.2.2.2 matt conn->ssl_cert = SSL_get_peer_certificate(conn->ssl);
353 1.2.2.2 matt name = X509_get_subject_name(conn->ssl_cert);
354 1.2.2.2 matt str = X509_NAME_oneline(name, 0, 0);
355 1.2.2.2 matt printf("Certificate subject: %s\n", str);
356 1.2.2.2 matt free(str);
357 1.2.2.2 matt name = X509_get_issuer_name(conn->ssl_cert);
358 1.2.2.2 matt str = X509_NAME_oneline(name, 0, 0);
359 1.2.2.2 matt printf("Certificate issuer: %s\n", str);
360 1.2.2.2 matt free(str);
361 1.2.2.2 matt }
362 1.2.2.2 matt
363 1.2.2.2 matt return (0);
364 1.2.2.2 matt #else
365 1.2.2.2 matt /* LINTED */
366 1.2.2.2 matt (void)conn;
367 1.2.2.2 matt /* LINTED */
368 1.2.2.2 matt (void)verbose;
369 1.2.2.2 matt fprintf(stderr, "SSL support disabled\n");
370 1.2.2.2 matt return (-1);
371 1.2.2.2 matt #endif
372 1.2.2.2 matt }
373 1.2.2.2 matt
374 1.2.2.2 matt
375 1.2.2.2 matt /*
376 1.2.2.2 matt * Read a character from a connection w/ timeout
377 1.2.2.2 matt */
378 1.2.2.2 matt ssize_t
379 1.2.2.2 matt _fetch_read(conn_t *conn, char *buf, size_t len)
380 1.2.2.2 matt {
381 1.2.2.2 matt struct timeval now, timeout, wait;
382 1.2.2.2 matt fd_set readfds;
383 1.2.2.2 matt ssize_t rlen, total;
384 1.2.2.2 matt int r;
385 1.2.2.2 matt
386 1.2.2.2 matt if (fetchTimeout) {
387 1.2.2.2 matt FD_ZERO(&readfds);
388 1.2.2.2 matt gettimeofday(&timeout, NULL);
389 1.2.2.2 matt timeout.tv_sec += fetchTimeout;
390 1.2.2.2 matt }
391 1.2.2.2 matt
392 1.2.2.2 matt total = 0;
393 1.2.2.2 matt while (len > 0) {
394 1.2.2.2 matt while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
395 1.2.2.2 matt FD_SET(conn->sd, &readfds);
396 1.2.2.2 matt gettimeofday(&now, NULL);
397 1.2.2.2 matt wait.tv_sec = timeout.tv_sec - now.tv_sec;
398 1.2.2.2 matt wait.tv_usec = timeout.tv_usec - now.tv_usec;
399 1.2.2.2 matt if (wait.tv_usec < 0) {
400 1.2.2.2 matt wait.tv_usec += 1000000;
401 1.2.2.2 matt wait.tv_sec--;
402 1.2.2.2 matt }
403 1.2.2.2 matt if (wait.tv_sec < 0) {
404 1.2.2.2 matt errno = ETIMEDOUT;
405 1.2.2.2 matt _fetch_syserr();
406 1.2.2.2 matt return (-1);
407 1.2.2.2 matt }
408 1.2.2.2 matt errno = 0;
409 1.2.2.2 matt r = select(conn->sd + 1, &readfds, NULL, NULL, &wait);
410 1.2.2.2 matt if (r == -1) {
411 1.2.2.2 matt if (errno == EINTR && fetchRestartCalls)
412 1.2.2.2 matt continue;
413 1.2.2.2 matt _fetch_syserr();
414 1.2.2.2 matt return (-1);
415 1.2.2.2 matt }
416 1.2.2.2 matt }
417 1.2.2.2 matt #ifdef WITH_SSL
418 1.2.2.2 matt if (conn->ssl != NULL)
419 1.2.2.2 matt rlen = SSL_read(conn->ssl, buf, len);
420 1.2.2.2 matt else
421 1.2.2.2 matt #endif
422 1.2.2.2 matt rlen = read(conn->sd, buf, len);
423 1.2.2.2 matt if (rlen == 0)
424 1.2.2.2 matt break;
425 1.2.2.2 matt if (rlen < 0) {
426 1.2.2.2 matt if (errno == EINTR && fetchRestartCalls)
427 1.2.2.2 matt continue;
428 1.2.2.2 matt return (-1);
429 1.2.2.2 matt }
430 1.2.2.2 matt len -= rlen;
431 1.2.2.2 matt buf += rlen;
432 1.2.2.2 matt total += rlen;
433 1.2.2.2 matt }
434 1.2.2.2 matt return (total);
435 1.2.2.2 matt }
436 1.2.2.2 matt
437 1.2.2.2 matt
438 1.2.2.2 matt /*
439 1.2.2.2 matt * Read a line of text from a connection w/ timeout
440 1.2.2.2 matt */
441 1.2.2.2 matt #define MIN_BUF_SIZE 1024
442 1.2.2.2 matt
443 1.2.2.2 matt int
444 1.2.2.2 matt _fetch_getln(conn_t *conn)
445 1.2.2.2 matt {
446 1.2.2.2 matt char *tmp;
447 1.2.2.2 matt size_t tmpsize;
448 1.2.2.2 matt ssize_t len;
449 1.2.2.2 matt char c;
450 1.2.2.2 matt
451 1.2.2.2 matt if (conn->buf == NULL) {
452 1.2.2.2 matt if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
453 1.2.2.2 matt errno = ENOMEM;
454 1.2.2.2 matt return (-1);
455 1.2.2.2 matt }
456 1.2.2.2 matt conn->bufsize = MIN_BUF_SIZE;
457 1.2.2.2 matt }
458 1.2.2.2 matt
459 1.2.2.2 matt conn->buf[0] = '\0';
460 1.2.2.2 matt conn->buflen = 0;
461 1.2.2.2 matt
462 1.2.2.2 matt do {
463 1.2.2.2 matt len = _fetch_read(conn, &c, 1);
464 1.2.2.2 matt if (len == -1)
465 1.2.2.2 matt return (-1);
466 1.2.2.2 matt if (len == 0)
467 1.2.2.2 matt break;
468 1.2.2.2 matt conn->buf[conn->buflen++] = c;
469 1.2.2.2 matt if (conn->buflen == conn->bufsize) {
470 1.2.2.2 matt tmp = conn->buf;
471 1.2.2.2 matt tmpsize = conn->bufsize * 2 + 1;
472 1.2.2.2 matt if ((tmp = realloc(tmp, tmpsize)) == NULL) {
473 1.2.2.2 matt errno = ENOMEM;
474 1.2.2.2 matt return (-1);
475 1.2.2.2 matt }
476 1.2.2.2 matt conn->buf = tmp;
477 1.2.2.2 matt conn->bufsize = tmpsize;
478 1.2.2.2 matt }
479 1.2.2.2 matt } while (c != '\n');
480 1.2.2.2 matt
481 1.2.2.2 matt conn->buf[conn->buflen] = '\0';
482 1.2.2.2 matt DEBUG(fprintf(stderr, "<<< %s", conn->buf));
483 1.2.2.2 matt return (0);
484 1.2.2.2 matt }
485 1.2.2.2 matt
486 1.2.2.2 matt
487 1.2.2.2 matt /*
488 1.2.2.2 matt * Write to a connection w/ timeout
489 1.2.2.2 matt */
490 1.2.2.2 matt ssize_t
491 1.2.2.2 matt _fetch_write(conn_t *conn, const char *buf, size_t len)
492 1.2.2.2 matt {
493 1.2.2.2 matt struct iovec iov;
494 1.2.2.2 matt
495 1.2.2.2 matt iov.iov_base = __DECONST(char *, buf);
496 1.2.2.2 matt iov.iov_len = len;
497 1.2.2.2 matt return _fetch_writev(conn, &iov, 1);
498 1.2.2.2 matt }
499 1.2.2.2 matt
500 1.2.2.2 matt /*
501 1.2.2.2 matt * Write a vector to a connection w/ timeout
502 1.2.2.2 matt * Note: can modify the iovec.
503 1.2.2.2 matt */
504 1.2.2.2 matt ssize_t
505 1.2.2.2 matt _fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
506 1.2.2.2 matt {
507 1.2.2.2 matt struct timeval now, timeout, wait;
508 1.2.2.2 matt fd_set writefds;
509 1.2.2.2 matt ssize_t wlen, total;
510 1.2.2.2 matt int r;
511 1.2.2.2 matt
512 1.2.2.2 matt if (fetchTimeout) {
513 1.2.2.2 matt FD_ZERO(&writefds);
514 1.2.2.2 matt gettimeofday(&timeout, NULL);
515 1.2.2.2 matt timeout.tv_sec += fetchTimeout;
516 1.2.2.2 matt }
517 1.2.2.2 matt
518 1.2.2.2 matt total = 0;
519 1.2.2.2 matt while (iovcnt > 0) {
520 1.2.2.2 matt while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
521 1.2.2.2 matt FD_SET(conn->sd, &writefds);
522 1.2.2.2 matt gettimeofday(&now, NULL);
523 1.2.2.2 matt wait.tv_sec = timeout.tv_sec - now.tv_sec;
524 1.2.2.2 matt wait.tv_usec = timeout.tv_usec - now.tv_usec;
525 1.2.2.2 matt if (wait.tv_usec < 0) {
526 1.2.2.2 matt wait.tv_usec += 1000000;
527 1.2.2.2 matt wait.tv_sec--;
528 1.2.2.2 matt }
529 1.2.2.2 matt if (wait.tv_sec < 0) {
530 1.2.2.2 matt errno = ETIMEDOUT;
531 1.2.2.2 matt _fetch_syserr();
532 1.2.2.2 matt return (-1);
533 1.2.2.2 matt }
534 1.2.2.2 matt errno = 0;
535 1.2.2.2 matt r = select(conn->sd + 1, NULL, &writefds, NULL, &wait);
536 1.2.2.2 matt if (r == -1) {
537 1.2.2.2 matt if (errno == EINTR && fetchRestartCalls)
538 1.2.2.2 matt continue;
539 1.2.2.2 matt return (-1);
540 1.2.2.2 matt }
541 1.2.2.2 matt }
542 1.2.2.2 matt errno = 0;
543 1.2.2.2 matt #ifdef WITH_SSL
544 1.2.2.2 matt if (conn->ssl != NULL)
545 1.2.2.2 matt wlen = SSL_write(conn->ssl,
546 1.2.2.2 matt iov->iov_base, iov->iov_len);
547 1.2.2.2 matt else
548 1.2.2.2 matt #endif
549 1.2.2.2 matt wlen = writev(conn->sd, iov, iovcnt);
550 1.2.2.2 matt if (wlen == 0) {
551 1.2.2.2 matt /* we consider a short write a failure */
552 1.2.2.2 matt errno = EPIPE;
553 1.2.2.2 matt _fetch_syserr();
554 1.2.2.2 matt return (-1);
555 1.2.2.2 matt }
556 1.2.2.2 matt if (wlen < 0) {
557 1.2.2.2 matt if (errno == EINTR && fetchRestartCalls)
558 1.2.2.2 matt continue;
559 1.2.2.2 matt return (-1);
560 1.2.2.2 matt }
561 1.2.2.2 matt total += wlen;
562 1.2.2.2 matt while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
563 1.2.2.2 matt wlen -= iov->iov_len;
564 1.2.2.2 matt iov++;
565 1.2.2.2 matt iovcnt--;
566 1.2.2.2 matt }
567 1.2.2.2 matt if (iovcnt > 0) {
568 1.2.2.2 matt iov->iov_len -= wlen;
569 1.2.2.2 matt iov->iov_base = (__DECONST(char *, iov->iov_base)) + wlen;
570 1.2.2.2 matt }
571 1.2.2.2 matt }
572 1.2.2.2 matt return (total);
573 1.2.2.2 matt }
574 1.2.2.2 matt
575 1.2.2.2 matt
576 1.2.2.2 matt /*
577 1.2.2.2 matt * Write a line of text to a connection w/ timeout
578 1.2.2.2 matt */
579 1.2.2.2 matt int
580 1.2.2.2 matt _fetch_putln(conn_t *conn, const char *str, size_t len)
581 1.2.2.2 matt {
582 1.2.2.2 matt struct iovec iov[2];
583 1.2.2.2 matt int ret;
584 1.2.2.2 matt
585 1.2.2.2 matt DEBUG(fprintf(stderr, ">>> %s\n", str));
586 1.2.2.2 matt iov[0].iov_base = __DECONST(char *, str);
587 1.2.2.2 matt iov[0].iov_len = len;
588 1.2.2.2 matt iov[1].iov_base = __DECONST(char *, ENDL);
589 1.2.2.2 matt iov[1].iov_len = sizeof(ENDL);
590 1.2.2.2 matt if (len == 0)
591 1.2.2.2 matt ret = _fetch_writev(conn, &iov[1], 1);
592 1.2.2.2 matt else
593 1.2.2.2 matt ret = _fetch_writev(conn, iov, 2);
594 1.2.2.2 matt if (ret == -1)
595 1.2.2.2 matt return (-1);
596 1.2.2.2 matt return (0);
597 1.2.2.2 matt }
598 1.2.2.2 matt
599 1.2.2.2 matt
600 1.2.2.2 matt /*
601 1.2.2.2 matt * Close connection
602 1.2.2.2 matt */
603 1.2.2.2 matt int
604 1.2.2.2 matt _fetch_close(conn_t *conn)
605 1.2.2.2 matt {
606 1.2.2.2 matt int ret;
607 1.2.2.2 matt
608 1.2.2.2 matt if (--conn->ref > 0)
609 1.2.2.2 matt return (0);
610 1.2.2.2 matt ret = close(conn->sd);
611 1.2.2.2 matt free(conn->buf);
612 1.2.2.2 matt free(conn);
613 1.2.2.2 matt return (ret);
614 1.2.2.2 matt }
615 1.2.2.2 matt
616 1.2.2.2 matt
617 1.2.2.2 matt /*** Directory-related utility functions *************************************/
618 1.2.2.2 matt
619 1.2.2.2 matt int
620 1.2.2.2 matt _fetch_add_entry(struct url_ent **p, int *size, int *len,
621 1.2.2.2 matt const char *name, struct url_stat *us)
622 1.2.2.2 matt {
623 1.2.2.2 matt struct url_ent *tmp;
624 1.2.2.2 matt
625 1.2.2.2 matt if (*p == NULL) {
626 1.2.2.2 matt *size = 0;
627 1.2.2.2 matt *len = 0;
628 1.2.2.2 matt }
629 1.2.2.2 matt
630 1.2.2.2 matt if (*len >= *size - 1) {
631 1.2.2.2 matt tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p));
632 1.2.2.2 matt if (tmp == NULL) {
633 1.2.2.2 matt errno = ENOMEM;
634 1.2.2.2 matt _fetch_syserr();
635 1.2.2.2 matt return (-1);
636 1.2.2.2 matt }
637 1.2.2.2 matt *size = (*size * 2 + 1);
638 1.2.2.2 matt *p = tmp;
639 1.2.2.2 matt }
640 1.2.2.2 matt
641 1.2.2.2 matt tmp = *p + *len;
642 1.2.2.2 matt snprintf(tmp->name, PATH_MAX, "%s", name);
643 1.2.2.2 matt bcopy(us, &tmp->stat, sizeof(*us));
644 1.2.2.2 matt
645 1.2.2.2 matt (*len)++;
646 1.2.2.2 matt (++tmp)->name[0] = 0;
647 1.2.2.2 matt
648 1.2.2.2 matt return (0);
649 1.2.2.2 matt }
650 1.2.2.2 matt
651 1.2.2.2 matt
652 1.2.2.2 matt /*** Authentication-related utility functions ********************************/
653 1.2.2.2 matt
654 1.2.2.2 matt static const char *
655 1.2.2.2 matt _fetch_read_word(FILE *f)
656 1.2.2.2 matt {
657 1.2.2.2 matt static char word[1024];
658 1.2.2.2 matt
659 1.2.2.2 matt if (fscanf(f, " %1024s ", word) != 1)
660 1.2.2.2 matt return (NULL);
661 1.2.2.2 matt return (word);
662 1.2.2.2 matt }
663 1.2.2.2 matt
664 1.2.2.2 matt /*
665 1.2.2.2 matt * Get authentication data for a URL from .netrc
666 1.2.2.2 matt */
667 1.2.2.2 matt int
668 1.2.2.2 matt _fetch_netrc_auth(struct url *url)
669 1.2.2.2 matt {
670 1.2.2.2 matt char fn[PATH_MAX];
671 1.2.2.2 matt const char *word;
672 1.2.2.2 matt char *p;
673 1.2.2.2 matt FILE *f;
674 1.2.2.2 matt
675 1.2.2.2 matt if ((p = getenv("NETRC")) != NULL) {
676 1.2.2.2 matt if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
677 1.2.2.2 matt _fetch_info("$NETRC specifies a file name "
678 1.2.2.2 matt "longer than PATH_MAX");
679 1.2.2.2 matt return (-1);
680 1.2.2.2 matt }
681 1.2.2.2 matt } else {
682 1.2.2.2 matt if ((p = getenv("HOME")) != NULL) {
683 1.2.2.2 matt struct passwd *pwd;
684 1.2.2.2 matt
685 1.2.2.2 matt if ((pwd = getpwuid(getuid())) == NULL ||
686 1.2.2.2 matt (p = pwd->pw_dir) == NULL)
687 1.2.2.2 matt return (-1);
688 1.2.2.2 matt }
689 1.2.2.2 matt if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn))
690 1.2.2.2 matt return (-1);
691 1.2.2.2 matt }
692 1.2.2.2 matt
693 1.2.2.2 matt if ((f = fopen(fn, "r")) == NULL)
694 1.2.2.2 matt return (-1);
695 1.2.2.2 matt while ((word = _fetch_read_word(f)) != NULL) {
696 1.2.2.2 matt if (strcmp(word, "default") == 0) {
697 1.2.2.2 matt DEBUG(_fetch_info("Using default .netrc settings"));
698 1.2.2.2 matt break;
699 1.2.2.2 matt }
700 1.2.2.2 matt if (strcmp(word, "machine") == 0 &&
701 1.2.2.2 matt (word = _fetch_read_word(f)) != NULL &&
702 1.2.2.2 matt strcasecmp(word, url->host) == 0) {
703 1.2.2.2 matt DEBUG(_fetch_info("Using .netrc settings for %s", word));
704 1.2.2.2 matt break;
705 1.2.2.2 matt }
706 1.2.2.2 matt }
707 1.2.2.2 matt if (word == NULL)
708 1.2.2.2 matt goto ferr;
709 1.2.2.2 matt while ((word = _fetch_read_word(f)) != NULL) {
710 1.2.2.2 matt if (strcmp(word, "login") == 0) {
711 1.2.2.2 matt if ((word = _fetch_read_word(f)) == NULL)
712 1.2.2.2 matt goto ferr;
713 1.2.2.2 matt if (snprintf(url->user, sizeof(url->user),
714 1.2.2.2 matt "%s", word) > (int)sizeof(url->user)) {
715 1.2.2.2 matt _fetch_info("login name in .netrc is too long");
716 1.2.2.2 matt url->user[0] = '\0';
717 1.2.2.2 matt }
718 1.2.2.2 matt } else if (strcmp(word, "password") == 0) {
719 1.2.2.2 matt if ((word = _fetch_read_word(f)) == NULL)
720 1.2.2.2 matt goto ferr;
721 1.2.2.2 matt if (snprintf(url->pwd, sizeof(url->pwd),
722 1.2.2.2 matt "%s", word) > (int)sizeof(url->pwd)) {
723 1.2.2.2 matt _fetch_info("password in .netrc is too long");
724 1.2.2.2 matt url->pwd[0] = '\0';
725 1.2.2.2 matt }
726 1.2.2.2 matt } else if (strcmp(word, "account") == 0) {
727 1.2.2.2 matt if ((word = _fetch_read_word(f)) == NULL)
728 1.2.2.2 matt goto ferr;
729 1.2.2.2 matt /* XXX not supported! */
730 1.2.2.2 matt } else {
731 1.2.2.2 matt break;
732 1.2.2.2 matt }
733 1.2.2.2 matt }
734 1.2.2.2 matt fclose(f);
735 1.2.2.2 matt return (0);
736 1.2.2.2 matt ferr:
737 1.2.2.2 matt fclose(f);
738 1.2.2.2 matt return (-1);
739 1.2.2.2 matt }
740