1234313Sbapt/*-
2263038Sbapt * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org>
3263038Sbapt * 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>
32263038Sbapt#include <sys/queue.h>
33263038Sbapt#include <sys/types.h>
34263038Sbapt#include <sys/sbuf.h>
35235112Sbapt#include <sys/wait.h>
36234313Sbapt
37263038Sbapt#define _WITH_GETLINE
38234313Sbapt#include <archive.h>
39234313Sbapt#include <archive_entry.h>
40263038Sbapt#include <dirent.h>
41234313Sbapt#include <err.h>
42234313Sbapt#include <errno.h>
43234313Sbapt#include <fcntl.h>
44235112Sbapt#include <fetch.h>
45235112Sbapt#include <paths.h>
46263038Sbapt#include <stdbool.h>
47234313Sbapt#include <stdlib.h>
48234313Sbapt#include <stdio.h>
49234313Sbapt#include <string.h>
50234313Sbapt#include <unistd.h>
51263038Sbapt#include <ucl.h>
52234313Sbapt
53263038Sbapt#include <openssl/err.h>
54263038Sbapt#include <openssl/ssl.h>
55263038Sbapt
56245394Sbapt#include "dns_utils.h"
57263038Sbapt#include "config.h"
58234313Sbapt
59263038Sbaptstruct sig_cert {
60263038Sbapt	char *name;
61263038Sbapt	unsigned char *sig;
62263038Sbapt	int siglen;
63263038Sbapt	unsigned char *cert;
64263038Sbapt	int certlen;
65263038Sbapt	bool trusted;
66263038Sbapt};
67234313Sbapt
68287873Sdelphijstruct pubkey {
69287873Sdelphij	unsigned char *sig;
70287873Sdelphij	int siglen;
71287873Sdelphij};
72287873Sdelphij
73263038Sbapttypedef enum {
74263038Sbapt       HASH_UNKNOWN,
75263038Sbapt       HASH_SHA256,
76263038Sbapt} hash_t;
77234313Sbapt
78263038Sbaptstruct fingerprint {
79263038Sbapt       hash_t type;
80263038Sbapt       char *name;
81263038Sbapt       char hash[BUFSIZ];
82263038Sbapt       STAILQ_ENTRY(fingerprint) next;
83263038Sbapt};
84234313Sbapt
85263038SbaptSTAILQ_HEAD(fingerprint_list, fingerprint);
86234313Sbapt
87234313Sbaptstatic int
88234313Sbaptextract_pkg_static(int fd, char *p, int sz)
89234313Sbapt{
90234313Sbapt	struct archive *a;
91234313Sbapt	struct archive_entry *ae;
92234313Sbapt	char *end;
93234313Sbapt	int ret, r;
94234313Sbapt
95235112Sbapt	ret = -1;
96234313Sbapt	a = archive_read_new();
97235112Sbapt	if (a == NULL) {
98235112Sbapt		warn("archive_read_new");
99235112Sbapt		return (ret);
100235112Sbapt	}
101234313Sbapt	archive_read_support_compression_all(a);
102234313Sbapt	archive_read_support_format_tar(a);
103234313Sbapt
104235112Sbapt	if (lseek(fd, 0, 0) == -1) {
105235112Sbapt		warn("lseek");
106235112Sbapt		goto cleanup;
107235112Sbapt	}
108234313Sbapt
109234313Sbapt	if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
110235112Sbapt		warnx("archive_read_open_fd: %s", archive_error_string(a));
111234313Sbapt		goto cleanup;
112234313Sbapt	}
113234313Sbapt
114234313Sbapt	ae = NULL;
115234313Sbapt	while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) {
116234313Sbapt		end = strrchr(archive_entry_pathname(ae), '/');
117234313Sbapt		if (end == NULL)
118234313Sbapt			continue;
119234313Sbapt
120234313Sbapt		if (strcmp(end, "/pkg-static") == 0) {
121234313Sbapt			r = archive_read_extract(a, ae,
122235112Sbapt			    ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
123235112Sbapt			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL |
124235112Sbapt			    ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR);
125235112Sbapt			strlcpy(p, archive_entry_pathname(ae), sz);
126234313Sbapt			break;
127234313Sbapt		}
128234313Sbapt	}
129234313Sbapt
130235112Sbapt	if (r == ARCHIVE_OK)
131235112Sbapt		ret = 0;
132235112Sbapt	else
133234313Sbapt		warnx("fail to extract pkg-static");
134234313Sbapt
135234313Sbaptcleanup:
136263038Sbapt	archive_read_free(a);
137235112Sbapt	return (ret);
138234313Sbapt
139234313Sbapt}
140234313Sbapt
141234313Sbaptstatic int
142263038Sbaptinstall_pkg_static(const char *path, const char *pkgpath, bool force)
143234313Sbapt{
144234313Sbapt	int pstat;
145234313Sbapt	pid_t pid;
146234313Sbapt
147234313Sbapt	switch ((pid = fork())) {
148235112Sbapt	case -1:
149235112Sbapt		return (-1);
150235112Sbapt	case 0:
151263038Sbapt		if (force)
152263038Sbapt			execl(path, "pkg-static", "add", "-f", pkgpath,
153263038Sbapt			    (char *)NULL);
154263038Sbapt		else
155263038Sbapt			execl(path, "pkg-static", "add", pkgpath,
156263038Sbapt			    (char *)NULL);
157235112Sbapt		_exit(1);
158235112Sbapt	default:
159235112Sbapt		break;
160234313Sbapt	}
161234313Sbapt
162235112Sbapt	while (waitpid(pid, &pstat, 0) == -1)
163234313Sbapt		if (errno != EINTR)
164234313Sbapt			return (-1);
165234313Sbapt
166235112Sbapt	if (WEXITSTATUS(pstat))
167235112Sbapt		return (WEXITSTATUS(pstat));
168235112Sbapt	else if (WIFSIGNALED(pstat))
169235112Sbapt		return (128 & (WTERMSIG(pstat)));
170235112Sbapt	return (pstat);
171234313Sbapt}
172234313Sbapt
173234313Sbaptstatic int
174263038Sbaptfetch_to_fd(const char *url, char *path)
175234313Sbapt{
176245394Sbapt	struct url *u;
177263038Sbapt	struct dns_srvinfo *mirrors, *current;
178263038Sbapt	struct url_stat st;
179234313Sbapt	FILE *remote;
180245394Sbapt	/* To store _https._tcp. + hostname + \0 */
181263038Sbapt	int fd;
182263038Sbapt	int retry, max_retry;
183287873Sdelphij	ssize_t r;
184263038Sbapt	char buf[10240];
185245394Sbapt	char zone[MAXHOSTNAMELEN + 13];
186263038Sbapt	static const char *mirror_type = NULL;
187234313Sbapt
188245394Sbapt	max_retry = 3;
189263038Sbapt	current = mirrors = NULL;
190234313Sbapt	remote = NULL;
191234313Sbapt
192263038Sbapt	if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type)
193263038Sbapt	    != 0) {
194263038Sbapt		warnx("No MIRROR_TYPE defined");
195235112Sbapt		return (-1);
196234313Sbapt	}
197234313Sbapt
198263038Sbapt	if ((fd = mkstemp(path)) == -1) {
199234313Sbapt		warn("mkstemp()");
200235112Sbapt		return (-1);
201234313Sbapt	}
202234313Sbapt
203245394Sbapt	retry = max_retry;
204234313Sbapt
205245394Sbapt	u = fetchParseURL(url);
206245394Sbapt	while (remote == NULL) {
207245394Sbapt		if (retry == max_retry) {
208263038Sbapt			if (strcmp(u->scheme, "file") != 0 &&
209263038Sbapt			    strcasecmp(mirror_type, "srv") == 0) {
210245394Sbapt				snprintf(zone, sizeof(zone),
211245394Sbapt				    "_%s._tcp.%s", u->scheme, u->host);
212245394Sbapt				mirrors = dns_getsrvinfo(zone);
213245394Sbapt				current = mirrors;
214245394Sbapt			}
215245394Sbapt		}
216245394Sbapt
217263038Sbapt		if (mirrors != NULL) {
218245394Sbapt			strlcpy(u->host, current->host, sizeof(u->host));
219263038Sbapt			u->port = current->port;
220263038Sbapt		}
221245394Sbapt
222245394Sbapt		remote = fetchXGet(u, &st, "");
223245394Sbapt		if (remote == NULL) {
224245394Sbapt			--retry;
225245394Sbapt			if (retry <= 0)
226245394Sbapt				goto fetchfail;
227245394Sbapt			if (mirrors == NULL) {
228245394Sbapt				sleep(1);
229245394Sbapt			} else {
230245394Sbapt				current = current->next;
231245394Sbapt				if (current == NULL)
232245394Sbapt					current = mirrors;
233245394Sbapt			}
234245394Sbapt		}
235245394Sbapt	}
236245394Sbapt
237287873Sdelphij	while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) {
238234313Sbapt		if (write(fd, buf, r) != r) {
239234313Sbapt			warn("write()");
240263038Sbapt			goto fetchfail;
241234313Sbapt		}
242287873Sdelphij	}
243234313Sbapt
244287873Sdelphij	if (r != 0) {
245287873Sdelphij		warn("An error occurred while fetching pkg(8)");
246287873Sdelphij		goto fetchfail;
247234313Sbapt	}
248234313Sbapt
249235112Sbapt	if (ferror(remote))
250235112Sbapt		goto fetchfail;
251234313Sbapt
252263038Sbapt	goto cleanup;
253234313Sbapt
254263038Sbaptfetchfail:
255263038Sbapt	if (fd != -1) {
256263038Sbapt		close(fd);
257263038Sbapt		fd = -1;
258263038Sbapt		unlink(path);
259263038Sbapt	}
260235112Sbapt
261263038Sbaptcleanup:
262263038Sbapt	if (remote != NULL)
263263038Sbapt		fclose(remote);
264235112Sbapt
265263038Sbapt	return fd;
266263038Sbapt}
267263038Sbapt
268263038Sbaptstatic struct fingerprint *
269263038Sbaptparse_fingerprint(ucl_object_t *obj)
270263038Sbapt{
271263038Sbapt	ucl_object_t *cur;
272263038Sbapt	ucl_object_iter_t it = NULL;
273263038Sbapt	const char *function, *fp, *key;
274263038Sbapt	struct fingerprint *f;
275263038Sbapt	hash_t fct = HASH_UNKNOWN;
276263038Sbapt
277263038Sbapt	function = fp = NULL;
278263038Sbapt
279263038Sbapt	while ((cur = ucl_iterate_object(obj, &it, true))) {
280263038Sbapt		key = ucl_object_key(cur);
281263038Sbapt		if (cur->type != UCL_STRING)
282263038Sbapt			continue;
283263038Sbapt		if (strcasecmp(key, "function") == 0) {
284263038Sbapt			function = ucl_object_tostring(cur);
285263038Sbapt			continue;
286263038Sbapt		}
287263038Sbapt		if (strcasecmp(key, "fingerprint") == 0) {
288263038Sbapt			fp = ucl_object_tostring(cur);
289263038Sbapt			continue;
290263038Sbapt		}
291263038Sbapt	}
292263038Sbapt
293263038Sbapt	if (fp == NULL || function == NULL)
294263038Sbapt		return (NULL);
295263038Sbapt
296263038Sbapt	if (strcasecmp(function, "sha256") == 0)
297263038Sbapt		fct = HASH_SHA256;
298263038Sbapt
299263038Sbapt	if (fct == HASH_UNKNOWN) {
300263038Sbapt		warnx("Unsupported hashing function: %s", function);
301263038Sbapt		return (NULL);
302263038Sbapt	}
303263038Sbapt
304263038Sbapt	f = calloc(1, sizeof(struct fingerprint));
305263038Sbapt	f->type = fct;
306263038Sbapt	strlcpy(f->hash, fp, sizeof(f->hash));
307263038Sbapt
308263038Sbapt	return (f);
309263038Sbapt}
310263038Sbapt
311263038Sbaptstatic void
312263038Sbaptfree_fingerprint_list(struct fingerprint_list* list)
313263038Sbapt{
314263038Sbapt	struct fingerprint *fingerprint, *tmp;
315263038Sbapt
316263038Sbapt	STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) {
317263038Sbapt		free(fingerprint->name);
318263038Sbapt		free(fingerprint);
319263038Sbapt	}
320263038Sbapt	free(list);
321263038Sbapt}
322263038Sbapt
323263038Sbaptstatic struct fingerprint *
324263038Sbaptload_fingerprint(const char *dir, const char *filename)
325263038Sbapt{
326263038Sbapt	ucl_object_t *obj = NULL;
327263038Sbapt	struct ucl_parser *p = NULL;
328263038Sbapt	struct fingerprint *f;
329263038Sbapt	char path[MAXPATHLEN];
330263038Sbapt
331263038Sbapt	f = NULL;
332263038Sbapt
333263038Sbapt	snprintf(path, MAXPATHLEN, "%s/%s", dir, filename);
334263038Sbapt
335263038Sbapt	p = ucl_parser_new(0);
336263038Sbapt	if (!ucl_parser_add_file(p, path)) {
337263038Sbapt		warnx("%s: %s", path, ucl_parser_get_error(p));
338263038Sbapt		ucl_parser_free(p);
339263038Sbapt		return (NULL);
340263038Sbapt	}
341263038Sbapt
342263038Sbapt	obj = ucl_parser_get_object(p);
343263038Sbapt
344263038Sbapt	if (obj->type == UCL_OBJECT)
345263038Sbapt		f = parse_fingerprint(obj);
346263038Sbapt
347263038Sbapt	if (f != NULL)
348263038Sbapt		f->name = strdup(filename);
349263038Sbapt
350263038Sbapt	ucl_object_free(obj);
351263038Sbapt	ucl_parser_free(p);
352263038Sbapt
353263038Sbapt	return (f);
354263038Sbapt}
355263038Sbapt
356263038Sbaptstatic struct fingerprint_list *
357263038Sbaptload_fingerprints(const char *path, int *count)
358263038Sbapt{
359263038Sbapt	DIR *d;
360263038Sbapt	struct dirent *ent;
361263038Sbapt	struct fingerprint *finger;
362263038Sbapt	struct fingerprint_list *fingerprints;
363263038Sbapt
364263038Sbapt	*count = 0;
365263038Sbapt
366263038Sbapt	fingerprints = calloc(1, sizeof(struct fingerprint_list));
367263038Sbapt	if (fingerprints == NULL)
368263038Sbapt		return (NULL);
369263038Sbapt	STAILQ_INIT(fingerprints);
370263038Sbapt
371263038Sbapt	if ((d = opendir(path)) == NULL)
372263038Sbapt		return (NULL);
373263038Sbapt
374263038Sbapt	while ((ent = readdir(d))) {
375263038Sbapt		if (strcmp(ent->d_name, ".") == 0 ||
376263038Sbapt		    strcmp(ent->d_name, "..") == 0)
377263038Sbapt			continue;
378263038Sbapt		finger = load_fingerprint(path, ent->d_name);
379263038Sbapt		if (finger != NULL) {
380263038Sbapt			STAILQ_INSERT_TAIL(fingerprints, finger, next);
381263038Sbapt			++(*count);
382263038Sbapt		}
383263038Sbapt	}
384263038Sbapt
385263038Sbapt	closedir(d);
386263038Sbapt
387263038Sbapt	return (fingerprints);
388263038Sbapt}
389263038Sbapt
390263038Sbaptstatic void
391263038Sbaptsha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH],
392263038Sbapt    char out[SHA256_DIGEST_LENGTH * 2 + 1])
393263038Sbapt{
394263038Sbapt	int i;
395263038Sbapt
396263038Sbapt	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
397263038Sbapt		sprintf(out + (i * 2), "%02x", hash[i]);
398263038Sbapt
399263038Sbapt	out[SHA256_DIGEST_LENGTH * 2] = '\0';
400263038Sbapt}
401263038Sbapt
402263038Sbaptstatic void
403263038Sbaptsha256_buf_bin(char *buf, size_t len, char hash[SHA256_DIGEST_LENGTH])
404263038Sbapt{
405263038Sbapt	SHA256_CTX sha256;
406263038Sbapt
407263038Sbapt	SHA256_Init(&sha256);
408263038Sbapt	SHA256_Update(&sha256, buf, len);
409263038Sbapt	SHA256_Final(hash, &sha256);
410263038Sbapt}
411263038Sbapt
412263038Sbapt
413263038Sbaptstatic void
414263038Sbaptsha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1])
415263038Sbapt{
416263038Sbapt	unsigned char hash[SHA256_DIGEST_LENGTH];
417263038Sbapt	SHA256_CTX sha256;
418263038Sbapt
419263038Sbapt	out[0] = '\0';
420263038Sbapt
421263038Sbapt	SHA256_Init(&sha256);
422263038Sbapt	SHA256_Update(&sha256, buf, len);
423263038Sbapt	SHA256_Final(hash, &sha256);
424263038Sbapt	sha256_hash(hash, out);
425263038Sbapt}
426263038Sbapt
427263038Sbaptstatic int
428263038Sbaptsha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1])
429263038Sbapt{
430263038Sbapt	int my_fd;
431263038Sbapt	FILE *fp;
432263038Sbapt	char buffer[BUFSIZ];
433263038Sbapt	unsigned char hash[SHA256_DIGEST_LENGTH];
434263038Sbapt	size_t r;
435263038Sbapt	int ret;
436263038Sbapt	SHA256_CTX sha256;
437263038Sbapt
438263038Sbapt	my_fd = -1;
439263038Sbapt	fp = NULL;
440263038Sbapt	r = 0;
441263038Sbapt	ret = 1;
442263038Sbapt
443263038Sbapt	out[0] = '\0';
444263038Sbapt
445263038Sbapt	/* Duplicate the fd so that fclose(3) does not close it. */
446263038Sbapt	if ((my_fd = dup(fd)) == -1) {
447263038Sbapt		warnx("dup");
448263038Sbapt		goto cleanup;
449263038Sbapt	}
450263038Sbapt
451263038Sbapt	if ((fp = fdopen(my_fd, "rb")) == NULL) {
452263038Sbapt		warnx("fdopen");
453263038Sbapt		goto cleanup;
454263038Sbapt	}
455263038Sbapt
456263038Sbapt	SHA256_Init(&sha256);
457263038Sbapt
458263038Sbapt	while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0)
459263038Sbapt		SHA256_Update(&sha256, buffer, r);
460263038Sbapt
461263038Sbapt	if (ferror(fp) != 0) {
462263038Sbapt		warnx("fread");
463263038Sbapt		goto cleanup;
464263038Sbapt	}
465263038Sbapt
466263038Sbapt	SHA256_Final(hash, &sha256);
467263038Sbapt	sha256_hash(hash, out);
468263038Sbapt	ret = 0;
469263038Sbapt
470263038Sbaptcleanup:
471263038Sbapt	if (fp != NULL)
472263038Sbapt		fclose(fp);
473263038Sbapt	else if (my_fd != -1)
474263038Sbapt		close(my_fd);
475263038Sbapt	(void)lseek(fd, 0, SEEK_SET);
476263038Sbapt
477263038Sbapt	return (ret);
478263038Sbapt}
479263038Sbapt
480263038Sbaptstatic RSA *
481287873Sdelphijload_rsa_public_key_file(const char *file)
482287873Sdelphij{
483287873Sdelphij	RSA *rsa = NULL;
484287873Sdelphij	BIO *bp;
485287873Sdelphij	char errbuf[1024];
486287873Sdelphij
487287873Sdelphij	bp = BIO_new_file(file, "r");
488287873Sdelphij	if (!bp)
489287873Sdelphij		errx(EXIT_FAILURE, "Unable to read %s", file);
490287873Sdelphij
491287873Sdelphij	if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) {
492287873Sdelphij		warn("error reading public key: %s",
493287873Sdelphij		    ERR_error_string(ERR_get_error(), errbuf));
494287873Sdelphij		BIO_free(bp);
495287873Sdelphij		return (NULL);
496287873Sdelphij	}
497287873Sdelphij
498287873Sdelphij	BIO_free(bp);
499287873Sdelphij
500287873Sdelphij	return (rsa);
501287873Sdelphij}
502287873Sdelphij
503287873Sdelphijstatic RSA *
504263038Sbaptload_rsa_public_key_buf(unsigned char *cert, int certlen)
505263038Sbapt{
506263038Sbapt	RSA *rsa = NULL;
507263038Sbapt	BIO *bp;
508263038Sbapt	char errbuf[1024];
509263038Sbapt
510263038Sbapt	bp = BIO_new_mem_buf((void *)cert, certlen);
511263038Sbapt	if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) {
512263038Sbapt		warn("error reading public key: %s",
513263038Sbapt		    ERR_error_string(ERR_get_error(), errbuf));
514263038Sbapt		BIO_free(bp);
515263038Sbapt		return (NULL);
516263038Sbapt	}
517263038Sbapt	BIO_free(bp);
518263038Sbapt	return (rsa);
519263038Sbapt}
520263038Sbapt
521263038Sbapt
522263038Sbaptstatic bool
523287873Sdelphijrsa_verify_cert(int fd, const char *sigfile, unsigned char *key,
524287873Sdelphij    int keylen, unsigned char *sig, int siglen)
525263038Sbapt{
526263038Sbapt	char sha256[SHA256_DIGEST_LENGTH *2 +1];
527263038Sbapt	char hash[SHA256_DIGEST_LENGTH];
528263038Sbapt	char errbuf[1024];
529263038Sbapt	RSA *rsa = NULL;
530263038Sbapt	int ret;
531263038Sbapt
532263038Sbapt	lseek(fd, 0, SEEK_SET);
533263038Sbapt	sha256_fd(fd, sha256);
534263038Sbapt
535263038Sbapt	SSL_load_error_strings();
536263038Sbapt	OpenSSL_add_all_algorithms();
537263038Sbapt	OpenSSL_add_all_ciphers();
538263038Sbapt
539263038Sbapt	sha256_buf_bin(sha256, strlen(sha256), hash);
540263038Sbapt
541287873Sdelphij	if (sigfile != NULL) {
542287873Sdelphij		rsa = load_rsa_public_key_file(sigfile);
543287873Sdelphij	} else {
544287873Sdelphij		rsa = load_rsa_public_key_buf(key, keylen);
545287873Sdelphij	}
546263038Sbapt	if (rsa == NULL)
547263038Sbapt		return (false);
548263038Sbapt	ret = RSA_verify(NID_sha256, hash, sizeof(hash), sig, siglen, rsa);
549263038Sbapt	if (ret == 0) {
550263038Sbapt		warnx("%s: %s", key, ERR_error_string(ERR_get_error(), errbuf));
551263038Sbapt		return (false);
552263038Sbapt	}
553263038Sbapt
554263038Sbapt	RSA_free(rsa);
555263038Sbapt	ERR_free_strings();
556263038Sbapt
557263038Sbapt	return (true);
558263038Sbapt}
559263038Sbapt
560287873Sdelphijstatic struct pubkey *
561287873Sdelphijread_pubkey(int fd)
562287873Sdelphij{
563287873Sdelphij	struct pubkey *pk;
564287873Sdelphij	struct sbuf *sig;
565287873Sdelphij	char buf[4096];
566287873Sdelphij	int r;
567287873Sdelphij
568287873Sdelphij	if (lseek(fd, 0, 0) == -1) {
569287873Sdelphij		warn("lseek");
570287873Sdelphij		return (NULL);
571287873Sdelphij	}
572287873Sdelphij
573287873Sdelphij	sig = sbuf_new_auto();
574287873Sdelphij
575287873Sdelphij	while ((r = read(fd, buf, sizeof(buf))) >0) {
576287873Sdelphij		sbuf_bcat(sig, buf, r);
577287873Sdelphij	}
578287873Sdelphij
579287873Sdelphij	sbuf_finish(sig);
580287873Sdelphij	pk = calloc(1, sizeof(struct pubkey));
581287873Sdelphij	pk->siglen = sbuf_len(sig);
582287873Sdelphij	pk->sig = calloc(1, pk->siglen);
583287873Sdelphij	memcpy(pk->sig, sbuf_data(sig), pk->siglen);
584287873Sdelphij	sbuf_delete(sig);
585287873Sdelphij
586287873Sdelphij	return (pk);
587287873Sdelphij}
588287873Sdelphij
589263038Sbaptstatic struct sig_cert *
590263038Sbaptparse_cert(int fd) {
591263038Sbapt	int my_fd;
592263038Sbapt	struct sig_cert *sc;
593263038Sbapt	FILE *fp;
594263038Sbapt	struct sbuf *buf, *sig, *cert;
595263038Sbapt	char *line;
596263038Sbapt	size_t linecap;
597263038Sbapt	ssize_t linelen;
598263038Sbapt
599263038Sbapt	buf = NULL;
600263038Sbapt	my_fd = -1;
601263038Sbapt	sc = NULL;
602263038Sbapt	line = NULL;
603263038Sbapt	linecap = 0;
604263038Sbapt
605263038Sbapt	if (lseek(fd, 0, 0) == -1) {
606263038Sbapt		warn("lseek");
607263038Sbapt		return (NULL);
608263038Sbapt	}
609263038Sbapt
610263038Sbapt	/* Duplicate the fd so that fclose(3) does not close it. */
611263038Sbapt	if ((my_fd = dup(fd)) == -1) {
612263038Sbapt		warnx("dup");
613263038Sbapt		return (NULL);
614263038Sbapt	}
615263038Sbapt
616263038Sbapt	if ((fp = fdopen(my_fd, "rb")) == NULL) {
617263038Sbapt		warn("fdopen");
618263038Sbapt		close(my_fd);
619263038Sbapt		return (NULL);
620263038Sbapt	}
621263038Sbapt
622263038Sbapt	sig = sbuf_new_auto();
623263038Sbapt	cert = sbuf_new_auto();
624263038Sbapt
625263038Sbapt	while ((linelen = getline(&line, &linecap, fp)) > 0) {
626263038Sbapt		if (strcmp(line, "SIGNATURE\n") == 0) {
627263038Sbapt			buf = sig;
628263038Sbapt			continue;
629263038Sbapt		} else if (strcmp(line, "CERT\n") == 0) {
630263038Sbapt			buf = cert;
631263038Sbapt			continue;
632263038Sbapt		} else if (strcmp(line, "END\n") == 0) {
633263038Sbapt			break;
634263038Sbapt		}
635263038Sbapt		if (buf != NULL)
636263038Sbapt			sbuf_bcat(buf, line, linelen);
637263038Sbapt	}
638263038Sbapt
639263038Sbapt	fclose(fp);
640263038Sbapt
641263038Sbapt	/* Trim out unrelated trailing newline */
642263038Sbapt	sbuf_setpos(sig, sbuf_len(sig) - 1);
643263038Sbapt
644263038Sbapt	sbuf_finish(sig);
645263038Sbapt	sbuf_finish(cert);
646263038Sbapt
647263038Sbapt	sc = calloc(1, sizeof(struct sig_cert));
648263038Sbapt	sc->siglen = sbuf_len(sig);
649263038Sbapt	sc->sig = calloc(1, sc->siglen);
650263038Sbapt	memcpy(sc->sig, sbuf_data(sig), sc->siglen);
651263038Sbapt
652263038Sbapt	sc->certlen = sbuf_len(cert);
653263038Sbapt	sc->cert = strdup(sbuf_data(cert));
654263038Sbapt
655263038Sbapt	sbuf_delete(sig);
656263038Sbapt	sbuf_delete(cert);
657263038Sbapt
658263038Sbapt	return (sc);
659263038Sbapt}
660263038Sbapt
661263038Sbaptstatic bool
662287873Sdelphijverify_pubsignature(int fd_pkg, int fd_sig)
663287873Sdelphij{
664287873Sdelphij	struct pubkey *pk;
665287873Sdelphij	const char *pubkey;
666287873Sdelphij	bool ret;
667287873Sdelphij
668287873Sdelphij	pk = NULL;
669287873Sdelphij	pubkey = NULL;
670287873Sdelphij	ret = false;
671287873Sdelphij	if (config_string(PUBKEY, &pubkey) != 0) {
672287873Sdelphij		warnx("No CONFIG_PUBKEY defined");
673287873Sdelphij		goto cleanup;
674287873Sdelphij	}
675287873Sdelphij
676287873Sdelphij	if ((pk = read_pubkey(fd_sig)) == NULL) {
677287873Sdelphij		warnx("Error reading signature");
678287873Sdelphij		goto cleanup;
679287873Sdelphij	}
680287873Sdelphij
681287873Sdelphij	/* Verify the signature. */
682287873Sdelphij	printf("Verifying signature with public key %s... ", pubkey);
683287873Sdelphij	if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig,
684287873Sdelphij	    pk->siglen) == false) {
685287873Sdelphij		fprintf(stderr, "Signature is not valid\n");
686287873Sdelphij		goto cleanup;
687287873Sdelphij	}
688287873Sdelphij
689287873Sdelphij	ret = true;
690287873Sdelphij
691287873Sdelphijcleanup:
692287873Sdelphij	if (pk) {
693287873Sdelphij		free(pk->sig);
694287873Sdelphij		free(pk);
695287873Sdelphij	}
696287873Sdelphij
697287873Sdelphij	return (ret);
698287873Sdelphij}
699287873Sdelphij
700287873Sdelphijstatic bool
701263038Sbaptverify_signature(int fd_pkg, int fd_sig)
702263038Sbapt{
703263038Sbapt	struct fingerprint_list *trusted, *revoked;
704263038Sbapt	struct fingerprint *fingerprint;
705263038Sbapt	struct sig_cert *sc;
706263038Sbapt	bool ret;
707263038Sbapt	int trusted_count, revoked_count;
708263038Sbapt	const char *fingerprints;
709263038Sbapt	char path[MAXPATHLEN];
710263038Sbapt	char hash[SHA256_DIGEST_LENGTH * 2 + 1];
711263038Sbapt
712263038Sbapt	sc = NULL;
713263038Sbapt	trusted = revoked = NULL;
714263038Sbapt	ret = false;
715263038Sbapt
716263038Sbapt	/* Read and parse fingerprints. */
717263038Sbapt	if (config_string(FINGERPRINTS, &fingerprints) != 0) {
718263038Sbapt		warnx("No CONFIG_FINGERPRINTS defined");
719263038Sbapt		goto cleanup;
720263038Sbapt	}
721263038Sbapt
722263038Sbapt	snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints);
723263038Sbapt	if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) {
724263038Sbapt		warnx("Error loading trusted certificates");
725263038Sbapt		goto cleanup;
726263038Sbapt	}
727263038Sbapt
728263038Sbapt	if (trusted_count == 0 || trusted == NULL) {
729263038Sbapt		fprintf(stderr, "No trusted certificates found.\n");
730263038Sbapt		goto cleanup;
731263038Sbapt	}
732263038Sbapt
733263038Sbapt	snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints);
734263038Sbapt	if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) {
735263038Sbapt		warnx("Error loading revoked certificates");
736263038Sbapt		goto cleanup;
737263038Sbapt	}
738263038Sbapt
739263038Sbapt	/* Read certificate and signature in. */
740263038Sbapt	if ((sc = parse_cert(fd_sig)) == NULL) {
741263038Sbapt		warnx("Error parsing certificate");
742263038Sbapt		goto cleanup;
743263038Sbapt	}
744263038Sbapt	/* Explicitly mark as non-trusted until proven otherwise. */
745263038Sbapt	sc->trusted = false;
746263038Sbapt
747263038Sbapt	/* Parse signature and pubkey out of the certificate */
748263038Sbapt	sha256_buf(sc->cert, sc->certlen, hash);
749263038Sbapt
750263038Sbapt	/* Check if this hash is revoked */
751263038Sbapt	if (revoked != NULL) {
752263038Sbapt		STAILQ_FOREACH(fingerprint, revoked, next) {
753263038Sbapt			if (strcasecmp(fingerprint->hash, hash) == 0) {
754263038Sbapt				fprintf(stderr, "The package was signed with "
755263038Sbapt				    "revoked certificate %s\n",
756263038Sbapt				    fingerprint->name);
757263038Sbapt				goto cleanup;
758263038Sbapt			}
759263038Sbapt		}
760263038Sbapt	}
761263038Sbapt
762263038Sbapt	STAILQ_FOREACH(fingerprint, trusted, next) {
763263038Sbapt		if (strcasecmp(fingerprint->hash, hash) == 0) {
764263038Sbapt			sc->trusted = true;
765263038Sbapt			sc->name = strdup(fingerprint->name);
766263038Sbapt			break;
767263038Sbapt		}
768263038Sbapt	}
769263038Sbapt
770263038Sbapt	if (sc->trusted == false) {
771263038Sbapt		fprintf(stderr, "No trusted fingerprint found matching "
772263038Sbapt		    "package's certificate\n");
773263038Sbapt		goto cleanup;
774263038Sbapt	}
775263038Sbapt
776263038Sbapt	/* Verify the signature. */
777263038Sbapt	printf("Verifying signature with trusted certificate %s... ", sc->name);
778287873Sdelphij	if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig,
779263038Sbapt	    sc->siglen) == false) {
780263038Sbapt		printf("failed\n");
781263038Sbapt		fprintf(stderr, "Signature is not valid\n");
782263038Sbapt		goto cleanup;
783263038Sbapt	}
784263038Sbapt	printf("done\n");
785263038Sbapt
786263038Sbapt	ret = true;
787263038Sbapt
788263038Sbaptcleanup:
789263038Sbapt	if (trusted)
790263038Sbapt		free_fingerprint_list(trusted);
791263038Sbapt	if (revoked)
792263038Sbapt		free_fingerprint_list(revoked);
793263038Sbapt	if (sc) {
794263038Sbapt		free(sc->cert);
795263038Sbapt		free(sc->sig);
796263038Sbapt		free(sc->name);
797263038Sbapt		free(sc);
798263038Sbapt	}
799263038Sbapt
800263038Sbapt	return (ret);
801263038Sbapt}
802263038Sbapt
803263038Sbaptstatic int
804263038Sbaptbootstrap_pkg(bool force)
805263038Sbapt{
806263038Sbapt	int fd_pkg, fd_sig;
807263038Sbapt	int ret;
808263038Sbapt	char url[MAXPATHLEN];
809263038Sbapt	char tmppkg[MAXPATHLEN];
810263038Sbapt	char tmpsig[MAXPATHLEN];
811263038Sbapt	const char *packagesite;
812263038Sbapt	const char *signature_type;
813263038Sbapt	char pkgstatic[MAXPATHLEN];
814263038Sbapt
815263038Sbapt	fd_sig = -1;
816263038Sbapt	ret = -1;
817263038Sbapt
818263038Sbapt	if (config_string(PACKAGESITE, &packagesite) != 0) {
819263038Sbapt		warnx("No PACKAGESITE defined");
820263038Sbapt		return (-1);
821263038Sbapt	}
822263038Sbapt
823263038Sbapt	if (config_string(SIGNATURE_TYPE, &signature_type) != 0) {
824263038Sbapt		warnx("Error looking up SIGNATURE_TYPE");
825263038Sbapt		return (-1);
826263038Sbapt	}
827263038Sbapt
828263038Sbapt	printf("Bootstrapping pkg from %s, please wait...\n", packagesite);
829263038Sbapt
830263038Sbapt	/* Support pkg+http:// for PACKAGESITE which is the new format
831263038Sbapt	   in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has
832263038Sbapt	   no A record. */
833263038Sbapt	if (strncmp(URL_SCHEME_PREFIX, packagesite,
834263038Sbapt	    strlen(URL_SCHEME_PREFIX)) == 0)
835263038Sbapt		packagesite += strlen(URL_SCHEME_PREFIX);
836263038Sbapt	snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite);
837263038Sbapt
838263038Sbapt	snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
839263038Sbapt	    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
840263038Sbapt
841263038Sbapt	if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1)
842263038Sbapt		goto fetchfail;
843263038Sbapt
844263038Sbapt	if (signature_type != NULL &&
845287147Sdelphij	    strcasecmp(signature_type, "NONE") != 0) {
846287873Sdelphij		if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
847287873Sdelphij
848287873Sdelphij			snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX",
849287873Sdelphij			    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
850287873Sdelphij			snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
851287873Sdelphij			    packagesite);
852287873Sdelphij
853287873Sdelphij			if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
854287873Sdelphij				fprintf(stderr, "Signature for pkg not "
855287873Sdelphij				    "available.\n");
856287873Sdelphij				goto fetchfail;
857287873Sdelphij			}
858287873Sdelphij
859287873Sdelphij			if (verify_signature(fd_pkg, fd_sig) == false)
860287873Sdelphij				goto cleanup;
861287873Sdelphij		} else if (strcasecmp(signature_type, "PUBKEY") == 0) {
862287873Sdelphij
863287873Sdelphij			snprintf(tmpsig, MAXPATHLEN,
864287873Sdelphij			    "%s/pkg.txz.pubkeysig.XXXXXX",
865287873Sdelphij			    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
866287873Sdelphij			snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig",
867287873Sdelphij			    packagesite);
868287873Sdelphij
869287873Sdelphij			if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
870287873Sdelphij				fprintf(stderr, "Signature for pkg not "
871287873Sdelphij				    "available.\n");
872287873Sdelphij				goto fetchfail;
873287873Sdelphij			}
874287873Sdelphij
875287873Sdelphij			if (verify_pubsignature(fd_pkg, fd_sig) == false)
876287873Sdelphij				goto cleanup;
877287873Sdelphij		} else {
878287147Sdelphij			warnx("Signature type %s is not supported for "
879287147Sdelphij			    "bootstrapping.", signature_type);
880287147Sdelphij			goto cleanup;
881287147Sdelphij		}
882235112Sbapt	}
883235112Sbapt
884263038Sbapt	if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
885263038Sbapt		ret = install_pkg_static(pkgstatic, tmppkg, force);
886263038Sbapt
887235112Sbapt	goto cleanup;
888235112Sbapt
889235112Sbaptfetchfail:
890235112Sbapt	warnx("Error fetching %s: %s", url, fetchLastErrString);
891263038Sbapt	fprintf(stderr, "A pre-built version of pkg could not be found for "
892263038Sbapt	    "your system.\n");
893263038Sbapt	fprintf(stderr, "Consider changing PACKAGESITE or installing it from "
894263038Sbapt	    "ports: 'ports-mgmt/pkg'.\n");
895235112Sbapt
896234313Sbaptcleanup:
897263038Sbapt	if (fd_sig != -1) {
898263038Sbapt		close(fd_sig);
899263038Sbapt		unlink(tmpsig);
900263038Sbapt	}
901263038Sbapt	close(fd_pkg);
902234313Sbapt	unlink(tmppkg);
903234313Sbapt
904235112Sbapt	return (ret);
905234313Sbapt}
906234313Sbapt
907238829Sbaptstatic const char confirmation_message[] =
908238829Sbapt"The package management tool is not yet installed on your system.\n"
909238829Sbapt"Do you want to fetch and install it now? [y/N]: ";
910238829Sbapt
911263038Sbaptstatic const char non_interactive_message[] =
912263038Sbapt"The package management tool is not yet installed on your system.\n"
913263038Sbapt"Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap "
914263038Sbapt"in non-interactive (stdin not being a tty)\n";
915263038Sbapt
916238829Sbaptstatic int
917238829Sbaptpkg_query_yes_no(void)
918238829Sbapt{
919238829Sbapt	int ret, c;
920238829Sbapt
921238829Sbapt	c = getchar();
922238829Sbapt
923238829Sbapt	if (c == 'y' || c == 'Y')
924238829Sbapt		ret = 1;
925238829Sbapt	else
926238829Sbapt		ret = 0;
927238829Sbapt
928238829Sbapt	while (c != '\n' && c != EOF)
929238829Sbapt		c = getchar();
930238829Sbapt
931238829Sbapt	return (ret);
932238829Sbapt}
933238829Sbapt
934263038Sbaptstatic int
935263038Sbaptbootstrap_pkg_local(const char *pkgpath, bool force)
936263038Sbapt{
937263038Sbapt	char path[MAXPATHLEN];
938263038Sbapt	char pkgstatic[MAXPATHLEN];
939263038Sbapt	const char *signature_type;
940263038Sbapt	int fd_pkg, fd_sig, ret;
941263038Sbapt
942263038Sbapt	fd_sig = -1;
943263038Sbapt	ret = -1;
944263038Sbapt
945263038Sbapt	fd_pkg = open(pkgpath, O_RDONLY);
946263038Sbapt	if (fd_pkg == -1)
947263038Sbapt		err(EXIT_FAILURE, "Unable to open %s", pkgpath);
948263038Sbapt
949263038Sbapt	if (config_string(SIGNATURE_TYPE, &signature_type) != 0) {
950263038Sbapt		warnx("Error looking up SIGNATURE_TYPE");
951263038Sbapt		return (-1);
952263038Sbapt	}
953263038Sbapt	if (signature_type != NULL &&
954287147Sdelphij	    strcasecmp(signature_type, "NONE") != 0) {
955287873Sdelphij		if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
956287873Sdelphij
957287873Sdelphij			snprintf(path, sizeof(path), "%s.sig", pkgpath);
958287873Sdelphij
959287873Sdelphij			if ((fd_sig = open(path, O_RDONLY)) == -1) {
960287873Sdelphij				fprintf(stderr, "Signature for pkg not "
961287873Sdelphij				    "available.\n");
962287873Sdelphij				goto cleanup;
963287873Sdelphij			}
964287873Sdelphij
965287873Sdelphij			if (verify_signature(fd_pkg, fd_sig) == false)
966287873Sdelphij				goto cleanup;
967287873Sdelphij
968287873Sdelphij		} else if (strcasecmp(signature_type, "PUBKEY") == 0) {
969287873Sdelphij
970287873Sdelphij			snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath);
971287873Sdelphij
972287873Sdelphij			if ((fd_sig = open(path, O_RDONLY)) == -1) {
973287873Sdelphij				fprintf(stderr, "Signature for pkg not "
974287873Sdelphij				    "available.\n");
975287873Sdelphij				goto cleanup;
976287873Sdelphij			}
977287873Sdelphij
978287873Sdelphij			if (verify_pubsignature(fd_pkg, fd_sig) == false)
979287873Sdelphij				goto cleanup;
980287873Sdelphij
981287873Sdelphij		} else {
982287147Sdelphij			warnx("Signature type %s is not supported for "
983287147Sdelphij			    "bootstrapping.", signature_type);
984287147Sdelphij			goto cleanup;
985287147Sdelphij		}
986263038Sbapt	}
987263038Sbapt
988263038Sbapt	if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
989263038Sbapt		ret = install_pkg_static(pkgstatic, pkgpath, force);
990263038Sbapt
991263038Sbaptcleanup:
992263038Sbapt	close(fd_pkg);
993263038Sbapt	if (fd_sig != -1)
994263038Sbapt		close(fd_sig);
995263038Sbapt
996263038Sbapt	return (ret);
997263038Sbapt}
998263038Sbapt
999234313Sbaptint
1000263038Sbaptmain(int argc, char *argv[])
1001234313Sbapt{
1002234313Sbapt	char pkgpath[MAXPATHLEN];
1003263038Sbapt	const char *pkgarg;
1004263038Sbapt	bool bootstrap_only, force, yes;
1005234313Sbapt
1006263038Sbapt	bootstrap_only = false;
1007263038Sbapt	force = false;
1008263038Sbapt	pkgarg = NULL;
1009263038Sbapt	yes = false;
1010263038Sbapt
1011234313Sbapt	snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg",
1012235112Sbapt	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
1013234313Sbapt
1014263038Sbapt	if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) {
1015263038Sbapt		bootstrap_only = true;
1016263038Sbapt		if (argc == 3 && strcmp(argv[2], "-f") == 0)
1017263038Sbapt			force = true;
1018263038Sbapt	}
1019263038Sbapt
1020263038Sbapt	if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) {
1021245451Sbapt		/*
1022245451Sbapt		 * To allow 'pkg -N' to be used as a reliable test for whether
1023245451Sbapt		 * a system is configured to use pkg, don't bootstrap pkg
1024245451Sbapt		 * when that argument is given as argv[1].
1025245451Sbapt		 */
1026245451Sbapt		if (argv[1] != NULL && strcmp(argv[1], "-N") == 0)
1027245451Sbapt			errx(EXIT_FAILURE, "pkg is not installed");
1028245451Sbapt
1029263038Sbapt		config_init();
1030263038Sbapt
1031263038Sbapt		if (argc > 1 && strcmp(argv[1], "add") == 0) {
1032263038Sbapt			if (argc > 2 && strcmp(argv[2], "-f") == 0) {
1033263038Sbapt				force = true;
1034263038Sbapt				pkgarg = argv[3];
1035263038Sbapt			} else
1036263038Sbapt				pkgarg = argv[2];
1037263038Sbapt			if (pkgarg == NULL) {
1038263038Sbapt				fprintf(stderr, "Path to pkg.txz required\n");
1039263038Sbapt				exit(EXIT_FAILURE);
1040263038Sbapt			}
1041263038Sbapt			if (access(pkgarg, R_OK) == -1) {
1042263038Sbapt				fprintf(stderr, "No such file: %s\n", pkgarg);
1043263038Sbapt				exit(EXIT_FAILURE);
1044263038Sbapt			}
1045263038Sbapt			if (bootstrap_pkg_local(pkgarg, force) != 0)
1046263038Sbapt				exit(EXIT_FAILURE);
1047263038Sbapt			exit(EXIT_SUCCESS);
1048263038Sbapt		}
1049238829Sbapt		/*
1050238829Sbapt		 * Do not ask for confirmation if either of stdin or stdout is
1051238829Sbapt		 * not tty. Check the environment to see if user has answer
1052238829Sbapt		 * tucked in there already.
1053238829Sbapt		 */
1054263038Sbapt		config_bool(ASSUME_ALWAYS_YES, &yes);
1055263038Sbapt		if (!yes) {
1056263038Sbapt			if (!isatty(fileno(stdin))) {
1057263038Sbapt				fprintf(stderr, non_interactive_message);
1058240290Sbapt				exit(EXIT_FAILURE);
1059263038Sbapt			}
1060240290Sbapt
1061263038Sbapt			printf("%s", confirmation_message);
1062238829Sbapt			if (pkg_query_yes_no() == 0)
1063238829Sbapt				exit(EXIT_FAILURE);
1064238829Sbapt		}
1065263038Sbapt		if (bootstrap_pkg(force) != 0)
1066235112Sbapt			exit(EXIT_FAILURE);
1067263038Sbapt		config_finish();
1068263038Sbapt
1069263038Sbapt		if (bootstrap_only)
1070263038Sbapt			exit(EXIT_SUCCESS);
1071263038Sbapt	} else if (bootstrap_only) {
1072263038Sbapt		printf("pkg already bootstrapped at %s\n", pkgpath);
1073263038Sbapt		exit(EXIT_SUCCESS);
1074238829Sbapt	}
1075234313Sbapt
1076234313Sbapt	execv(pkgpath, argv);
1077234313Sbapt
1078235112Sbapt	/* NOT REACHED */
1079235112Sbapt	return (EXIT_FAILURE);
1080234313Sbapt}
1081