1 /*
2  * Copyright (c) 2011-2021 Baptiste Daroussin <bapt@FreeBSD.org>
3  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4  * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
5  * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer
13  *    in this position and unchanged.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "pkg_config.h"
31 
32 #include <assert.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <ctype.h>
36 #include <dirent.h>
37 #include <dlfcn.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #ifdef HAVE_OSRELDATE_H
41 #include <osreldate.h>
42 #endif
43 #include <ucl.h>
44 
45 #include "pkg.h"
46 #include "private/pkg.h"
47 #include "private/event.h"
48 #include "pkg_repos.h"
49 
50 #ifndef PORTSDIR
51 #define PORTSDIR "/usr/dports"
52 #endif
53 #ifndef DEFAULT_VULNXML_URL
54 #define DEFAULT_VULNXML_URL "http://vuxml.freebsd.org/freebsd/vuln.xml.xz"
55 #endif
56 
57 #ifdef	OSMAJOR
58 #define STRINGIFY(X)	TEXT(X)
59 #define TEXT(X)		#X
60 #define INDEXFILE	"INDEX-" STRINGIFY(OSMAJOR)
61 #else
62 #define INDEXFILE	"INDEX"
63 #endif
64 
65 struct pkg_ctx ctx = {
66 	.eventpipe = -1,
67 	.debug_level = 0,
68 	.developer_mode = false,
69 	.pkg_rootdir = NULL,
70 	.dbdir = NULL,
71 	.cachedir = NULL,
72 	.rootfd = -1,
73 	.cachedirfd = -1,
74 	.pkg_dbdirfd = -1,
75 	.osversion = 0,
76 	.backup_libraries = false,
77 	.triggers = true,
78 	.compression_level = -1,
79 	.defer_triggers = false,
80 };
81 
82 struct config_entry {
83 	uint8_t type;
84 	const char *key;
85 	const char *def;
86 	const char *desc;
87 };
88 
89 static char myabi[BUFSIZ], myabi_legacy[BUFSIZ];
90 #ifdef __FreeBSD__
91 static char myosversion[BUFSIZ];
92 #endif
93 static struct pkg_repo *repos = NULL;
94 ucl_object_t *config = NULL;
95 
96 static struct config_entry c[] = {
97 	{
98 		PKG_STRING,
99 		"PKG_DBDIR",
100 		"/var/db/pkg",
101 		"Where the package databases are stored",
102 	},
103 	{
104 		PKG_STRING,
105 		"PKG_CACHEDIR",
106 		"/var/cache/pkg",
107 		"Directory containing cache of downloaded packages",
108 	},
109 	{
110 		PKG_STRING,
111 		"PORTSDIR",
112 		"/usr/dports",
113 		"Location of the ports collection",
114 	},
115 	{
116 		PKG_STRING,
117 		"INDEXDIR",
118 		NULL,		/* Default to PORTSDIR unless defined */
119 		"Location of the ports INDEX",
120 	},
121 	{
122 		PKG_STRING,
123 		"INDEXFILE",
124 		INDEXFILE,
125 		"Filename of the ports INDEX",
126 	},
127 	{
128 		PKG_BOOL,
129 		"HANDLE_RC_SCRIPTS",
130 		"NO",
131 		"Automatically handle restarting services",
132 	},
133 	{
134 		PKG_BOOL,
135 		"DEFAULT_ALWAYS_YES",
136 		"NO",
137 		"Default to 'yes' for all pkg(8) questions",
138 	},
139 	{
140 		PKG_BOOL,
141 		"ASSUME_ALWAYS_YES",
142 		"NO",
143 		"Answer 'yes' to all pkg(8) questions",
144 	},
145 	{
146 		PKG_ARRAY,
147 		"REPOS_DIR",
148 		"/etc/pkg/,"PREFIX"/etc/pkg/repos/",
149 		"Location of the repository configuration files"
150 	},
151 	{
152 		PKG_STRING,
153 		"PLIST_KEYWORDS_DIR",
154 		NULL,
155 		"Directory containing definitions of plist keywords",
156 	},
157 	{
158 		PKG_BOOL,
159 		"SYSLOG",
160 		"YES",
161 		"Log pkg(8) operations via syslog(3)",
162 	},
163 	{
164 		PKG_STRING,
165 		"ABI",
166 		myabi,
167 		"Override the automatically detected ABI",
168 	},
169 	{
170 		PKG_STRING,
171 		"ALTABI",
172 		myabi_legacy,
173 		"Override the automatically detected old-form ABI",
174 	},
175 	{
176 		PKG_BOOL,
177 		"DEVELOPER_MODE",
178 		"NO",
179 		"Add extra strict, pedantic warnings as an aid to package maintainers",
180 	},
181 	{
182 		PKG_STRING,
183 		"VULNXML_SITE",
184 		DEFAULT_VULNXML_URL,
185 		"URL giving location of the vulnxml database",
186 	},
187 	{
188 		PKG_INT,
189 		"FETCH_RETRY",
190 		"3",
191 		"How many times to retry fetching files",
192 	},
193 	{
194 		PKG_STRING,
195 		"PKG_PLUGINS_DIR",
196 		PREFIX"/lib/pkg/",
197 		"Directory which pkg(8) will load plugins from",
198 	},
199 	{
200 		PKG_BOOL,
201 		"PKG_ENABLE_PLUGINS",
202 		"YES",
203 		"Activate plugin support",
204 	},
205 	{
206 		PKG_ARRAY,
207 		"PLUGINS",
208 		NULL,
209 		"List of plugins that pkg(8) should load",
210 	},
211 	{
212 		PKG_BOOL,
213 		"DEBUG_SCRIPTS",
214 		"NO",
215 		"Run shell scripts in verbose mode to facilitate debugging",
216 	},
217 	{
218 		PKG_STRING,
219 		"PLUGINS_CONF_DIR",
220 		PREFIX"/etc/pkg/",
221 		"Directory containing plugin configuration data",
222 	},
223 	{
224 		PKG_BOOL,
225 		"PERMISSIVE",
226 		"NO",
227 		"Permit package installation despite presence of conflicting packages",
228 	},
229 	{
230 		PKG_BOOL,
231 		"REPO_AUTOUPDATE",
232 		"YES",
233 		"Automatically update repository catalogues prior to package updates",
234 	},
235 	{
236 		PKG_STRING,
237 		"NAMESERVER",
238 		NULL,
239 		"Use this nameserver when looking up addresses",
240 	},
241 	{
242 		PKG_STRING,
243 		"HTTP_USER_AGENT",
244 		"pkg/"PKGVERSION,
245 		"HTTP User-Agent",
246 	},
247 	{
248 		PKG_STRING,
249 		"EVENT_PIPE",
250 		NULL,
251 		"Send all events to the specified fifo or Unix socket",
252 	},
253 	{
254 		PKG_INT,
255 		"FETCH_TIMEOUT",
256 		"30",
257 		"Number of seconds before fetch(3) times out",
258 	},
259 	{
260 		PKG_BOOL,
261 		"UNSET_TIMESTAMP",
262 		"NO",
263 		"Do not include timestamps in the package",
264 	},
265 	{
266 		PKG_STRING,
267 		"SSH_RESTRICT_DIR",
268 		NULL,
269 		"Directory the ssh subsystem will be restricted to",
270 	},
271 	{
272 		PKG_OBJECT,
273 		"PKG_ENV",
274 		NULL,
275 		"Environment variables pkg will use",
276 	},
277 	{
278 		PKG_STRING,
279 		"PKG_SSH_ARGS",
280 		NULL,
281 		"Extras arguments to pass to ssh(1)",
282 	},
283 	{
284 		PKG_INT,
285 		"DEBUG_LEVEL",
286 		"0",
287 		"Level for debug messages",
288 	},
289 	{
290 		PKG_OBJECT,
291 		"ALIAS",
292 		NULL,
293 		"Command aliases",
294 	},
295 	{
296 		PKG_STRING,
297 		"CUDF_SOLVER",
298 		NULL,
299 		"Experimental: tells pkg to use an external CUDF solver",
300 	},
301 	{
302 		PKG_STRING,
303 		"SAT_SOLVER",
304 		NULL,
305 		"Experimental: tells pkg to use an external SAT solver",
306 	},
307 	{
308 		PKG_BOOL,
309 		"RUN_SCRIPTS",
310 		"YES",
311 		"Run post/pre actions scripts",
312 	},
313 	{
314 		PKG_BOOL,
315 		"CASE_SENSITIVE_MATCH",
316 		"NO",
317 		"Match package names case sensitively",
318 	},
319 	{
320 		PKG_INT,
321 		"LOCK_WAIT",
322 		"1",
323 		"Wait time to regain a lock if it is not available"
324 	},
325 	{
326 		PKG_INT,
327 		"LOCK_RETRIES",
328 		"5",
329 		"Retries performed to obtain a lock"
330 	},
331 	{
332 		PKG_BOOL,
333 		"SQLITE_PROFILE",
334 		"NO",
335 		"Profile sqlite queries"
336 	},
337 	{
338 		PKG_INT,
339 		"WORKERS_COUNT",
340 		"0",
341 		"How many workers are used for pkg-repo (hw.ncpu if 0)"
342 	},
343 	{
344 		PKG_BOOL,
345 		"READ_LOCK",
346 		"NO",
347 		"Use read locking for query database"
348 	},
349 	{
350 		PKG_BOOL,
351 		"PLIST_ACCEPT_DIRECTORIES",
352 		"NO",
353 		"Accept directories listed like plain files in plist"
354 	},
355 	{
356 		PKG_INT,
357 		"IP_VERSION",
358 		"0",
359 		"Restrict network access to IPv4 or IPv6 only"
360 	},
361 	{
362 		PKG_BOOL,
363 		"AUTOMERGE",
364 		"YES",
365 		"Automatically merge configuration files"
366 	},
367 	{
368 		PKG_STRING,
369 		"VERSION_SOURCE",
370 		NULL,
371 		"Version source for pkg-version (I, P, R), default is auto detect"
372 	},
373 	{
374 		PKG_BOOL,
375 		"CONSERVATIVE_UPGRADE",
376 		"YES",
377 		"Prefer repos with higher priority during upgrade"
378 	},
379 	{
380 		PKG_BOOL,
381 		"PKG_CREATE_VERBOSE",
382 		"NO",
383 		"Enable verbose mode for 'pkg create'",
384 	},
385 	{
386 		PKG_BOOL,
387 		"AUTOCLEAN",
388 		"NO",
389 		"Always cleanup the cache directory after install/upgrade",
390 	},
391 	{
392 		PKG_STRING,
393 		"DOT_FILE",
394 		NULL,
395 		"Save SAT problem to the specified dot file"
396 	},
397 	{
398 		PKG_OBJECT,
399 		"REPOSITORIES",
400 		NULL,
401 		"Repository config in pkg.conf"
402 	},
403 	{
404 		PKG_ARRAY,
405 		"VALID_URL_SCHEME",
406 		"pkg+http,pkg+https,https,http,file,ssh,ftp,ftps,pkg+ssh,pkg+ftp,pkg+ftps",
407 	},
408 	{
409 		PKG_BOOL,
410 		"ALLOW_BASE_SHLIBS",
411 		"NO",
412 		"Enable base libraries analysis",
413 	},
414 	{
415 		PKG_INT,
416 		"WARN_SIZE_LIMIT",
417 		"1048576", /* 1 meg */
418 		"Ask user when performing changes for more than this limit"
419 	},
420 	{
421 		PKG_STRING,
422 		"METALOG",
423 		NULL,
424 		"Write out the METALOG to the specified file",
425 	},
426 #ifdef __FreeBSD__
427 	{
428 		PKG_INT,
429 		"OSVERSION",
430 		myosversion,
431 		"FreeBSD OS version",
432 	},
433 	{
434 		PKG_BOOL,
435 		"IGNORE_OSVERSION",
436 		"NO",
437 		"Ignore FreeBSD OS version check",
438 	},
439 #endif
440 	{
441 		PKG_BOOL,
442 		"BACKUP_LIBRARIES",
443 		"NO",
444 		"Backup old versions of libraries during an upgrade",
445 	},
446 	{
447 		PKG_STRING,
448 		"BACKUP_LIBRARY_PATH",
449 		PREFIX "/lib/compat/pkg",
450 		"Path where pkg will backup libraries",
451 	},
452 	{
453 		PKG_STRING,
454 		"PKG_TRIGGERS_DIR",
455 		PREFIX "/share/pkg/triggers",
456 		"Path where the triggers should be installed",
457 	},
458 	{
459 		PKG_BOOL,
460 		"PKG_TRIGGERS_ENABLE",
461 		"YES",
462 		"Disable triggers",
463 	},
464 	{
465 		PKG_ARRAY,
466 		"AUDIT_IGNORE_GLOB",
467 		NULL,
468 		"List of glob to ignore while autiditing for vulnerabilities",
469 	},
470 	{
471 		PKG_ARRAY,
472 		"AUDIT_IGNORE_REGEX",
473 		"NULL",
474 		"List of regex to ignore while autiditing for vulnerabilities",
475 	},
476 	{
477 		PKG_INT,
478 		"COMPRESSION_LEVEL",
479 		"-1",
480 		"Set the default compression level",
481 	},
482 	{
483 		PKG_BOOL,
484 		"ARCHIVE_SYMLINK",
485 		"FALSE",
486 		"Create a symlink to legacy extension for backward compatibility",
487 	},
488 	{
489 		PKG_BOOL,
490 		"REPO_ACCEPT_LEGACY_PKG",
491 		"FALSE",
492 		"Accept legacy package extensions when creating the repository",
493 	},
494 };
495 
496 static bool parsed = false;
497 static size_t c_size = NELEM(c);
498 
499 static struct pkg_repo* pkg_repo_new(const char *name,
500 	const char *url, const char *type);
501 static void pkg_repo_overwrite(struct pkg_repo*, const char *name,
502 	const char *url, const char *type);
503 static void pkg_repo_free(struct pkg_repo *r);
504 
505 static void
connect_evpipe(const char * evpipe)506 connect_evpipe(const char *evpipe) {
507 	struct stat st;
508 	struct sockaddr_un sock;
509 	int flag = O_WRONLY;
510 
511 	if (stat(evpipe, &st) != 0) {
512 		pkg_emit_error("No such event pipe: %s", evpipe);
513 		return;
514 	}
515 
516 	if (!S_ISFIFO(st.st_mode) && !S_ISSOCK(st.st_mode)) {
517 		pkg_emit_error("%s is not a fifo or socket", evpipe);
518 		return;
519 	}
520 
521 	if (S_ISFIFO(st.st_mode)) {
522 		flag |= O_NONBLOCK;
523 		if ((ctx.eventpipe = open(evpipe, flag)) == -1)
524 			pkg_emit_errno("open event pipe", evpipe);
525 		return;
526 	}
527 
528 	if (S_ISSOCK(st.st_mode)) {
529 		if ((ctx.eventpipe = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
530 			pkg_emit_errno("Open event pipe", evpipe);
531 			return;
532 		}
533 		memset(&sock, 0, sizeof(struct sockaddr_un));
534 		sock.sun_family = AF_UNIX;
535 		if (strlcpy(sock.sun_path, evpipe, sizeof(sock.sun_path)) >=
536 		    sizeof(sock.sun_path)) {
537 			pkg_emit_error("Socket path too long: %s", evpipe);
538 			close(ctx.eventpipe);
539 			ctx.eventpipe = -1;
540 			return;
541 		}
542 
543 		if (connect(ctx.eventpipe, (struct sockaddr *)&sock, SUN_LEN(&sock)) == -1) {
544 			pkg_emit_errno("Connect event pipe", evpipe);
545 			close(ctx.eventpipe);
546 			ctx.eventpipe = -1;
547 			return;
548 		}
549 	}
550 
551 }
552 
553 int
pkg_initialized(void)554 pkg_initialized(void)
555 {
556 	return (parsed);
557 }
558 
559 const pkg_object *
pkg_config_get(const char * key)560 pkg_config_get(const char *key) {
561 	return (ucl_object_find_key(config, key));
562 }
563 
564 char *
pkg_config_dump(void)565 pkg_config_dump(void)
566 {
567 	return (pkg_object_dump(config));
568 }
569 
570 static void
disable_plugins_if_static(void)571 disable_plugins_if_static(void)
572 {
573 	void *dlh;
574 
575 	dlh = dlopen(0, RTLD_NOW);
576 
577 	/* if dlh is NULL then we are in static binary */
578 	if (dlh == NULL)
579 		ucl_object_replace_key(config, ucl_object_frombool(false), "PKG_ENABLE_PLUGINS", 18, false);
580 	else
581 		dlclose(dlh);
582 
583 	return;
584 }
585 
586 static void
add_repo(const ucl_object_t * obj,struct pkg_repo * r,const char * rname,pkg_init_flags flags)587 add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_init_flags flags)
588 {
589 	const ucl_object_t *cur, *enabled, *env;
590 	ucl_object_iter_t it = NULL;
591 	struct pkg_kv *kv;
592 	bool enable = true;
593 	const char *url = NULL, *pubkey = NULL, *mirror_type = NULL;
594 	const char *signature_type = NULL, *fingerprints = NULL;
595 	const char *key;
596 	const char *type = NULL;
597 	int use_ipvx = 0;
598 	int priority = 0;
599 
600 	pkg_debug(1, "PkgConfig: parsing repository object %s", rname);
601 
602 	env = NULL;
603 	enabled = ucl_object_find_key(obj, "enabled");
604 	if (enabled == NULL)
605 		enabled = ucl_object_find_key(obj, "ENABLED");
606 	if (enabled != NULL) {
607 		enable = ucl_object_toboolean(enabled);
608 		if (!enable && r != NULL) {
609 			/*
610 			 * We basically want to remove the existing repo r and
611 			 * forget all stuff parsed
612 			 */
613 			pkg_debug(1, "PkgConfig: disabling repo %s", rname);
614 			HASH_DEL(repos, r);
615 			pkg_repo_free(r);
616 			return;
617 		}
618 	}
619 
620 	while ((cur = ucl_iterate_object(obj, &it, true))) {
621 		key = ucl_object_key(cur);
622 		if (key == NULL)
623 			continue;
624 
625 		if (strcasecmp(key, "url") == 0) {
626 			if (cur->type != UCL_STRING) {
627 				pkg_emit_error("Expecting a string for the "
628 				    "'%s' key of the '%s' repo",
629 				    key, rname);
630 				return;
631 			}
632 			url = ucl_object_tostring(cur);
633 		} else if (strcasecmp(key, "pubkey") == 0) {
634 			if (cur->type != UCL_STRING) {
635 				pkg_emit_error("Expecting a string for the "
636 				    "'%s' key of the '%s' repo",
637 				    key, rname);
638 				return;
639 			}
640 			pubkey = ucl_object_tostring(cur);
641 		} else if (strcasecmp(key, "mirror_type") == 0) {
642 			if (cur->type != UCL_STRING) {
643 				pkg_emit_error("Expecting a string for the "
644 				    "'%s' key of the '%s' repo",
645 				    key, rname);
646 				return;
647 			}
648 			mirror_type = ucl_object_tostring(cur);
649 		} else if (strcasecmp(key, "signature_type") == 0) {
650 			if (cur->type != UCL_STRING) {
651 				pkg_emit_error("Expecting a string for the "
652 				    "'%s' key of the '%s' repo",
653 				    key, rname);
654 				return;
655 			}
656 			signature_type = ucl_object_tostring(cur);
657 		} else if (strcasecmp(key, "fingerprints") == 0) {
658 			if (cur->type != UCL_STRING) {
659 				pkg_emit_error("Expecting a string for the "
660 				    "'%s' key of the '%s' repo",
661 				    key, rname);
662 				return;
663 			}
664 			fingerprints = ucl_object_tostring(cur);
665 		} else if (strcasecmp(key, "type") == 0) {
666 			if (cur->type != UCL_STRING) {
667 				pkg_emit_error("Expecting a string for the "
668 					"'%s' key of the '%s' repo",
669 					key, rname);
670 				return;
671 			}
672 			type = ucl_object_tostring(cur);
673 		} else if (strcasecmp(key, "ip_version") == 0) {
674 			if (cur->type != UCL_INT) {
675 				pkg_emit_error("Expecting a integer for the "
676 					"'%s' key of the '%s' repo",
677 					key, rname);
678 				return;
679 			}
680 			use_ipvx = ucl_object_toint(cur);
681 			if (use_ipvx != 4 && use_ipvx != 6)
682 				use_ipvx = 0;
683 		} else if (strcasecmp(key, "priority") == 0) {
684 			if (cur->type != UCL_INT) {
685 				pkg_emit_error("Expecting a integer for the "
686 					"'%s' key of the '%s' repo",
687 					key, rname);
688 				return;
689 			}
690 			priority = ucl_object_toint(cur);
691 		} else if (strcasecmp(key, "env") == 0) {
692 			if (cur->type != UCL_OBJECT) {
693 				pkg_emit_error("Expecting an object for the "
694 					"'%s' key of the '%s' repo",
695 					key, rname);
696 			}
697 			env = cur;
698 		}
699 	}
700 
701 	if (r == NULL && url == NULL) {
702 		pkg_debug(1, "No repo and no url for %s", rname);
703 		return;
704 	}
705 
706 	if (r == NULL)
707 		r = pkg_repo_new(rname, url, type);
708 	else
709 		pkg_repo_overwrite(r, rname, url, type);
710 
711 	if (signature_type != NULL) {
712 		if (strcasecmp(signature_type, "pubkey") == 0)
713 			r->signature_type = SIG_PUBKEY;
714 		else if (strcasecmp(signature_type, "fingerprints") == 0)
715 			r->signature_type = SIG_FINGERPRINT;
716 		else
717 			r->signature_type = SIG_NONE;
718 	}
719 
720 
721 	if (fingerprints != NULL) {
722 		free(r->fingerprints);
723 		r->fingerprints = xstrdup(fingerprints);
724 	}
725 
726 	if (pubkey != NULL) {
727 		free(r->pubkey);
728 		r->pubkey = xstrdup(pubkey);
729 	}
730 
731 	r->enable = enable;
732 	r->priority = priority;
733 
734 	if (mirror_type != NULL) {
735 		if (strcasecmp(mirror_type, "srv") == 0)
736 			r->mirror_type = SRV;
737 		else if (strcasecmp(mirror_type, "http") == 0)
738 			r->mirror_type = HTTP;
739 		else
740 			r->mirror_type = NOMIRROR;
741 	}
742 
743 	if ((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
744 		use_ipvx = 4;
745 	else if ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)
746 		use_ipvx = 6;
747 
748 	if (use_ipvx != 4 && use_ipvx != 6)
749 		use_ipvx = pkg_object_int(pkg_config_get("IP_VERSION"));
750 
751 	if (use_ipvx == 4)
752 		r->flags = REPO_FLAGS_USE_IPV4;
753 	else if (use_ipvx == 6)
754 		r->flags = REPO_FLAGS_USE_IPV6;
755 
756 	if (env != NULL) {
757 		it = NULL;
758 		while ((cur = ucl_iterate_object(env, &it, true))) {
759 			kv = pkg_kv_new(ucl_object_key(cur),
760 			    ucl_object_tostring_forced(cur));
761 			DL_APPEND(r->env, kv);
762 		}
763 	}
764 }
765 
766 static void
add_repo_obj(const ucl_object_t * obj,const char * file,pkg_init_flags flags)767 add_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
768 {
769 	struct pkg_repo *r;
770 	const char *key;
771 
772 	key = ucl_object_key(obj);
773 	pkg_debug(1, "PkgConfig: parsing repo key '%s' in file '%s'", key, file);
774 	r = pkg_repo_find(key);
775 	if (r != NULL)
776 		pkg_debug(1, "PkgConfig: overwriting repository %s", key);
777        add_repo(obj, r, key, flags);
778 }
779 
780 static void
walk_repo_obj(const ucl_object_t * obj,const char * file,pkg_init_flags flags)781 walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
782 {
783 	const ucl_object_t *cur;
784 	ucl_object_iter_t it = NULL;
785 	struct pkg_repo *r;
786 	const char *key;
787 
788 	while ((cur = ucl_iterate_object(obj, &it, true))) {
789 		key = ucl_object_key(cur);
790 		pkg_debug(1, "PkgConfig: parsing key '%s'", key);
791 		r = pkg_repo_find(key);
792 		if (r != NULL)
793 			pkg_debug(1, "PkgConfig: overwriting repository %s", key);
794 		if (cur->type == UCL_OBJECT)
795 			add_repo(cur, r, key, flags);
796 		else
797 			pkg_emit_error("Ignoring bad configuration entry in %s: %s",
798 			    file, ucl_object_emit(cur, UCL_EMIT_YAML));
799 	}
800 }
801 
802 static void
load_repo_file(int dfd,const char * repodir,const char * repofile,pkg_init_flags flags,struct os_info * oi)803 load_repo_file(int dfd, const char *repodir, const char *repofile,
804     pkg_init_flags flags, struct os_info *oi)
805 {
806 	struct ucl_parser *p;
807 	ucl_object_t *obj = NULL;
808 	const char *myarch = NULL;
809 	const char *myarch_legacy = NULL;
810 	int fd;
811 
812 	p = ucl_parser_new(0);
813 
814 	myarch = pkg_object_string(pkg_config_get("ABI"));
815 	ucl_parser_register_variable (p, "ABI", myarch);
816 
817 	myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
818 	ucl_parser_register_variable (p, "ALTABI", myarch_legacy);
819 #ifdef __FreeBSD__
820 	ucl_parser_register_variable(p, "OSVERSION", myosversion);
821 #endif
822 	if (oi->name != NULL) {
823 		ucl_parser_register_variable(p, "OSNAME", oi->name);
824 	}
825 	if (oi->version != NULL) {
826 		ucl_parser_register_variable(p, "RELEASE", oi->version);
827 	}
828 	if (oi->version_major != NULL) {
829 		ucl_parser_register_variable(p, "VERSION_MAJOR", oi->version_major);
830 	}
831 	if (oi->version_minor != NULL) {
832 		ucl_parser_register_variable(p, "VERSION_MINOR", oi->version_minor);
833 	}
834 	if (oi->arch != NULL) {
835 		ucl_parser_register_variable(p, "ARCH", oi->arch);
836 	}
837 
838 	errno = 0;
839 	obj = NULL;
840 
841 	pkg_debug(1, "PKgConfig: loading %s/%s", repodir, repofile);
842 	fd = openat(dfd, repofile, O_RDONLY);
843 	if (fd == -1) {
844 		pkg_errno("Unable to open '%s/%s'", repodir, repofile);
845 		return;
846 	}
847 	if (!ucl_parser_add_fd(p, fd)) {
848 		pkg_emit_error("Error parsing: '%s/%s': %s", repodir,
849 		    repofile, ucl_parser_get_error(p));
850 		ucl_parser_free(p);
851 		close(fd);
852 		return;
853 	}
854 	close(fd);
855 
856 	obj = ucl_parser_get_object(p);
857 	if (obj == NULL)
858 		return;
859 
860 	if (obj->type == UCL_OBJECT)
861 		walk_repo_obj(obj, repofile, flags);
862 
863 	ucl_object_unref(obj);
864 }
865 
866 static int
configfile(const struct dirent * dp)867 configfile(const struct dirent *dp)
868 {
869 	const char *p;
870 	size_t n;
871 
872 	if (dp->d_name[0] == '.')
873 		return (0);
874 
875 	n = strlen(dp->d_name);
876 	if (n <= 5)
877 		return (0);
878 
879 	p = &dp->d_name[n - 5];
880 	if (strcmp(p, ".conf") != 0)
881 		return (0);
882 	return (1);
883 }
884 
885 static void
load_repo_files(const char * repodir,pkg_init_flags flags,struct os_info * oi)886 load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)
887 {
888 	struct dirent **ent;
889 	int nents, i, fd;
890 
891 	pkg_debug(1, "PkgConfig: loading repositories in %s", repodir);
892 	if ((fd = open(repodir, O_DIRECTORY|O_CLOEXEC)) == -1)
893 		return;
894 
895 	nents = scandir(repodir, &ent, configfile, alphasort);
896 	for (i = 0; i < nents; i++) {
897 		load_repo_file(fd, repodir, ent[i]->d_name, flags, oi);
898 		free(ent[i]);
899 	}
900 	if (nents >= 0)
901 		free(ent);
902 	close(fd);
903 }
904 
905 static void
load_repositories(const char * repodir,pkg_init_flags flags,struct os_info * oi)906 load_repositories(const char *repodir, pkg_init_flags flags, struct os_info *oi)
907 {
908 	const pkg_object *reposlist, *cur;
909 	pkg_iter it = NULL;
910 
911 	if (repodir != NULL) {
912 		load_repo_files(repodir, flags, oi);
913 		return;
914 	}
915 
916 	reposlist = pkg_config_get("REPOS_DIR");
917 	while ((cur = pkg_object_iterate(reposlist, &it)))
918 		load_repo_files(pkg_object_string(cur), flags, oi);
919 }
920 
921 bool
pkg_compiled_for_same_os_major(void)922 pkg_compiled_for_same_os_major(void)
923 {
924 #ifdef OSMAJOR
925 	const char	*myabi;
926 	int		 osmajor;
927 
928 	if (getenv("IGNORE_OSMAJOR") != NULL)
929 		return (true);
930 
931 	myabi = pkg_object_string(pkg_config_get("ABI"));
932 	myabi = strchr(myabi,':');
933 	if (myabi == NULL) {
934 		pkg_emit_error("Invalid ABI");
935 		return (false);
936 	}
937 	myabi++;
938 
939 	osmajor = (int) strtol(myabi, NULL, 10);
940 
941 	return (osmajor == OSMAJOR);
942 #else
943 	return (true);		/* Can't tell, so assume yes  */
944 #endif
945 }
946 
947 
948 int
pkg_init(const char * path,const char * reposdir)949 pkg_init(const char *path, const char *reposdir)
950 {
951 	return (pkg_ini(path, reposdir, 0));
952 }
953 
954 static const char *
type_to_string(int type)955 type_to_string(int type)
956 {
957 	if (type == UCL_ARRAY)
958 		return ("array");
959 	if (type == UCL_OBJECT)
960 		return ("object");
961 	if (type == UCL_STRING)
962 		return ("string");
963 	if (type == UCL_INT)
964 		return ("integer");
965 	if (type == UCL_BOOLEAN)
966 		return ("boolean");
967 	return ("unknown");
968 }
969 int
pkg_ini(const char * path,const char * reposdir,pkg_init_flags flags)970 pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
971 {
972 	struct ucl_parser *p = NULL;
973 	size_t i;
974 	const char *val = NULL;
975 	const char *buf, *walk, *value, *key, *k;
976 	const char *evkey = NULL;
977 	const char *nsname = NULL;
978 	const char *metalog = NULL;
979 	const char *useragent = NULL;
980 	const char *evpipe = NULL;
981 	const char *url;
982 	struct pkg_repo *repo = NULL;
983 	const ucl_object_t *cur, *object;
984 	ucl_object_t *obj = NULL, *o, *ncfg;
985 	ucl_object_iter_t it = NULL;
986 	xstring *ukey = NULL;
987 	bool fatal_errors = false;
988 	int conffd = -1;
989 	char *tmp = NULL;
990 	struct os_info oi;
991 	size_t ukeylen;
992 	int err = EPKG_OK;
993 
994 	k = NULL;
995 	o = NULL;
996 	if (ctx.rootfd == -1 && (ctx.rootfd = open("/", O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
997 		pkg_emit_error("Impossible to open /");
998 		/* Note: Not goto out since oi.arch hasn't been initialized yet. */
999 		return (EPKG_FATAL);
1000 	}
1001 
1002 	memset(&oi, 0, sizeof(oi));
1003 	pkg_get_myarch(myabi, BUFSIZ, &oi);
1004 	pkg_get_myarch_legacy(myabi_legacy, BUFSIZ);
1005 #ifdef __FreeBSD__
1006 	ctx.osversion = oi.osversion;
1007 	snprintf(myosversion, sizeof(myosversion), "%d", ctx.osversion);
1008 #endif
1009 	if (parsed != false) {
1010 		pkg_emit_error("pkg_init() must only be called once");
1011 		err = EPKG_FATAL;
1012 		goto out;
1013 	}
1014 
1015 	if (((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4) &&
1016 	    ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)) {
1017 		pkg_emit_error("Invalid flags for pkg_init()");
1018 		err = EPKG_FATAL;
1019 		goto out;
1020 	}
1021 
1022 	config = ucl_object_typed_new(UCL_OBJECT);
1023 
1024 	for (i = 0; i < c_size; i++) {
1025 		switch (c[i].type) {
1026 		case PKG_STRING:
1027 			tmp = NULL;
1028 			if (c[i].def != NULL && c[i].def[0] == '/' &&
1029 			    ctx.pkg_rootdir != NULL) {
1030 				xasprintf(&tmp, "%s%s", ctx.pkg_rootdir, c[i].def);
1031 			}
1032 			obj = ucl_object_fromstring_common(
1033 			    c[i].def != NULL ? tmp != NULL ? tmp : c[i].def : "", 0, UCL_STRING_TRIM);
1034 			free(tmp);
1035 			ucl_object_insert_key(config, obj,
1036 			    c[i].key, strlen(c[i].key), false);
1037 			break;
1038 		case PKG_INT:
1039 			ucl_object_insert_key(config,
1040 			    ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_INT),
1041 			    c[i].key, strlen(c[i].key), false);
1042 			break;
1043 		case PKG_BOOL:
1044 			ucl_object_insert_key(config,
1045 			    ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_BOOLEAN),
1046 			    c[i].key, strlen(c[i].key), false);
1047 			break;
1048 		case PKG_OBJECT:
1049 			obj = ucl_object_typed_new(UCL_OBJECT);
1050 			if (c[i].def != NULL) {
1051 				walk = buf = c[i].def;
1052 				while ((buf = strchr(buf, ',')) != NULL) {
1053 					key = walk;
1054 					value = walk;
1055 					while (*value != ',') {
1056 						if (*value == '=')
1057 							break;
1058 						value++;
1059 					}
1060 					ucl_object_insert_key(obj,
1061 					    ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM),
1062 					    key, value - key, false);
1063 					buf++;
1064 					walk = buf;
1065 				}
1066 				key = walk;
1067 				value = walk;
1068 				while (*value != ',') {
1069 					if (*value == '=')
1070 						break;
1071 					value++;
1072 				}
1073 				if (o == NULL)
1074 					o = ucl_object_typed_new(UCL_OBJECT);
1075 				ucl_object_insert_key(o,
1076 				    ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM),
1077 				    key, value - key, false);
1078 			}
1079 			ucl_object_insert_key(config, obj,
1080 			    c[i].key, strlen(c[i].key), false);
1081 			break;
1082 		case PKG_ARRAY:
1083 			obj = ucl_object_typed_new(UCL_ARRAY);
1084 			if (c[i].def != NULL) {
1085 				walk = buf = c[i].def;
1086 				while ((buf = strchr(buf, ',')) != NULL) {
1087 					ucl_array_append(obj,
1088 					    ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM));
1089 					buf++;
1090 					walk = buf;
1091 				}
1092 				ucl_array_append(obj,
1093 				    ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM));
1094 			}
1095 			ucl_object_insert_key(config, obj,
1096 			    c[i].key, strlen(c[i].key), false);
1097 			break;
1098 		}
1099 	}
1100 
1101 	if (path == NULL)
1102 		conffd = openat(ctx.rootfd, &PREFIX"/etc/pkg.conf"[1], 0);
1103 	else
1104 		conffd = open(path, O_RDONLY);
1105 	if (conffd == -1 && errno != ENOENT) {
1106 		pkg_errno("Cannot open %s/%s",
1107 		    ctx.pkg_rootdir != NULL ? ctx.pkg_rootdir : "",
1108 		    path);
1109 	}
1110 
1111 	p = ucl_parser_new(0);
1112 	ucl_parser_register_variable (p, "ABI", myabi);
1113 	ucl_parser_register_variable (p, "ALTABI", myabi_legacy);
1114 #ifdef __FreeBSD__
1115 	ucl_parser_register_variable(p, "OSVERSION", myosversion);
1116 #endif
1117 	if (oi.name != NULL) {
1118 		ucl_parser_register_variable(p, "OSNAME", oi.name);
1119 	}
1120 	if (oi.version != NULL) {
1121 		ucl_parser_register_variable(p, "RELEASE", oi.version);
1122 	}
1123 	if (oi.version_major != NULL) {
1124 		ucl_parser_register_variable(p, "VERSION_MAJOR", oi.version_major);
1125 	}
1126 	if (oi.version_minor != NULL) {
1127 		ucl_parser_register_variable(p, "VERSION_MINOR", oi.version_minor);
1128 	}
1129 	if (oi.arch != NULL) {
1130 		ucl_parser_register_variable(p, "ARCH", oi.arch);
1131 	}
1132 
1133 	errno = 0;
1134 	obj = NULL;
1135 	if (conffd != -1) {
1136 		if (!ucl_parser_add_fd(p, conffd)) {
1137 			pkg_emit_error("Invalid configuration file: %s", ucl_parser_get_error(p));
1138 		}
1139 		close(conffd);
1140 	}
1141 
1142 	obj = ucl_parser_get_object(p);
1143 	ncfg = NULL;
1144 	ukey = NULL;
1145 	while (obj != NULL && (cur = ucl_iterate_object(obj, &it, true))) {
1146 		xstring_renew(ukey);
1147 		key = ucl_object_key(cur);
1148 		for (i = 0; key[i] != '\0'; i++)
1149 			fputc(toupper(key[i]), ukey->fp);
1150 		fflush(ukey->fp);
1151 		ukeylen = strlen(ukey->buf);
1152 		object = ucl_object_find_keyl(config, ukey->buf, ukeylen);
1153 
1154 		if (strncasecmp(ukey->buf, "PACKAGESITE", ukeylen) == 0 ||
1155 		    strncasecmp(ukey->buf, "PUBKEY", ukeylen) == 0 ||
1156 		    strncasecmp(ukey->buf, "MIRROR_TYPE", ukeylen) == 0) {
1157 			pkg_emit_error("%s in pkg.conf is no longer "
1158 			    "supported.  Convert to the new repository style."
1159 			    "  See pkg.conf(5)", ukey->buf);
1160 			fatal_errors = true;
1161 			continue;
1162 		}
1163 
1164 		/* ignore unknown keys */
1165 		if (object == NULL)
1166 			continue;
1167 
1168 		if (object->type != cur->type) {
1169 			pkg_emit_error("Malformed key %s, got '%s' expecting "
1170 			    "'%s', ignoring", key,
1171 			    type_to_string(cur->type),
1172 			    type_to_string(object->type));
1173 			continue;
1174 		}
1175 
1176 		if (ncfg == NULL)
1177 			ncfg = ucl_object_typed_new(UCL_OBJECT);
1178 		ucl_object_insert_key(ncfg, ucl_object_copy(cur), ukey->buf,
1179 		    ukeylen, true);
1180 	}
1181 	xstring_free(ukey);
1182 
1183 	if (fatal_errors) {
1184 		ucl_object_unref(ncfg);
1185 		ucl_parser_free(p);
1186 		err = EPKG_FATAL;
1187 		goto out;
1188 	}
1189 
1190 	if (ncfg != NULL) {
1191 		it = NULL;
1192 		while (( cur = ucl_iterate_object(ncfg, &it, true))) {
1193 			key = ucl_object_key(cur);
1194 			ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true);
1195 		}
1196 	}
1197 
1198 	ncfg = NULL;
1199 	it = NULL;
1200 	while ((cur = ucl_iterate_object(config, &it, true))) {
1201 		o = NULL;
1202 		key = ucl_object_key(cur);
1203 		val = getenv(key);
1204 		if (val == NULL)
1205 			continue;
1206 		switch (cur->type) {
1207 		case UCL_STRING:
1208 			o = ucl_object_fromstring_common(val, 0, UCL_STRING_TRIM);
1209 			break;
1210 		case UCL_INT:
1211 			o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_INT);
1212 			if (o->type != UCL_INT) {
1213 				pkg_emit_error("Invalid type for environment "
1214 				    "variable %s, got %s, while expecting an integer",
1215 				    key, val);
1216 				ucl_object_unref(o);
1217 				continue;
1218 			}
1219 			break;
1220 		case UCL_BOOLEAN:
1221 			o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_BOOLEAN);
1222 			if (o->type != UCL_BOOLEAN) {
1223 				pkg_emit_error("Invalid type for environment "
1224 				    "variable %s, got %s, while expecting a boolean",
1225 				    key, val);
1226 				ucl_object_unref(o);
1227 				continue;
1228 			}
1229 			break;
1230 		case UCL_OBJECT:
1231 			o = ucl_object_typed_new(UCL_OBJECT);
1232 			walk = buf = val;
1233 			while ((buf = strchr(buf, ',')) != NULL) {
1234 				k = walk;
1235 				value = walk;
1236 				while (*value != ',') {
1237 					if (*value == '=')
1238 						break;
1239 					value++;
1240 				}
1241 				ucl_object_insert_key(o,
1242 				    ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM),
1243 				    k, value - k, false);
1244 				buf++;
1245 				walk = buf;
1246 			}
1247 			k = walk;
1248 			value = walk;
1249 			while (*value != '\0') {
1250 				if (*value == '=')
1251 					break;
1252 				value++;
1253 			}
1254 			ucl_object_insert_key(o,
1255 			    ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM),
1256 			    k, value - k, false);
1257 			break;
1258 		case UCL_ARRAY:
1259 			o = ucl_object_typed_new(UCL_ARRAY);
1260 			walk = buf = val;
1261 			while ((buf = strchr(buf, ',')) != NULL) {
1262 				ucl_array_append(o,
1263 				    ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM));
1264 				buf++;
1265 				walk = buf;
1266 			}
1267 			ucl_array_append(o,
1268 			    ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM));
1269 			break;
1270 		default:
1271 			/* ignore other types */
1272 			break;
1273 		}
1274 		if (o != NULL) {
1275 			if (ncfg == NULL)
1276 				ncfg = ucl_object_typed_new(UCL_OBJECT);
1277 			ucl_object_insert_key(ncfg, o, key, strlen(key), true);
1278 		}
1279 	}
1280 
1281 	if (ncfg != NULL) {
1282 		it = NULL;
1283 		while (( cur = ucl_iterate_object(ncfg, &it, true))) {
1284 			key = ucl_object_key(cur);
1285 			ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true);
1286 		}
1287 		ucl_object_unref(ncfg);
1288 	}
1289 
1290 	disable_plugins_if_static();
1291 
1292 	parsed = true;
1293 	ucl_object_unref(obj);
1294 	ucl_parser_free(p);
1295 
1296 	if (pkg_object_string(pkg_config_get("ABI")) == NULL ||
1297 	    strcmp(pkg_object_string(pkg_config_get("ABI")), "unknown") == 0) {
1298 		pkg_emit_error("Unable to determine ABI");
1299 		err = EPKG_FATAL;
1300 		goto out;
1301 	}
1302 
1303 	pkg_debug(1, "%s", "pkg initialized");
1304 
1305 #ifdef __FreeBSD__
1306 	ctx.osversion = pkg_object_int(pkg_config_get("OSVERSION"));
1307 #endif
1308 	/* Start the event pipe */
1309 	evpipe = pkg_object_string(pkg_config_get("EVENT_PIPE"));
1310 	if (evpipe != NULL)
1311 		connect_evpipe(evpipe);
1312 
1313 	ctx.debug_level = pkg_object_int(pkg_config_get("DEBUG_LEVEL"));
1314 	ctx.developer_mode = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));
1315 	ctx.dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
1316 	ctx.cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
1317 	ctx.backup_libraries = pkg_object_bool(pkg_config_get("BACKUP_LIBRARIES"));
1318 	ctx.backup_library_path = pkg_object_string(pkg_config_get("BACKUP_LIBRARY_PATH"));
1319 	ctx.triggers = pkg_object_bool(pkg_config_get("PKG_TRIGGERS_ENABLE"));
1320 	ctx.triggers_path = pkg_object_string(pkg_config_get("PKG_TRIGGERS_DIR"));
1321 	ctx.compression_level = pkg_object_int(pkg_config_get("COMPRESSION_LEVEL"));
1322 	ctx.archive_symlink = pkg_object_bool(pkg_config_get("ARCHIVE_SYMLINK"));
1323 	ctx.repo_accept_legacy_pkg = pkg_object_bool(pkg_config_get("REPO_ACCEPT_LEGACY_PKG"));
1324 
1325 	it = NULL;
1326 	object = ucl_object_find_key(config, "PKG_ENV");
1327 	while ((cur = ucl_iterate_object(object, &it, true))) {
1328 		evkey = ucl_object_key(cur);
1329 		pkg_debug(1, "Setting env var: %s", evkey);
1330 		if (evkey != NULL && evkey[0] != '\0')
1331 			setenv(evkey, ucl_object_tostring_forced(cur), 1);
1332 	}
1333 
1334 	/* Set user-agent */
1335 	useragent = pkg_object_string(pkg_config_get("HTTP_USER_AGENT"));
1336 	if (useragent != NULL)
1337 		setenv("HTTP_USER_AGENT", useragent, 1);
1338 	else
1339 		setenv("HTTP_USER_AGENT", "pkg/"PKGVERSION, 1);
1340 
1341 	/* load the repositories */
1342 	load_repositories(reposdir, flags, &oi);
1343 
1344 	object = ucl_object_find_key(config, "REPOSITORIES");
1345 	while ((cur = ucl_iterate_object(object, &it, true))) {
1346 		add_repo_obj(cur, path, flags);
1347 	}
1348 
1349 	/* validate the different scheme */
1350 	while (pkg_repos(&repo) == EPKG_OK) {
1351 		object = ucl_object_find_key(config, "VALID_URL_SCHEME");
1352 		url = pkg_repo_url(repo);
1353 		buf = strstr(url, ":/");
1354 		if (buf == NULL) {
1355 			pkg_emit_error("invalid url: %s", url);
1356 			err = EPKG_FATAL;
1357 			goto out;
1358 		}
1359 		fatal_errors = true;
1360 		it = NULL;
1361 		while ((cur = ucl_iterate_object(object, &it, true))) {
1362 			if (strncmp(url, ucl_object_tostring_forced(cur),
1363 			    buf - url) == 0) {
1364 				fatal_errors = false;
1365 				break;
1366 			}
1367 		}
1368 
1369 		if (fatal_errors) {
1370 			pkg_emit_error("invalid scheme %.*s", (int)(buf - url), url);
1371 			err = EPKG_FATAL;
1372 			goto out;
1373 		}
1374 	}
1375 
1376 	/* bypass resolv.conf with specified NAMESERVER if any */
1377 	nsname = pkg_object_string(pkg_config_get("NAMESERVER"));
1378 	if (nsname != NULL && set_nameserver(nsname) != 0)
1379 			pkg_emit_error("Unable to set nameserver, ignoring");
1380 
1381 	/* Open metalog */
1382 	metalog = pkg_object_string(pkg_config_get("METALOG"));
1383 	if (metalog != NULL) {
1384 		if(metalog_open(metalog) != EPKG_OK) {
1385 			err = EPKG_FATAL;
1386 			goto out;
1387 		}
1388 	}
1389 
1390 out:
1391 	free(oi.arch);
1392 	free(oi.name);
1393 	return err;
1394 
1395 }
1396 
1397 static struct pkg_repo_ops*
pkg_repo_find_type(const char * type)1398 pkg_repo_find_type(const char *type)
1399 {
1400 	struct pkg_repo_ops *found = NULL, **cur;
1401 
1402 	/* Default repo type */
1403 	if (type == NULL)
1404 		return (pkg_repo_find_type("binary"));
1405 
1406 	cur = &repos_ops[0];
1407 	while (*cur != NULL) {
1408 		if (strcasecmp(type, (*cur)->type) == 0) {
1409 			found = *cur;
1410 		}
1411 		cur ++;
1412 	}
1413 
1414 	if (found == NULL)
1415 		return (pkg_repo_find_type("binary"));
1416 
1417 	return (found);
1418 }
1419 
1420 static struct pkg_repo *
pkg_repo_new(const char * name,const char * url,const char * type)1421 pkg_repo_new(const char *name, const char *url, const char *type)
1422 {
1423 	struct pkg_repo *r;
1424 
1425 	r = xcalloc(1, sizeof(struct pkg_repo));
1426 	r->ops = pkg_repo_find_type(type);
1427 	r->url = xstrdup(url);
1428 	r->signature_type = SIG_NONE;
1429 	r->mirror_type = NOMIRROR;
1430 	r->enable = true;
1431 	r->meta = pkg_repo_meta_default();
1432 	r->name = xstrdup(name);
1433 	HASH_ADD_KEYPTR(hh, repos, r->name, strlen(r->name), r);
1434 
1435 	return (r);
1436 }
1437 
1438 static void
pkg_repo_overwrite(struct pkg_repo * r,const char * name,const char * url,const char * type)1439 pkg_repo_overwrite(struct pkg_repo *r, const char *name, const char *url,
1440     const char *type)
1441 {
1442 
1443 	free(r->name);
1444 	r->name = xstrdup(name);
1445 	if (url != NULL) {
1446 		free(r->url);
1447 		r->url = xstrdup(url);
1448 	}
1449 	r->ops = pkg_repo_find_type(type);
1450 	HASH_DEL(repos, r);
1451 	HASH_ADD_KEYPTR(hh, repos, r->name, strlen(r->name), r);
1452 }
1453 
1454 static void
pkg_repo_free(struct pkg_repo * r)1455 pkg_repo_free(struct pkg_repo *r)
1456 {
1457 	struct pkg_kv *kv, *tmp;
1458 
1459 	free(r->url);
1460 	free(r->name);
1461 	free(r->pubkey);
1462 	free(r->meta);
1463 	if (r->ssh != NULL) {
1464 		fprintf(r->ssh, "quit\n");
1465 		pclose(r->ssh);
1466 	}
1467 	LL_FOREACH_SAFE(r->env, kv, tmp) {
1468 		LL_DELETE(r->env, kv);
1469 		pkg_kv_free(kv);
1470 	}
1471 	free(r);
1472 }
1473 
1474 void
pkg_shutdown(void)1475 pkg_shutdown(void)
1476 {
1477 	if (!parsed) {
1478 		pkg_emit_error("pkg_shutdown() must be called after pkg_init()");
1479 		_exit(EXIT_FAILURE);
1480 		/* NOTREACHED */
1481 	}
1482 
1483 	metalog_close();
1484 	ucl_object_unref(config);
1485 	HASH_FREE(repos, pkg_repo_free);
1486 
1487 	if (ctx.rootfd != -1) {
1488 		close(ctx.rootfd);
1489 		ctx.rootfd = -1;
1490 	}
1491 	if (ctx.cachedirfd != -1) {
1492 		close(ctx.cachedirfd);
1493 		ctx.cachedirfd = -1;
1494 	}
1495 	if (ctx.pkg_dbdirfd != -1) {
1496 		close(ctx.pkg_dbdirfd);
1497 		ctx.pkg_dbdirfd = -1;
1498 	}
1499 
1500 	parsed = false;
1501 
1502 	return;
1503 }
1504 
1505 int
pkg_repos_total_count(void)1506 pkg_repos_total_count(void)
1507 {
1508 
1509 	return (HASH_COUNT(repos));
1510 }
1511 
1512 int
pkg_repos_activated_count(void)1513 pkg_repos_activated_count(void)
1514 {
1515 	struct pkg_repo *r = NULL;
1516 	int count = 0;
1517 
1518 	for (r = repos; r != NULL; r = r->hh.next) {
1519 		if (r->enable)
1520 			count++;
1521 	}
1522 
1523 	return (count);
1524 }
1525 
1526 int
pkg_repos(struct pkg_repo ** r)1527 pkg_repos(struct pkg_repo **r)
1528 {
1529 	HASH_NEXT(repos, (*r));
1530 }
1531 
1532 const char *
pkg_repo_url(struct pkg_repo * r)1533 pkg_repo_url(struct pkg_repo *r)
1534 {
1535 	return (r->url);
1536 }
1537 
1538 /* The basename of the sqlite DB file and the database name */
1539 const char *
pkg_repo_name(struct pkg_repo * r)1540 pkg_repo_name(struct pkg_repo *r)
1541 {
1542 	return (r->name);
1543 }
1544 
1545 const char *
pkg_repo_key(struct pkg_repo * r)1546 pkg_repo_key(struct pkg_repo *r)
1547 {
1548 	return (r->pubkey);
1549 }
1550 
1551 const char *
pkg_repo_fingerprints(struct pkg_repo * r)1552 pkg_repo_fingerprints(struct pkg_repo *r)
1553 {
1554 	return (r->fingerprints);
1555 }
1556 
1557 signature_t
pkg_repo_signature_type(struct pkg_repo * r)1558 pkg_repo_signature_type(struct pkg_repo *r)
1559 {
1560 	return (r->signature_type);
1561 }
1562 
1563 bool
pkg_repo_enabled(struct pkg_repo * r)1564 pkg_repo_enabled(struct pkg_repo *r)
1565 {
1566 	return (r->enable);
1567 }
1568 
1569 mirror_t
pkg_repo_mirror_type(struct pkg_repo * r)1570 pkg_repo_mirror_type(struct pkg_repo *r)
1571 {
1572 	return (r->mirror_type);
1573 }
1574 
1575 unsigned int
pkg_repo_priority(struct pkg_repo * r)1576 pkg_repo_priority(struct pkg_repo *r)
1577 {
1578 	return (r->priority);
1579 }
1580 
1581 unsigned int
pkg_repo_ip_version(struct pkg_repo * r)1582 pkg_repo_ip_version(struct pkg_repo *r)
1583 {
1584 	if ((r->flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
1585 		return 4;
1586 	else if ((r->flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)
1587 		return 6;
1588 	else
1589 		return 0;
1590 }
1591 
1592 /* Locate the repo by the file basename / database name */
1593 struct pkg_repo *
pkg_repo_find(const char * reponame)1594 pkg_repo_find(const char *reponame)
1595 {
1596 	struct pkg_repo *r;
1597 
1598 	HASH_FIND_STR(repos, reponame, r);
1599 	return (r);
1600 }
1601 
1602 int64_t
pkg_set_debug_level(int64_t new_debug_level)1603 pkg_set_debug_level(int64_t new_debug_level) {
1604 	int64_t old_debug_level = ctx.debug_level;
1605 
1606 	ctx.debug_level = new_debug_level;
1607 	return old_debug_level;
1608 }
1609 
1610 int
pkg_set_rootdir(const char * rootdir)1611 pkg_set_rootdir(const char *rootdir) {
1612 	if (pkg_initialized())
1613 		return (EPKG_FATAL);
1614 
1615 	if (ctx.rootfd != -1)
1616 		close(ctx.rootfd);
1617 
1618 	if ((ctx.rootfd = open(rootdir, O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
1619 		pkg_emit_error("Impossible to open %s", rootdir);
1620 		return (EPKG_FATAL);
1621 	}
1622 	ctx.pkg_rootdir = rootdir;
1623 	ctx.defer_triggers = true;
1624 
1625 	return (EPKG_OK);
1626 }
1627 
1628 const char *
pkg_get_cachedir(void)1629 pkg_get_cachedir(void)
1630 {
1631 
1632 	return (ctx.cachedir);
1633 }
1634 
1635 int
pkg_get_cachedirfd(void)1636 pkg_get_cachedirfd(void)
1637 {
1638 
1639 	if (ctx.cachedirfd == -1) {
1640 		/*
1641 		 * do not check the value as if we cannot open it means
1642 		 * it has not been created yet
1643 		 */
1644 		ctx.cachedirfd = open(ctx.cachedir, O_DIRECTORY|O_CLOEXEC);
1645 	}
1646 
1647 	return (ctx.cachedirfd);
1648 }
1649 
1650 int
pkg_get_dbdirfd(void)1651 pkg_get_dbdirfd(void)
1652 {
1653 
1654 	if (ctx.pkg_dbdirfd == -1) {
1655 		/*
1656 		 * do not check the value as if we cannot open it means
1657 		 * it has not been created yet
1658 		 */
1659 		ctx.pkg_dbdirfd = open(ctx.dbdir, O_DIRECTORY|O_CLOEXEC);
1660 	}
1661 
1662 	return (ctx.pkg_dbdirfd);
1663 }
1664