1234313Sbapt/*-
2263020Sbapt * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org>
3257353Sbdrewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org>
4234313Sbapt * All rights reserved.
5234313Sbapt *
6234313Sbapt * Redistribution and use in source and binary forms, with or without
7234313Sbapt * modification, are permitted provided that the following conditions
8234313Sbapt * are met:
9234313Sbapt * 1. Redistributions of source code must retain the above copyright
10234313Sbapt *    notice, this list of conditions and the following disclaimer.
11234313Sbapt * 2. Redistributions in binary form must reproduce the above copyright
12234313Sbapt *    notice, this list of conditions and the following disclaimer in the
13234313Sbapt *    documentation and/or other materials provided with the distribution.
14234313Sbapt *
15234313Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16234313Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17234313Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18234313Sbapt * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19234313Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20234313Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21234313Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22234313Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23234313Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24234313Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25234313Sbapt * SUCH DAMAGE.
26234313Sbapt */
27234313Sbapt
28234313Sbapt#include <sys/cdefs.h>
29234313Sbapt__FBSDID("$FreeBSD$");
30234313Sbapt
31234313Sbapt#include <sys/param.h>
32257353Sbdrewery#include <sys/queue.h>
33257353Sbdrewery#include <sys/types.h>
34257353Sbdrewery#include <sys/sbuf.h>
35234322Sbapt#include <sys/wait.h>
36234313Sbapt
37257353Sbdrewery#define _WITH_GETLINE
38234313Sbapt#include <archive.h>
39234313Sbapt#include <archive_entry.h>
40257353Sbdrewery#include <dirent.h>
41234313Sbapt#include <err.h>
42234313Sbapt#include <errno.h>
43257309Sbapt#include <fcntl.h>
44234322Sbapt#include <fetch.h>
45234351Sbapt#include <paths.h>
46247841Sbapt#include <stdbool.h>
47234313Sbapt#include <stdlib.h>
48234313Sbapt#include <stdio.h>
49234313Sbapt#include <string.h>
50234313Sbapt#include <time.h>
51234313Sbapt#include <unistd.h>
52263020Sbapt#include <ucl.h>
53234313Sbapt
54257353Sbdrewery#include <openssl/err.h>
55257353Sbdrewery#include <openssl/ssl.h>
56257353Sbdrewery
57243883Sbapt#include "dns_utils.h"
58247841Sbapt#include "config.h"
59234313Sbapt
60257353Sbdrewerystruct sig_cert {
61257353Sbdrewery	char *name;
62257353Sbdrewery	unsigned char *sig;
63257353Sbdrewery	int siglen;
64257353Sbdrewery	unsigned char *cert;
65257353Sbdrewery	int certlen;
66257353Sbdrewery	bool trusted;
67257353Sbdrewery};
68257353Sbdrewery
69287873Sdelphijstruct pubkey {
70287873Sdelphij	unsigned char *sig;
71287873Sdelphij	int siglen;
72287873Sdelphij};
73287873Sdelphij
74257353Sbdrewerytypedef enum {
75257353Sbdrewery       HASH_UNKNOWN,
76257353Sbdrewery       HASH_SHA256,
77257353Sbdrewery} hash_t;
78257353Sbdrewery
79257353Sbdrewerystruct fingerprint {
80257353Sbdrewery       hash_t type;
81257353Sbdrewery       char *name;
82257353Sbdrewery       char hash[BUFSIZ];
83257353Sbdrewery       STAILQ_ENTRY(fingerprint) next;
84257353Sbdrewery};
85257353Sbdrewery
86257353SbdrewerySTAILQ_HEAD(fingerprint_list, fingerprint);
87257353Sbdrewery
88234313Sbaptstatic int
89234313Sbaptextract_pkg_static(int fd, char *p, int sz)
90234313Sbapt{
91234313Sbapt	struct archive *a;
92234313Sbapt	struct archive_entry *ae;
93234313Sbapt	char *end;
94234313Sbapt	int ret, r;
95234313Sbapt
96234351Sbapt	ret = -1;
97234313Sbapt	a = archive_read_new();
98234351Sbapt	if (a == NULL) {
99234351Sbapt		warn("archive_read_new");
100234351Sbapt		return (ret);
101234351Sbapt	}
102247060Sbapt	archive_read_support_filter_all(a);
103234313Sbapt	archive_read_support_format_tar(a);
104234313Sbapt
105234351Sbapt	if (lseek(fd, 0, 0) == -1) {
106234351Sbapt		warn("lseek");
107234351Sbapt		goto cleanup;
108234351Sbapt	}
109234313Sbapt
110234313Sbapt	if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
111234351Sbapt		warnx("archive_read_open_fd: %s", archive_error_string(a));
112234313Sbapt		goto cleanup;
113234313Sbapt	}
114234313Sbapt
115234313Sbapt	ae = NULL;
116234313Sbapt	while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) {
117234313Sbapt		end = strrchr(archive_entry_pathname(ae), '/');
118234313Sbapt		if (end == NULL)
119234313Sbapt			continue;
120234313Sbapt
121234313Sbapt		if (strcmp(end, "/pkg-static") == 0) {
122234313Sbapt			r = archive_read_extract(a, ae,
123234322Sbapt			    ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
124234322Sbapt			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL |
125234322Sbapt			    ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR);
126234351Sbapt			strlcpy(p, archive_entry_pathname(ae), sz);
127234313Sbapt			break;
128234313Sbapt		}
129234313Sbapt	}
130234313Sbapt
131234351Sbapt	if (r == ARCHIVE_OK)
132234351Sbapt		ret = 0;
133234351Sbapt	else
134269937Sgavin		warnx("failed to extract pkg-static: %s",
135269937Sgavin		    archive_error_string(a));
136234313Sbapt
137234313Sbaptcleanup:
138247060Sbapt	archive_read_free(a);
139234322Sbapt	return (ret);
140234313Sbapt
141234313Sbapt}
142234313Sbapt
143234313Sbaptstatic int
144257632Sbdreweryinstall_pkg_static(const char *path, const char *pkgpath, bool force)
145234313Sbapt{
146234313Sbapt	int pstat;
147234313Sbapt	pid_t pid;
148234313Sbapt
149234313Sbapt	switch ((pid = fork())) {
150234351Sbapt	case -1:
151234351Sbapt		return (-1);
152234351Sbapt	case 0:
153257632Sbdrewery		if (force)
154257632Sbdrewery			execl(path, "pkg-static", "add", "-f", pkgpath,
155257632Sbdrewery			    (char *)NULL);
156257632Sbdrewery		else
157257632Sbdrewery			execl(path, "pkg-static", "add", pkgpath,
158257632Sbdrewery			    (char *)NULL);
159234351Sbapt		_exit(1);
160234351Sbapt	default:
161234351Sbapt		break;
162234313Sbapt	}
163234313Sbapt
164234351Sbapt	while (waitpid(pid, &pstat, 0) == -1)
165234313Sbapt		if (errno != EINTR)
166234313Sbapt			return (-1);
167234313Sbapt
168234351Sbapt	if (WEXITSTATUS(pstat))
169234351Sbapt		return (WEXITSTATUS(pstat));
170234351Sbapt	else if (WIFSIGNALED(pstat))
171234351Sbapt		return (128 & (WTERMSIG(pstat)));
172234351Sbapt	return (pstat);
173234313Sbapt}
174234313Sbapt
175234313Sbaptstatic int
176257353Sbdreweryfetch_to_fd(const char *url, char *path)
177234313Sbapt{
178243883Sbapt	struct url *u;
179257353Sbdrewery	struct dns_srvinfo *mirrors, *current;
180257353Sbdrewery	struct url_stat st;
181234313Sbapt	FILE *remote;
182243883Sbapt	/* To store _https._tcp. + hostname + \0 */
183257353Sbdrewery	int fd;
184257353Sbdrewery	int retry, max_retry;
185257353Sbdrewery	off_t done, r;
186257353Sbdrewery	time_t now, last;
187257353Sbdrewery	char buf[10240];
188243883Sbapt	char zone[MAXHOSTNAMELEN + 13];
189257353Sbdrewery	static const char *mirror_type = NULL;
190234313Sbapt
191234313Sbapt	done = 0;
192234351Sbapt	last = 0;
193243883Sbapt	max_retry = 3;
194257353Sbdrewery	current = mirrors = NULL;
195234313Sbapt	remote = NULL;
196234313Sbapt
197257353Sbdrewery	if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type)
198257353Sbdrewery	    != 0) {
199247841Sbapt		warnx("No MIRROR_TYPE defined");
200247841Sbapt		return (-1);
201247841Sbapt	}
202257328Sbdrewery
203257353Sbdrewery	if ((fd = mkstemp(path)) == -1) {
204234313Sbapt		warn("mkstemp()");
205234322Sbapt		return (-1);
206234313Sbapt	}
207234313Sbapt
208243883Sbapt	retry = max_retry;
209234313Sbapt
210243883Sbapt	u = fetchParseURL(url);
211243883Sbapt	while (remote == NULL) {
212243883Sbapt		if (retry == max_retry) {
213247841Sbapt			if (strcmp(u->scheme, "file") != 0 &&
214247841Sbapt			    strcasecmp(mirror_type, "srv") == 0) {
215243883Sbapt				snprintf(zone, sizeof(zone),
216243883Sbapt				    "_%s._tcp.%s", u->scheme, u->host);
217243883Sbapt				mirrors = dns_getsrvinfo(zone);
218243883Sbapt				current = mirrors;
219243883Sbapt			}
220243883Sbapt		}
221243883Sbapt
222257309Sbapt		if (mirrors != NULL) {
223243883Sbapt			strlcpy(u->host, current->host, sizeof(u->host));
224257309Sbapt			u->port = current->port;
225257309Sbapt		}
226243883Sbapt
227243883Sbapt		remote = fetchXGet(u, &st, "");
228243883Sbapt		if (remote == NULL) {
229243883Sbapt			--retry;
230243883Sbapt			if (retry <= 0)
231243883Sbapt				goto fetchfail;
232243883Sbapt			if (mirrors == NULL) {
233243883Sbapt				sleep(1);
234243883Sbapt			} else {
235243883Sbapt				current = current->next;
236243883Sbapt				if (current == NULL)
237243883Sbapt					current = mirrors;
238243883Sbapt			}
239243883Sbapt		}
240243883Sbapt	}
241243883Sbapt
242234351Sbapt	if (remote == NULL)
243234351Sbapt		goto fetchfail;
244234351Sbapt
245234313Sbapt	while (done < st.size) {
246234313Sbapt		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
247234313Sbapt			break;
248234313Sbapt
249234313Sbapt		if (write(fd, buf, r) != r) {
250234313Sbapt			warn("write()");
251257353Sbdrewery			goto fetchfail;
252234313Sbapt		}
253234313Sbapt
254234313Sbapt		done += r;
255234313Sbapt		now = time(NULL);
256234351Sbapt		if (now > last || done == st.size)
257234313Sbapt			last = now;
258234313Sbapt	}
259234313Sbapt
260234351Sbapt	if (ferror(remote))
261234351Sbapt		goto fetchfail;
262234313Sbapt
263257353Sbdrewery	goto cleanup;
264257353Sbdrewery
265257353Sbdreweryfetchfail:
266257353Sbdrewery	if (fd != -1) {
267257353Sbdrewery		close(fd);
268257353Sbdrewery		fd = -1;
269257353Sbdrewery		unlink(path);
270257353Sbdrewery	}
271257353Sbdrewery
272257353Sbdrewerycleanup:
273257353Sbdrewery	if (remote != NULL)
274257353Sbdrewery		fclose(remote);
275257353Sbdrewery
276257353Sbdrewery	return fd;
277257353Sbdrewery}
278257353Sbdrewery
279257353Sbdrewerystatic struct fingerprint *
280263020Sbaptparse_fingerprint(ucl_object_t *obj)
281257353Sbdrewery{
282268896Sbapt	const ucl_object_t *cur;
283263020Sbapt	ucl_object_iter_t it = NULL;
284263020Sbapt	const char *function, *fp, *key;
285257353Sbdrewery	struct fingerprint *f;
286257353Sbdrewery	hash_t fct = HASH_UNKNOWN;
287257353Sbdrewery
288257353Sbdrewery	function = fp = NULL;
289257353Sbdrewery
290263020Sbapt	while ((cur = ucl_iterate_object(obj, &it, true))) {
291263020Sbapt		key = ucl_object_key(cur);
292263020Sbapt		if (cur->type != UCL_STRING)
293257353Sbdrewery			continue;
294263020Sbapt		if (strcasecmp(key, "function") == 0) {
295263020Sbapt			function = ucl_object_tostring(cur);
296263020Sbapt			continue;
297257353Sbdrewery		}
298263020Sbapt		if (strcasecmp(key, "fingerprint") == 0) {
299263020Sbapt			fp = ucl_object_tostring(cur);
300257353Sbdrewery			continue;
301257353Sbdrewery		}
302257353Sbdrewery	}
303257353Sbdrewery
304257353Sbdrewery	if (fp == NULL || function == NULL)
305257353Sbdrewery		return (NULL);
306257353Sbdrewery
307257353Sbdrewery	if (strcasecmp(function, "sha256") == 0)
308257353Sbdrewery		fct = HASH_SHA256;
309257353Sbdrewery
310257353Sbdrewery	if (fct == HASH_UNKNOWN) {
311263020Sbapt		warnx("Unsupported hashing function: %s", function);
312257353Sbdrewery		return (NULL);
313257353Sbdrewery	}
314257353Sbdrewery
315257353Sbdrewery	f = calloc(1, sizeof(struct fingerprint));
316257353Sbdrewery	f->type = fct;
317257353Sbdrewery	strlcpy(f->hash, fp, sizeof(f->hash));
318257353Sbdrewery
319257353Sbdrewery	return (f);
320257353Sbdrewery}
321257353Sbdrewery
322257353Sbdrewerystatic void
323257353Sbdreweryfree_fingerprint_list(struct fingerprint_list* list)
324257353Sbdrewery{
325258126Sglebius	struct fingerprint *fingerprint, *tmp;
326257353Sbdrewery
327258126Sglebius	STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) {
328257353Sbdrewery		if (fingerprint->name)
329257353Sbdrewery			free(fingerprint->name);
330257353Sbdrewery		free(fingerprint);
331257353Sbdrewery	}
332257353Sbdrewery	free(list);
333257353Sbdrewery}
334257353Sbdrewery
335257353Sbdrewerystatic struct fingerprint *
336257353Sbdreweryload_fingerprint(const char *dir, const char *filename)
337257353Sbdrewery{
338263020Sbapt	ucl_object_t *obj = NULL;
339263020Sbapt	struct ucl_parser *p = NULL;
340257353Sbdrewery	struct fingerprint *f;
341257353Sbdrewery	char path[MAXPATHLEN];
342257353Sbdrewery
343257353Sbdrewery	f = NULL;
344257353Sbdrewery
345257353Sbdrewery	snprintf(path, MAXPATHLEN, "%s/%s", dir, filename);
346257353Sbdrewery
347263020Sbapt	p = ucl_parser_new(0);
348263020Sbapt	if (!ucl_parser_add_file(p, path)) {
349263020Sbapt		warnx("%s: %s", path, ucl_parser_get_error(p));
350263020Sbapt		ucl_parser_free(p);
351257353Sbdrewery		return (NULL);
352263020Sbapt	}
353257353Sbdrewery
354263020Sbapt	obj = ucl_parser_get_object(p);
355257353Sbdrewery
356263020Sbapt	if (obj->type == UCL_OBJECT)
357263020Sbapt		f = parse_fingerprint(obj);
358257353Sbdrewery
359263020Sbapt	if (f != NULL)
360263020Sbapt		f->name = strdup(filename);
361257353Sbdrewery
362268896Sbapt	ucl_object_unref(obj);
363263020Sbapt	ucl_parser_free(p);
364257353Sbdrewery
365257353Sbdrewery	return (f);
366257353Sbdrewery}
367257353Sbdrewery
368257353Sbdrewerystatic struct fingerprint_list *
369257353Sbdreweryload_fingerprints(const char *path, int *count)
370257353Sbdrewery{
371257353Sbdrewery	DIR *d;
372257353Sbdrewery	struct dirent *ent;
373257353Sbdrewery	struct fingerprint *finger;
374257353Sbdrewery	struct fingerprint_list *fingerprints;
375257353Sbdrewery
376257353Sbdrewery	*count = 0;
377257353Sbdrewery
378257353Sbdrewery	fingerprints = calloc(1, sizeof(struct fingerprint_list));
379257353Sbdrewery	if (fingerprints == NULL)
380257353Sbdrewery		return (NULL);
381257353Sbdrewery	STAILQ_INIT(fingerprints);
382257353Sbdrewery
383257353Sbdrewery	if ((d = opendir(path)) == NULL)
384257353Sbdrewery		return (NULL);
385257353Sbdrewery
386257353Sbdrewery	while ((ent = readdir(d))) {
387257353Sbdrewery		if (strcmp(ent->d_name, ".") == 0 ||
388257353Sbdrewery		    strcmp(ent->d_name, "..") == 0)
389257353Sbdrewery			continue;
390257353Sbdrewery		finger = load_fingerprint(path, ent->d_name);
391257353Sbdrewery		if (finger != NULL) {
392257353Sbdrewery			STAILQ_INSERT_TAIL(fingerprints, finger, next);
393257353Sbdrewery			++(*count);
394257353Sbdrewery		}
395257353Sbdrewery	}
396257353Sbdrewery
397257353Sbdrewery	closedir(d);
398257353Sbdrewery
399257353Sbdrewery	return (fingerprints);
400257353Sbdrewery}
401257353Sbdrewery
402257353Sbdrewerystatic void
403257353Sbdrewerysha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH],
404257353Sbdrewery    char out[SHA256_DIGEST_LENGTH * 2 + 1])
405257353Sbdrewery{
406257353Sbdrewery	int i;
407257353Sbdrewery
408257353Sbdrewery	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
409257353Sbdrewery		sprintf(out + (i * 2), "%02x", hash[i]);
410257353Sbdrewery
411257353Sbdrewery	out[SHA256_DIGEST_LENGTH * 2] = '\0';
412257353Sbdrewery}
413257353Sbdrewery
414257353Sbdrewerystatic void
415257353Sbdrewerysha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1])
416257353Sbdrewery{
417257353Sbdrewery	unsigned char hash[SHA256_DIGEST_LENGTH];
418257353Sbdrewery	SHA256_CTX sha256;
419257353Sbdrewery
420257353Sbdrewery	out[0] = '\0';
421257353Sbdrewery
422257353Sbdrewery	SHA256_Init(&sha256);
423257353Sbdrewery	SHA256_Update(&sha256, buf, len);
424257353Sbdrewery	SHA256_Final(hash, &sha256);
425257353Sbdrewery	sha256_hash(hash, out);
426257353Sbdrewery}
427257353Sbdrewery
428257353Sbdrewerystatic int
429257353Sbdrewerysha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1])
430257353Sbdrewery{
431257353Sbdrewery	int my_fd;
432257353Sbdrewery	FILE *fp;
433257353Sbdrewery	char buffer[BUFSIZ];
434257353Sbdrewery	unsigned char hash[SHA256_DIGEST_LENGTH];
435257353Sbdrewery	size_t r;
436257353Sbdrewery	int ret;
437257353Sbdrewery	SHA256_CTX sha256;
438257353Sbdrewery
439257353Sbdrewery	my_fd = -1;
440257353Sbdrewery	fp = NULL;
441257353Sbdrewery	r = 0;
442257353Sbdrewery	ret = 1;
443257353Sbdrewery
444257353Sbdrewery	out[0] = '\0';
445257353Sbdrewery
446257353Sbdrewery	/* Duplicate the fd so that fclose(3) does not close it. */
447257353Sbdrewery	if ((my_fd = dup(fd)) == -1) {
448257353Sbdrewery		warnx("dup");
449257353Sbdrewery		goto cleanup;
450257353Sbdrewery	}
451257353Sbdrewery
452257353Sbdrewery	if ((fp = fdopen(my_fd, "rb")) == NULL) {
453257353Sbdrewery		warnx("fdopen");
454257353Sbdrewery		goto cleanup;
455257353Sbdrewery	}
456257353Sbdrewery
457257353Sbdrewery	SHA256_Init(&sha256);
458257353Sbdrewery
459257353Sbdrewery	while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0)
460257353Sbdrewery		SHA256_Update(&sha256, buffer, r);
461257353Sbdrewery
462257353Sbdrewery	if (ferror(fp) != 0) {
463257353Sbdrewery		warnx("fread");
464257353Sbdrewery		goto cleanup;
465257353Sbdrewery	}
466257353Sbdrewery
467257353Sbdrewery	SHA256_Final(hash, &sha256);
468257353Sbdrewery	sha256_hash(hash, out);
469257353Sbdrewery	ret = 0;
470257353Sbdrewery
471257353Sbdrewerycleanup:
472257353Sbdrewery	if (fp != NULL)
473257353Sbdrewery		fclose(fp);
474257353Sbdrewery	else if (my_fd != -1)
475257353Sbdrewery		close(my_fd);
476257353Sbdrewery	(void)lseek(fd, 0, SEEK_SET);
477257353Sbdrewery
478257353Sbdrewery	return (ret);
479257353Sbdrewery}
480257353Sbdrewery
481257353Sbdrewerystatic EVP_PKEY *
482287873Sdelphijload_public_key_file(const char *file)
483287873Sdelphij{
484287873Sdelphij	EVP_PKEY *pkey;
485287873Sdelphij	BIO *bp;
486287873Sdelphij	char errbuf[1024];
487287873Sdelphij
488287873Sdelphij	bp = BIO_new_file(file, "r");
489287873Sdelphij	if (!bp)
490287873Sdelphij		errx(EXIT_FAILURE, "Unable to read %s", file);
491287873Sdelphij
492287873Sdelphij	if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL)
493287873Sdelphij		warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf));
494287873Sdelphij
495287873Sdelphij	BIO_free(bp);
496287873Sdelphij
497287873Sdelphij	return (pkey);
498287873Sdelphij}
499287873Sdelphij
500287873Sdelphijstatic EVP_PKEY *
501257353Sbdreweryload_public_key_buf(const unsigned char *cert, int certlen)
502257353Sbdrewery{
503257353Sbdrewery	EVP_PKEY *pkey;
504257353Sbdrewery	BIO *bp;
505257353Sbdrewery	char errbuf[1024];
506257353Sbdrewery
507257353Sbdrewery	bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen);
508257353Sbdrewery
509257353Sbdrewery	if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL)
510257353Sbdrewery		warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
511257353Sbdrewery
512257353Sbdrewery	BIO_free(bp);
513257353Sbdrewery
514257353Sbdrewery	return (pkey);
515257353Sbdrewery}
516257353Sbdrewery
517257353Sbdrewerystatic bool
518287873Sdelphijrsa_verify_cert(int fd, const char *sigfile, const unsigned char *key,
519287873Sdelphij    int keylen, unsigned char *sig, int siglen)
520257353Sbdrewery{
521257353Sbdrewery	EVP_MD_CTX *mdctx;
522257353Sbdrewery	EVP_PKEY *pkey;
523257353Sbdrewery	char sha256[(SHA256_DIGEST_LENGTH * 2) + 2];
524257353Sbdrewery	char errbuf[1024];
525257353Sbdrewery	bool ret;
526257353Sbdrewery
527257353Sbdrewery	pkey = NULL;
528257353Sbdrewery	mdctx = NULL;
529257353Sbdrewery	ret = false;
530257353Sbdrewery
531287873Sdelphij	SSL_load_error_strings();
532287873Sdelphij
533257353Sbdrewery	/* Compute SHA256 of the package. */
534257353Sbdrewery	if (lseek(fd, 0, 0) == -1) {
535257353Sbdrewery		warn("lseek");
536257353Sbdrewery		goto cleanup;
537257353Sbdrewery	}
538257353Sbdrewery	if ((sha256_fd(fd, sha256)) == -1) {
539257353Sbdrewery		warnx("Error creating SHA256 hash for package");
540257353Sbdrewery		goto cleanup;
541257353Sbdrewery	}
542257353Sbdrewery
543287873Sdelphij	if (sigfile != NULL) {
544287873Sdelphij		if ((pkey = load_public_key_file(sigfile)) == NULL) {
545287873Sdelphij			warnx("Error reading public key");
546287873Sdelphij			goto cleanup;
547287873Sdelphij		}
548287873Sdelphij	} else {
549287873Sdelphij		if ((pkey = load_public_key_buf(key, keylen)) == NULL) {
550287873Sdelphij			warnx("Error reading public key");
551287873Sdelphij			goto cleanup;
552287873Sdelphij		}
553257353Sbdrewery	}
554257353Sbdrewery
555257353Sbdrewery	/* Verify signature of the SHA256(pkg) is valid. */
556257353Sbdrewery	if ((mdctx = EVP_MD_CTX_create()) == NULL) {
557257353Sbdrewery		warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
558257353Sbdrewery		goto error;
559257353Sbdrewery	}
560257353Sbdrewery
561257353Sbdrewery	if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
562257353Sbdrewery		warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
563257353Sbdrewery		goto error;
564257353Sbdrewery	}
565257353Sbdrewery	if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) {
566257353Sbdrewery		warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
567257353Sbdrewery		goto error;
568257353Sbdrewery	}
569257353Sbdrewery
570257353Sbdrewery	if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) {
571257353Sbdrewery		warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
572257353Sbdrewery		goto error;
573257353Sbdrewery	}
574257353Sbdrewery
575257353Sbdrewery	ret = true;
576257353Sbdrewery	printf("done\n");
577257353Sbdrewery	goto cleanup;
578257353Sbdrewery
579257353Sbdreweryerror:
580257353Sbdrewery	printf("failed\n");
581257353Sbdrewery
582257353Sbdrewerycleanup:
583257353Sbdrewery	if (pkey)
584257353Sbdrewery		EVP_PKEY_free(pkey);
585257353Sbdrewery	if (mdctx)
586257353Sbdrewery		EVP_MD_CTX_destroy(mdctx);
587257353Sbdrewery	ERR_free_strings();
588257353Sbdrewery
589257353Sbdrewery	return (ret);
590257353Sbdrewery}
591257353Sbdrewery
592287873Sdelphijstatic struct pubkey *
593287873Sdelphijread_pubkey(int fd)
594287873Sdelphij{
595287873Sdelphij	struct pubkey *pk;
596287873Sdelphij	struct sbuf *sig;
597287873Sdelphij	char buf[4096];
598287873Sdelphij	int r;
599287873Sdelphij
600287873Sdelphij	if (lseek(fd, 0, 0) == -1) {
601287873Sdelphij		warn("lseek");
602287873Sdelphij		return (NULL);
603287873Sdelphij	}
604287873Sdelphij
605287873Sdelphij	sig = sbuf_new_auto();
606287873Sdelphij
607287873Sdelphij	while ((r = read(fd, buf, sizeof(buf))) >0) {
608287873Sdelphij		sbuf_bcat(sig, buf, r);
609287873Sdelphij	}
610287873Sdelphij
611287873Sdelphij	sbuf_finish(sig);
612287873Sdelphij	pk = calloc(1, sizeof(struct pubkey));
613287873Sdelphij	pk->siglen = sbuf_len(sig);
614287873Sdelphij	pk->sig = calloc(1, pk->siglen);
615287873Sdelphij	memcpy(pk->sig, sbuf_data(sig), pk->siglen);
616287873Sdelphij	sbuf_delete(sig);
617287873Sdelphij
618287873Sdelphij	return (pk);
619287873Sdelphij}
620287873Sdelphij
621257353Sbdrewerystatic struct sig_cert *
622257353Sbdreweryparse_cert(int fd) {
623257353Sbdrewery	int my_fd;
624257353Sbdrewery	struct sig_cert *sc;
625257353Sbdrewery	FILE *fp;
626257353Sbdrewery	struct sbuf *buf, *sig, *cert;
627257353Sbdrewery	char *line;
628257353Sbdrewery	size_t linecap;
629257353Sbdrewery	ssize_t linelen;
630257353Sbdrewery
631257353Sbdrewery	buf = NULL;
632257353Sbdrewery	my_fd = -1;
633257353Sbdrewery	sc = NULL;
634257353Sbdrewery	line = NULL;
635257353Sbdrewery	linecap = 0;
636257353Sbdrewery
637257353Sbdrewery	if (lseek(fd, 0, 0) == -1) {
638257353Sbdrewery		warn("lseek");
639257353Sbdrewery		return (NULL);
640257353Sbdrewery	}
641257353Sbdrewery
642257353Sbdrewery	/* Duplicate the fd so that fclose(3) does not close it. */
643257353Sbdrewery	if ((my_fd = dup(fd)) == -1) {
644257353Sbdrewery		warnx("dup");
645257353Sbdrewery		return (NULL);
646257353Sbdrewery	}
647257353Sbdrewery
648257353Sbdrewery	if ((fp = fdopen(my_fd, "rb")) == NULL) {
649257353Sbdrewery		warn("fdopen");
650257353Sbdrewery		close(my_fd);
651257353Sbdrewery		return (NULL);
652257353Sbdrewery	}
653257353Sbdrewery
654257353Sbdrewery	sig = sbuf_new_auto();
655257353Sbdrewery	cert = sbuf_new_auto();
656257353Sbdrewery
657257353Sbdrewery	while ((linelen = getline(&line, &linecap, fp)) > 0) {
658257353Sbdrewery		if (strcmp(line, "SIGNATURE\n") == 0) {
659257353Sbdrewery			buf = sig;
660257353Sbdrewery			continue;
661257353Sbdrewery		} else if (strcmp(line, "CERT\n") == 0) {
662257353Sbdrewery			buf = cert;
663257353Sbdrewery			continue;
664257353Sbdrewery		} else if (strcmp(line, "END\n") == 0) {
665257353Sbdrewery			break;
666257353Sbdrewery		}
667257353Sbdrewery		if (buf != NULL)
668257353Sbdrewery			sbuf_bcat(buf, line, linelen);
669257353Sbdrewery	}
670257353Sbdrewery
671257353Sbdrewery	fclose(fp);
672257353Sbdrewery
673257353Sbdrewery	/* Trim out unrelated trailing newline */
674257353Sbdrewery	sbuf_setpos(sig, sbuf_len(sig) - 1);
675257353Sbdrewery
676257353Sbdrewery	sbuf_finish(sig);
677257353Sbdrewery	sbuf_finish(cert);
678257353Sbdrewery
679257353Sbdrewery	sc = calloc(1, sizeof(struct sig_cert));
680257353Sbdrewery	sc->siglen = sbuf_len(sig);
681257353Sbdrewery	sc->sig = calloc(1, sc->siglen);
682257353Sbdrewery	memcpy(sc->sig, sbuf_data(sig), sc->siglen);
683257353Sbdrewery
684257353Sbdrewery	sc->certlen = sbuf_len(cert);
685257353Sbdrewery	sc->cert = strdup(sbuf_data(cert));
686257353Sbdrewery
687257353Sbdrewery	sbuf_delete(sig);
688257353Sbdrewery	sbuf_delete(cert);
689257353Sbdrewery
690257353Sbdrewery	return (sc);
691257353Sbdrewery}
692257353Sbdrewery
693257353Sbdrewerystatic bool
694287873Sdelphijverify_pubsignature(int fd_pkg, int fd_sig)
695287873Sdelphij{
696287873Sdelphij	struct pubkey *pk;
697287873Sdelphij	const char *pubkey;
698287873Sdelphij	bool ret;
699287873Sdelphij
700287873Sdelphij	pk = NULL;
701287873Sdelphij	pubkey = NULL;
702287873Sdelphij	ret = false;
703287873Sdelphij	if (config_string(PUBKEY, &pubkey) != 0) {
704287873Sdelphij		warnx("No CONFIG_PUBKEY defined");
705287873Sdelphij		goto cleanup;
706287873Sdelphij	}
707287873Sdelphij
708287873Sdelphij	if ((pk = read_pubkey(fd_sig)) == NULL) {
709287873Sdelphij		warnx("Error reading signature");
710287873Sdelphij		goto cleanup;
711287873Sdelphij	}
712287873Sdelphij
713287873Sdelphij	/* Verify the signature. */
714287873Sdelphij	printf("Verifying signature with public key %s... ", pubkey);
715287873Sdelphij	if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig,
716287873Sdelphij	    pk->siglen) == false) {
717287873Sdelphij		fprintf(stderr, "Signature is not valid\n");
718287873Sdelphij		goto cleanup;
719287873Sdelphij	}
720287873Sdelphij
721287873Sdelphij	ret = true;
722287873Sdelphij
723287873Sdelphijcleanup:
724287873Sdelphij	if (pk) {
725287873Sdelphij		free(pk->sig);
726287873Sdelphij		free(pk);
727287873Sdelphij	}
728287873Sdelphij
729287873Sdelphij	return (ret);
730287873Sdelphij}
731287873Sdelphij
732287873Sdelphijstatic bool
733257353Sbdreweryverify_signature(int fd_pkg, int fd_sig)
734257353Sbdrewery{
735257353Sbdrewery	struct fingerprint_list *trusted, *revoked;
736257353Sbdrewery	struct fingerprint *fingerprint;
737257353Sbdrewery	struct sig_cert *sc;
738257353Sbdrewery	bool ret;
739257353Sbdrewery	int trusted_count, revoked_count;
740257353Sbdrewery	const char *fingerprints;
741257353Sbdrewery	char path[MAXPATHLEN];
742257353Sbdrewery	char hash[SHA256_DIGEST_LENGTH * 2 + 1];
743257353Sbdrewery
744257353Sbdrewery	sc = NULL;
745257353Sbdrewery	trusted = revoked = NULL;
746257353Sbdrewery	ret = false;
747257353Sbdrewery
748257353Sbdrewery	/* Read and parse fingerprints. */
749257353Sbdrewery	if (config_string(FINGERPRINTS, &fingerprints) != 0) {
750257353Sbdrewery		warnx("No CONFIG_FINGERPRINTS defined");
751257353Sbdrewery		goto cleanup;
752257353Sbdrewery	}
753257353Sbdrewery
754257353Sbdrewery	snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints);
755257353Sbdrewery	if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) {
756257353Sbdrewery		warnx("Error loading trusted certificates");
757257353Sbdrewery		goto cleanup;
758257353Sbdrewery	}
759257353Sbdrewery
760257353Sbdrewery	if (trusted_count == 0 || trusted == NULL) {
761257353Sbdrewery		fprintf(stderr, "No trusted certificates found.\n");
762257353Sbdrewery		goto cleanup;
763257353Sbdrewery	}
764257353Sbdrewery
765257353Sbdrewery	snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints);
766257353Sbdrewery	if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) {
767257353Sbdrewery		warnx("Error loading revoked certificates");
768257353Sbdrewery		goto cleanup;
769257353Sbdrewery	}
770257353Sbdrewery
771257353Sbdrewery	/* Read certificate and signature in. */
772257353Sbdrewery	if ((sc = parse_cert(fd_sig)) == NULL) {
773257353Sbdrewery		warnx("Error parsing certificate");
774257353Sbdrewery		goto cleanup;
775257353Sbdrewery	}
776257353Sbdrewery	/* Explicitly mark as non-trusted until proven otherwise. */
777257353Sbdrewery	sc->trusted = false;
778257353Sbdrewery
779257353Sbdrewery	/* Parse signature and pubkey out of the certificate */
780257353Sbdrewery	sha256_buf(sc->cert, sc->certlen, hash);
781257353Sbdrewery
782257353Sbdrewery	/* Check if this hash is revoked */
783257353Sbdrewery	if (revoked != NULL) {
784257353Sbdrewery		STAILQ_FOREACH(fingerprint, revoked, next) {
785257353Sbdrewery			if (strcasecmp(fingerprint->hash, hash) == 0) {
786257353Sbdrewery				fprintf(stderr, "The package was signed with "
787257353Sbdrewery				    "revoked certificate %s\n",
788257353Sbdrewery				    fingerprint->name);
789257353Sbdrewery				goto cleanup;
790257353Sbdrewery			}
791257353Sbdrewery		}
792257353Sbdrewery	}
793257353Sbdrewery
794257353Sbdrewery	STAILQ_FOREACH(fingerprint, trusted, next) {
795257353Sbdrewery		if (strcasecmp(fingerprint->hash, hash) == 0) {
796257353Sbdrewery			sc->trusted = true;
797257353Sbdrewery			sc->name = strdup(fingerprint->name);
798257353Sbdrewery			break;
799257353Sbdrewery		}
800257353Sbdrewery	}
801257353Sbdrewery
802257353Sbdrewery	if (sc->trusted == false) {
803257353Sbdrewery		fprintf(stderr, "No trusted fingerprint found matching "
804257353Sbdrewery		    "package's certificate\n");
805257353Sbdrewery		goto cleanup;
806257353Sbdrewery	}
807257353Sbdrewery
808257353Sbdrewery	/* Verify the signature. */
809257353Sbdrewery	printf("Verifying signature with trusted certificate %s... ", sc->name);
810287873Sdelphij	if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig,
811257353Sbdrewery	    sc->siglen) == false) {
812257353Sbdrewery		fprintf(stderr, "Signature is not valid\n");
813257353Sbdrewery		goto cleanup;
814257353Sbdrewery	}
815257353Sbdrewery
816257353Sbdrewery	ret = true;
817257353Sbdrewery
818257353Sbdrewerycleanup:
819257353Sbdrewery	if (trusted)
820257353Sbdrewery		free_fingerprint_list(trusted);
821257353Sbdrewery	if (revoked)
822257353Sbdrewery		free_fingerprint_list(revoked);
823257353Sbdrewery	if (sc) {
824257353Sbdrewery		if (sc->cert)
825257353Sbdrewery			free(sc->cert);
826257353Sbdrewery		if (sc->sig)
827257353Sbdrewery			free(sc->sig);
828257353Sbdrewery		if (sc->name)
829257353Sbdrewery			free(sc->name);
830257353Sbdrewery		free(sc);
831257353Sbdrewery	}
832257353Sbdrewery
833257353Sbdrewery	return (ret);
834257353Sbdrewery}
835257353Sbdrewery
836257353Sbdrewerystatic int
837257632Sbdrewerybootstrap_pkg(bool force)
838257353Sbdrewery{
839257353Sbdrewery	int fd_pkg, fd_sig;
840257353Sbdrewery	int ret;
841257353Sbdrewery	char url[MAXPATHLEN];
842257353Sbdrewery	char tmppkg[MAXPATHLEN];
843257353Sbdrewery	char tmpsig[MAXPATHLEN];
844257353Sbdrewery	const char *packagesite;
845257353Sbdrewery	const char *signature_type;
846257353Sbdrewery	char pkgstatic[MAXPATHLEN];
847257353Sbdrewery
848257353Sbdrewery	fd_sig = -1;
849257353Sbdrewery	ret = -1;
850257353Sbdrewery
851257353Sbdrewery	if (config_string(PACKAGESITE, &packagesite) != 0) {
852257353Sbdrewery		warnx("No PACKAGESITE defined");
853257353Sbdrewery		return (-1);
854257353Sbdrewery	}
855257353Sbdrewery
856257353Sbdrewery	if (config_string(SIGNATURE_TYPE, &signature_type) != 0) {
857257353Sbdrewery		warnx("Error looking up SIGNATURE_TYPE");
858257353Sbdrewery		return (-1);
859257353Sbdrewery	}
860257353Sbdrewery
861257353Sbdrewery	printf("Bootstrapping pkg from %s, please wait...\n", packagesite);
862257353Sbdrewery
863257353Sbdrewery	/* Support pkg+http:// for PACKAGESITE which is the new format
864257353Sbdrewery	   in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has
865257353Sbdrewery	   no A record. */
866257353Sbdrewery	if (strncmp(URL_SCHEME_PREFIX, packagesite,
867257353Sbdrewery	    strlen(URL_SCHEME_PREFIX)) == 0)
868257353Sbdrewery		packagesite += strlen(URL_SCHEME_PREFIX);
869257353Sbdrewery	snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite);
870257353Sbdrewery
871257353Sbdrewery	snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
872257353Sbdrewery	    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
873257353Sbdrewery
874257353Sbdrewery	if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1)
875257353Sbdrewery		goto fetchfail;
876257353Sbdrewery
877257353Sbdrewery	if (signature_type != NULL &&
878287146Sdelphij	    strcasecmp(signature_type, "NONE") != 0) {
879287873Sdelphij		if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
880287873Sdelphij
881287873Sdelphij			snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX",
882287873Sdelphij			    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
883287873Sdelphij			snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
884287873Sdelphij			    packagesite);
885287873Sdelphij
886287873Sdelphij			if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
887287873Sdelphij				fprintf(stderr, "Signature for pkg not "
888287873Sdelphij				    "available.\n");
889287873Sdelphij				goto fetchfail;
890287873Sdelphij			}
891287873Sdelphij
892287873Sdelphij			if (verify_signature(fd_pkg, fd_sig) == false)
893287873Sdelphij				goto cleanup;
894287873Sdelphij		} else if (strcasecmp(signature_type, "PUBKEY") == 0) {
895287873Sdelphij
896287873Sdelphij			snprintf(tmpsig, MAXPATHLEN,
897287873Sdelphij			    "%s/pkg.txz.pubkeysig.XXXXXX",
898287873Sdelphij			    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
899287873Sdelphij			snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig",
900287873Sdelphij			    packagesite);
901287873Sdelphij
902287873Sdelphij			if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
903287873Sdelphij				fprintf(stderr, "Signature for pkg not "
904287873Sdelphij				    "available.\n");
905287873Sdelphij				goto fetchfail;
906287873Sdelphij			}
907287873Sdelphij
908287873Sdelphij			if (verify_pubsignature(fd_pkg, fd_sig) == false)
909287873Sdelphij				goto cleanup;
910287873Sdelphij		} else {
911287146Sdelphij			warnx("Signature type %s is not supported for "
912287146Sdelphij			    "bootstrapping.", signature_type);
913287146Sdelphij			goto cleanup;
914287146Sdelphij		}
915257353Sbdrewery	}
916257353Sbdrewery
917257353Sbdrewery	if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
918257632Sbdrewery		ret = install_pkg_static(pkgstatic, tmppkg, force);
919234313Sbapt
920234351Sbapt	goto cleanup;
921234351Sbapt
922234351Sbaptfetchfail:
923234351Sbapt	warnx("Error fetching %s: %s", url, fetchLastErrString);
924257353Sbdrewery	fprintf(stderr, "A pre-built version of pkg could not be found for "
925257353Sbdrewery	    "your system.\n");
926257353Sbdrewery	fprintf(stderr, "Consider changing PACKAGESITE or installing it from "
927257353Sbdrewery	    "ports: 'ports-mgmt/pkg'.\n");
928234351Sbapt
929234313Sbaptcleanup:
930257353Sbdrewery	if (fd_sig != -1) {
931257353Sbdrewery		close(fd_sig);
932257353Sbdrewery		unlink(tmpsig);
933257353Sbdrewery	}
934257353Sbdrewery	close(fd_pkg);
935234313Sbapt	unlink(tmppkg);
936234313Sbapt
937234351Sbapt	return (ret);
938234313Sbapt}
939234313Sbapt
940238461Skanstatic const char confirmation_message[] =
941238461Skan"The package management tool is not yet installed on your system.\n"
942238461Skan"Do you want to fetch and install it now? [y/N]: ";
943238461Skan
944238461Skanstatic int
945238461Skanpkg_query_yes_no(void)
946238461Skan{
947238461Skan	int ret, c;
948238461Skan
949238461Skan	c = getchar();
950238461Skan
951238461Skan	if (c == 'y' || c == 'Y')
952238461Skan		ret = 1;
953238461Skan	else
954238461Skan		ret = 0;
955238461Skan
956238461Skan	while (c != '\n' && c != EOF)
957238461Skan		c = getchar();
958238461Skan
959238461Skan	return (ret);
960238461Skan}
961238461Skan
962257353Sbdrewerystatic int
963257632Sbdrewerybootstrap_pkg_local(const char *pkgpath, bool force)
964257353Sbdrewery{
965257353Sbdrewery	char path[MAXPATHLEN];
966257353Sbdrewery	char pkgstatic[MAXPATHLEN];
967257353Sbdrewery	const char *signature_type;
968257353Sbdrewery	int fd_pkg, fd_sig, ret;
969257353Sbdrewery
970257353Sbdrewery	fd_sig = -1;
971257353Sbdrewery	ret = -1;
972257353Sbdrewery
973257353Sbdrewery	fd_pkg = open(pkgpath, O_RDONLY);
974257353Sbdrewery	if (fd_pkg == -1)
975257353Sbdrewery		err(EXIT_FAILURE, "Unable to open %s", pkgpath);
976257353Sbdrewery
977257353Sbdrewery	if (config_string(SIGNATURE_TYPE, &signature_type) != 0) {
978257353Sbdrewery		warnx("Error looking up SIGNATURE_TYPE");
979257353Sbdrewery		return (-1);
980257353Sbdrewery	}
981257353Sbdrewery	if (signature_type != NULL &&
982287146Sdelphij	    strcasecmp(signature_type, "NONE") != 0) {
983287873Sdelphij		if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
984287873Sdelphij
985287873Sdelphij			snprintf(path, sizeof(path), "%s.sig", pkgpath);
986287873Sdelphij
987287873Sdelphij			if ((fd_sig = open(path, O_RDONLY)) == -1) {
988287873Sdelphij				fprintf(stderr, "Signature for pkg not "
989287873Sdelphij				    "available.\n");
990287873Sdelphij				goto cleanup;
991287873Sdelphij			}
992287873Sdelphij
993287873Sdelphij			if (verify_signature(fd_pkg, fd_sig) == false)
994287873Sdelphij				goto cleanup;
995287873Sdelphij
996287873Sdelphij		} else if (strcasecmp(signature_type, "PUBKEY") == 0) {
997287873Sdelphij
998287873Sdelphij			snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath);
999287873Sdelphij
1000287873Sdelphij			if ((fd_sig = open(path, O_RDONLY)) == -1) {
1001287873Sdelphij				fprintf(stderr, "Signature for pkg not "
1002287873Sdelphij				    "available.\n");
1003287873Sdelphij				goto cleanup;
1004287873Sdelphij			}
1005287873Sdelphij
1006287873Sdelphij			if (verify_pubsignature(fd_pkg, fd_sig) == false)
1007287873Sdelphij				goto cleanup;
1008287873Sdelphij
1009287873Sdelphij		} else {
1010287146Sdelphij			warnx("Signature type %s is not supported for "
1011287146Sdelphij			    "bootstrapping.", signature_type);
1012287146Sdelphij			goto cleanup;
1013287146Sdelphij		}
1014257353Sbdrewery	}
1015257353Sbdrewery
1016257353Sbdrewery	if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
1017257632Sbdrewery		ret = install_pkg_static(pkgstatic, pkgpath, force);
1018257353Sbdrewery
1019257353Sbdrewerycleanup:
1020257353Sbdrewery	close(fd_pkg);
1021257353Sbdrewery	if (fd_sig != -1)
1022257353Sbdrewery		close(fd_sig);
1023257353Sbdrewery
1024257353Sbdrewery	return (ret);
1025257353Sbdrewery}
1026257353Sbdrewery
1027234313Sbaptint
1028234322Sbaptmain(__unused int argc, char *argv[])
1029234313Sbapt{
1030234313Sbapt	char pkgpath[MAXPATHLEN];
1031257632Sbdrewery	const char *pkgarg;
1032257632Sbdrewery	bool bootstrap_only, force, yes;
1033234313Sbapt
1034257632Sbdrewery	bootstrap_only = false;
1035257632Sbdrewery	force = false;
1036257632Sbdrewery	pkgarg = NULL;
1037257632Sbdrewery	yes = false;
1038257632Sbdrewery
1039234313Sbapt	snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg",
1040234322Sbapt	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
1041234313Sbapt
1042257632Sbdrewery	if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) {
1043257632Sbdrewery		bootstrap_only = true;
1044257632Sbdrewery		if (argc == 3 && strcmp(argv[2], "-f") == 0)
1045257632Sbdrewery			force = true;
1046257632Sbdrewery	}
1047257632Sbdrewery
1048257632Sbdrewery	if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) {
1049244553Smatthew		/*
1050244594Smatthew		 * To allow 'pkg -N' to be used as a reliable test for whether
1051244553Smatthew		 * a system is configured to use pkg, don't bootstrap pkg
1052244553Smatthew		 * when that argument is given as argv[1].
1053244553Smatthew		 */
1054244639Smatthew		if (argv[1] != NULL && strcmp(argv[1], "-N") == 0)
1055244639Smatthew			errx(EXIT_FAILURE, "pkg is not installed");
1056244553Smatthew
1057257353Sbdrewery		config_init();
1058257353Sbdrewery
1059257632Sbdrewery		if (argc > 1 && strcmp(argv[1], "add") == 0) {
1060257632Sbdrewery			if (argc > 2 && strcmp(argv[2], "-f") == 0) {
1061257632Sbdrewery				force = true;
1062257632Sbdrewery				pkgarg = argv[3];
1063257632Sbdrewery			} else
1064257632Sbdrewery				pkgarg = argv[2];
1065257632Sbdrewery			if (pkgarg == NULL) {
1066257632Sbdrewery				fprintf(stderr, "Path to pkg.txz required\n");
1067257309Sbapt				exit(EXIT_FAILURE);
1068257632Sbdrewery			}
1069257632Sbdrewery			if (access(pkgarg, R_OK) == -1) {
1070257632Sbdrewery				fprintf(stderr, "No such file: %s\n", pkgarg);
1071257632Sbdrewery				exit(EXIT_FAILURE);
1072257632Sbdrewery			}
1073257632Sbdrewery			if (bootstrap_pkg_local(pkgarg, force) != 0)
1074257632Sbdrewery				exit(EXIT_FAILURE);
1075257309Sbapt			exit(EXIT_SUCCESS);
1076257309Sbapt		}
1077238461Skan		/*
1078238461Skan		 * Do not ask for confirmation if either of stdin or stdout is
1079238461Skan		 * not tty. Check the environment to see if user has answer
1080238461Skan		 * tucked in there already.
1081238461Skan		 */
1082247841Sbapt		config_bool(ASSUME_ALWAYS_YES, &yes);
1083247841Sbapt		if (!yes) {
1084238461Skan			printf("%s", confirmation_message);
1085239664Sbapt			if (!isatty(fileno(stdin)))
1086238461Skan				exit(EXIT_FAILURE);
1087239664Sbapt
1088239664Sbapt			if (pkg_query_yes_no() == 0)
1089239663Sbapt				exit(EXIT_FAILURE);
1090238461Skan		}
1091257632Sbdrewery		if (bootstrap_pkg(force) != 0)
1092234351Sbapt			exit(EXIT_FAILURE);
1093247841Sbapt		config_finish();
1094257571Sbdrewery
1095257632Sbdrewery		if (bootstrap_only)
1096257571Sbdrewery			exit(EXIT_SUCCESS);
1097257632Sbdrewery	} else if (bootstrap_only) {
1098257632Sbdrewery		printf("pkg already bootstrapped at %s\n", pkgpath);
1099257632Sbdrewery		exit(EXIT_SUCCESS);
1100238461Skan	}
1101234313Sbapt
1102234313Sbapt	execv(pkgpath, argv);
1103234313Sbapt
1104234351Sbapt	/* NOT REACHED */
1105234322Sbapt	return (EXIT_FAILURE);
1106234313Sbapt}
1107