New upstream version 6.8p0
Marco d'Itri
3 years ago
9 | 9 | Platform Requirements |
10 | 10 | --------------------- |
11 | 11 | |
12 | At the time of writing the Portable version is known to build and work on: | |
12 | At the time of writing the portable version is known to build and work on: | |
13 | 13 | |
14 | 14 | - OpenBSD-current |
15 | - Linux (Debian 9) | |
15 | - Linux (Alpine 3.12, Debian 9, Debian 10, Fedora 31, Fedora 32, Fedora 33, | |
16 | RHEL/CentOS 7, RHEL/CentOS 8) | |
16 | 17 | |
17 | 18 | Building |
18 | 19 | -------- |
44 | 44 | libcompat_la_SOURCES += strlcpy.c |
45 | 45 | endif |
46 | 46 | |
47 | if !HAVE_STRTONUM | |
48 | libcompat_la_SOURCES += strtonum.c | |
49 | endif | |
50 | ||
47 | 51 | if !HAVE_SETRESGID |
48 | 52 | libcompat_la_SOURCES += bsd-setresgid.c |
49 | 53 | endif |
107 | 107 | @HAVE_RECALLOCARRAY_FALSE@am__append_3 = recallocarray.c |
108 | 108 | @HAVE_STRLCAT_FALSE@am__append_4 = strlcat.c |
109 | 109 | @HAVE_STRLCPY_FALSE@am__append_5 = strlcpy.c |
110 | @HAVE_SETRESGID_FALSE@am__append_6 = bsd-setresgid.c | |
111 | @HAVE_SETRESUID_FALSE@am__append_7 = bsd-setresuid.c | |
110 | @HAVE_STRTONUM_FALSE@am__append_6 = strtonum.c | |
111 | @HAVE_SETRESGID_FALSE@am__append_7 = bsd-setresgid.c | |
112 | @HAVE_SETRESUID_FALSE@am__append_8 = bsd-setresuid.c | |
112 | 113 | subdir = compat |
113 | 114 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 |
114 | 115 | am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ |
124 | 125 | LTLIBRARIES = $(noinst_LTLIBRARIES) |
125 | 126 | libcompat_la_DEPENDENCIES = |
126 | 127 | am__libcompat_la_SOURCES_DIST = reallocarray.c recallocarray.c \ |
127 | strlcat.c strlcpy.c bsd-setresgid.c bsd-setresuid.c | |
128 | strlcat.c strlcpy.c strtonum.c bsd-setresgid.c bsd-setresuid.c | |
128 | 129 | @HAVE_REALLOCARRAY_FALSE@am__objects_1 = reallocarray.lo |
129 | 130 | @HAVE_RECALLOCARRAY_FALSE@am__objects_2 = recallocarray.lo |
130 | 131 | @HAVE_STRLCAT_FALSE@am__objects_3 = strlcat.lo |
131 | 132 | @HAVE_STRLCPY_FALSE@am__objects_4 = strlcpy.lo |
132 | @HAVE_SETRESGID_FALSE@am__objects_5 = bsd-setresgid.lo | |
133 | @HAVE_SETRESUID_FALSE@am__objects_6 = bsd-setresuid.lo | |
133 | @HAVE_STRTONUM_FALSE@am__objects_5 = strtonum.lo | |
134 | @HAVE_SETRESGID_FALSE@am__objects_6 = bsd-setresgid.lo | |
135 | @HAVE_SETRESUID_FALSE@am__objects_7 = bsd-setresuid.lo | |
134 | 136 | am_libcompat_la_OBJECTS = $(am__objects_1) $(am__objects_2) \ |
135 | 137 | $(am__objects_3) $(am__objects_4) $(am__objects_5) \ |
136 | $(am__objects_6) | |
138 | $(am__objects_6) $(am__objects_7) | |
137 | 139 | libcompat_la_OBJECTS = $(am_libcompat_la_OBJECTS) |
138 | 140 | AM_V_lt = $(am__v_lt_@AM_V@) |
139 | 141 | am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) |
141 | 143 | am__v_lt_1 = |
142 | 144 | libcompatnoopt_la_LIBADD = |
143 | 145 | am__libcompatnoopt_la_SOURCES_DIST = explicit_bzero.c |
144 | @HAVE_EXPLICIT_BZERO_FALSE@am__objects_7 = libcompatnoopt_la-explicit_bzero.lo | |
145 | am_libcompatnoopt_la_OBJECTS = $(am__objects_7) | |
146 | @HAVE_EXPLICIT_BZERO_FALSE@am__objects_8 = libcompatnoopt_la-explicit_bzero.lo | |
147 | am_libcompatnoopt_la_OBJECTS = $(am__objects_8) | |
146 | 148 | libcompatnoopt_la_OBJECTS = $(am_libcompatnoopt_la_OBJECTS) |
147 | 149 | libcompatnoopt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ |
148 | 150 | $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ |
167 | 169 | ./$(DEPDIR)/bsd-setresuid.Plo \ |
168 | 170 | ./$(DEPDIR)/libcompatnoopt_la-explicit_bzero.Plo \ |
169 | 171 | ./$(DEPDIR)/reallocarray.Plo ./$(DEPDIR)/recallocarray.Plo \ |
170 | ./$(DEPDIR)/strlcat.Plo ./$(DEPDIR)/strlcpy.Plo | |
172 | ./$(DEPDIR)/strlcat.Plo ./$(DEPDIR)/strlcpy.Plo \ | |
173 | ./$(DEPDIR)/strtonum.Plo | |
171 | 174 | am__mv = mv -f |
172 | 175 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ |
173 | 176 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
349 | 352 | |
350 | 353 | # other compatibility functions |
351 | 354 | libcompat_la_SOURCES = $(am__append_2) $(am__append_3) $(am__append_4) \ |
352 | $(am__append_5) $(am__append_6) $(am__append_7) | |
355 | $(am__append_5) $(am__append_6) $(am__append_7) \ | |
356 | $(am__append_8) | |
353 | 357 | libcompat_la_LIBADD = $(PLATFORM_LDADD) |
354 | 358 | all: all-am |
355 | 359 | |
415 | 419 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recallocarray.Plo@am__quote@ # am--include-marker |
416 | 420 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcat.Plo@am__quote@ # am--include-marker |
417 | 421 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Plo@am__quote@ # am--include-marker |
422 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtonum.Plo@am__quote@ # am--include-marker | |
418 | 423 | |
419 | 424 | $(am__depfiles_remade): |
420 | 425 | @$(MKDIR_P) $(@D) |
591 | 596 | -rm -f ./$(DEPDIR)/recallocarray.Plo |
592 | 597 | -rm -f ./$(DEPDIR)/strlcat.Plo |
593 | 598 | -rm -f ./$(DEPDIR)/strlcpy.Plo |
599 | -rm -f ./$(DEPDIR)/strtonum.Plo | |
594 | 600 | -rm -f Makefile |
595 | 601 | distclean-am: clean-am distclean-compile distclean-generic \ |
596 | 602 | distclean-tags |
643 | 649 | -rm -f ./$(DEPDIR)/recallocarray.Plo |
644 | 650 | -rm -f ./$(DEPDIR)/strlcat.Plo |
645 | 651 | -rm -f ./$(DEPDIR)/strlcpy.Plo |
652 | -rm -f ./$(DEPDIR)/strtonum.Plo | |
646 | 653 | -rm -f Makefile |
647 | 654 | maintainer-clean-am: distclean-am maintainer-clean-generic |
648 | 655 |
0 | /* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */ | |
1 | ||
2 | /* | |
3 | * Copyright (c) 2004 Ted Unangst and Todd Miller | |
4 | * All rights reserved. | |
5 | * | |
6 | * Permission to use, copy, modify, and distribute this software for any | |
7 | * purpose with or without fee is hereby granted, provided that the above | |
8 | * copyright notice and this permission notice appear in all copies. | |
9 | * | |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 | */ | |
18 | ||
19 | #include <errno.h> | |
20 | #include <limits.h> | |
21 | #include <stdlib.h> | |
22 | ||
23 | #define INVALID 1 | |
24 | #define TOOSMALL 2 | |
25 | #define TOOLARGE 3 | |
26 | ||
27 | long long | |
28 | strtonum(const char *numstr, long long minval, long long maxval, | |
29 | const char **errstrp) | |
30 | { | |
31 | long long ll = 0; | |
32 | int error = 0; | |
33 | char *ep; | |
34 | struct errval { | |
35 | const char *errstr; | |
36 | int err; | |
37 | } ev[4] = { | |
38 | { NULL, 0 }, | |
39 | { "invalid", EINVAL }, | |
40 | { "too small", ERANGE }, | |
41 | { "too large", ERANGE }, | |
42 | }; | |
43 | ||
44 | ev[0].err = errno; | |
45 | errno = 0; | |
46 | if (minval > maxval) { | |
47 | error = INVALID; | |
48 | } else { | |
49 | ll = strtoll(numstr, &ep, 10); | |
50 | if (numstr == ep || *ep != '\0') | |
51 | error = INVALID; | |
52 | else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) | |
53 | error = TOOSMALL; | |
54 | else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) | |
55 | error = TOOLARGE; | |
56 | } | |
57 | if (errstrp != NULL) | |
58 | *errstrp = ev[error].errstr; | |
59 | errno = ev[error].err; | |
60 | if (error) | |
61 | ll = 0; | |
62 | ||
63 | return (ll); | |
64 | } |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for rpki-client 6.7p1. | |
2 | # Generated by GNU Autoconf 2.69 for rpki-client 6.8p0. | |
3 | 3 | # |
4 | 4 | # |
5 | 5 | # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. |
586 | 586 | # Identity of this package. |
587 | 587 | PACKAGE_NAME='rpki-client' |
588 | 588 | PACKAGE_TARNAME='rpki-client' |
589 | PACKAGE_VERSION='6.7p1' | |
590 | PACKAGE_STRING='rpki-client 6.7p1' | |
589 | PACKAGE_VERSION='6.8p0' | |
590 | PACKAGE_STRING='rpki-client 6.8p0' | |
591 | 591 | PACKAGE_BUGREPORT='' |
592 | 592 | PACKAGE_URL='' |
593 | 593 | |
642 | 642 | HAVE_UNVEIL_TRUE |
643 | 643 | HAVE_PLEDGE_FALSE |
644 | 644 | HAVE_PLEDGE_TRUE |
645 | HAVE_STRTONUM_FALSE | |
646 | HAVE_STRTONUM_TRUE | |
645 | 647 | HAVE_STRLCPY_FALSE |
646 | 648 | HAVE_STRLCPY_TRUE |
647 | 649 | HAVE_STRLCAT_FALSE |
1364 | 1366 | # Omit some internal or obsolete options to make the list less imposing. |
1365 | 1367 | # This message is too long to be a string in the A/UX 3.1 sh. |
1366 | 1368 | cat <<_ACEOF |
1367 | \`configure' configures rpki-client 6.7p1 to adapt to many kinds of systems. | |
1369 | \`configure' configures rpki-client 6.8p0 to adapt to many kinds of systems. | |
1368 | 1370 | |
1369 | 1371 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1370 | 1372 | |
1435 | 1437 | |
1436 | 1438 | if test -n "$ac_init_help"; then |
1437 | 1439 | case $ac_init_help in |
1438 | short | recursive ) echo "Configuration of rpki-client 6.7p1:";; | |
1440 | short | recursive ) echo "Configuration of rpki-client 6.8p0:";; | |
1439 | 1441 | esac |
1440 | 1442 | cat <<\_ACEOF |
1441 | 1443 | |
1552 | 1554 | test -n "$ac_init_help" && exit $ac_status |
1553 | 1555 | if $ac_init_version; then |
1554 | 1556 | cat <<\_ACEOF |
1555 | rpki-client configure 6.7p1 | |
1557 | rpki-client configure 6.8p0 | |
1556 | 1558 | generated by GNU Autoconf 2.69 |
1557 | 1559 | |
1558 | 1560 | Copyright (C) 2012 Free Software Foundation, Inc. |
1917 | 1919 | This file contains any messages produced by compilers while |
1918 | 1920 | running configure, to aid debugging if configure makes a mistake. |
1919 | 1921 | |
1920 | It was created by rpki-client $as_me 6.7p1, which was | |
1922 | It was created by rpki-client $as_me 6.8p0, which was | |
1921 | 1923 | generated by GNU Autoconf 2.69. Invocation command line was |
1922 | 1924 | |
1923 | 1925 | $ $0 $@ |
2852 | 2854 | |
2853 | 2855 | # Define the identity of the package. |
2854 | 2856 | PACKAGE='rpki-client' |
2855 | VERSION='6.7p1' | |
2857 | VERSION='6.8p0' | |
2856 | 2858 | |
2857 | 2859 | |
2858 | 2860 | cat >>confdefs.h <<_ACEOF |
12620 | 12622 | fi |
12621 | 12623 | done |
12622 | 12624 | |
12623 | for ac_func in explicit_bzero strlcat strlcpy | |
12625 | for ac_func in explicit_bzero strlcat strlcpy strtonum | |
12624 | 12626 | do : |
12625 | 12627 | as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` |
12626 | 12628 | ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" |
12713 | 12715 | fi |
12714 | 12716 | done |
12715 | 12717 | |
12718 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fts_open" >&5 | |
12719 | $as_echo_n "checking for library containing fts_open... " >&6; } | |
12720 | if ${ac_cv_search_fts_open+:} false; then : | |
12721 | $as_echo_n "(cached) " >&6 | |
12722 | else | |
12723 | ac_func_search_save_LIBS=$LIBS | |
12724 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext | |
12725 | /* end confdefs.h. */ | |
12726 | ||
12727 | /* Override any GCC internal prototype to avoid an error. | |
12728 | Use char because int might match the return type of a GCC | |
12729 | builtin and then its argument prototype would still apply. */ | |
12730 | #ifdef __cplusplus | |
12731 | extern "C" | |
12732 | #endif | |
12733 | char fts_open (); | |
12734 | int | |
12735 | main () | |
12736 | { | |
12737 | return fts_open (); | |
12738 | ; | |
12739 | return 0; | |
12740 | } | |
12741 | _ACEOF | |
12742 | for ac_lib in '' fts; do | |
12743 | if test -z "$ac_lib"; then | |
12744 | ac_res="none required" | |
12745 | else | |
12746 | ac_res=-l$ac_lib | |
12747 | LIBS="-l$ac_lib $ac_func_search_save_LIBS" | |
12748 | fi | |
12749 | if ac_fn_c_try_link "$LINENO"; then : | |
12750 | ac_cv_search_fts_open=$ac_res | |
12751 | fi | |
12752 | rm -f core conftest.err conftest.$ac_objext \ | |
12753 | conftest$ac_exeext | |
12754 | if ${ac_cv_search_fts_open+:} false; then : | |
12755 | break | |
12756 | fi | |
12757 | done | |
12758 | if ${ac_cv_search_fts_open+:} false; then : | |
12759 | ||
12760 | else | |
12761 | ac_cv_search_fts_open=no | |
12762 | fi | |
12763 | rm conftest.$ac_ext | |
12764 | LIBS=$ac_func_search_save_LIBS | |
12765 | fi | |
12766 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fts_open" >&5 | |
12767 | $as_echo "$ac_cv_search_fts_open" >&6; } | |
12768 | ac_res=$ac_cv_search_fts_open | |
12769 | if test "$ac_res" != no; then : | |
12770 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" | |
12771 | ||
12772 | fi | |
12773 | ||
12774 | for ac_func in fts_open | |
12775 | do : | |
12776 | ac_fn_c_check_func "$LINENO" "fts_open" "ac_cv_func_fts_open" | |
12777 | if test "x$ac_cv_func_fts_open" = xyes; then : | |
12778 | cat >>confdefs.h <<_ACEOF | |
12779 | #define HAVE_FTS_OPEN 1 | |
12780 | _ACEOF | |
12781 | ||
12782 | fi | |
12783 | done | |
12784 | ||
12716 | 12785 | |
12717 | 12786 | if test "x$ac_cv_func_reallocarray" = xyes; then |
12718 | 12787 | HAVE_REALLOCARRAY_TRUE= |
12776 | 12845 | else |
12777 | 12846 | HAVE_STRLCPY_TRUE='#' |
12778 | 12847 | HAVE_STRLCPY_FALSE= |
12848 | fi | |
12849 | ||
12850 | if test "x$ac_cv_func_strtonum" = xyes; then | |
12851 | HAVE_STRTONUM_TRUE= | |
12852 | HAVE_STRTONUM_FALSE='#' | |
12853 | else | |
12854 | HAVE_STRTONUM_TRUE='#' | |
12855 | HAVE_STRTONUM_FALSE= | |
12779 | 12856 | fi |
12780 | 12857 | |
12781 | 12858 | if test "x$ac_cv_func_pledge" = xyes; then |
13289 | 13366 | as_fn_error $? "conditional \"HAVE_STRLCPY\" was never defined. |
13290 | 13367 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 |
13291 | 13368 | fi |
13369 | if test -z "${HAVE_STRTONUM_TRUE}" && test -z "${HAVE_STRTONUM_FALSE}"; then | |
13370 | as_fn_error $? "conditional \"HAVE_STRTONUM\" was never defined. | |
13371 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 | |
13372 | fi | |
13292 | 13373 | if test -z "${HAVE_PLEDGE_TRUE}" && test -z "${HAVE_PLEDGE_FALSE}"; then |
13293 | 13374 | as_fn_error $? "conditional \"HAVE_PLEDGE\" was never defined. |
13294 | 13375 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 |
13694 | 13775 | # report actual input values of CONFIG_FILES etc. instead of their |
13695 | 13776 | # values after options handling. |
13696 | 13777 | ac_log=" |
13697 | This file was extended by rpki-client $as_me 6.7p1, which was | |
13778 | This file was extended by rpki-client $as_me 6.8p0, which was | |
13698 | 13779 | generated by GNU Autoconf 2.69. Invocation command line was |
13699 | 13780 | |
13700 | 13781 | CONFIG_FILES = $CONFIG_FILES |
13751 | 13832 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
13752 | 13833 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
13753 | 13834 | ac_cs_version="\\ |
13754 | rpki-client config.status 6.7p1 | |
13835 | rpki-client config.status 6.8p0 | |
13755 | 13836 | configured by $0, generated by GNU Autoconf 2.69, |
13756 | 13837 | with options \\"\$ac_cs_config\\" |
13757 | 13838 |
104 | 104 | AC_CHECK_FUNCS([reallocarray recallocarray]) |
105 | 105 | AC_CHECK_FUNCS([setgroups]) |
106 | 106 | AC_CHECK_FUNCS([setregid setresgid setreuid setresuid]) |
107 | AC_CHECK_FUNCS([explicit_bzero strlcat strlcpy]) | |
107 | AC_CHECK_FUNCS([explicit_bzero strlcat strlcpy strtonum]) | |
108 | 108 | AC_CHECK_FUNCS([pledge unveil]) |
109 | 109 | |
110 | 110 | # Share test results with automake |
111 | 111 | AC_SEARCH_LIBS([__b64_pton],[resolv]) |
112 | 112 | AC_CHECK_FUNCS([__b64_pton]) |
113 | AC_SEARCH_LIBS([fts_open],[fts]) | |
114 | AC_CHECK_FUNCS([fts_open]) | |
113 | 115 | |
114 | 116 | AM_CONDITIONAL([HAVE_REALLOCARRAY], [test "x$ac_cv_func_reallocarray" = xyes]) |
115 | 117 | AM_CONDITIONAL([HAVE_RECALLOCARRAY], [test "x$ac_cv_func_recallocarray" = xyes]) |
119 | 121 | AM_CONDITIONAL([HAVE_EXPLICIT_BZERO], [test "x$ac_cv_func_explicit_bzero" = xyes]) |
120 | 122 | AM_CONDITIONAL([HAVE_STRLCAT], [test "x$ac_cv_func_strlcat" = xyes]) |
121 | 123 | AM_CONDITIONAL([HAVE_STRLCPY], [test "x$ac_cv_func_strlcpy" = xyes]) |
124 | AM_CONDITIONAL([HAVE_STRTONUM], [test "x$ac_cv_func_strtonum" = xyes]) | |
122 | 125 | AM_CONDITIONAL([HAVE_PLEDGE], [test "x$ac_cv_func_pledge" = xyes]) |
123 | 126 | AM_CONDITIONAL([HAVE_UNVEIL], [test "x$ac_cv_func_unveil" = xyes]) |
124 | 127 |
15 | 15 | void *recallocarray(void *, size_t, size_t, size_t); |
16 | 16 | #endif |
17 | 17 | |
18 | #ifndef HAVE_STRTONUM | |
19 | long long strtonum(const char *nptr, long long minval, | |
20 | long long maxval, const char **errstr); | |
18 | 21 | #endif |
22 | ||
23 | #endif |
0 | /* $OpenBSD: as.c,v 1.5 2019/11/27 17:18:24 deraadt Exp $ */ | |
0 | /* $OpenBSD: as.c,v 1.6 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
23 | 23 | #include <stdlib.h> |
24 | 24 | #include <string.h> |
25 | 25 | #include <unistd.h> |
26 | ||
27 | #include <openssl/ssl.h> | |
28 | 26 | |
29 | 27 | #include "extern.h" |
30 | 28 |
0 | /* $OpenBSD: cert.c,v 1.15.4.1 2020/07/27 14:30:30 deraadt Exp $ */ | |
0 | /* $OpenBSD: cert.c,v 1.18 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
25 | 25 | #include <string.h> |
26 | 26 | #include <unistd.h> |
27 | 27 | |
28 | #include <openssl/ssl.h> | |
29 | 28 | #include <openssl/x509v3.h> /* DIST_POINT */ |
30 | 29 | |
31 | 30 | #include "extern.h" |
134 | 133 | } |
135 | 134 | |
136 | 135 | /* |
136 | * Parse the SIA notify URL, 4.8.8.1. | |
137 | * Returns zero on failure, non-zero on success. | |
138 | */ | |
139 | static int | |
140 | sbgp_sia_resource_notify(struct parse *p, | |
141 | const unsigned char *d, size_t dsz) | |
142 | { | |
143 | if (p->res->notify != NULL) { | |
144 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
145 | "Notify location already specified", p->fn); | |
146 | return 0; | |
147 | } | |
148 | ||
149 | /* Make sure it's a https:// address. */ | |
150 | if (dsz <= 8 || strncasecmp(d, "https://", 8)) { | |
151 | warnx("%s: RFC8182 section 3.2: not using https schema", p->fn); | |
152 | return 0; | |
153 | } | |
154 | ||
155 | if ((p->res->notify = strndup((const char *)d, dsz)) == NULL) | |
156 | err(1, NULL); | |
157 | ||
158 | return 1; | |
159 | } | |
160 | ||
161 | /* | |
137 | 162 | * Parse the SIA manifest, 4.8.8.1. |
138 | * There may be multiple different resources at this location, so throw | |
139 | * out all but the matching resource type. | |
140 | 163 | * Returns zero on failure, non-zero on success. |
141 | 164 | */ |
142 | 165 | static int |
143 | 166 | sbgp_sia_resource_mft(struct parse *p, |
144 | 167 | const unsigned char *d, size_t dsz) |
145 | 168 | { |
146 | ASN1_SEQUENCE_ANY *seq; | |
147 | const ASN1_TYPE *t; | |
148 | int rc = 0, ptag; | |
149 | char buf[128]; | |
150 | long plen; | |
151 | enum rtype rt; | |
152 | ||
153 | if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) { | |
154 | cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: " | |
155 | "failed ASN.1 sequence parse", p->fn); | |
156 | goto out; | |
157 | } | |
158 | if (sk_ASN1_TYPE_num(seq) != 2) { | |
159 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
160 | "want 2 elements, have %d", | |
161 | p->fn, sk_ASN1_TYPE_num(seq)); | |
162 | goto out; | |
163 | } | |
164 | ||
165 | /* Composed of an OID and its continuation. */ | |
166 | ||
167 | t = sk_ASN1_TYPE_value(seq, 0); | |
168 | if (t->type != V_ASN1_OBJECT) { | |
169 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
170 | "want ASN.1 object, have %s (NID %d)", | |
171 | p->fn, ASN1_tag2str(t->type), t->type); | |
172 | goto out; | |
173 | } | |
174 | OBJ_obj2txt(buf, sizeof(buf), t->value.object, 1); | |
175 | ||
176 | /* | |
177 | * Ignore all but manifest. | |
178 | * Things we may want to consider later: | |
179 | * - 1.3.6.1.5.5.7.48.13 (rpkiNotify) | |
180 | * - 1.3.6.1.5.5.7.48.5 (CA repository) | |
181 | */ | |
182 | ||
183 | if (strcmp(buf, "1.3.6.1.5.5.7.48.10")) { | |
184 | rc = 1; | |
185 | goto out; | |
186 | } | |
169 | enum rtype rt; | |
170 | ||
187 | 171 | if (p->res->mft != NULL) { |
188 | 172 | warnx("%s: RFC 6487 section 4.8.8: SIA: " |
189 | 173 | "MFT location already specified", p->fn); |
190 | goto out; | |
191 | } | |
192 | ||
193 | t = sk_ASN1_TYPE_value(seq, 1); | |
194 | if (t->type != V_ASN1_OTHER) { | |
195 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
196 | "want ASN.1 external, have %s (NID %d)", | |
197 | p->fn, ASN1_tag2str(t->type), t->type); | |
198 | goto out; | |
199 | } | |
200 | ||
201 | /* FIXME: there must be a way to do this without ASN1_frame. */ | |
202 | ||
203 | d = t->value.asn1_string->data; | |
204 | dsz = t->value.asn1_string->length; | |
205 | if (!ASN1_frame(p, dsz, &d, &plen, &ptag)) | |
206 | goto out; | |
207 | ||
208 | if ((p->res->mft = strndup((const char *)d, plen)) == NULL) | |
174 | return 0; | |
175 | } | |
176 | if ((p->res->mft = strndup((const char *)d, dsz)) == NULL) | |
209 | 177 | err(1, NULL); |
210 | 178 | |
211 | 179 | /* Make sure it's an MFT rsync address. */ |
212 | ||
213 | 180 | if (!rsync_uri_parse(NULL, NULL, NULL, |
214 | 181 | NULL, NULL, NULL, &rt, p->res->mft)) { |
215 | 182 | warnx("%s: RFC 6487 section 4.8.8: SIA: " |
216 | 183 | "failed to parse rsync URI", p->fn); |
217 | 184 | free(p->res->mft); |
218 | 185 | p->res->mft = NULL; |
219 | goto out; | |
186 | return 0; | |
220 | 187 | } |
221 | 188 | if (rt != RTYPE_MFT) { |
222 | 189 | warnx("%s: RFC 6487 section 4.8.8: SIA: " |
223 | 190 | "invalid rsync URI suffix", p->fn); |
224 | 191 | free(p->res->mft); |
225 | 192 | p->res->mft = NULL; |
226 | goto out; | |
227 | } | |
228 | ||
229 | rc = 1; | |
193 | return 0; | |
194 | } | |
195 | return 1; | |
196 | } | |
197 | ||
198 | /* | |
199 | * Parse the SIA entries, 4.8.8.1. | |
200 | * There may be multiple different resources at this location, so throw | |
201 | * out all but the matching resource type. Currently only two entries | |
202 | * are of interest: rpkiManifest and rpkiNotify. | |
203 | * Returns zero on failure, non-zero on success. | |
204 | */ | |
205 | static int | |
206 | sbgp_sia_resource_entry(struct parse *p, | |
207 | const unsigned char *d, size_t dsz) | |
208 | { | |
209 | ASN1_SEQUENCE_ANY *seq; | |
210 | const ASN1_TYPE *t; | |
211 | int rc = 0, ptag; | |
212 | char buf[128]; | |
213 | long plen; | |
214 | ||
215 | if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) { | |
216 | cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: " | |
217 | "failed ASN.1 sequence parse", p->fn); | |
218 | goto out; | |
219 | } | |
220 | if (sk_ASN1_TYPE_num(seq) != 2) { | |
221 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
222 | "want 2 elements, have %d", | |
223 | p->fn, sk_ASN1_TYPE_num(seq)); | |
224 | goto out; | |
225 | } | |
226 | ||
227 | /* Composed of an OID and its continuation. */ | |
228 | ||
229 | t = sk_ASN1_TYPE_value(seq, 0); | |
230 | if (t->type != V_ASN1_OBJECT) { | |
231 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
232 | "want ASN.1 object, have %s (NID %d)", | |
233 | p->fn, ASN1_tag2str(t->type), t->type); | |
234 | goto out; | |
235 | } | |
236 | OBJ_obj2txt(buf, sizeof(buf), t->value.object, 1); | |
237 | ||
238 | t = sk_ASN1_TYPE_value(seq, 1); | |
239 | if (t->type != V_ASN1_OTHER) { | |
240 | warnx("%s: RFC 6487 section 4.8.8: SIA: " | |
241 | "want ASN.1 external, have %s (NID %d)", | |
242 | p->fn, ASN1_tag2str(t->type), t->type); | |
243 | goto out; | |
244 | } | |
245 | ||
246 | /* FIXME: there must be a way to do this without ASN1_frame. */ | |
247 | ||
248 | d = t->value.asn1_string->data; | |
249 | dsz = t->value.asn1_string->length; | |
250 | if (!ASN1_frame(p, dsz, &d, &plen, &ptag)) | |
251 | goto out; | |
252 | ||
253 | /* | |
254 | * Ignore all but manifest and RRDP notify URL. | |
255 | * Things we may see: | |
256 | * - 1.3.6.1.5.5.7.48.10 (rpkiManifest) | |
257 | * - 1.3.6.1.5.5.7.48.13 (rpkiNotify) | |
258 | * - 1.3.6.1.5.5.7.48.5 (CA repository) | |
259 | */ | |
260 | if (strcmp(buf, "1.3.6.1.5.5.7.48.10") == 0) | |
261 | rc = sbgp_sia_resource_mft(p, d, plen); | |
262 | else if (strcmp(buf, "1.3.6.1.5.5.7.48.13") == 0) | |
263 | rc = sbgp_sia_resource_notify(p, d, plen); | |
264 | else | |
265 | rc = 1; /* silently ignore */ | |
230 | 266 | out: |
231 | 267 | sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free); |
232 | 268 | return rc; |
259 | 295 | } |
260 | 296 | d = t->value.asn1_string->data; |
261 | 297 | dsz = t->value.asn1_string->length; |
262 | if (!sbgp_sia_resource_mft(p, d, dsz)) | |
298 | if (!sbgp_sia_resource_entry(p, d, dsz)) | |
263 | 299 | goto out; |
264 | 300 | } |
265 | 301 | |
1160 | 1196 | |
1161 | 1197 | free(p->crl); |
1162 | 1198 | free(p->mft); |
1199 | free(p->notify); | |
1163 | 1200 | free(p->ips); |
1164 | 1201 | free(p->as); |
1165 | 1202 | free(p->aki); |
1220 | 1257 | cert_as_buffer(b, bsz, bmax, &p->as[i]); |
1221 | 1258 | |
1222 | 1259 | io_str_buffer(b, bsz, bmax, p->mft); |
1260 | io_str_buffer(b, bsz, bmax, p->notify); | |
1223 | 1261 | |
1224 | 1262 | has_crl = (p->crl != NULL); |
1225 | 1263 | io_simple_buffer(b, bsz, bmax, &has_crl, sizeof(int)); |
1293 | 1331 | cert_as_read(fd, &p->as[i]); |
1294 | 1332 | |
1295 | 1333 | io_str_read(fd, &p->mft); |
1334 | io_str_read(fd, &p->notify); | |
1296 | 1335 | io_simple_read(fd, &has_crl, sizeof(int)); |
1297 | 1336 | if (has_crl) |
1298 | 1337 | io_str_read(fd, &p->crl); |
0 | /* $OpenBSD: crl.c,v 1.8 2020/04/02 09:16:43 claudio Exp $ */ | |
0 | /* $OpenBSD: crl.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
24 | 24 | #include <stdlib.h> |
25 | 25 | #include <string.h> |
26 | 26 | #include <unistd.h> |
27 | ||
28 | #include <openssl/ssl.h> | |
29 | 27 | |
30 | 28 | #include "extern.h" |
31 | 29 |
0 | /* $OpenBSD: extern.h,v 1.29 2020/04/30 13:46:39 deraadt Exp $ */ | |
0 | /* $OpenBSD: extern.h,v 1.34 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
19 | 19 | #include <sys/tree.h> |
20 | 20 | #include <sys/time.h> |
21 | 21 | |
22 | #include <openssl/x509.h> | |
23 | ||
22 | 24 | enum cert_as_type { |
23 | 25 | CERT_AS_ID, /* single identifier */ |
24 | 26 | CERT_AS_INHERIT, /* inherit from parent */ |
109 | 111 | struct cert_as *as; /* list of AS numbers and ranges */ |
110 | 112 | size_t asz; /* length of "asz" */ |
111 | 113 | char *mft; /* manifest (rsync:// uri) */ |
114 | char *notify; /* RRDP notify (https:// uri) */ | |
112 | 115 | char *crl; /* CRL location (rsync:// or NULL) */ |
113 | 116 | char *aki; /* AKI (or NULL, for trust anchor) */ |
114 | 117 | char *ski; /* SKI */ |
262 | 265 | size_t crls; /* revocation lists */ |
263 | 266 | size_t vrps; /* total number of vrps */ |
264 | 267 | size_t uniqs; /* number of unique vrps */ |
268 | size_t del_files; /* number of files removed in cleanup */ | |
265 | 269 | char *talnames; |
266 | 270 | struct timeval elapsed_time; |
267 | 271 | struct timeval user_time; |
287 | 291 | |
288 | 292 | void mft_buffer(char **, size_t *, size_t *, const struct mft *); |
289 | 293 | void mft_free(struct mft *); |
290 | struct mft *mft_parse(X509 **, const char *, int); | |
294 | struct mft *mft_parse(X509 **, const char *); | |
291 | 295 | int mft_check(const char *, struct mft *); |
292 | 296 | struct mft *mft_read(int); |
293 | 297 | |
352 | 356 | int rsync_uri_parse(const char **, size_t *, |
353 | 357 | const char **, size_t *, const char **, size_t *, |
354 | 358 | enum rtype *, const char *); |
359 | void proc_rsync(char *, char *, int) __attribute__((noreturn)); | |
355 | 360 | |
356 | 361 | /* Logging (though really used for OpenSSL errors). */ |
357 | 362 |
0 | /* $OpenBSD: io.c,v 1.8 2019/11/29 05:09:50 benno Exp $ */ | |
0 | /* $OpenBSD: io.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
23 | 23 | #include <stdlib.h> |
24 | 24 | #include <string.h> |
25 | 25 | #include <unistd.h> |
26 | ||
27 | #include <openssl/x509.h> | |
28 | 26 | |
29 | 27 | #include "extern.h" |
30 | 28 |
0 | /* $OpenBSD: ip.c,v 1.12 2020/04/16 14:39:44 claudio Exp $ */ | |
0 | /* $OpenBSD: ip.c,v 1.13 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
23 | 23 | #include <stdlib.h> |
24 | 24 | #include <string.h> |
25 | 25 | #include <unistd.h> |
26 | ||
27 | #include <openssl/ssl.h> | |
28 | 26 | |
29 | 27 | #include "extern.h" |
30 | 28 |
0 | /* $OpenBSD: log.c,v 1.5 2019/11/29 05:14:11 benno Exp $ */ | |
0 | /* $OpenBSD: log.c,v 1.6 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
20 | 20 | #include <stdint.h> |
21 | 21 | |
22 | 22 | #include <openssl/err.h> |
23 | #include <openssl/ssl.h> | |
24 | 23 | |
25 | 24 | #include "extern.h" |
26 | 25 |
0 | /* $OpenBSD: main.c,v 1.69.4.1 2020/05/18 18:52:08 benno Exp $ */ | |
0 | /* $OpenBSD: main.c,v 1.82 2020/10/01 11:06:47 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
58 | 58 | #include <inttypes.h> |
59 | 59 | #include <poll.h> |
60 | 60 | #include <pwd.h> |
61 | #include <signal.h> | |
62 | 61 | #include <stdio.h> |
63 | 62 | #include <stdlib.h> |
63 | #include <signal.h> | |
64 | 64 | #include <string.h> |
65 | 65 | #include <limits.h> |
66 | #include <syslog.h> | |
66 | 67 | #include <unistd.h> |
67 | 68 | |
68 | 69 | #include <openssl/err.h> |
86 | 87 | size_t id; /* identifier (array index) */ |
87 | 88 | }; |
88 | 89 | |
89 | /* | |
90 | * A running rsync process. | |
91 | * We can have multiple of these simultaneously and need to keep track | |
92 | * of which process maps to which request. | |
93 | */ | |
94 | struct rsyncproc { | |
95 | char *uri; /* uri of this rsync proc */ | |
96 | size_t id; /* identity of request */ | |
97 | pid_t pid; /* pid of process or 0 if unassociated */ | |
98 | }; | |
90 | int timeout = 60*60; | |
91 | volatile sig_atomic_t killme; | |
92 | void suicide(int sig); | |
99 | 93 | |
100 | 94 | /* |
101 | 95 | * Table of all known repositories. |
127 | 121 | TAILQ_HEAD(entityq, entity); |
128 | 122 | |
129 | 123 | /* |
124 | * Database of all file path accessed during a run. | |
125 | */ | |
126 | struct filepath { | |
127 | RB_ENTRY(filepath) entry; | |
128 | char *file; | |
129 | }; | |
130 | ||
131 | static inline int | |
132 | filepathcmp(struct filepath *a, struct filepath *b) | |
133 | { | |
134 | return strcasecmp(a->file, b->file); | |
135 | } | |
136 | ||
137 | RB_HEAD(filepath_tree, filepath); | |
138 | RB_PROTOTYPE(filepath_tree, filepath, entry, filepathcmp); | |
139 | struct filepath_tree fpt = RB_INITIALIZER(&fpt); | |
140 | ||
141 | /* | |
130 | 142 | * Mark that our subprocesses will never return. |
131 | 143 | */ |
132 | static void proc_parser(int, int) __attribute__((noreturn)); | |
133 | static void proc_rsync(char *, char *, int, int) | |
134 | __attribute__((noreturn)); | |
144 | static void entityq_flush(int, struct entityq *, const struct repo *); | |
145 | static void proc_parser(int) __attribute__((noreturn)); | |
135 | 146 | static void build_chain(const struct auth *, STACK_OF(X509) **); |
136 | 147 | static void build_crls(const struct auth *, struct crl_tree *, |
137 | 148 | STACK_OF(X509_CRL) **); |
138 | 149 | |
139 | 150 | const char *bird_tablename = "ROAS"; |
140 | 151 | |
141 | int verbose; | |
152 | int verbose; | |
153 | int noop; | |
142 | 154 | |
143 | 155 | struct stats stats; |
144 | 156 | |
157 | 169 | va_end(ap); |
158 | 170 | } |
159 | 171 | } |
172 | ||
173 | /* | |
174 | * Functions to lookup which files have been accessed during computation. | |
175 | */ | |
176 | static void | |
177 | filepath_add(char *file) | |
178 | { | |
179 | struct filepath *fp; | |
180 | ||
181 | if ((fp = malloc(sizeof(*fp))) == NULL) | |
182 | err(1, NULL); | |
183 | if ((fp->file = strdup(file)) == NULL) | |
184 | err(1, NULL); | |
185 | ||
186 | if (RB_INSERT(filepath_tree, &fpt, fp) != NULL) { | |
187 | /* already in the tree */ | |
188 | free(fp->file); | |
189 | free(fp); | |
190 | } | |
191 | } | |
192 | ||
193 | static int | |
194 | filepath_exists(char *file) | |
195 | { | |
196 | struct filepath needle; | |
197 | ||
198 | needle.file = file; | |
199 | return RB_FIND(filepath_tree, &fpt, &needle) != NULL; | |
200 | } | |
201 | ||
202 | RB_GENERATE(filepath_tree, filepath, entry, filepathcmp); | |
160 | 203 | |
161 | 204 | /* |
162 | 205 | * Resolve the media type of a resource by looking at its suffice. |
208 | 251 | } |
209 | 252 | |
210 | 253 | /* |
211 | * Look up a repository, queueing it for discovery if not found. | |
212 | */ | |
213 | static const struct repo * | |
214 | repo_lookup(int fd, struct repotab *rt, const char *uri) | |
215 | { | |
216 | const char *host, *mod; | |
217 | size_t hostsz, modsz, i; | |
218 | struct repo *rp; | |
219 | ||
220 | if (!rsync_uri_parse(&host, &hostsz, | |
221 | &mod, &modsz, NULL, NULL, NULL, uri)) | |
222 | errx(1, "%s: malformed", uri); | |
223 | ||
224 | /* Look up in repository table. */ | |
225 | ||
226 | for (i = 0; i < rt->reposz; i++) { | |
227 | if (strlen(rt->repos[i].host) != hostsz) | |
228 | continue; | |
229 | if (strlen(rt->repos[i].module) != modsz) | |
230 | continue; | |
231 | if (strncasecmp(rt->repos[i].host, host, hostsz)) | |
232 | continue; | |
233 | if (strncasecmp(rt->repos[i].module, mod, modsz)) | |
234 | continue; | |
235 | return &rt->repos[i]; | |
236 | } | |
237 | ||
238 | rt->repos = reallocarray(rt->repos, | |
239 | rt->reposz + 1, sizeof(struct repo)); | |
240 | if (rt->repos == NULL) | |
241 | err(1, "reallocarray"); | |
242 | ||
243 | rp = &rt->repos[rt->reposz++]; | |
244 | memset(rp, 0, sizeof(struct repo)); | |
245 | rp->id = rt->reposz - 1; | |
246 | ||
247 | if ((rp->host = strndup(host, hostsz)) == NULL || | |
248 | (rp->module = strndup(mod, modsz)) == NULL) | |
249 | err(1, "strndup"); | |
250 | ||
251 | i = rt->reposz - 1; | |
252 | ||
253 | logx("%s/%s: pulling from network", rp->host, rp->module); | |
254 | io_simple_write(fd, &i, sizeof(size_t)); | |
255 | io_str_write(fd, rp->host); | |
256 | io_str_write(fd, rp->module); | |
257 | return rp; | |
258 | } | |
259 | ||
260 | /* | |
261 | * Read the next entity from the parser process, removing it from the | |
262 | * queue of pending requests in the process. | |
263 | * This always returns a valid entity. | |
264 | */ | |
265 | static struct entity * | |
266 | entityq_next(int fd, struct entityq *q) | |
267 | { | |
268 | size_t id; | |
269 | struct entity *entp; | |
270 | ||
271 | io_simple_read(fd, &id, sizeof(size_t)); | |
272 | ||
273 | TAILQ_FOREACH(entp, q, entries) | |
274 | if (entp->id == id) | |
275 | break; | |
276 | ||
277 | assert(entp != NULL); | |
278 | TAILQ_REMOVE(q, entp, entries); | |
279 | return entp; | |
280 | } | |
281 | ||
282 | static void | |
283 | entity_buffer_resp(char **b, size_t *bsz, size_t *bmax, | |
284 | const struct entity *ent) | |
285 | { | |
286 | ||
287 | io_simple_buffer(b, bsz, bmax, &ent->id, sizeof(size_t)); | |
288 | } | |
289 | ||
290 | /* | |
291 | 254 | * Like entity_write_req() but into a buffer. |
292 | 255 | * Matched by entity_read_req(). |
293 | 256 | */ |
339 | 302 | continue; |
340 | 303 | entity_write_req(fd, p); |
341 | 304 | } |
305 | } | |
306 | ||
307 | /* | |
308 | * Look up a repository, queueing it for discovery if not found. | |
309 | */ | |
310 | static const struct repo * | |
311 | repo_lookup(int fd, struct repotab *rt, const char *uri) | |
312 | { | |
313 | const char *host, *mod; | |
314 | size_t hostsz, modsz, i; | |
315 | struct repo *rp; | |
316 | ||
317 | if (!rsync_uri_parse(&host, &hostsz, | |
318 | &mod, &modsz, NULL, NULL, NULL, uri)) | |
319 | errx(1, "%s: malformed", uri); | |
320 | ||
321 | /* Look up in repository table. */ | |
322 | ||
323 | for (i = 0; i < rt->reposz; i++) { | |
324 | if (strlen(rt->repos[i].host) != hostsz) | |
325 | continue; | |
326 | if (strlen(rt->repos[i].module) != modsz) | |
327 | continue; | |
328 | if (strncasecmp(rt->repos[i].host, host, hostsz)) | |
329 | continue; | |
330 | if (strncasecmp(rt->repos[i].module, mod, modsz)) | |
331 | continue; | |
332 | return &rt->repos[i]; | |
333 | } | |
334 | ||
335 | rt->repos = reallocarray(rt->repos, | |
336 | rt->reposz + 1, sizeof(struct repo)); | |
337 | if (rt->repos == NULL) | |
338 | err(1, "reallocarray"); | |
339 | ||
340 | rp = &rt->repos[rt->reposz++]; | |
341 | memset(rp, 0, sizeof(struct repo)); | |
342 | rp->id = rt->reposz - 1; | |
343 | ||
344 | if ((rp->host = strndup(host, hostsz)) == NULL || | |
345 | (rp->module = strndup(mod, modsz)) == NULL) | |
346 | err(1, "strndup"); | |
347 | ||
348 | i = rt->reposz - 1; | |
349 | ||
350 | if (!noop) { | |
351 | logx("%s/%s: pulling from network", rp->host, rp->module); | |
352 | io_simple_write(fd, &i, sizeof(size_t)); | |
353 | io_str_write(fd, rp->host); | |
354 | io_str_write(fd, rp->module); | |
355 | } else { | |
356 | rp->loaded = 1; | |
357 | logx("%s/%s: using cache", rp->host, rp->module); | |
358 | stats.repos++; | |
359 | /* there is nothing in the queue so no need to flush */ | |
360 | } | |
361 | return rp; | |
362 | } | |
363 | ||
364 | /* | |
365 | * Read the next entity from the parser process, removing it from the | |
366 | * queue of pending requests in the process. | |
367 | * This always returns a valid entity. | |
368 | */ | |
369 | static struct entity * | |
370 | entityq_next(int fd, struct entityq *q) | |
371 | { | |
372 | size_t id; | |
373 | struct entity *entp; | |
374 | ||
375 | io_simple_read(fd, &id, sizeof(size_t)); | |
376 | ||
377 | TAILQ_FOREACH(entp, q, entries) | |
378 | if (entp->id == id) | |
379 | break; | |
380 | ||
381 | assert(entp != NULL); | |
382 | TAILQ_REMOVE(q, entp, entries); | |
383 | return entp; | |
384 | } | |
385 | ||
386 | static void | |
387 | entity_buffer_resp(char **b, size_t *bsz, size_t *bmax, | |
388 | const struct entity *ent) | |
389 | { | |
390 | ||
391 | io_simple_buffer(b, bsz, bmax, &ent->id, sizeof(size_t)); | |
342 | 392 | } |
343 | 393 | |
344 | 394 | /* |
373 | 423 | if ((p->descr = strdup(descr)) == NULL) |
374 | 424 | err(1, "strdup"); |
375 | 425 | |
426 | filepath_add(file); | |
376 | 427 | TAILQ_INSERT_TAIL(q, p, entries); |
377 | 428 | |
378 | 429 | /* |
478 | 529 | stats.talnames = strdup(file); |
479 | 530 | else { |
480 | 531 | char *tmp; |
481 | asprintf(&tmp, "%s %s", stats.talnames, file); | |
532 | if (asprintf(&tmp, "%s %s", stats.talnames, file) == -1) | |
533 | err(1, "asprintf"); | |
482 | 534 | free(stats.talnames); |
483 | 535 | stats.talnames = tmp; |
484 | 536 | } |
530 | 582 | |
531 | 583 | if ((type = rtype_resolve(uri)) == RTYPE_EOF) |
532 | 584 | errx(1, "%s: unknown file type", uri); |
533 | if (type != RTYPE_MFT && type != RTYPE_CRL) | |
585 | if (type != RTYPE_MFT) | |
534 | 586 | errx(1, "%s: invalid file type", uri); |
535 | ||
536 | /* ignore the CRL since it is already loaded via the MFT */ | |
537 | if (type == RTYPE_CRL) | |
538 | return; | |
539 | 587 | |
540 | 588 | /* Look up the repository. */ |
541 | 589 | |
546 | 594 | err(1, "asprintf"); |
547 | 595 | |
548 | 596 | entityq_add(proc, q, nfile, type, repo, NULL, NULL, 0, NULL, eid); |
549 | } | |
550 | ||
551 | static void | |
552 | proc_child(int signal) | |
553 | { | |
554 | ||
555 | /* Nothing: just discard. */ | |
556 | } | |
557 | ||
558 | /* | |
559 | * Process used for synchronising repositories. | |
560 | * This simply waits to be told which repository to synchronise, then | |
561 | * does so. | |
562 | * It then responds with the identifier of the repo that it updated. | |
563 | * It only exits cleanly when fd is closed. | |
564 | * FIXME: this should use buffered output to prevent deadlocks, but it's | |
565 | * very unlikely that we're going to fill our buffer, so whatever. | |
566 | * FIXME: limit the number of simultaneous process. | |
567 | * Currently, an attacker can trivially specify thousands of different | |
568 | * repositories and saturate our system. | |
569 | */ | |
570 | static void | |
571 | proc_rsync(char *prog, char *bind_addr, int fd, int noop) | |
572 | { | |
573 | size_t id, i, idsz = 0; | |
574 | ssize_t ssz; | |
575 | char *host = NULL, *mod = NULL, *uri = NULL, | |
576 | *dst = NULL, *path, *save, *cmd; | |
577 | const char *pp; | |
578 | pid_t pid; | |
579 | char *args[32]; | |
580 | int st, rc = 0; | |
581 | struct stat stt; | |
582 | struct pollfd pfd; | |
583 | sigset_t mask, oldmask; | |
584 | struct rsyncproc *ids = NULL; | |
585 | ||
586 | pfd.fd = fd; | |
587 | pfd.events = POLLIN; | |
588 | ||
589 | /* | |
590 | * Unveil the command we want to run. | |
591 | * If this has a pathname component in it, interpret as a file | |
592 | * and unveil the file directly. | |
593 | * Otherwise, look up the command in our PATH. | |
594 | */ | |
595 | ||
596 | if (!noop) { | |
597 | if (strchr(prog, '/') == NULL) { | |
598 | if (getenv("PATH") == NULL) | |
599 | errx(1, "PATH is unset"); | |
600 | if ((path = strdup(getenv("PATH"))) == NULL) | |
601 | err(1, "strdup"); | |
602 | save = path; | |
603 | while ((pp = strsep(&path, ":")) != NULL) { | |
604 | if (*pp == '\0') | |
605 | continue; | |
606 | if (asprintf(&cmd, "%s/%s", pp, prog) == -1) | |
607 | err(1, "asprintf"); | |
608 | if (lstat(cmd, &stt) == -1) { | |
609 | free(cmd); | |
610 | continue; | |
611 | } else if (unveil(cmd, "x") == -1) | |
612 | err(1, "%s: unveil", cmd); | |
613 | free(cmd); | |
614 | break; | |
615 | } | |
616 | free(save); | |
617 | } else if (unveil(prog, "x") == -1) | |
618 | err(1, "%s: unveil", prog); | |
619 | ||
620 | /* Unveil the repository directory and terminate unveiling. */ | |
621 | ||
622 | if (unveil(".", "c") == -1) | |
623 | err(1, "unveil"); | |
624 | if (unveil(NULL, NULL) == -1) | |
625 | err(1, "unveil"); | |
626 | } | |
627 | ||
628 | /* Initialise retriever for children exiting. */ | |
629 | ||
630 | if (sigemptyset(&mask) == -1) | |
631 | err(1, NULL); | |
632 | if (signal(SIGCHLD, proc_child) == SIG_ERR) | |
633 | err(1, NULL); | |
634 | if (sigaddset(&mask, SIGCHLD) == -1) | |
635 | err(1, NULL); | |
636 | if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1) | |
637 | err(1, NULL); | |
638 | ||
639 | for (;;) { | |
640 | if (ppoll(&pfd, 1, NULL, &oldmask) == -1) { | |
641 | if (errno != EINTR) | |
642 | err(1, "ppoll"); | |
643 | ||
644 | /* | |
645 | * If we've received an EINTR, it means that one | |
646 | * of our children has exited and we can reap it | |
647 | * and look up its identifier. | |
648 | * Then we respond to the parent. | |
649 | */ | |
650 | ||
651 | while ((pid = waitpid(WAIT_ANY, &st, WNOHANG)) > 0) { | |
652 | for (i = 0; i < idsz; i++) | |
653 | if (ids[i].pid == pid) | |
654 | break; | |
655 | assert(i < idsz); | |
656 | ||
657 | if (!WIFEXITED(st)) { | |
658 | warnx("rsync %s terminated abnormally", | |
659 | ids[i].uri); | |
660 | rc = 1; | |
661 | } else if (WEXITSTATUS(st) != 0) { | |
662 | warnx("rsync %s failed", ids[i].uri); | |
663 | } | |
664 | ||
665 | io_simple_write(fd, &ids[i].id, sizeof(size_t)); | |
666 | free(ids[i].uri); | |
667 | ids[i].uri = NULL; | |
668 | ids[i].pid = 0; | |
669 | ids[i].id = 0; | |
670 | } | |
671 | if (pid == -1 && errno != ECHILD) | |
672 | err(1, "waitpid"); | |
673 | continue; | |
674 | } | |
675 | ||
676 | /* | |
677 | * Read til the parent exits. | |
678 | * That will mean that we can safely exit. | |
679 | */ | |
680 | ||
681 | if ((ssz = read(fd, &id, sizeof(size_t))) == -1) | |
682 | err(1, "read"); | |
683 | if (ssz == 0) | |
684 | break; | |
685 | ||
686 | /* Read host and module. */ | |
687 | ||
688 | io_str_read(fd, &host); | |
689 | io_str_read(fd, &mod); | |
690 | ||
691 | if (noop) { | |
692 | io_simple_write(fd, &id, sizeof(size_t)); | |
693 | free(host); | |
694 | free(mod); | |
695 | continue; | |
696 | } | |
697 | ||
698 | /* | |
699 | * Create source and destination locations. | |
700 | * Build up the tree to this point because GPL rsync(1) | |
701 | * will not build the destination for us. | |
702 | */ | |
703 | ||
704 | if (mkdir(host, 0700) == -1 && EEXIST != errno) | |
705 | err(1, "%s", host); | |
706 | ||
707 | if (asprintf(&dst, "%s/%s", host, mod) == -1) | |
708 | err(1, NULL); | |
709 | if (mkdir(dst, 0700) == -1 && EEXIST != errno) | |
710 | err(1, "%s", dst); | |
711 | ||
712 | if (asprintf(&uri, "rsync://%s/%s", host, mod) == -1) | |
713 | err(1, NULL); | |
714 | ||
715 | /* Run process itself, wait for exit, check error. */ | |
716 | ||
717 | if ((pid = fork()) == -1) | |
718 | err(1, "fork"); | |
719 | ||
720 | if (pid == 0) { | |
721 | if (pledge("stdio exec", NULL) == -1) | |
722 | err(1, "pledge"); | |
723 | i = 0; | |
724 | args[i++] = (char *)prog; | |
725 | args[i++] = "-rt"; | |
726 | args[i++] = "--delete"; | |
727 | if (bind_addr != NULL) { | |
728 | args[i++] = "--address"; | |
729 | args[i++] = (char *)bind_addr; | |
730 | } | |
731 | args[i++] = uri; | |
732 | args[i++] = dst; | |
733 | args[i] = NULL; | |
734 | execvp(args[0], args); | |
735 | err(1, "%s: execvp", prog); | |
736 | } | |
737 | ||
738 | /* Augment the list of running processes. */ | |
739 | ||
740 | for (i = 0; i < idsz; i++) | |
741 | if (ids[i].pid == 0) | |
742 | break; | |
743 | if (i == idsz) { | |
744 | ids = reallocarray(ids, idsz + 1, sizeof(*ids)); | |
745 | if (ids == NULL) | |
746 | err(1, NULL); | |
747 | idsz++; | |
748 | } | |
749 | ||
750 | ids[i].id = id; | |
751 | ids[i].pid = pid; | |
752 | ids[i].uri = uri; | |
753 | ||
754 | /* Clean up temporary values. */ | |
755 | ||
756 | free(mod); | |
757 | free(dst); | |
758 | free(host); | |
759 | } | |
760 | ||
761 | /* No need for these to be hanging around. */ | |
762 | for (i = 0; i < idsz; i++) | |
763 | if (ids[i].pid > 0) { | |
764 | kill(ids[i].pid, SIGTERM); | |
765 | free(ids[i].uri); | |
766 | } | |
767 | ||
768 | free(ids); | |
769 | exit(rc); | |
770 | /* NOTREACHED */ | |
771 | 597 | } |
772 | 598 | |
773 | 599 | /* |
842 | 668 | * Return the mft on success or NULL on failure. |
843 | 669 | */ |
844 | 670 | static struct mft * |
845 | proc_parser_mft(struct entity *entp, int force, X509_STORE *store, | |
846 | X509_STORE_CTX *ctx, struct auth_tree *auths, struct crl_tree *crlt) | |
671 | proc_parser_mft(struct entity *entp, X509_STORE *store, X509_STORE_CTX *ctx, | |
672 | struct auth_tree *auths, struct crl_tree *crlt) | |
847 | 673 | { |
848 | 674 | struct mft *mft; |
849 | 675 | X509 *x509; |
852 | 678 | STACK_OF(X509) *chain; |
853 | 679 | |
854 | 680 | assert(!entp->has_dgst); |
855 | if ((mft = mft_parse(&x509, entp->uri, force)) == NULL) | |
681 | if ((mft = mft_parse(&x509, entp->uri)) == NULL) | |
856 | 682 | return NULL; |
857 | 683 | |
858 | 684 | a = valid_ski_aki(entp->uri, auths, mft->ski, mft->aki); |
887 | 713 | } |
888 | 714 | |
889 | 715 | /* |
890 | * Certificates are from manifests (has a digest and is signed with another | |
891 | * certificate) or TALs (has a pkey and is self-signed). Parse the certificate, | |
892 | * make sure its signatures are valid (with CRLs), then validate the RPKI | |
893 | * content. This returns a certificate (which must not be freed) or NULL on | |
716 | * Certificates are from manifests (has a digest and is signed with | |
717 | * another certificate) Parse the certificate, make sure its | |
718 | * signatures are valid (with CRLs), then validate the RPKI content. | |
719 | * This returns a certificate (which must not be freed) or NULL on | |
894 | 720 | * parse failure. |
895 | 721 | */ |
896 | 722 | static struct cert * |
906 | 732 | STACK_OF(X509) *chain; |
907 | 733 | STACK_OF(X509_CRL) *crls; |
908 | 734 | |
909 | assert(!entp->has_dgst != !entp->has_pkey); | |
735 | assert(entp->has_dgst); | |
736 | assert(!entp->has_pkey); | |
910 | 737 | |
911 | 738 | /* Extract certificate data and X509. */ |
912 | 739 | |
913 | cert = entp->has_dgst ? cert_parse(&x509, entp->uri, entp->dgst) : | |
914 | ta_parse(&x509, entp->uri, entp->pkey, entp->pkeysz); | |
740 | cert = cert_parse(&x509, entp->uri, entp->dgst); | |
915 | 741 | if (cert == NULL) |
916 | 742 | return NULL; |
917 | 743 | |
918 | if (entp->has_dgst) | |
919 | a = valid_ski_aki(entp->uri, auths, cert->ski, cert->aki); | |
744 | a = valid_ski_aki(entp->uri, auths, cert->ski, cert->aki); | |
920 | 745 | build_chain(a, &chain); |
921 | 746 | build_crls(a, crlt, &crls); |
922 | 747 | |
933 | 758 | X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK); |
934 | 759 | X509_STORE_CTX_set0_crls(ctx, crls); |
935 | 760 | |
936 | /* | |
937 | * FIXME: can we pass any options to the verification that make | |
938 | * the depth-zero self-signed bits verify properly? | |
939 | */ | |
940 | ||
941 | 761 | if (X509_verify_cert(ctx) <= 0) { |
942 | 762 | c = X509_STORE_CTX_get_error(ctx); |
943 | if (c != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || | |
944 | !entp->has_pkey) { | |
945 | warnx("%s: %s", entp->uri, | |
946 | X509_verify_cert_error_string(c)); | |
947 | X509_STORE_CTX_cleanup(ctx); | |
948 | cert_free(cert); | |
949 | sk_X509_free(chain); | |
950 | sk_X509_CRL_free(crls); | |
951 | X509_free(x509); | |
952 | return NULL; | |
953 | } | |
954 | } | |
763 | warnx("%s: %s", entp->uri, | |
764 | X509_verify_cert_error_string(c)); | |
765 | X509_STORE_CTX_cleanup(ctx); | |
766 | cert_free(cert); | |
767 | sk_X509_free(chain); | |
768 | sk_X509_CRL_free(crls); | |
769 | X509_free(x509); | |
770 | return NULL; | |
771 | } | |
772 | ||
955 | 773 | X509_STORE_CTX_cleanup(ctx); |
956 | 774 | sk_X509_free(chain); |
957 | 775 | sk_X509_CRL_free(crls); |
958 | 776 | |
959 | 777 | /* Validate the cert to get the parent */ |
960 | if (!(entp->has_pkey ? | |
961 | valid_ta(entp->uri, auths, cert) : | |
962 | valid_cert(entp->uri, auths, cert))) { | |
778 | if (!valid_cert(entp->uri, auths, cert)) { | |
963 | 779 | X509_free(x509); // needed? XXX |
964 | 780 | return cert; |
965 | 781 | } |
966 | 782 | |
967 | 783 | /* |
968 | * Only on success of all do we add the certificate to the store | |
969 | * of trusted certificates, both X509 and RPKI semantic. | |
784 | * Add validated certs to the RPKI auth tree. | |
970 | 785 | */ |
971 | 786 | |
972 | 787 | cert->valid = 1; |
975 | 790 | if (na == NULL) |
976 | 791 | err(1, NULL); |
977 | 792 | |
978 | if (entp->has_pkey) { | |
979 | if ((tal = strdup(entp->descr)) == NULL) | |
980 | err(1, NULL); | |
981 | } else | |
982 | tal = a->tal; | |
793 | tal = a->tal; | |
983 | 794 | |
984 | 795 | na->parent = a; |
985 | 796 | na->cert = cert; |
991 | 802 | if (RB_INSERT(auth_tree, auths, na) != NULL) |
992 | 803 | err(1, "auth tree corrupted"); |
993 | 804 | |
994 | /* only a ta goes into the store */ | |
995 | if (a == NULL) | |
996 | X509_STORE_add_cert(store, x509); | |
997 | ||
805 | return cert; | |
806 | } | |
807 | ||
808 | ||
809 | /* | |
810 | * Root certificates come from TALs (has a pkey and is self-signed). | |
811 | * Parse the certificate, ensure that it's public key matches the | |
812 | * known public key from the TAL, and then validate the RPKI | |
813 | * content. If valid, we add it as a trusted root (trust anchor) to | |
814 | * "store". | |
815 | * | |
816 | * This returns a certificate (which must not be freed) or NULL on | |
817 | * parse failure. | |
818 | */ | |
819 | static struct cert * | |
820 | proc_parser_root_cert(const struct entity *entp, | |
821 | X509_STORE *store, X509_STORE_CTX *ctx, | |
822 | struct auth_tree *auths, struct crl_tree *crlt) | |
823 | { | |
824 | char subject[256]; | |
825 | ASN1_TIME *notBefore, *notAfter; | |
826 | X509_NAME *name; | |
827 | struct cert *cert; | |
828 | X509 *x509; | |
829 | struct auth *na; | |
830 | char *tal; | |
831 | ||
832 | assert(!entp->has_dgst); | |
833 | assert(entp->has_pkey); | |
834 | ||
835 | /* Extract certificate data and X509. */ | |
836 | ||
837 | cert = ta_parse(&x509, entp->uri, entp->pkey, entp->pkeysz); | |
838 | if (cert == NULL) | |
839 | return NULL; | |
840 | ||
841 | if ((name = X509_get_subject_name(x509)) == NULL) { | |
842 | warnx("%s Unable to get certificate subject", entp->uri); | |
843 | goto badcert; | |
844 | } | |
845 | if (X509_NAME_oneline(name, subject, sizeof(subject)) == NULL) { | |
846 | warnx("%s: Unable to parse certificate subject name", | |
847 | entp->uri); | |
848 | goto badcert; | |
849 | } | |
850 | if ((notBefore = X509_get_notBefore(x509)) == NULL) { | |
851 | warnx("%s: certificate has invalid notBefore, subject='%s'", | |
852 | entp->uri, subject); | |
853 | goto badcert; | |
854 | } | |
855 | if ((notAfter = X509_get_notAfter(x509)) == NULL) { | |
856 | warnx("%s: certificate has invalid notAfter, subject='%s'", | |
857 | entp->uri, subject); | |
858 | goto badcert; | |
859 | } | |
860 | if (X509_cmp_current_time(notBefore) != -1) { | |
861 | warnx("%s: certificate not yet valid, subject='%s'", entp->uri, | |
862 | subject); | |
863 | goto badcert; | |
864 | } | |
865 | if (X509_cmp_current_time(notAfter) != 1) { | |
866 | warnx("%s: certificate has expired, subject='%s'", entp->uri, | |
867 | subject); | |
868 | goto badcert; | |
869 | } | |
870 | if (!valid_ta(entp->uri, auths, cert)) { | |
871 | warnx("%s: certificate not a valid ta, subject='%s'", | |
872 | entp->uri, subject); | |
873 | goto badcert; | |
874 | } | |
875 | ||
876 | /* | |
877 | * Add valid roots to the RPKI auth tree and as a trusted root | |
878 | * for chain validation to the X509_STORE. | |
879 | */ | |
880 | ||
881 | cert->valid = 1; | |
882 | ||
883 | na = malloc(sizeof(*na)); | |
884 | if (na == NULL) | |
885 | err(1, NULL); | |
886 | ||
887 | if ((tal = strdup(entp->descr)) == NULL) | |
888 | err(1, NULL); | |
889 | ||
890 | na->parent = NULL; | |
891 | na->cert = cert; | |
892 | na->tal = tal; | |
893 | na->fn = strdup(entp->uri); | |
894 | if (na->fn == NULL) | |
895 | err(1, NULL); | |
896 | ||
897 | if (RB_INSERT(auth_tree, auths, na) != NULL) | |
898 | err(1, "auth tree corrupted"); | |
899 | ||
900 | X509_STORE_add_cert(store, x509); | |
901 | ||
902 | return cert; | |
903 | badcert: | |
904 | X509_free(x509); // needed? XXX | |
998 | 905 | return cert; |
999 | 906 | } |
1000 | 907 | |
1011 | 918 | X509_CRL *x509_crl; |
1012 | 919 | struct crl *crl; |
1013 | 920 | const unsigned char *dgst; |
1014 | char *t; | |
1015 | 921 | |
1016 | 922 | dgst = entp->has_dgst ? entp->dgst : NULL; |
1017 | 923 | if ((x509_crl = crl_parse(entp->uri, dgst)) != NULL) { |
1018 | 924 | if ((crl = malloc(sizeof(*crl))) == NULL) |
1019 | err(1, NULL); | |
1020 | if ((t = strdup(entp->uri)) == NULL) | |
1021 | 925 | err(1, NULL); |
1022 | 926 | if ((crl->aki = x509_crl_get_aki(x509_crl)) == NULL) |
1023 | 927 | errx(1, "x509_crl_get_aki failed"); |
1077 | 981 | * The process will exit cleanly only when fd is closed. |
1078 | 982 | */ |
1079 | 983 | static void |
1080 | proc_parser(int fd, int force) | |
984 | proc_parser(int fd) | |
1081 | 985 | { |
1082 | 986 | struct tal *tal; |
1083 | 987 | struct cert *cert; |
1186 | 1090 | tal_free(tal); |
1187 | 1091 | break; |
1188 | 1092 | case RTYPE_CER: |
1189 | cert = proc_parser_cert(entp, store, ctx, | |
1190 | &auths, &crlt); | |
1093 | if (entp->has_dgst) | |
1094 | cert = proc_parser_cert(entp, store, ctx, | |
1095 | &auths, &crlt); | |
1096 | else | |
1097 | cert = proc_parser_root_cert(entp, store, ctx, | |
1098 | &auths, &crlt); | |
1191 | 1099 | c = (cert != NULL); |
1192 | 1100 | io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int)); |
1193 | 1101 | if (cert != NULL) |
1199 | 1107 | */ |
1200 | 1108 | break; |
1201 | 1109 | case RTYPE_MFT: |
1202 | mft = proc_parser_mft(entp, force, | |
1203 | store, ctx, &auths, &crlt); | |
1110 | mft = proc_parser_mft(entp, store, ctx, &auths, &crlt); | |
1204 | 1111 | c = (mft != NULL); |
1205 | 1112 | io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int)); |
1206 | 1113 | if (mft != NULL) |
1364 | 1271 | return (s); |
1365 | 1272 | } |
1366 | 1273 | |
1274 | static char ** | |
1275 | add_to_del(char **del, size_t *dsz, char *file) | |
1276 | { | |
1277 | size_t i = *dsz; | |
1278 | ||
1279 | del = reallocarray(del, i + 1, sizeof(*del)); | |
1280 | if (del == NULL) | |
1281 | err(1, "reallocarray"); | |
1282 | del[i] = strdup(file); | |
1283 | if (del[i] == NULL) | |
1284 | err(1, "strdup"); | |
1285 | *dsz = i + 1; | |
1286 | return del; | |
1287 | } | |
1288 | ||
1289 | static size_t | |
1290 | repo_cleanup(const char *cachedir, struct repotab *rt) | |
1291 | { | |
1292 | size_t i, delsz = 0; | |
1293 | char *argv[2], **del = NULL; | |
1294 | FTS *fts; | |
1295 | FTSENT *e; | |
1296 | ||
1297 | /* change working directory to the cache directory */ | |
1298 | if (chdir(cachedir) == -1) | |
1299 | err(1, "%s: chdir", cachedir); | |
1300 | ||
1301 | for (i = 0; i < rt->reposz; i++) { | |
1302 | if (asprintf(&argv[0], "%s/%s", rt->repos[i].host, | |
1303 | rt->repos[i].module) == -1) | |
1304 | err(1, NULL); | |
1305 | argv[1] = NULL; | |
1306 | if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, | |
1307 | NULL)) == NULL) | |
1308 | err(1, "fts_open"); | |
1309 | errno = 0; | |
1310 | while ((e = fts_read(fts)) != NULL) { | |
1311 | switch (e->fts_info) { | |
1312 | case FTS_NSOK: | |
1313 | if (!filepath_exists(e->fts_path)) | |
1314 | del = add_to_del(del, &delsz, | |
1315 | e->fts_path); | |
1316 | break; | |
1317 | case FTS_D: | |
1318 | case FTS_DP: | |
1319 | /* TODO empty directory pruning */ | |
1320 | break; | |
1321 | case FTS_SL: | |
1322 | case FTS_SLNONE: | |
1323 | warnx("symlink %s", e->fts_path); | |
1324 | del = add_to_del(del, &delsz, e->fts_path); | |
1325 | break; | |
1326 | case FTS_NS: | |
1327 | case FTS_ERR: | |
1328 | warnx("fts_read %s: %s", e->fts_path, | |
1329 | strerror(e->fts_errno)); | |
1330 | break; | |
1331 | default: | |
1332 | warnx("unhandled[%x] %s", e->fts_info, | |
1333 | e->fts_path); | |
1334 | break; | |
1335 | } | |
1336 | ||
1337 | errno = 0; | |
1338 | } | |
1339 | if (errno) | |
1340 | err(1, "fts_read"); | |
1341 | if (fts_close(fts) == -1) | |
1342 | err(1, "fts_close"); | |
1343 | } | |
1344 | ||
1345 | for (i = 0; i < delsz; i++) { | |
1346 | if (unlink(del[i]) == -1) | |
1347 | warn("unlink %s", del[i]); | |
1348 | if (verbose > 1) | |
1349 | logx("deleted %s", del[i]); | |
1350 | free(del[i]); | |
1351 | } | |
1352 | free(del); | |
1353 | ||
1354 | return delsz; | |
1355 | } | |
1356 | ||
1357 | void | |
1358 | suicide(int sig __attribute__((unused))) | |
1359 | { | |
1360 | killme = 1; | |
1361 | ||
1362 | } | |
1363 | ||
1367 | 1364 | int |
1368 | 1365 | main(int argc, char *argv[]) |
1369 | 1366 | { |
1370 | 1367 | int rc = 1, c, proc, st, rsync, |
1371 | fl = SOCK_STREAM | SOCK_CLOEXEC, noop = 0, | |
1372 | force = 0; | |
1368 | fl = SOCK_STREAM | SOCK_CLOEXEC; | |
1373 | 1369 | size_t i, j, eid = 1, outsz = 0, talsz = 0; |
1374 | 1370 | pid_t procpid, rsyncpid; |
1375 | 1371 | int fd[2]; |
1380 | 1376 | struct roa **out = NULL; |
1381 | 1377 | char *rsync_prog = RPKI_RSYNC_CMD; |
1382 | 1378 | char *bind_addr = NULL; |
1383 | const char *cachedir = NULL; | |
1379 | const char *cachedir = NULL, *errs; | |
1384 | 1380 | const char *tals[TALSZ_MAX]; |
1385 | 1381 | struct vrp_tree v = RB_INITIALIZER(&v); |
1386 | 1382 | struct rusage ru; |
1407 | 1403 | if (pledge("stdio rpath wpath cpath fattr proc exec unveil", NULL) == -1) |
1408 | 1404 | err(1, "pledge"); |
1409 | 1405 | |
1410 | while ((c = getopt(argc, argv, "b:Bcd:e:fjnot:T:v")) != -1) | |
1406 | while ((c = getopt(argc, argv, "b:Bcd:e:jnos:t:T:v")) != -1) | |
1411 | 1407 | switch (c) { |
1412 | 1408 | case 'b': |
1413 | 1409 | bind_addr = optarg; |
1424 | 1420 | case 'e': |
1425 | 1421 | rsync_prog = optarg; |
1426 | 1422 | break; |
1427 | case 'f': | |
1428 | force = 1; | |
1429 | break; | |
1430 | 1423 | case 'j': |
1431 | 1424 | outformats |= FORMAT_JSON; |
1432 | 1425 | break; |
1435 | 1428 | break; |
1436 | 1429 | case 'o': |
1437 | 1430 | outformats |= FORMAT_OPENBGPD; |
1431 | break; | |
1432 | case 's': | |
1433 | timeout = strtonum(optarg, 0, 24*60*60, &errs); | |
1434 | if (errs) | |
1435 | errx(1, "-s: %s", errs); | |
1438 | 1436 | break; |
1439 | 1437 | case 't': |
1440 | 1438 | if (talsz >= TALSZ_MAX) |
1459 | 1457 | else if (argc > 1) |
1460 | 1458 | goto usage; |
1461 | 1459 | |
1460 | if (timeout) { | |
1461 | signal(SIGALRM, suicide); | |
1462 | /* Commit suicide eventually - cron will normally start a new one */ | |
1463 | alarm(timeout); | |
1464 | } | |
1465 | ||
1462 | 1466 | if (cachedir == NULL) { |
1463 | 1467 | warnx("cache directory required"); |
1464 | 1468 | goto usage; |
1502 | 1506 | err(1, "%s: unveil", cachedir); |
1503 | 1507 | if (pledge("stdio rpath", NULL) == -1) |
1504 | 1508 | err(1, "pledge"); |
1505 | proc_parser(fd[0], force); | |
1509 | proc_parser(fd[0]); | |
1506 | 1510 | /* NOTREACHED */ |
1507 | 1511 | } |
1508 | 1512 | |
1516 | 1520 | * TAL) exists and has been downloaded. |
1517 | 1521 | */ |
1518 | 1522 | |
1519 | if (socketpair(AF_UNIX, fl, 0, fd) == -1) | |
1520 | err(1, "socketpair"); | |
1521 | if ((rsyncpid = fork()) == -1) | |
1522 | err(1, "fork"); | |
1523 | ||
1524 | if (rsyncpid == 0) { | |
1525 | close(proc); | |
1526 | close(fd[1]); | |
1527 | ||
1528 | /* change working directory to the cache directory */ | |
1529 | if (chdir(cachedir) == -1) | |
1530 | err(1, "%s: chdir", cachedir); | |
1531 | ||
1532 | if (pledge("stdio rpath cpath proc exec unveil", NULL) == -1) | |
1533 | err(1, "pledge"); | |
1534 | ||
1535 | /* If -n, we don't exec or mkdir. */ | |
1536 | ||
1537 | if (noop && pledge("stdio", NULL) == -1) | |
1538 | err(1, "pledge"); | |
1539 | proc_rsync(rsync_prog, bind_addr, fd[0], noop); | |
1540 | /* NOTREACHED */ | |
1541 | } | |
1542 | ||
1543 | close(fd[0]); | |
1544 | rsync = fd[1]; | |
1523 | if (!noop) { | |
1524 | if (socketpair(AF_UNIX, fl, 0, fd) == -1) | |
1525 | err(1, "socketpair"); | |
1526 | if ((rsyncpid = fork()) == -1) | |
1527 | err(1, "fork"); | |
1528 | ||
1529 | if (rsyncpid == 0) { | |
1530 | close(proc); | |
1531 | close(fd[1]); | |
1532 | ||
1533 | /* change working directory to the cache directory */ | |
1534 | if (chdir(cachedir) == -1) | |
1535 | err(1, "%s: chdir", cachedir); | |
1536 | ||
1537 | if (pledge("stdio rpath cpath proc exec unveil", NULL) | |
1538 | == -1) | |
1539 | err(1, "pledge"); | |
1540 | ||
1541 | proc_rsync(rsync_prog, bind_addr, fd[0]); | |
1542 | /* NOTREACHED */ | |
1543 | } | |
1544 | ||
1545 | close(fd[0]); | |
1546 | rsync = fd[1]; | |
1547 | } else | |
1548 | rsync = -1; | |
1545 | 1549 | |
1546 | 1550 | assert(rsync != proc); |
1547 | 1551 | |
1567 | 1571 | pfd[1].fd = proc; |
1568 | 1572 | pfd[0].events = pfd[1].events = POLLIN; |
1569 | 1573 | |
1570 | while (!TAILQ_EMPTY(&q)) { | |
1571 | if ((c = poll(pfd, 2, verbose ? 10000 : INFTIM)) == -1) | |
1574 | while (!TAILQ_EMPTY(&q) && !killme) { | |
1575 | if ((c = poll(pfd, 2, verbose ? 10000 : INFTIM)) == -1) { | |
1576 | if (errno == EINTR) | |
1577 | continue; | |
1572 | 1578 | err(1, "poll"); |
1579 | } | |
1573 | 1580 | |
1574 | 1581 | /* Debugging: print some statistics if we stall. */ |
1575 | 1582 | |
1600 | 1607 | */ |
1601 | 1608 | |
1602 | 1609 | if ((pfd[0].revents & POLLIN)) { |
1610 | int ok; | |
1603 | 1611 | io_simple_read(rsync, &i, sizeof(size_t)); |
1612 | io_simple_read(rsync, &ok, sizeof(ok)); | |
1604 | 1613 | assert(i < rt.reposz); |
1605 | 1614 | assert(!rt.repos[i].loaded); |
1606 | 1615 | rt.repos[i].loaded = 1; |
1607 | logx("%s/%s: loaded from cache", rt.repos[i].host, | |
1608 | rt.repos[i].module); | |
1616 | if (ok) | |
1617 | logx("%s/%s: loaded from network", | |
1618 | rt.repos[i].host, rt.repos[i].module); | |
1619 | else | |
1620 | logx("%s/%s: load from network failed, " | |
1621 | "fallback to cache", | |
1622 | rt.repos[i].host, rt.repos[i].module); | |
1609 | 1623 | stats.repos++; |
1610 | 1624 | entityq_flush(proc, &q, &rt.repos[i]); |
1611 | 1625 | } |
1619 | 1633 | ent = entityq_next(proc, &q); |
1620 | 1634 | entity_process(proc, rsync, &stats, |
1621 | 1635 | &q, ent, &rt, &eid, &v); |
1622 | if (verbose > 1) | |
1636 | if (verbose > 2) | |
1623 | 1637 | fprintf(stderr, "%s\n", ent->uri); |
1624 | 1638 | entity_free(ent); |
1625 | 1639 | } |
1640 | } | |
1641 | ||
1642 | if (killme) { | |
1643 | syslog(LOG_CRIT|LOG_DAEMON, | |
1644 | "excessive runtime (%d seconds), giving up", timeout); | |
1645 | errx(1, "excessive runtime (%d seconds), giving up", timeout); | |
1626 | 1646 | } |
1627 | 1647 | |
1628 | 1648 | assert(TAILQ_EMPTY(&q)); |
1644 | 1664 | warnx("parser process exited abnormally"); |
1645 | 1665 | rc = 1; |
1646 | 1666 | } |
1647 | if (waitpid(rsyncpid, &st, 0) == -1) | |
1648 | err(1, "waitpid"); | |
1649 | if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) { | |
1650 | warnx("rsync process exited abnormally"); | |
1651 | rc = 1; | |
1652 | } | |
1653 | ||
1667 | if (!noop) { | |
1668 | if (waitpid(rsyncpid, &st, 0) == -1) | |
1669 | err(1, "waitpid"); | |
1670 | if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) { | |
1671 | warnx("rsync process exited abnormally"); | |
1672 | rc = 1; | |
1673 | } | |
1674 | } | |
1654 | 1675 | gettimeofday(&now_time, NULL); |
1655 | 1676 | timersub(&now_time, &start_time, &stats.elapsed_time); |
1656 | 1677 | if (getrusage(RUSAGE_SELF, &ru) == 0) { |
1664 | 1685 | |
1665 | 1686 | if (outputfiles(&v, &stats)) |
1666 | 1687 | rc = 1; |
1688 | ||
1689 | stats.del_files = repo_cleanup(cachedir, &rt); | |
1667 | 1690 | |
1668 | 1691 | logx("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)", |
1669 | 1692 | stats.roas, stats.roas_fail, stats.roas_invalid); |
1674 | 1697 | stats.mfts, stats.mfts_fail, stats.mfts_stale); |
1675 | 1698 | logx("Certificate revocation lists: %zu", stats.crls); |
1676 | 1699 | logx("Repositories: %zu", stats.repos); |
1700 | logx("Files removed: %zu", stats.del_files); | |
1677 | 1701 | logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs); |
1678 | 1702 | |
1679 | 1703 | /* Memory cleanup. */ |
1680 | ||
1681 | 1704 | for (i = 0; i < rt.reposz; i++) { |
1682 | 1705 | free(rt.repos[i].host); |
1683 | 1706 | free(rt.repos[i].module); |
1692 | 1715 | |
1693 | 1716 | usage: |
1694 | 1717 | fprintf(stderr, |
1695 | "usage: rpki-client [-Bcfjnov] [-b sourceaddr] [-d cachedir]" | |
1718 | "usage: rpki-client [-Bcjnov] [-b sourceaddr] [-d cachedir]" | |
1696 | 1719 | " [-e rsync_prog]\n" |
1697 | " [-T table] [-t tal] [outputdir]\n"); | |
1720 | " [-s timeout] [-T table] [-t tal] [outputdir]\n"); | |
1698 | 1721 | return 1; |
1699 | 1722 | } |
0 | /* $OpenBSD: mft.c,v 1.14 2020/04/11 15:53:44 deraadt Exp $ */ | |
0 | /* $OpenBSD: mft.c,v 1.16 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
23 | 23 | #include <string.h> |
24 | 24 | #include <unistd.h> |
25 | 25 | |
26 | #include <openssl/ssl.h> | |
27 | 26 | #include <openssl/sha.h> |
28 | 27 | |
29 | 28 | #include "extern.h" |
60 | 59 | */ |
61 | 60 | static time_t |
62 | 61 | check_validity(const ASN1_GENERALIZEDTIME *from, |
63 | const ASN1_GENERALIZEDTIME *until, const char *fn, int force) | |
62 | const ASN1_GENERALIZEDTIME *until, const char *fn) | |
64 | 63 | { |
65 | 64 | time_t now = time(NULL); |
66 | 65 | |
81 | 80 | } |
82 | 81 | /* check that now is not after until */ |
83 | 82 | if (X509_cmp_time(until, &now) < 0) { |
84 | warnx("%s: mft expired on %s%s", fn, gentime2str(until), | |
85 | force ? " (ignoring)" : ""); | |
86 | if (!force) | |
87 | return 0; | |
83 | warnx("%s: mft expired on %s", fn, gentime2str(until)); | |
84 | return 0; | |
88 | 85 | } |
89 | 86 | |
90 | 87 | return 1; |
236 | 233 | * Returns <0 on failure, 0 on stale, >0 on success. |
237 | 234 | */ |
238 | 235 | static int |
239 | mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p, int force) | |
236 | mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) | |
240 | 237 | { |
241 | 238 | ASN1_SEQUENCE_ANY *seq; |
242 | 239 | const ASN1_TYPE *t; |
310 | 307 | } |
311 | 308 | until = t->value.generalizedtime; |
312 | 309 | |
313 | validity = check_validity(from, until, p->fn, force); | |
310 | validity = check_validity(from, until, p->fn); | |
314 | 311 | if (validity != 1) |
315 | 312 | goto out; |
316 | 313 | |
355 | 352 | * The MFT content is otherwise returned. |
356 | 353 | */ |
357 | 354 | struct mft * |
358 | mft_parse(X509 **x509, const char *fn, int force) | |
355 | mft_parse(X509 **x509, const char *fn) | |
359 | 356 | { |
360 | 357 | struct parse p; |
361 | 358 | int c, rc = 0; |
383 | 380 | * references as well as marking it as stale. |
384 | 381 | */ |
385 | 382 | |
386 | if ((c = mft_parse_econtent(cms, cmsz, &p, force)) == 0) { | |
383 | if ((c = mft_parse_econtent(cms, cmsz, &p)) == 0) { | |
387 | 384 | /* |
388 | 385 | * FIXME: it should suffice to just mark this as stale |
389 | 386 | * and have the logic around mft_read() simply ignore |
0 | /* $OpenBSD: output-bgpd.c,v 1.17 2020/04/28 13:41:35 deraadt Exp $ */ | |
0 | /* $OpenBSD: output-bgpd.c,v 1.18 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
15 | 15 | */ |
16 | 16 | |
17 | 17 | #include <stdlib.h> |
18 | #include <openssl/ssl.h> | |
19 | 18 | |
20 | 19 | #include "extern.h" |
21 | 20 |
0 | /* $OpenBSD: output-bird.c,v 1.9 2020/04/28 15:03:39 deraadt Exp $ */ | |
0 | /* $OpenBSD: output-bird.c,v 1.10 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * Copyright (c) 2020 Robert Scheck <robert@fedoraproject.org> |
16 | 16 | */ |
17 | 17 | |
18 | 18 | #include <stdlib.h> |
19 | #include <openssl/ssl.h> | |
20 | 19 | |
21 | 20 | #include "extern.h" |
22 | 21 |
0 | /* $OpenBSD: output-csv.c,v 1.7 2020/04/28 13:41:35 deraadt Exp $ */ | |
0 | /* $OpenBSD: output-csv.c,v 1.8 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * |
15 | 15 | */ |
16 | 16 | |
17 | 17 | #include <stdlib.h> |
18 | #include <openssl/ssl.h> | |
19 | 18 | |
20 | 19 | #include "extern.h" |
21 | 20 |
0 | /* $OpenBSD: output-json.c,v 1.12 2020/05/03 20:24:02 deraadt Exp $ */ | |
0 | /* $OpenBSD: output-json.c,v 1.13 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * |
18 | 18 | #include <unistd.h> |
19 | 19 | #include <time.h> |
20 | 20 | #include <netdb.h> |
21 | #include <openssl/ssl.h> | |
22 | 21 | |
23 | 22 | #include "extern.h" |
24 | 23 |
0 | /* $OpenBSD: output.c,v 1.15 2020/05/03 20:24:02 deraadt Exp $ */ | |
0 | /* $OpenBSD: output.c,v 1.17 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Theo de Raadt <deraadt@openbsd.org> |
3 | 3 | * |
26 | 26 | #include <unistd.h> |
27 | 27 | #include <time.h> |
28 | 28 | |
29 | #include <openssl/x509v3.h> | |
30 | ||
31 | 29 | #include "extern.h" |
32 | 30 | |
33 | 31 | char *outputdir; |
110 | 108 | err(1, "path too long"); |
111 | 109 | fd = mkostemp(output_tmpname, O_CLOEXEC); |
112 | 110 | if (fd == -1) |
113 | err(1, "mkostemp"); | |
111 | err(1, "mkostemp: %s", output_tmpname); | |
114 | 112 | (void) fchmod(fd, 0644); |
115 | 113 | f = fdopen(fd, "w"); |
116 | 114 | if (f == NULL) |
0 | /* $OpenBSD: roa.c,v 1.8 2019/11/29 05:14:11 benno Exp $ */ | |
0 | /* $OpenBSD: roa.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
21 | 21 | #include <stdlib.h> |
22 | 22 | #include <string.h> |
23 | 23 | #include <unistd.h> |
24 | ||
25 | #include <openssl/ssl.h> | |
26 | 24 | |
27 | 25 | #include "extern.h" |
28 | 26 |
0 | .\" $OpenBSD: rpki-client.8,v 1.26 2020/04/21 05:36:04 jmc Exp $ | |
0 | .\" $OpenBSD: rpki-client.8,v 1.30 2020/09/15 20:02:30 job Exp $ | |
1 | 1 | .\" |
2 | 2 | .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | .\" |
13 | 13 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | 14 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | 15 | .\" |
16 | .Dd $Mdocdate: April 21 2020 $ | |
16 | .Dd $Mdocdate: September 15 2020 $ | |
17 | 17 | .Dt RPKI-CLIENT 8 |
18 | 18 | .Os |
19 | 19 | .Sh NAME |
21 | 21 | .Nd RPKI validator to support BGP Origin Validation |
22 | 22 | .Sh SYNOPSIS |
23 | 23 | .Nm |
24 | .Op Fl Bcfjnov | |
24 | .Op Fl Bcjnov | |
25 | 25 | .Op Fl b Ar sourceaddr |
26 | 26 | .Op Fl d Ar cachedir |
27 | 27 | .Op Fl e Ar rsync_prog |
28 | .Op Fl s Ar timeout | |
28 | 29 | .Op Fl T Ar table |
29 | 30 | .Op Fl t Ar tal |
30 | 31 | .Op Ar outputdir |
75 | 76 | .Xr @RSYNC@ 1 |
76 | 77 | to fetch repositories. |
77 | 78 | It must accept the |
78 | .Fl rlt , | |
79 | .Fl rt | |
80 | and | |
79 | 81 | .Fl -address |
80 | and | |
81 | .Fl -delete | |
82 | 82 | flags and connect with rsync-protocol locations. |
83 | .It Fl f | |
84 | Accept out-of-date manifests. | |
85 | This will still report if a manifest has expired. | |
86 | 83 | .It Fl j |
87 | 84 | Create output in the file |
88 | 85 | .Pa json |
109 | 106 | option use |
110 | 107 | .Ar table |
111 | 108 | as roa table name instead of the default 'ROAS'. |
109 | .It Fl s Ar timeout | |
110 | Terminate after | |
111 | .Ar timeout | |
112 | seconds of runtime, because normal practice will restart from | |
113 | .Xr cron 8 . | |
114 | Disable by specifying 0. | |
115 | Defaults to 1 hour. | |
112 | 116 | .It Fl t Ar tal |
113 | 117 | Specify a |
114 | 118 | .Em Trust Anchor Location Pq TAL |
0 | /* $OpenBSD: rsync.c,v 1.7 2019/10/31 08:36:43 claudio Exp $ */ | |
0 | /* $OpenBSD: rsync.c,v 1.9 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
14 | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | 15 | */ |
16 | 16 | |
17 | #include <sys/stat.h> | |
18 | #include <sys/wait.h> | |
17 | 19 | #include <netinet/in.h> |
18 | 20 | #include <assert.h> |
19 | 21 | #include <err.h> |
22 | #include <errno.h> | |
23 | #include <poll.h> | |
20 | 24 | #include <resolv.h> |
25 | #include <signal.h> | |
21 | 26 | #include <stdio.h> |
22 | 27 | #include <stdlib.h> |
23 | 28 | #include <string.h> |
24 | ||
25 | #include <openssl/ssl.h> | |
29 | #include <unistd.h> | |
26 | 30 | |
27 | 31 | #include "extern.h" |
32 | ||
33 | /* | |
34 | * A running rsync process. | |
35 | * We can have multiple of these simultaneously and need to keep track | |
36 | * of which process maps to which request. | |
37 | */ | |
38 | struct rsyncproc { | |
39 | char *uri; /* uri of this rsync proc */ | |
40 | size_t id; /* identity of request */ | |
41 | pid_t pid; /* pid of process or 0 if unassociated */ | |
42 | }; | |
28 | 43 | |
29 | 44 | /* |
30 | 45 | * Conforms to RFC 5781. |
132 | 147 | |
133 | 148 | return 1; |
134 | 149 | } |
150 | ||
151 | static void | |
152 | proc_child(int signal) | |
153 | { | |
154 | ||
155 | /* Nothing: just discard. */ | |
156 | } | |
157 | ||
158 | /* | |
159 | * Process used for synchronising repositories. | |
160 | * This simply waits to be told which repository to synchronise, then | |
161 | * does so. | |
162 | * It then responds with the identifier of the repo that it updated. | |
163 | * It only exits cleanly when fd is closed. | |
164 | * FIXME: this should use buffered output to prevent deadlocks, but it's | |
165 | * very unlikely that we're going to fill our buffer, so whatever. | |
166 | * FIXME: limit the number of simultaneous process. | |
167 | * Currently, an attacker can trivially specify thousands of different | |
168 | * repositories and saturate our system. | |
169 | */ | |
170 | void | |
171 | proc_rsync(char *prog, char *bind_addr, int fd) | |
172 | { | |
173 | size_t id, i, idsz = 0; | |
174 | ssize_t ssz; | |
175 | char *host = NULL, *mod = NULL, *uri = NULL, | |
176 | *dst = NULL, *path, *save, *cmd; | |
177 | const char *pp; | |
178 | pid_t pid; | |
179 | char *args[32]; | |
180 | int st, rc = 0; | |
181 | struct stat stt; | |
182 | struct pollfd pfd; | |
183 | sigset_t mask, oldmask; | |
184 | struct rsyncproc *ids = NULL; | |
185 | ||
186 | pfd.fd = fd; | |
187 | pfd.events = POLLIN; | |
188 | ||
189 | /* | |
190 | * Unveil the command we want to run. | |
191 | * If this has a pathname component in it, interpret as a file | |
192 | * and unveil the file directly. | |
193 | * Otherwise, look up the command in our PATH. | |
194 | */ | |
195 | ||
196 | if (strchr(prog, '/') == NULL) { | |
197 | if (getenv("PATH") == NULL) | |
198 | errx(1, "PATH is unset"); | |
199 | if ((path = strdup(getenv("PATH"))) == NULL) | |
200 | err(1, "strdup"); | |
201 | save = path; | |
202 | while ((pp = strsep(&path, ":")) != NULL) { | |
203 | if (*pp == '\0') | |
204 | continue; | |
205 | if (asprintf(&cmd, "%s/%s", pp, prog) == -1) | |
206 | err(1, "asprintf"); | |
207 | if (lstat(cmd, &stt) == -1) { | |
208 | free(cmd); | |
209 | continue; | |
210 | } else if (unveil(cmd, "x") == -1) | |
211 | err(1, "%s: unveil", cmd); | |
212 | free(cmd); | |
213 | break; | |
214 | } | |
215 | free(save); | |
216 | } else if (unveil(prog, "x") == -1) | |
217 | err(1, "%s: unveil", prog); | |
218 | ||
219 | /* Unveil the repository directory and terminate unveiling. */ | |
220 | ||
221 | if (unveil(".", "c") == -1) | |
222 | err(1, "unveil"); | |
223 | if (unveil(NULL, NULL) == -1) | |
224 | err(1, "unveil"); | |
225 | ||
226 | /* Initialise retriever for children exiting. */ | |
227 | ||
228 | if (sigemptyset(&mask) == -1) | |
229 | err(1, NULL); | |
230 | if (signal(SIGCHLD, proc_child) == SIG_ERR) | |
231 | err(1, NULL); | |
232 | if (sigaddset(&mask, SIGCHLD) == -1) | |
233 | err(1, NULL); | |
234 | if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1) | |
235 | err(1, NULL); | |
236 | ||
237 | for (;;) { | |
238 | if (ppoll(&pfd, 1, NULL, &oldmask) == -1) { | |
239 | if (errno != EINTR) | |
240 | err(1, "ppoll"); | |
241 | ||
242 | /* | |
243 | * If we've received an EINTR, it means that one | |
244 | * of our children has exited and we can reap it | |
245 | * and look up its identifier. | |
246 | * Then we respond to the parent. | |
247 | */ | |
248 | ||
249 | while ((pid = waitpid(WAIT_ANY, &st, WNOHANG)) > 0) { | |
250 | int ok = 1; | |
251 | ||
252 | for (i = 0; i < idsz; i++) | |
253 | if (ids[i].pid == pid) | |
254 | break; | |
255 | assert(i < idsz); | |
256 | ||
257 | if (!WIFEXITED(st)) { | |
258 | warnx("rsync %s terminated abnormally", | |
259 | ids[i].uri); | |
260 | rc = 1; | |
261 | ok = 0; | |
262 | } else if (WEXITSTATUS(st) != 0) { | |
263 | warnx("rsync %s failed", ids[i].uri); | |
264 | ok = 0; | |
265 | } | |
266 | ||
267 | io_simple_write(fd, &ids[i].id, sizeof(size_t)); | |
268 | io_simple_write(fd, &ok, sizeof(ok)); | |
269 | free(ids[i].uri); | |
270 | ids[i].uri = NULL; | |
271 | ids[i].pid = 0; | |
272 | ids[i].id = 0; | |
273 | } | |
274 | if (pid == -1 && errno != ECHILD) | |
275 | err(1, "waitpid"); | |
276 | continue; | |
277 | } | |
278 | ||
279 | /* | |
280 | * Read til the parent exits. | |
281 | * That will mean that we can safely exit. | |
282 | */ | |
283 | ||
284 | if ((ssz = read(fd, &id, sizeof(size_t))) == -1) | |
285 | err(1, "read"); | |
286 | if (ssz == 0) | |
287 | break; | |
288 | ||
289 | /* Read host and module. */ | |
290 | ||
291 | io_str_read(fd, &host); | |
292 | io_str_read(fd, &mod); | |
293 | ||
294 | /* | |
295 | * Create source and destination locations. | |
296 | * Build up the tree to this point because GPL rsync(1) | |
297 | * will not build the destination for us. | |
298 | */ | |
299 | ||
300 | if (mkdir(host, 0700) == -1 && EEXIST != errno) | |
301 | err(1, "%s", host); | |
302 | ||
303 | if (asprintf(&dst, "%s/%s", host, mod) == -1) | |
304 | err(1, NULL); | |
305 | if (mkdir(dst, 0700) == -1 && EEXIST != errno) | |
306 | err(1, "%s", dst); | |
307 | ||
308 | if (asprintf(&uri, "rsync://%s/%s", host, mod) == -1) | |
309 | err(1, NULL); | |
310 | ||
311 | /* Run process itself, wait for exit, check error. */ | |
312 | ||
313 | if ((pid = fork()) == -1) | |
314 | err(1, "fork"); | |
315 | ||
316 | if (pid == 0) { | |
317 | if (pledge("stdio exec", NULL) == -1) | |
318 | err(1, "pledge"); | |
319 | i = 0; | |
320 | args[i++] = (char *)prog; | |
321 | args[i++] = "-rt"; | |
322 | if (bind_addr != NULL) { | |
323 | args[i++] = "--address"; | |
324 | args[i++] = (char *)bind_addr; | |
325 | } | |
326 | args[i++] = uri; | |
327 | args[i++] = dst; | |
328 | args[i] = NULL; | |
329 | execvp(args[0], args); | |
330 | err(1, "%s: execvp", prog); | |
331 | } | |
332 | ||
333 | /* Augment the list of running processes. */ | |
334 | ||
335 | for (i = 0; i < idsz; i++) | |
336 | if (ids[i].pid == 0) | |
337 | break; | |
338 | if (i == idsz) { | |
339 | ids = reallocarray(ids, idsz + 1, sizeof(*ids)); | |
340 | if (ids == NULL) | |
341 | err(1, NULL); | |
342 | idsz++; | |
343 | } | |
344 | ||
345 | ids[i].id = id; | |
346 | ids[i].pid = pid; | |
347 | ids[i].uri = uri; | |
348 | ||
349 | /* Clean up temporary values. */ | |
350 | ||
351 | free(mod); | |
352 | free(dst); | |
353 | free(host); | |
354 | } | |
355 | ||
356 | /* No need for these to be hanging around. */ | |
357 | for (i = 0; i < idsz; i++) | |
358 | if (ids[i].pid > 0) { | |
359 | kill(ids[i].pid, SIGTERM); | |
360 | free(ids[i].uri); | |
361 | } | |
362 | ||
363 | free(ids); | |
364 | exit(rc); | |
365 | /* NOTREACHED */ | |
366 | } |
0 | /* $OpenBSD: tal.c,v 1.18 2020/04/11 15:52:24 deraadt Exp $ */ | |
0 | /* $OpenBSD: tal.c,v 1.21 2020/10/01 19:57:00 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
18 | 18 | #include <assert.h> |
19 | 19 | #include <ctype.h> |
20 | 20 | #include <err.h> |
21 | #include <limits.h> | |
21 | 22 | #include <libgen.h> |
22 | #include <resolv.h> | |
23 | 23 | #include <stdio.h> |
24 | 24 | #include <stdlib.h> |
25 | 25 | #include <string.h> |
26 | 26 | |
27 | #include <openssl/x509.h> | |
28 | ||
29 | 27 | #include "extern.h" |
28 | ||
29 | static int | |
30 | base64_decode(const unsigned char *in, size_t inlen, unsigned char **out, | |
31 | size_t *outlen) | |
32 | { | |
33 | static EVP_ENCODE_CTX *ctx; | |
34 | unsigned char *to; | |
35 | int tolen; | |
36 | ||
37 | if (ctx == NULL && (ctx = EVP_ENCODE_CTX_new()) == NULL) | |
38 | err(1, "EVP_ENCODE_CTX_new"); | |
39 | ||
40 | *out = NULL; | |
41 | *outlen = 0; | |
42 | ||
43 | if (inlen >= INT_MAX - 3) | |
44 | return -1; | |
45 | tolen = ((inlen + 3) / 4) * 3 + 1; | |
46 | if ((to = malloc(tolen)) == NULL) | |
47 | return -1; | |
48 | ||
49 | EVP_DecodeInit(ctx); | |
50 | if (EVP_DecodeUpdate(ctx, to, &tolen, in, inlen) == -1) | |
51 | goto fail; | |
52 | *outlen = tolen; | |
53 | if (EVP_DecodeFinal(ctx, to + tolen, &tolen) == -1) | |
54 | goto fail; | |
55 | *outlen += tolen; | |
56 | *out = to; | |
57 | return 0; | |
58 | ||
59 | fail: | |
60 | free(to); | |
61 | return -1; | |
62 | } | |
30 | 63 | |
31 | 64 | /* |
32 | 65 | * Inner function for parsing RFC 7730 from a buffer. |
37 | 70 | tal_parse_buffer(const char *fn, char *buf) |
38 | 71 | { |
39 | 72 | char *nl, *line; |
40 | unsigned char *b64 = NULL; | |
41 | size_t sz; | |
42 | int rc = 0, b64sz; | |
73 | unsigned char *der; | |
74 | size_t sz, dersz; | |
75 | int rc = 0; | |
43 | 76 | struct tal *tal = NULL; |
44 | 77 | enum rtype rp; |
45 | 78 | EVP_PKEY *pkey = NULL; |
106 | 139 | } |
107 | 140 | |
108 | 141 | /* Now the BASE64-encoded public key. */ |
109 | sz = ((sz + 3) / 4) * 3 + 1; | |
110 | if ((b64 = malloc(sz)) == NULL) | |
111 | err(1, NULL); | |
112 | if ((b64sz = b64_pton(buf, b64, sz)) < 0) | |
113 | errx(1, "b64_pton"); | |
114 | ||
115 | tal->pkey = b64; | |
116 | tal->pkeysz = b64sz; | |
142 | if ((base64_decode(buf, sz, &der, &dersz)) == -1) | |
143 | errx(1, "base64 decode"); | |
144 | ||
145 | tal->pkey = der; | |
146 | tal->pkeysz = dersz; | |
117 | 147 | |
118 | 148 | /* Make sure it's a valid public key. */ |
119 | pkey = d2i_PUBKEY(NULL, (const unsigned char **)&b64, b64sz); | |
149 | pkey = d2i_PUBKEY(NULL, (const unsigned char **)&der, dersz); | |
120 | 150 | if (pkey == NULL) { |
121 | 151 | cryptowarnx("%s: RFC 7730 section 2.1: subjectPublicKeyInfo: " |
122 | 152 | "failed public key parse", fn); |
0 | /* $OpenBSD: validate.c,v 1.10 2019/11/29 05:16:54 benno Exp $ */ | |
0 | /* $OpenBSD: validate.c,v 1.11 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
24 | 24 | #include <stdlib.h> |
25 | 25 | #include <string.h> |
26 | 26 | #include <unistd.h> |
27 | ||
28 | #include <openssl/ssl.h> | |
29 | 27 | |
30 | 28 | #include "extern.h" |
31 | 29 |
0 | /* $OpenBSD: x509.c,v 1.13 2019/11/29 05:00:24 benno Exp $ */ | |
0 | /* $OpenBSD: x509.c,v 1.14 2020/09/12 15:46:48 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
24 | 24 | #include <string.h> |
25 | 25 | #include <unistd.h> |
26 | 26 | |
27 | #include <openssl/ssl.h> | |
28 | 27 | #include <openssl/x509v3.h> |
29 | 28 | |
30 | 29 | #include "extern.h" |