Update upstream source from tag 'upstream/7.6'
Update to upstream version '7.6'
with Debian dir 424e7aba58fb9114b8f7bba04e10d4bb03f08cc0
Marco d'Itri
2 years ago
0 | /* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */ | |
0 | /* $OpenBSD: imsg.c,v 1.17 2022/01/28 10:41:44 claudio Exp $ */ | |
1 | 1 | |
2 | 2 | /* |
3 | 3 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> |
151 | 151 | else |
152 | 152 | imsg->fd = -1; |
153 | 153 | |
154 | memcpy(imsg->data, ibuf->r.rptr, datalen); | |
154 | if (datalen != 0) | |
155 | memcpy(imsg->data, ibuf->r.rptr, datalen); | |
155 | 156 | |
156 | 157 | if (imsg->hdr.len < av) { |
157 | 158 | left = av - imsg->hdr.len; |
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 7.5. | |
2 | # Generated by GNU Autoconf 2.69 for rpki-client 7.6. | |
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='7.5' | |
590 | PACKAGE_STRING='rpki-client 7.5' | |
589 | PACKAGE_VERSION='7.6' | |
590 | PACKAGE_STRING='rpki-client 7.6' | |
591 | 591 | PACKAGE_BUGREPORT='' |
592 | 592 | PACKAGE_URL='' |
593 | 593 | |
1398 | 1398 | # Omit some internal or obsolete options to make the list less imposing. |
1399 | 1399 | # This message is too long to be a string in the A/UX 3.1 sh. |
1400 | 1400 | cat <<_ACEOF |
1401 | \`configure' configures rpki-client 7.5 to adapt to many kinds of systems. | |
1401 | \`configure' configures rpki-client 7.6 to adapt to many kinds of systems. | |
1402 | 1402 | |
1403 | 1403 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1404 | 1404 | |
1469 | 1469 | |
1470 | 1470 | if test -n "$ac_init_help"; then |
1471 | 1471 | case $ac_init_help in |
1472 | short | recursive ) echo "Configuration of rpki-client 7.5:";; | |
1472 | short | recursive ) echo "Configuration of rpki-client 7.6:";; | |
1473 | 1473 | esac |
1474 | 1474 | cat <<\_ACEOF |
1475 | 1475 | |
1596 | 1596 | test -n "$ac_init_help" && exit $ac_status |
1597 | 1597 | if $ac_init_version; then |
1598 | 1598 | cat <<\_ACEOF |
1599 | rpki-client configure 7.5 | |
1599 | rpki-client configure 7.6 | |
1600 | 1600 | generated by GNU Autoconf 2.69 |
1601 | 1601 | |
1602 | 1602 | Copyright (C) 2012 Free Software Foundation, Inc. |
1961 | 1961 | This file contains any messages produced by compilers while |
1962 | 1962 | running configure, to aid debugging if configure makes a mistake. |
1963 | 1963 | |
1964 | It was created by rpki-client $as_me 7.5, which was | |
1964 | It was created by rpki-client $as_me 7.6, which was | |
1965 | 1965 | generated by GNU Autoconf 2.69. Invocation command line was |
1966 | 1966 | |
1967 | 1967 | $ $0 $@ |
2891 | 2891 | |
2892 | 2892 | # Define the identity of the package. |
2893 | 2893 | PACKAGE='rpki-client' |
2894 | VERSION='7.5' | |
2894 | VERSION='7.6' | |
2895 | 2895 | |
2896 | 2896 | |
2897 | 2897 | cat >>confdefs.h <<_ACEOF |
14238 | 14238 | # report actual input values of CONFIG_FILES etc. instead of their |
14239 | 14239 | # values after options handling. |
14240 | 14240 | ac_log=" |
14241 | This file was extended by rpki-client $as_me 7.5, which was | |
14241 | This file was extended by rpki-client $as_me 7.6, which was | |
14242 | 14242 | generated by GNU Autoconf 2.69. Invocation command line was |
14243 | 14243 | |
14244 | 14244 | CONFIG_FILES = $CONFIG_FILES |
14295 | 14295 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
14296 | 14296 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
14297 | 14297 | ac_cs_version="\\ |
14298 | rpki-client config.status 7.5 | |
14298 | rpki-client config.status 7.6 | |
14299 | 14299 | configured by $0, generated by GNU Autoconf 2.69, |
14300 | 14300 | with options \\"\$ac_cs_config\\" |
14301 | 14301 |
51 | 51 | rpki_client_SOURCES += output-csv.c |
52 | 52 | rpki_client_SOURCES += output-json.c |
53 | 53 | rpki_client_SOURCES += parser.c |
54 | rpki_client_SOURCES += print.c | |
54 | 55 | rpki_client_SOURCES += repo.c |
55 | 56 | rpki_client_SOURCES += roa.c |
56 | 57 | rpki_client_SOURCES += rrdp.c |
57 | 58 | rpki_client_SOURCES += rrdp_delta.c |
58 | 59 | rpki_client_SOURCES += rrdp_notification.c |
59 | 60 | rpki_client_SOURCES += rrdp_snapshot.c |
61 | rpki_client_SOURCES += rrdp_util.c | |
60 | 62 | rpki_client_SOURCES += rsync.c |
61 | 63 | rpki_client_SOURCES += tal.c |
62 | 64 | rpki_client_SOURCES += validate.c |
130 | 130 | rpki_client-output-bird.$(OBJEXT) \ |
131 | 131 | rpki_client-output-csv.$(OBJEXT) \ |
132 | 132 | rpki_client-output-json.$(OBJEXT) rpki_client-parser.$(OBJEXT) \ |
133 | rpki_client-repo.$(OBJEXT) rpki_client-roa.$(OBJEXT) \ | |
134 | rpki_client-rrdp.$(OBJEXT) rpki_client-rrdp_delta.$(OBJEXT) \ | |
133 | rpki_client-print.$(OBJEXT) rpki_client-repo.$(OBJEXT) \ | |
134 | rpki_client-roa.$(OBJEXT) rpki_client-rrdp.$(OBJEXT) \ | |
135 | rpki_client-rrdp_delta.$(OBJEXT) \ | |
135 | 136 | rpki_client-rrdp_notification.$(OBJEXT) \ |
136 | 137 | rpki_client-rrdp_snapshot.$(OBJEXT) \ |
137 | rpki_client-rsync.$(OBJEXT) rpki_client-tal.$(OBJEXT) \ | |
138 | rpki_client-validate.$(OBJEXT) rpki_client-x509.$(OBJEXT) | |
138 | rpki_client-rrdp_util.$(OBJEXT) rpki_client-rsync.$(OBJEXT) \ | |
139 | rpki_client-tal.$(OBJEXT) rpki_client-validate.$(OBJEXT) \ | |
140 | rpki_client-x509.$(OBJEXT) | |
139 | 141 | rpki_client_OBJECTS = $(am_rpki_client_OBJECTS) |
140 | 142 | AM_V_lt = $(am__v_lt_@AM_V@) |
141 | 143 | am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) |
174 | 176 | ./$(DEPDIR)/rpki_client-output-json.Po \ |
175 | 177 | ./$(DEPDIR)/rpki_client-output.Po \ |
176 | 178 | ./$(DEPDIR)/rpki_client-parser.Po \ |
179 | ./$(DEPDIR)/rpki_client-print.Po \ | |
177 | 180 | ./$(DEPDIR)/rpki_client-repo.Po ./$(DEPDIR)/rpki_client-roa.Po \ |
178 | 181 | ./$(DEPDIR)/rpki_client-rrdp.Po \ |
179 | 182 | ./$(DEPDIR)/rpki_client-rrdp_delta.Po \ |
180 | 183 | ./$(DEPDIR)/rpki_client-rrdp_notification.Po \ |
181 | 184 | ./$(DEPDIR)/rpki_client-rrdp_snapshot.Po \ |
185 | ./$(DEPDIR)/rpki_client-rrdp_util.Po \ | |
182 | 186 | ./$(DEPDIR)/rpki_client-rsync.Po \ |
183 | 187 | ./$(DEPDIR)/rpki_client-tal.Po \ |
184 | 188 | ./$(DEPDIR)/rpki_client-validate.Po \ |
403 | 407 | $(top_builddir)/compat/libcompatnoopt.la |
404 | 408 | rpki_client_SOURCES = as.c cert.c cms.c crl.c encoding.c gbr.c http.c \ |
405 | 409 | io.c ip.c log.c main.c mft.c mkdir.c output.c output-bgpd.c \ |
406 | output-bird.c output-csv.c output-json.c parser.c repo.c roa.c \ | |
407 | rrdp.c rrdp_delta.c rrdp_notification.c rrdp_snapshot.c \ | |
408 | rsync.c tal.c validate.c x509.c | |
410 | output-bird.c output-csv.c output-json.c parser.c print.c \ | |
411 | repo.c roa.c rrdp.c rrdp_delta.c rrdp_notification.c \ | |
412 | rrdp_snapshot.c rrdp_util.c rsync.c tal.c validate.c x509.c | |
409 | 413 | rpki_client_DEPENDENCIES = rpki-client.8 |
410 | 414 | noinst_HEADERS = extern.h rrdp.h version.h |
411 | 415 | all: all-am |
520 | 524 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-output-json.Po@am__quote@ # am--include-marker |
521 | 525 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-output.Po@am__quote@ # am--include-marker |
522 | 526 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-parser.Po@am__quote@ # am--include-marker |
527 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-print.Po@am__quote@ # am--include-marker | |
523 | 528 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-repo.Po@am__quote@ # am--include-marker |
524 | 529 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-roa.Po@am__quote@ # am--include-marker |
525 | 530 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp.Po@am__quote@ # am--include-marker |
526 | 531 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_delta.Po@am__quote@ # am--include-marker |
527 | 532 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_notification.Po@am__quote@ # am--include-marker |
528 | 533 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_snapshot.Po@am__quote@ # am--include-marker |
534 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rrdp_util.Po@am__quote@ # am--include-marker | |
529 | 535 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-rsync.Po@am__quote@ # am--include-marker |
530 | 536 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-tal.Po@am__quote@ # am--include-marker |
531 | 537 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpki_client-validate.Po@am__quote@ # am--include-marker |
827 | 833 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
828 | 834 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-parser.obj `if test -f 'parser.c'; then $(CYGPATH_W) 'parser.c'; else $(CYGPATH_W) '$(srcdir)/parser.c'; fi` |
829 | 835 | |
836 | rpki_client-print.o: print.c | |
837 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-print.o -MD -MP -MF $(DEPDIR)/rpki_client-print.Tpo -c -o rpki_client-print.o `test -f 'print.c' || echo '$(srcdir)/'`print.c | |
838 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-print.Tpo $(DEPDIR)/rpki_client-print.Po | |
839 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='print.c' object='rpki_client-print.o' libtool=no @AMDEPBACKSLASH@ | |
840 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
841 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-print.o `test -f 'print.c' || echo '$(srcdir)/'`print.c | |
842 | ||
843 | rpki_client-print.obj: print.c | |
844 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-print.obj -MD -MP -MF $(DEPDIR)/rpki_client-print.Tpo -c -o rpki_client-print.obj `if test -f 'print.c'; then $(CYGPATH_W) 'print.c'; else $(CYGPATH_W) '$(srcdir)/print.c'; fi` | |
845 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-print.Tpo $(DEPDIR)/rpki_client-print.Po | |
846 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='print.c' object='rpki_client-print.obj' libtool=no @AMDEPBACKSLASH@ | |
847 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
848 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-print.obj `if test -f 'print.c'; then $(CYGPATH_W) 'print.c'; else $(CYGPATH_W) '$(srcdir)/print.c'; fi` | |
849 | ||
830 | 850 | rpki_client-repo.o: repo.c |
831 | 851 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-repo.o -MD -MP -MF $(DEPDIR)/rpki_client-repo.Tpo -c -o rpki_client-repo.o `test -f 'repo.c' || echo '$(srcdir)/'`repo.c |
832 | 852 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-repo.Tpo $(DEPDIR)/rpki_client-repo.Po |
910 | 930 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rrdp_snapshot.c' object='rpki_client-rrdp_snapshot.obj' libtool=no @AMDEPBACKSLASH@ |
911 | 931 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
912 | 932 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-rrdp_snapshot.obj `if test -f 'rrdp_snapshot.c'; then $(CYGPATH_W) 'rrdp_snapshot.c'; else $(CYGPATH_W) '$(srcdir)/rrdp_snapshot.c'; fi` |
933 | ||
934 | rpki_client-rrdp_util.o: rrdp_util.c | |
935 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-rrdp_util.o -MD -MP -MF $(DEPDIR)/rpki_client-rrdp_util.Tpo -c -o rpki_client-rrdp_util.o `test -f 'rrdp_util.c' || echo '$(srcdir)/'`rrdp_util.c | |
936 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-rrdp_util.Tpo $(DEPDIR)/rpki_client-rrdp_util.Po | |
937 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rrdp_util.c' object='rpki_client-rrdp_util.o' libtool=no @AMDEPBACKSLASH@ | |
938 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
939 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-rrdp_util.o `test -f 'rrdp_util.c' || echo '$(srcdir)/'`rrdp_util.c | |
940 | ||
941 | rpki_client-rrdp_util.obj: rrdp_util.c | |
942 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-rrdp_util.obj -MD -MP -MF $(DEPDIR)/rpki_client-rrdp_util.Tpo -c -o rpki_client-rrdp_util.obj `if test -f 'rrdp_util.c'; then $(CYGPATH_W) 'rrdp_util.c'; else $(CYGPATH_W) '$(srcdir)/rrdp_util.c'; fi` | |
943 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/rpki_client-rrdp_util.Tpo $(DEPDIR)/rpki_client-rrdp_util.Po | |
944 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rrdp_util.c' object='rpki_client-rrdp_util.obj' libtool=no @AMDEPBACKSLASH@ | |
945 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
946 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -c -o rpki_client-rrdp_util.obj `if test -f 'rrdp_util.c'; then $(CYGPATH_W) 'rrdp_util.c'; else $(CYGPATH_W) '$(srcdir)/rrdp_util.c'; fi` | |
913 | 947 | |
914 | 948 | rpki_client-rsync.o: rsync.c |
915 | 949 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rpki_client_CFLAGS) $(CFLAGS) -MT rpki_client-rsync.o -MD -MP -MF $(DEPDIR)/rpki_client-rsync.Tpo -c -o rpki_client-rsync.o `test -f 'rsync.c' || echo '$(srcdir)/'`rsync.c |
1164 | 1198 | -rm -f ./$(DEPDIR)/rpki_client-output-json.Po |
1165 | 1199 | -rm -f ./$(DEPDIR)/rpki_client-output.Po |
1166 | 1200 | -rm -f ./$(DEPDIR)/rpki_client-parser.Po |
1201 | -rm -f ./$(DEPDIR)/rpki_client-print.Po | |
1167 | 1202 | -rm -f ./$(DEPDIR)/rpki_client-repo.Po |
1168 | 1203 | -rm -f ./$(DEPDIR)/rpki_client-roa.Po |
1169 | 1204 | -rm -f ./$(DEPDIR)/rpki_client-rrdp.Po |
1170 | 1205 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_delta.Po |
1171 | 1206 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_notification.Po |
1172 | 1207 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_snapshot.Po |
1208 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_util.Po | |
1173 | 1209 | -rm -f ./$(DEPDIR)/rpki_client-rsync.Po |
1174 | 1210 | -rm -f ./$(DEPDIR)/rpki_client-tal.Po |
1175 | 1211 | -rm -f ./$(DEPDIR)/rpki_client-validate.Po |
1238 | 1274 | -rm -f ./$(DEPDIR)/rpki_client-output-json.Po |
1239 | 1275 | -rm -f ./$(DEPDIR)/rpki_client-output.Po |
1240 | 1276 | -rm -f ./$(DEPDIR)/rpki_client-parser.Po |
1277 | -rm -f ./$(DEPDIR)/rpki_client-print.Po | |
1241 | 1278 | -rm -f ./$(DEPDIR)/rpki_client-repo.Po |
1242 | 1279 | -rm -f ./$(DEPDIR)/rpki_client-roa.Po |
1243 | 1280 | -rm -f ./$(DEPDIR)/rpki_client-rrdp.Po |
1244 | 1281 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_delta.Po |
1245 | 1282 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_notification.Po |
1246 | 1283 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_snapshot.Po |
1284 | -rm -f ./$(DEPDIR)/rpki_client-rrdp_util.Po | |
1247 | 1285 | -rm -f ./$(DEPDIR)/rpki_client-rsync.Po |
1248 | 1286 | -rm -f ./$(DEPDIR)/rpki_client-tal.Po |
1249 | 1287 | -rm -f ./$(DEPDIR)/rpki_client-validate.Po |
0 | /* $OpenBSD: as.c,v 1.6 2020/09/12 15:46:48 claudio Exp $ */ | |
0 | /* $OpenBSD: as.c,v 1.7 2021/12/26 12:32:28 tb Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
74 | 74 | { |
75 | 75 | size_t i; |
76 | 76 | |
77 | /* We can have only one inheritence statement. */ | |
77 | /* We can have only one inheritance statement. */ | |
78 | 78 | |
79 | 79 | if (asz && |
80 | 80 | (a->type == CERT_AS_INHERIT || as[0].type == CERT_AS_INHERIT)) { |
81 | 81 | warnx("%s: RFC 3779 section 3.2.3.3: " |
82 | "cannot have inheritence and multiple ASnum or " | |
83 | "multiple inheritence", fn); | |
82 | "cannot have inheritance and multiple ASnum or " | |
83 | "multiple inheritance", fn); | |
84 | 84 | return 0; |
85 | 85 | } |
86 | 86 |
0 | /* $OpenBSD: cert.c,v 1.47 2021/11/05 10:50:41 claudio Exp $ */ | |
0 | /* $OpenBSD: cert.c,v 1.56 2022/02/04 16:50:49 tb Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2021 Job Snijders <job@openbsd.org> |
3 | 3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
28 | 28 | |
29 | 29 | #include <openssl/asn1.h> |
30 | 30 | #include <openssl/x509.h> |
31 | #include <openssl/x509v3.h> | |
31 | 32 | |
32 | 33 | #include "extern.h" |
33 | 34 | |
46 | 47 | const char *fn; /* currently-parsed file */ |
47 | 48 | }; |
48 | 49 | |
49 | static ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ | |
50 | static ASN1_OBJECT *mft_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ | |
51 | static ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ | |
52 | ||
53 | static void | |
54 | cert_init_oid(void) | |
55 | { | |
56 | if ((carepo_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.5", 1)) == NULL) | |
57 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.5"); | |
58 | if ((mft_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.10", 1)) == NULL) | |
59 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.10"); | |
60 | if ((notify_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.13", 1)) == NULL) | |
61 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.13"); | |
62 | } | |
50 | extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ | |
51 | extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ | |
52 | extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ | |
53 | extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ | |
63 | 54 | |
64 | 55 | /* |
65 | 56 | * Append an IP address structure to our list of results. |
66 | * This will also constrain us to having at most one inheritence | |
67 | * statement per AFI and also not have overlapping rages (as prohibited | |
57 | * This will also constrain us to having at most one inheritance | |
58 | * statement per AFI and also not have overlapping ranges (as prohibited | |
68 | 59 | * in section 2.2.3.6). |
69 | 60 | * It does not make sure that ranges can't coalesce, that is, that any |
70 | 61 | * two ranges abut each other. |
71 | 62 | * This is warned against in section 2.2.3.6, but doesn't change the |
72 | 63 | * semantics of the system. |
73 | * Return zero on failure (IP overlap) non-zero on success. | |
64 | * Returns zero on failure (IP overlap) non-zero on success. | |
74 | 65 | */ |
75 | 66 | static int |
76 | 67 | append_ip(struct parse *p, const struct cert_ip *ip) |
112 | 103 | |
113 | 104 | /* |
114 | 105 | * Construct a RFC 3779 2.2.3.8 range by its bit string. |
115 | * Return zero on failure, non-zero on success. | |
106 | * Returns zero on failure, non-zero on success. | |
116 | 107 | */ |
117 | 108 | static int |
118 | 109 | sbgp_addr(struct parse *p, |
269 | 260 | if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag)) |
270 | 261 | goto out; |
271 | 262 | |
272 | if (carepo_oid == NULL) | |
273 | cert_init_oid(); | |
274 | ||
275 | 263 | if (OBJ_cmp(oid, carepo_oid) == 0) |
276 | 264 | rc = sbgp_sia_resource_carepo(p, d, plen); |
277 | else if (OBJ_cmp(oid, mft_oid) == 0) | |
265 | else if (OBJ_cmp(oid, manifest_oid) == 0) | |
278 | 266 | rc = sbgp_sia_resource_mft(p, d, plen); |
279 | 267 | else if (OBJ_cmp(oid, notify_oid) == 0) |
280 | 268 | rc = sbgp_sia_resource_notify(p, d, plen); |
587 | 575 | int dsz, rc = 0, i, ptag; |
588 | 576 | long plen; |
589 | 577 | |
578 | if (!X509_EXTENSION_get_critical(ext)) { | |
579 | cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: " | |
580 | "extension not critical", p->fn); | |
581 | goto out; | |
582 | } | |
583 | ||
590 | 584 | if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) { |
591 | 585 | cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: " |
592 | 586 | "failed extension parse", p->fn); |
686 | 680 | |
687 | 681 | /* |
688 | 682 | * Parse RFC 3779 2.2.3.9 range of addresses. |
689 | * Return zero on failure, non-zero on success. | |
683 | * Returns zero on failure, non-zero on success. | |
690 | 684 | */ |
691 | 685 | static int |
692 | 686 | sbgp_addr_range(struct parse *p, struct cert_ip *ip, |
890 | 884 | const ASN1_TYPE *t = NULL; |
891 | 885 | int i; |
892 | 886 | |
887 | if (!X509_EXTENSION_get_critical(ext)) { | |
888 | cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: " | |
889 | "extension not critical", p->fn); | |
890 | goto out; | |
891 | } | |
892 | ||
893 | 893 | if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) { |
894 | 894 | cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: " |
895 | 895 | "failed extension parse", p->fn); |
971 | 971 | } |
972 | 972 | |
973 | 973 | /* |
974 | * Parse the certificate policies extension and check that it follows RFC 7318. | |
975 | * Returns zero on failure, non-zero on success. | |
976 | */ | |
977 | static int | |
978 | certificate_policies(struct parse *p, X509_EXTENSION *ext) | |
979 | { | |
980 | STACK_OF(POLICYINFO) *policies = NULL; | |
981 | POLICYINFO *policy; | |
982 | STACK_OF(POLICYQUALINFO) *qualifiers; | |
983 | POLICYQUALINFO *qualifier; | |
984 | int nid; | |
985 | int rc = 0; | |
986 | ||
987 | if (!X509_EXTENSION_get_critical(ext)) { | |
988 | cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " | |
989 | "extension not critical", p->fn); | |
990 | goto out; | |
991 | } | |
992 | ||
993 | if ((policies = X509V3_EXT_d2i(ext)) == NULL) { | |
994 | cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " | |
995 | "failed extension parse", p->fn); | |
996 | goto out; | |
997 | } | |
998 | ||
999 | if (sk_POLICYINFO_num(policies) != 1) { | |
1000 | warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " | |
1001 | "want 1 policy, got %d", p->fn, | |
1002 | sk_POLICYINFO_num(policies)); | |
1003 | goto out; | |
1004 | } | |
1005 | ||
1006 | policy = sk_POLICYINFO_value(policies, 0); | |
1007 | assert(policy != NULL && policy->policyid != NULL); | |
1008 | ||
1009 | if (OBJ_cmp(policy->policyid, certpol_oid) != 0) { | |
1010 | char pbuf[128], cbuf[128]; | |
1011 | ||
1012 | OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1); | |
1013 | OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1); | |
1014 | warnx("%s: RFC 7318 section 2: certificatePolicies: " | |
1015 | "unexpected OID: %s, want %s", p->fn, pbuf, cbuf); | |
1016 | goto out; | |
1017 | } | |
1018 | ||
1019 | /* Policy qualifiers are optional. If they're absent, we're done. */ | |
1020 | if ((qualifiers = policy->qualifiers) == NULL) { | |
1021 | rc = 1; | |
1022 | goto out; | |
1023 | } | |
1024 | ||
1025 | if (sk_POLICYQUALINFO_num(qualifiers) != 1) { | |
1026 | warnx("%s: RFC 7318 section 2: certificatePolicies: " | |
1027 | "want 1 policy qualifier, got %d", p->fn, | |
1028 | sk_POLICYQUALINFO_num(qualifiers)); | |
1029 | goto out; | |
1030 | } | |
1031 | ||
1032 | qualifier = sk_POLICYQUALINFO_value(qualifiers, 0); | |
1033 | assert(qualifier != NULL && qualifier->pqualid != NULL); | |
1034 | ||
1035 | if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) { | |
1036 | warnx("%s: RFC 7318 section 2: certificatePolicies: " | |
1037 | "want CPS, got %d (%s)", p->fn, nid, OBJ_nid2sn(nid)); | |
1038 | goto out; | |
1039 | } | |
1040 | ||
1041 | if (verbose > 1) | |
1042 | warnx("%s: CPS %.*s", p->fn, qualifier->d.cpsuri->length, | |
1043 | qualifier->d.cpsuri->data); | |
1044 | ||
1045 | rc = 1; | |
1046 | out: | |
1047 | sk_POLICYINFO_pop_free(policies, POLICYINFO_free); | |
1048 | return rc; | |
1049 | } | |
1050 | ||
1051 | /* | |
974 | 1052 | * Parse and partially validate an RPKI X509 certificate (either a trust |
975 | 1053 | * anchor or a certificate) as defined in RFC 6487. |
976 | 1054 | * If "ta" is set, this is a trust anchor and must be self-signed. |
979 | 1057 | * is also dereferenced. |
980 | 1058 | */ |
981 | 1059 | static struct cert * |
982 | cert_parse_inner(X509 **xp, const char *fn, const unsigned char *der, | |
983 | size_t len, int ta) | |
1060 | cert_parse_inner(const char *fn, const unsigned char *der, size_t len, int ta) | |
984 | 1061 | { |
985 | 1062 | int rc = 0, extsz, c; |
986 | 1063 | int sia_present = 0; |
990 | 1067 | ASN1_OBJECT *obj; |
991 | 1068 | struct parse p; |
992 | 1069 | |
993 | *xp = NULL; | |
994 | ||
995 | 1070 | /* just fail for empty buffers, the warning was printed elsewhere */ |
996 | 1071 | if (der == NULL) |
997 | 1072 | return NULL; |
1001 | 1076 | if ((p.res = calloc(1, sizeof(struct cert))) == NULL) |
1002 | 1077 | err(1, NULL); |
1003 | 1078 | |
1004 | if ((x = *xp = d2i_X509(NULL, &der, len)) == NULL) { | |
1079 | if ((x = d2i_X509(NULL, &der, len)) == NULL) { | |
1005 | 1080 | cryptowarnx("%s: d2i_X509_bio", p.fn); |
1006 | 1081 | goto out; |
1007 | 1082 | } |
1028 | 1103 | case NID_sinfo_access: |
1029 | 1104 | sia_present = 1; |
1030 | 1105 | c = sbgp_sia(&p, ext); |
1106 | break; | |
1107 | case NID_certificate_policies: | |
1108 | c = certificate_policies(&p, ext); | |
1031 | 1109 | break; |
1032 | 1110 | case NID_crl_distribution_points: |
1033 | 1111 | /* ignored here, handled later */ |
1140 | 1218 | goto out; |
1141 | 1219 | } |
1142 | 1220 | |
1143 | if (X509_up_ref(x) == 0) | |
1144 | errx(1, "%s: X509_up_ref failed", __func__); | |
1145 | ||
1146 | 1221 | p.res->x509 = x; |
1147 | 1222 | |
1148 | 1223 | rc = 1; |
1150 | 1225 | if (rc == 0) { |
1151 | 1226 | cert_free(p.res); |
1152 | 1227 | X509_free(x); |
1153 | *xp = NULL; | |
1154 | 1228 | } |
1155 | 1229 | return (rc == 0) ? NULL : p.res; |
1156 | 1230 | } |
1157 | 1231 | |
1158 | 1232 | struct cert * |
1159 | cert_parse(X509 **xp, const char *fn, const unsigned char *der, size_t len) | |
1160 | { | |
1161 | return cert_parse_inner(xp, fn, der, len, 0); | |
1233 | cert_parse(const char *fn, const unsigned char *der, size_t len) | |
1234 | { | |
1235 | return cert_parse_inner(fn, der, len, 0); | |
1162 | 1236 | } |
1163 | 1237 | |
1164 | 1238 | struct cert * |
1165 | ta_parse(X509 **xp, const char *fn, const unsigned char *der, size_t len, | |
1239 | ta_parse(const char *fn, const unsigned char *der, size_t len, | |
1166 | 1240 | const unsigned char *pkey, size_t pkeysz) |
1167 | 1241 | { |
1242 | ASN1_TIME *notBefore, *notAfter; | |
1168 | 1243 | EVP_PKEY *pk = NULL, *opk = NULL; |
1169 | 1244 | struct cert *p; |
1170 | 1245 | int rc = 0; |
1171 | 1246 | |
1172 | if ((p = cert_parse_inner(xp, fn, der, len, 1)) == NULL) | |
1247 | if ((p = cert_parse_inner(fn, der, len, 1)) == NULL) | |
1173 | 1248 | return NULL; |
1174 | 1249 | |
1175 | if (pkey != NULL) { | |
1176 | assert(*xp != NULL); | |
1177 | pk = d2i_PUBKEY(NULL, &pkey, pkeysz); | |
1178 | assert(pk != NULL); | |
1179 | ||
1180 | if ((opk = X509_get_pubkey(*xp)) == NULL) | |
1181 | cryptowarnx("%s: RFC 6487 (trust anchor): " | |
1182 | "missing pubkey", fn); | |
1183 | else if (EVP_PKEY_cmp(pk, opk) != 1) | |
1184 | cryptowarnx("%s: RFC 6487 (trust anchor): " | |
1185 | "pubkey does not match TAL pubkey", fn); | |
1186 | else | |
1187 | rc = 1; | |
1188 | ||
1189 | EVP_PKEY_free(pk); | |
1190 | EVP_PKEY_free(opk); | |
1191 | } | |
1192 | ||
1250 | /* first check pubkey against the one from the TAL */ | |
1251 | pk = d2i_PUBKEY(NULL, &pkey, pkeysz); | |
1252 | if (pk == NULL) { | |
1253 | cryptowarnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn); | |
1254 | goto badcert; | |
1255 | } | |
1256 | if ((opk = X509_get0_pubkey(p->x509)) == NULL) { | |
1257 | cryptowarnx("%s: RFC 6487 (trust anchor): missing pubkey", fn); | |
1258 | goto badcert; | |
1259 | } else if (EVP_PKEY_cmp(pk, opk) != 1) { | |
1260 | cryptowarnx("%s: RFC 6487 (trust anchor): " | |
1261 | "pubkey does not match TAL pubkey", fn); | |
1262 | goto badcert; | |
1263 | } | |
1264 | ||
1265 | if ((notBefore = X509_get_notBefore(p->x509)) == NULL) { | |
1266 | warnx("%s: certificate has invalid notBefore", fn); | |
1267 | goto badcert; | |
1268 | } | |
1269 | if ((notAfter = X509_get_notAfter(p->x509)) == NULL) { | |
1270 | warnx("%s: certificate has invalid notAfter", fn); | |
1271 | goto badcert; | |
1272 | } | |
1273 | if (X509_cmp_current_time(notBefore) != -1) { | |
1274 | warnx("%s: certificate not yet valid", fn); | |
1275 | goto badcert; | |
1276 | } | |
1277 | if (X509_cmp_current_time(notAfter) != 1) { | |
1278 | warnx("%s: certificate has expired", fn); | |
1279 | goto badcert; | |
1280 | } | |
1281 | ||
1282 | rc = 1; | |
1283 | ||
1284 | badcert: | |
1285 | EVP_PKEY_free(pk); | |
1193 | 1286 | if (rc == 0) { |
1194 | 1287 | cert_free(p); |
1195 | 1288 | p = NULL; |
1196 | X509_free(*xp); | |
1197 | *xp = NULL; | |
1198 | 1289 | } |
1199 | 1290 | |
1200 | 1291 | return p; |
1306 | 1397 | return RB_FIND(auth_tree, auths, &a); |
1307 | 1398 | } |
1308 | 1399 | |
1309 | int | |
1400 | void | |
1310 | 1401 | auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *parent) |
1311 | 1402 | { |
1312 | 1403 | struct auth *na; |
1320 | 1411 | |
1321 | 1412 | if (RB_INSERT(auth_tree, auths, na) != NULL) |
1322 | 1413 | err(1, "auth tree corrupted"); |
1323 | ||
1324 | return 1; | |
1325 | 1414 | } |
1326 | 1415 | |
1327 | 1416 | static inline int |
0 | /* $OpenBSD: cms.c,v 1.11 2021/10/26 10:52:49 claudio Exp $ */ | |
0 | /* $OpenBSD: cms.c,v 1.13 2022/01/18 16:24:55 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
0 | /* $OpenBSD: encoding.c,v 1.9 2021/10/31 16:00:14 claudio Exp $ */ | |
0 | /* $OpenBSD: encoding.c,v 1.10 2021/11/24 15:24:16 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * |
17 | 17 | |
18 | 18 | #include <err.h> |
19 | 19 | #include <errno.h> |
20 | #include <ctype.h> | |
20 | 21 | #include <fcntl.h> |
21 | 22 | #include <limits.h> |
22 | 23 | #include <stdlib.h> |
184 | 185 | |
185 | 186 | return out; |
186 | 187 | } |
188 | ||
189 | /* | |
190 | * Hex decode hexstring into the supplied buffer. | |
191 | * Return 0 on success else -1, if buffer too small or bad encoding. | |
192 | */ | |
193 | int | |
194 | hex_decode(const char *hexstr, char *buf, size_t len) | |
195 | { | |
196 | unsigned char ch, r; | |
197 | size_t pos = 0; | |
198 | int i; | |
199 | ||
200 | while (*hexstr) { | |
201 | r = 0; | |
202 | for (i = 0; i < 2; i++) { | |
203 | ch = hexstr[i]; | |
204 | if (isdigit(ch)) | |
205 | ch -= '0'; | |
206 | else if (islower(ch)) | |
207 | ch -= ('a' - 10); | |
208 | else if (isupper(ch)) | |
209 | ch -= ('A' - 10); | |
210 | else | |
211 | return -1; | |
212 | if (ch > 0xf) | |
213 | return -1; | |
214 | r = r << 4 | ch; | |
215 | } | |
216 | if (pos < len) | |
217 | buf[pos++] = r; | |
218 | else | |
219 | return -1; | |
220 | ||
221 | hexstr += 2; | |
222 | } | |
223 | return 0; | |
224 | } | |
225 |
0 | /* $OpenBSD: extern.h,v 1.95 2021/11/09 11:03:39 claudio Exp $ */ | |
0 | /* $OpenBSD: extern.h,v 1.116 2022/01/28 15:30:23 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
148 | 148 | }; |
149 | 149 | |
150 | 150 | /* |
151 | * Resource types specified by the RPKI profiles. | |
152 | * There might be others we don't consider. | |
153 | */ | |
154 | enum rtype { | |
155 | RTYPE_INVALID, | |
156 | RTYPE_TAL, | |
157 | RTYPE_MFT, | |
158 | RTYPE_ROA, | |
159 | RTYPE_CER, | |
160 | RTYPE_CRL, | |
161 | RTYPE_GBR, | |
162 | RTYPE_REPO, | |
163 | RTYPE_FILE, | |
164 | }; | |
165 | ||
166 | enum location { | |
167 | DIR_UNKNOWN, | |
168 | DIR_TEMP, | |
169 | DIR_VALID, | |
170 | }; | |
171 | ||
172 | /* | |
151 | 173 | * Files specified in an MFT have their bodies hashed with SHA256. |
152 | 174 | */ |
153 | 175 | struct mftfile { |
154 | 176 | char *file; /* filename (CER/ROA/CRL, no path) */ |
177 | enum rtype type; /* file type as determined by extension */ | |
178 | enum location location; /* temporary or valid directory */ | |
155 | 179 | unsigned char hash[SHA256_DIGEST_LENGTH]; /* sha256 of body */ |
156 | 180 | }; |
157 | 181 | |
161 | 185 | * manifest file. |
162 | 186 | */ |
163 | 187 | struct mft { |
164 | char *file; /* full path of MFT file */ | |
188 | char *path; /* relative path to directory of the MFT */ | |
165 | 189 | struct mftfile *files; /* file and hash */ |
166 | size_t filesz; /* number of filenames */ | |
167 | int stale; /* if a stale manifest */ | |
168 | 190 | char *seqnum; /* manifestNumber */ |
169 | 191 | char *aia; /* AIA */ |
170 | 192 | char *aki; /* AKI */ |
171 | 193 | char *ski; /* SKI */ |
194 | time_t valid_from; | |
195 | time_t valid_until; | |
196 | size_t filesz; /* number of filenames */ | |
197 | unsigned int repoid; | |
198 | int stale; /* if a stale manifest */ | |
172 | 199 | }; |
173 | 200 | |
174 | 201 | /* |
178 | 205 | */ |
179 | 206 | struct roa_ip { |
180 | 207 | enum afi afi; /* AFI value */ |
181 | size_t maxlength; /* max length or zero */ | |
208 | struct ip_addr addr; /* the address prefix itself */ | |
182 | 209 | unsigned char min[16]; /* full range minimum */ |
183 | 210 | unsigned char max[16]; /* full range maximum */ |
184 | struct ip_addr addr; /* the address prefix itself */ | |
211 | unsigned char maxlength; /* max length or zero */ | |
185 | 212 | }; |
186 | 213 | |
187 | 214 | /* |
277 | 304 | RB_PROTOTYPE(auth_tree, auth, entry, authcmp); |
278 | 305 | |
279 | 306 | struct auth *auth_find(struct auth_tree *, const char *); |
280 | int auth_insert(struct auth_tree *, struct cert *, struct auth *); | |
281 | ||
282 | /* | |
283 | * Resource types specified by the RPKI profiles. | |
284 | * There might be others we don't consider. | |
285 | */ | |
286 | enum rtype { | |
287 | RTYPE_EOF = 0, | |
288 | RTYPE_TAL, | |
289 | RTYPE_MFT, | |
290 | RTYPE_ROA, | |
291 | RTYPE_CER, | |
292 | RTYPE_CRL, | |
293 | RTYPE_GBR, | |
294 | }; | |
307 | void auth_insert(struct auth_tree *, struct cert *, struct auth *); | |
295 | 308 | |
296 | 309 | enum http_result { |
297 | 310 | HTTP_FAILED, /* anything else */ |
306 | 319 | RRDP_START, |
307 | 320 | RRDP_SESSION, |
308 | 321 | RRDP_FILE, |
322 | RRDP_CLEAR, | |
309 | 323 | RRDP_END, |
310 | 324 | RRDP_HTTP_REQ, |
311 | 325 | RRDP_HTTP_INI, |
312 | RRDP_HTTP_FIN | |
326 | RRDP_HTTP_FIN, | |
313 | 327 | }; |
314 | 328 | |
315 | 329 | /* |
335 | 349 | * and parsed. |
336 | 350 | */ |
337 | 351 | struct entity { |
338 | enum rtype type; /* type of entity (not RTYPE_EOF) */ | |
339 | char *file; /* local path to file */ | |
340 | int has_data; /* whether data blob is specified */ | |
352 | TAILQ_ENTRY(entity) entries; | |
353 | char *path; /* path relative to repository */ | |
354 | char *file; /* filename or valid repo path */ | |
341 | 355 | unsigned char *data; /* optional data blob */ |
342 | 356 | size_t datasz; /* length of optional data blob */ |
357 | unsigned int repoid; /* repository identifier */ | |
343 | 358 | int talid; /* tal identifier */ |
344 | TAILQ_ENTRY(entity) entries; | |
359 | enum rtype type; /* type of entity (not RTYPE_EOF) */ | |
360 | enum location location; /* which directroy the file lives in */ | |
345 | 361 | }; |
346 | 362 | TAILQ_HEAD(entityq, entity); |
347 | 363 | |
375 | 391 | size_t vrps; /* total number of vrps */ |
376 | 392 | size_t uniqs; /* number of unique vrps */ |
377 | 393 | size_t del_files; /* number of files removed in cleanup */ |
394 | size_t extra_files; /* number of superfluous files */ | |
378 | 395 | size_t del_dirs; /* number of directories removed in cleanup */ |
379 | 396 | size_t brks; /* number of BGPsec Router Key (BRK) certificates */ |
380 | 397 | struct timeval elapsed_time; |
387 | 404 | |
388 | 405 | /* global variables */ |
389 | 406 | extern int verbose; |
407 | extern int filemode; | |
390 | 408 | extern const char *tals[]; |
391 | 409 | extern const char *taldescs[]; |
392 | 410 | extern unsigned int talrepocnt[]; |
401 | 419 | |
402 | 420 | void cert_buffer(struct ibuf *, const struct cert *); |
403 | 421 | void cert_free(struct cert *); |
404 | struct cert *cert_parse(X509 **, const char *, const unsigned char *, | |
405 | size_t); | |
406 | struct cert *ta_parse(X509 **, const char *, const unsigned char *, size_t, | |
422 | struct cert *cert_parse(const char *, const unsigned char *, size_t); | |
423 | struct cert *ta_parse(const char *, const unsigned char *, size_t, | |
407 | 424 | const unsigned char *, size_t); |
408 | 425 | struct cert *cert_read(struct ibuf *); |
409 | 426 | void cert_insert_brks(struct brk_tree *, struct cert *); |
410 | 427 | |
428 | enum rtype rtype_from_file_extension(const char *); | |
411 | 429 | void mft_buffer(struct ibuf *, const struct mft *); |
412 | 430 | void mft_free(struct mft *); |
413 | 431 | struct mft *mft_parse(X509 **, const char *, const unsigned char *, |
414 | 432 | size_t); |
415 | int mft_check(const char *, struct mft *); | |
416 | 433 | struct mft *mft_read(struct ibuf *); |
434 | int mft_compare(const struct mft *, const struct mft *); | |
417 | 435 | |
418 | 436 | void roa_buffer(struct ibuf *, const struct roa *); |
419 | 437 | void roa_free(struct roa *); |
437 | 455 | const char *, const char *); |
438 | 456 | int valid_ta(const char *, struct auth_tree *, |
439 | 457 | const struct cert *); |
440 | int valid_cert(const char *, struct auth_tree *, | |
441 | const struct cert *); | |
442 | int valid_roa(const char *, struct auth_tree *, struct roa *); | |
443 | int valid_filename(const char *); | |
444 | int valid_filehash(const char *, const char *, size_t); | |
458 | int valid_cert(const char *, struct auth *, const struct cert *); | |
459 | int valid_roa(const char *, struct auth *, struct roa *); | |
460 | int valid_filehash(int, const char *, size_t); | |
445 | 461 | int valid_uri(const char *, size_t, const char *); |
446 | 462 | int valid_origin(const char *, const char *); |
447 | 463 | |
497 | 513 | |
498 | 514 | /* Repository handling */ |
499 | 515 | int filepath_add(struct filepath_tree *, char *); |
500 | void rrdp_save_state(size_t, struct rrdp_session *); | |
501 | int rrdp_handle_file(size_t, enum publish_type, char *, | |
516 | void rrdp_clear(unsigned int); | |
517 | void rrdp_save_state(unsigned int, struct rrdp_session *); | |
518 | int rrdp_handle_file(unsigned int, enum publish_type, char *, | |
502 | 519 | char *, size_t, char *, size_t); |
503 | char *repo_filename(const struct repo *, const char *); | |
520 | char *repo_basedir(const struct repo *, int); | |
521 | unsigned int repo_id(const struct repo *); | |
522 | const char *repo_uri(const struct repo *); | |
504 | 523 | struct repo *ta_lookup(int, struct tal *); |
505 | 524 | struct repo *repo_lookup(int, const char *, const char *); |
525 | struct repo *repo_byid(unsigned int); | |
506 | 526 | int repo_queued(struct repo *, struct entity *); |
507 | 527 | void repo_cleanup(struct filepath_tree *); |
508 | 528 | void repo_free(void); |
509 | 529 | |
510 | void rsync_finish(size_t, int); | |
511 | void http_finish(size_t, enum http_result, const char *); | |
512 | void rrdp_finish(size_t, int); | |
513 | ||
514 | void rsync_fetch(size_t, const char *, const char *); | |
515 | void http_fetch(size_t, const char *, const char *, int); | |
516 | void rrdp_fetch(size_t, const char *, const char *, | |
530 | void rsync_finish(unsigned int, int); | |
531 | void http_finish(unsigned int, enum http_result, const char *); | |
532 | void rrdp_finish(unsigned int, int); | |
533 | ||
534 | void rsync_fetch(unsigned int, const char *, const char *, | |
535 | const char *); | |
536 | void http_fetch(unsigned int, const char *, const char *, int); | |
537 | void rrdp_fetch(unsigned int, const char *, const char *, | |
517 | 538 | struct rrdp_session *); |
518 | void rrdp_http_done(size_t, enum http_result, const char *); | |
519 | ||
520 | int repo_next_timeout(int); | |
521 | void repo_check_timeout(void); | |
539 | void rrdp_http_done(unsigned int, enum http_result, const char *); | |
540 | int repo_check_timeout(int); | |
522 | 541 | |
523 | 542 | /* Logging (though really used for OpenSSL errors). */ |
524 | 543 | |
537 | 556 | int base64_encode_len(size_t, size_t *); |
538 | 557 | int base64_encode(const unsigned char *, size_t, char **); |
539 | 558 | char *hex_encode(const unsigned char *, size_t); |
559 | int hex_decode(const char *, char *, size_t); | |
540 | 560 | |
541 | 561 | |
542 | 562 | /* Functions for moving data between processes. */ |
554 | 574 | |
555 | 575 | /* X509 helpers. */ |
556 | 576 | |
577 | void x509_init_oid(void); | |
557 | 578 | char *x509_get_aia(X509 *, const char *); |
558 | 579 | char *x509_get_aki(X509 *, int, const char *); |
559 | 580 | char *x509_get_ski(X509 *, const char *); |
628 | 649 | #define MAX_URI_LENGTH 2048 |
629 | 650 | |
630 | 651 | /* Maximum acceptable file size */ |
631 | #define MAX_FILE_SIZE 2000000 | |
652 | #define MAX_FILE_SIZE 4000000 | |
632 | 653 | |
633 | 654 | /* Maximum number of FileAndHash entries per manifest. */ |
634 | 655 | #define MAX_MANIFEST_ENTRIES 100000 |
642 | 663 | /* Maximum allowd repositories per tal */ |
643 | 664 | #define MAX_REPO_PER_TAL 1000 |
644 | 665 | |
645 | /* Timeout for repository synchronisation, in seconds */ | |
646 | #define MAX_REPO_TIMEOUT (15 * 60) | |
647 | ||
648 | 666 | #endif /* ! EXTERN_H */ |
0 | /* $OpenBSD: gbr.c,v 1.11 2021/10/26 10:52:50 claudio Exp $ */ | |
0 | /* $OpenBSD: gbr.c,v 1.14 2022/01/18 16:24:55 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * |
35 | 35 | struct gbr *res; /* results */ |
36 | 36 | }; |
37 | 37 | |
38 | static ASN1_OBJECT *gbr_oid; | |
38 | extern ASN1_OBJECT *gbr_oid; | |
39 | 39 | |
40 | 40 | /* |
41 | 41 | * Parse a full RFC 6493 file and signed by the certificate "cacert" |
51 | 51 | |
52 | 52 | memset(&p, 0, sizeof(struct parse)); |
53 | 53 | p.fn = fn; |
54 | ||
55 | /* OID from section 9.1, RFC 6493. */ | |
56 | if (gbr_oid == NULL) { | |
57 | gbr_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.35", 1); | |
58 | if (gbr_oid == NULL) | |
59 | errx(1, "OBJ_txt2obj for %s failed", | |
60 | "1.2.840.113549.1.9.16.1.35"); | |
61 | } | |
62 | 54 | |
63 | 55 | cms = cms_parse_validate(x509, fn, der, len, gbr_oid, &cmsz); |
64 | 56 | if (cms == NULL) |
0 | /* $OpenBSD: http.c,v 1.49 2021/11/09 11:00:43 claudio Exp $ */ | |
0 | /* $OpenBSD: http.c,v 1.52 2022/01/23 12:09:24 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> |
3 | 3 | * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> |
139 | 139 | char *host; |
140 | 140 | char *port; |
141 | 141 | const char *path; /* points into uri */ |
142 | size_t id; | |
142 | unsigned int id; | |
143 | 143 | int outfd; |
144 | 144 | int redirect_loop; |
145 | 145 | }; |
149 | 149 | static struct http_conn_list active = LIST_HEAD_INITIALIZER(active); |
150 | 150 | static struct http_conn_list idle = LIST_HEAD_INITIALIZER(idle); |
151 | 151 | static struct http_req_queue queue = TAILQ_HEAD_INITIALIZER(queue); |
152 | static size_t http_conn_count; | |
152 | static unsigned int http_conn_count; | |
153 | 153 | |
154 | 154 | static struct msgbuf msgq; |
155 | 155 | static struct sockaddr_storage http_bindaddr; |
160 | 160 | #endif |
161 | 161 | |
162 | 162 | /* HTTP request API */ |
163 | static void http_req_new(size_t, char *, char *, int, int); | |
163 | static void http_req_new(unsigned int, char *, char *, int, int); | |
164 | 164 | static void http_req_free(struct http_request *); |
165 | static void http_req_done(size_t, enum http_result, const char *); | |
166 | static void http_req_fail(size_t); | |
165 | static void http_req_done(unsigned int, enum http_result, const char *); | |
166 | static void http_req_fail(unsigned int); | |
167 | 167 | static int http_req_schedule(struct http_request *); |
168 | 168 | |
169 | 169 | /* HTTP connection API */ |
212 | 212 | } |
213 | 213 | |
214 | 214 | /* |
215 | * Determine whether the character needs encoding, per RFC1738: | |
216 | * - No corresponding graphic US-ASCII. | |
217 | * - Unsafe characters. | |
215 | * Determine whether the character needs encoding, per RFC2396. | |
218 | 216 | */ |
219 | 217 | static int |
220 | unsafe_char(const char *c0) | |
221 | { | |
222 | const char *unsafe_chars = " <>\"#{}|\\^~[]`"; | |
218 | to_encode(const char *c0) | |
219 | { | |
220 | /* 2.4.3. Excluded US-ASCII Characters */ | |
221 | const char *excluded_chars = | |
222 | " " /* space */ | |
223 | "<>#\"" /* delims (modulo "%", see below) */ | |
224 | "{}|\\^[]`" /* unwise */ | |
225 | ; | |
223 | 226 | const unsigned char *c = (const unsigned char *)c0; |
224 | 227 | |
225 | 228 | /* |
229 | 232 | return (iscntrl(*c) || !isascii(*c) || |
230 | 233 | |
231 | 234 | /* |
232 | * Unsafe characters. | |
233 | * '%' is also unsafe, if is not followed by two | |
235 | * '%' is also reserved, if is not followed by two | |
234 | 236 | * hexadecimal digits. |
235 | 237 | */ |
236 | strchr(unsafe_chars, *c) != NULL || | |
238 | strchr(excluded_chars, *c) != NULL || | |
237 | 239 | (*c == '%' && (!isxdigit(c[1]) || !isxdigit(c[2])))); |
238 | 240 | } |
239 | 241 | |
240 | 242 | /* |
241 | * Encode given URL, per RFC1738. | |
243 | * Encode given URL, per RFC2396. | |
242 | 244 | * Allocate and return string to the caller. |
243 | 245 | */ |
244 | 246 | static char * |
255 | 257 | * final URL. |
256 | 258 | */ |
257 | 259 | for (i = 0; i < length; i++) |
258 | if (unsafe_char(path + i)) | |
260 | if (to_encode(path + i)) | |
259 | 261 | new_length += 2; |
260 | 262 | |
261 | 263 | epath = epathp = malloc(new_length + 1); /* One more for '\0'. */ |
267 | 269 | * Encode, and copy final URL. |
268 | 270 | */ |
269 | 271 | for (i = 0; i < length; i++) |
270 | if (unsafe_char(path + i)) { | |
272 | if (to_encode(path + i)) { | |
271 | 273 | snprintf(epathp, 4, "%%" "%02x", |
272 | 274 | (unsigned char)path[i]); |
273 | 275 | epathp += 3; |
508 | 510 | * Create and queue a new request. |
509 | 511 | */ |
510 | 512 | static void |
511 | http_req_new(size_t id, char *uri, char *modified_since, int count, int outfd) | |
513 | http_req_new(unsigned int id, char *uri, char *modified_since, int count, | |
514 | int outfd) | |
512 | 515 | { |
513 | 516 | struct http_request *req; |
514 | 517 | char *host, *port, *path; |
559 | 562 | * Enqueue request response |
560 | 563 | */ |
561 | 564 | static void |
562 | http_req_done(size_t id, enum http_result res, const char *last_modified) | |
565 | http_req_done(unsigned int id, enum http_result res, const char *last_modified) | |
563 | 566 | { |
564 | 567 | struct ibuf *b; |
565 | 568 | |
574 | 577 | * Enqueue request failure response |
575 | 578 | */ |
576 | 579 | static void |
577 | http_req_fail(size_t id) | |
580 | http_req_fail(unsigned int id) | |
578 | 581 | { |
579 | 582 | struct ibuf *b; |
580 | 583 | enum http_result res = HTTP_FAILED; |
1847 | 1850 | errx(1, "too many connections"); |
1848 | 1851 | } |
1849 | 1852 | |
1850 | if (poll(pfds, i, timeout) == -1) | |
1853 | if (poll(pfds, i, timeout) == -1) { | |
1854 | if (errno == EINTR) | |
1855 | continue; | |
1851 | 1856 | err(1, "poll"); |
1857 | } | |
1852 | 1858 | |
1853 | 1859 | if (pfds[0].revents & POLLHUP) |
1854 | 1860 | break; |
1863 | 1869 | if (pfds[0].revents & POLLIN) { |
1864 | 1870 | b = io_buf_recvfd(fd, &inbuf); |
1865 | 1871 | if (b != NULL) { |
1866 | size_t id; | |
1872 | unsigned int id; | |
1867 | 1873 | char *uri; |
1868 | 1874 | char *mod; |
1869 | 1875 |
0 | /* $OpenBSD: io.c,v 1.17 2021/10/24 16:59:14 claudio Exp $ */ | |
0 | /* $OpenBSD: io.c,v 1.18 2021/12/05 12:26:27 jsg Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
141 | 141 | io_read_buf_alloc(struct ibuf *b, void **res, size_t *sz) |
142 | 142 | { |
143 | 143 | *res = NULL; |
144 | io_read_buf(b, sz, sizeof(sz)); | |
144 | io_read_buf(b, sz, sizeof(*sz)); | |
145 | 145 | if (*sz == 0) |
146 | 146 | return; |
147 | 147 | if ((*res = malloc(*sz)) == NULL) |
0 | /* $OpenBSD: ip.c,v 1.19 2021/11/05 10:50:41 claudio Exp $ */ | |
0 | /* $OpenBSD: ip.c,v 1.21 2021/12/26 12:32:28 tb Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
128 | 128 | has_v6 = 1; |
129 | 129 | } |
130 | 130 | |
131 | /* Disallow multiple inheritence per type. */ | |
131 | /* Disallow multiple inheritance per type. */ | |
132 | 132 | |
133 | 133 | if ((inherit_v4 && ip->afi == AFI_IPV4) || |
134 | 134 | (inherit_v6 && ip->afi == AFI_IPV6) || |
137 | 137 | (has_v6 && ip->afi == AFI_IPV6 && |
138 | 138 | ip->type == CERT_IP_INHERIT)) { |
139 | 139 | warnx("%s: RFC 3779 section 2.2.3.5: " |
140 | "cannot have multiple inheritence or inheritence and " | |
140 | "cannot have multiple inheritance or inheritance and " | |
141 | 141 | "addresses of the same class", fn); |
142 | 142 | return 0; |
143 | 143 | } |
233 | 233 | } |
234 | 234 | |
235 | 235 | /* |
236 | * Convert the IPv4 address into CIDR notation conforming to RFC 4632. | |
237 | * Buffer should be able to hold xxx.yyy.zzz.www/nn. | |
238 | */ | |
239 | static void | |
240 | ip4_addr2str(const struct ip_addr *addr, char *b, size_t bsz) | |
241 | { | |
242 | char buf[16]; | |
243 | int ret; | |
244 | ||
245 | if (inet_ntop(AF_INET, addr->addr, buf, sizeof(buf)) == NULL) | |
246 | err(1, "inet_ntop"); | |
247 | ret = snprintf(b, bsz, "%s/%hhu", buf, addr->prefixlen); | |
248 | if (ret < 0 || (size_t)ret >= bsz) | |
249 | err(1, "malformed IPV4 address"); | |
250 | } | |
251 | ||
252 | /* | |
253 | * Convert the IPv6 address into CIDR notation conforming to RFC 4291. | |
254 | * See also RFC 5952. | |
255 | * Must hold 0000:0000:0000:0000:0000:0000:0000:0000/nn. | |
256 | */ | |
257 | static void | |
258 | ip6_addr2str(const struct ip_addr *addr, char *b, size_t bsz) | |
259 | { | |
260 | char buf[44]; | |
261 | int ret; | |
262 | ||
263 | if (inet_ntop(AF_INET6, addr->addr, buf, sizeof(buf)) == NULL) | |
264 | err(1, "inet_ntop"); | |
265 | ret = snprintf(b, bsz, "%s/%hhu", buf, addr->prefixlen); | |
266 | if (ret < 0 || (size_t)ret >= bsz) | |
267 | err(1, "malformed IPV6 address"); | |
268 | } | |
269 | ||
270 | /* | |
271 | 236 | * Convert a ip_addr into a NUL-terminated CIDR notation string |
272 | 237 | * conforming to RFC 4632 or 4291. |
273 | 238 | * The size of the buffer must be at least 64 (inclusive). |
276 | 241 | ip_addr_print(const struct ip_addr *addr, |
277 | 242 | enum afi afi, char *buf, size_t bufsz) |
278 | 243 | { |
279 | ||
280 | if (afi == AFI_IPV4) | |
281 | ip4_addr2str(addr, buf, bufsz); | |
282 | else | |
283 | ip6_addr2str(addr, buf, bufsz); | |
244 | char ipbuf[INET6_ADDRSTRLEN]; | |
245 | int ret, af; | |
246 | ||
247 | switch (afi) { | |
248 | case AFI_IPV4: | |
249 | af = AF_INET; | |
250 | break; | |
251 | case AFI_IPV6: | |
252 | af = AF_INET6; | |
253 | break; | |
254 | default: | |
255 | errx(1, "unsupported address family identifier"); | |
256 | } | |
257 | ||
258 | if (inet_ntop(af, addr->addr, ipbuf, sizeof(ipbuf)) == NULL) | |
259 | err(1, "inet_ntop"); | |
260 | ret = snprintf(buf, bufsz, "%s/%hhu", ipbuf, addr->prefixlen); | |
261 | if (ret < 0 || (size_t)ret >= bufsz) | |
262 | err(1, "malformed IP address"); | |
284 | 263 | } |
285 | 264 | |
286 | 265 | /* |
0 | /* $OpenBSD: main.c,v 1.164 2021/11/09 11:03:39 claudio Exp $ */ | |
0 | /* $OpenBSD: main.c,v 1.187 2022/01/28 15:30:23 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
66 | 66 | |
67 | 67 | int verbose; |
68 | 68 | int noop; |
69 | int filemode; | |
69 | 70 | int rrdpon = 1; |
71 | int repo_timeout; | |
70 | 72 | |
71 | 73 | struct stats stats; |
72 | 74 | |
102 | 104 | if (ent == NULL) |
103 | 105 | return; |
104 | 106 | |
107 | free(ent->path); | |
108 | free(ent->file); | |
105 | 109 | free(ent->data); |
106 | free(ent->file); | |
107 | 110 | free(ent); |
108 | 111 | } |
109 | 112 | |
116 | 119 | entity_read_req(struct ibuf *b, struct entity *ent) |
117 | 120 | { |
118 | 121 | io_read_buf(b, &ent->type, sizeof(ent->type)); |
122 | io_read_buf(b, &ent->location, sizeof(ent->location)); | |
123 | io_read_buf(b, &ent->repoid, sizeof(ent->repoid)); | |
119 | 124 | io_read_buf(b, &ent->talid, sizeof(ent->talid)); |
125 | io_read_str(b, &ent->path); | |
120 | 126 | io_read_str(b, &ent->file); |
121 | io_read_buf(b, &ent->has_data, sizeof(ent->has_data)); | |
122 | if (ent->has_data) | |
123 | io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz); | |
127 | io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz); | |
124 | 128 | } |
125 | 129 | |
126 | 130 | /* |
132 | 136 | { |
133 | 137 | struct ibuf *b; |
134 | 138 | |
135 | if (filepath_add(&fpt, ent->file) == 0) { | |
136 | warnx("%s: File already visited", ent->file); | |
137 | entity_queue--; | |
138 | return; | |
139 | } | |
140 | ||
141 | 139 | b = io_new_buffer(); |
142 | 140 | io_simple_buffer(b, &ent->type, sizeof(ent->type)); |
141 | io_simple_buffer(b, &ent->location, sizeof(ent->location)); | |
142 | io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid)); | |
143 | 143 | io_simple_buffer(b, &ent->talid, sizeof(ent->talid)); |
144 | io_str_buffer(b, ent->path); | |
144 | 145 | io_str_buffer(b, ent->file); |
145 | io_simple_buffer(b, &ent->has_data, sizeof(int)); | |
146 | if (ent->has_data) | |
147 | io_buf_buffer(b, ent->data, ent->datasz); | |
146 | io_buf_buffer(b, ent->data, ent->datasz); | |
148 | 147 | io_close_buffer(&procq, b); |
148 | } | |
149 | ||
150 | static void | |
151 | entity_write_repo(struct repo *rp) | |
152 | { | |
153 | struct ibuf *b; | |
154 | enum rtype type = RTYPE_REPO; | |
155 | enum location loc = DIR_UNKNOWN; | |
156 | unsigned int repoid; | |
157 | char *path, *altpath; | |
158 | int talid = 0; | |
159 | ||
160 | repoid = repo_id(rp); | |
161 | path = repo_basedir(rp, 0); | |
162 | altpath = repo_basedir(rp, 1); | |
163 | b = io_new_buffer(); | |
164 | io_simple_buffer(b, &type, sizeof(type)); | |
165 | io_simple_buffer(b, &loc, sizeof(loc)); | |
166 | io_simple_buffer(b, &repoid, sizeof(repoid)); | |
167 | io_simple_buffer(b, &talid, sizeof(talid)); | |
168 | io_str_buffer(b, path); | |
169 | io_str_buffer(b, altpath); | |
170 | io_buf_buffer(b, NULL, 0); | |
171 | io_close_buffer(&procq, b); | |
172 | free(path); | |
173 | free(altpath); | |
149 | 174 | } |
150 | 175 | |
151 | 176 | /* |
157 | 182 | { |
158 | 183 | struct entity *p, *np; |
159 | 184 | |
185 | entity_write_repo(rp); | |
186 | ||
160 | 187 | TAILQ_FOREACH_SAFE(p, q, entries, np) { |
161 | char *file = p->file; | |
162 | ||
163 | /* | |
164 | * XXX fixup path here since the repo may change | |
165 | * during load because of fallback. In that case | |
166 | * the file path changes as well since RRDP and RSYNC | |
167 | * can not share a common repo. | |
168 | */ | |
169 | p->file = repo_filename(rp, file); | |
170 | if (p->file == NULL) | |
171 | err(1, "can't construct repo filename"); | |
172 | free(file); | |
173 | ||
174 | 188 | entity_write_req(p); |
175 | 189 | TAILQ_REMOVE(q, p, entries); |
176 | 190 | entity_free(p); |
181 | 195 | * Add the heap-allocated file to the queue for processing. |
182 | 196 | */ |
183 | 197 | static void |
184 | entityq_add(char *file, enum rtype type, struct repo *rp, | |
185 | unsigned char *data, size_t datasz, int talid) | |
198 | entityq_add(char *path, char *file, enum rtype type, enum location loc, | |
199 | struct repo *rp, unsigned char *data, size_t datasz, int talid) | |
186 | 200 | { |
187 | 201 | struct entity *p; |
188 | 202 | |
190 | 204 | err(1, NULL); |
191 | 205 | |
192 | 206 | p->type = type; |
207 | p->location = loc; | |
193 | 208 | p->talid = talid; |
209 | p->path = path; | |
210 | if (rp != NULL) | |
211 | p->repoid = repo_id(rp); | |
194 | 212 | p->file = file; |
195 | p->has_data = data != NULL; | |
196 | if (p->has_data) { | |
197 | p->data = data; | |
198 | p->datasz = datasz; | |
199 | } | |
213 | p->data = data; | |
214 | p->datasz = (data != NULL) ? datasz : 0; | |
200 | 215 | |
201 | 216 | entity_queue++; |
202 | 217 | |
206 | 221 | */ |
207 | 222 | |
208 | 223 | if (rp == NULL || !repo_queued(rp, p)) { |
209 | /* | |
210 | * XXX fixup path here since for repo path the | |
211 | * file path has not yet been fixed here. | |
212 | * This is a quick way to make this work but in | |
213 | * the long run repos need to be passed to the parser. | |
214 | */ | |
215 | if (rp != NULL) { | |
216 | file = p->file; | |
217 | p->file = repo_filename(rp, file); | |
218 | if (p->file == NULL) | |
219 | err(1, "can't construct repo filename from %s", | |
220 | file); | |
221 | free(file); | |
222 | } | |
223 | 224 | entity_write_req(p); |
224 | 225 | entity_free(p); |
225 | 226 | } |
226 | 227 | } |
227 | 228 | |
228 | 229 | static void |
229 | rrdp_file_resp(size_t id, int ok) | |
230 | rrdp_file_resp(unsigned int id, int ok) | |
230 | 231 | { |
231 | 232 | enum rrdp_msg type = RRDP_FILE; |
232 | 233 | struct ibuf *b; |
239 | 240 | } |
240 | 241 | |
241 | 242 | void |
242 | rrdp_fetch(size_t id, const char *uri, const char *local, | |
243 | rrdp_fetch(unsigned int id, const char *uri, const char *local, | |
243 | 244 | struct rrdp_session *s) |
244 | 245 | { |
245 | 246 | enum rrdp_msg type = RRDP_START; |
260 | 261 | * Request a repository sync via rsync URI to directory local. |
261 | 262 | */ |
262 | 263 | void |
263 | rsync_fetch(size_t id, const char *uri, const char *local) | |
264 | rsync_fetch(unsigned int id, const char *uri, const char *local, | |
265 | const char *base) | |
264 | 266 | { |
265 | 267 | struct ibuf *b; |
266 | 268 | |
267 | 269 | b = io_new_buffer(); |
268 | 270 | io_simple_buffer(b, &id, sizeof(id)); |
269 | 271 | io_str_buffer(b, local); |
272 | io_str_buffer(b, base); | |
270 | 273 | io_str_buffer(b, uri); |
271 | 274 | io_close_buffer(&rsyncq, b); |
272 | 275 | } |
275 | 278 | * Request a file from a https uri, data is written to the file descriptor fd. |
276 | 279 | */ |
277 | 280 | void |
278 | http_fetch(size_t id, const char *uri, const char *last_mod, int fd) | |
281 | http_fetch(unsigned int id, const char *uri, const char *last_mod, int fd) | |
279 | 282 | { |
280 | 283 | struct ibuf *b; |
281 | 284 | |
293 | 296 | * Create a pipe and pass the pipe endpoints to the http and rrdp process. |
294 | 297 | */ |
295 | 298 | static void |
296 | rrdp_http_fetch(size_t id, const char *uri, const char *last_mod) | |
299 | rrdp_http_fetch(unsigned int id, const char *uri, const char *last_mod) | |
297 | 300 | { |
298 | 301 | enum rrdp_msg type = RRDP_HTTP_INI; |
299 | 302 | struct ibuf *b; |
312 | 315 | } |
313 | 316 | |
314 | 317 | void |
315 | rrdp_http_done(size_t id, enum http_result res, const char *last_mod) | |
318 | rrdp_http_done(unsigned int id, enum http_result res, const char *last_mod) | |
316 | 319 | { |
317 | 320 | enum rrdp_msg type = RRDP_HTTP_FIN; |
318 | 321 | struct ibuf *b; |
331 | 334 | * These are always relative to the directory in which "mft" sits. |
332 | 335 | */ |
333 | 336 | static void |
334 | queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype type) | |
335 | { | |
336 | char *cp, *nfile; | |
337 | ||
338 | /* Construct local path from filename. */ | |
339 | cp = strrchr(mft, '/'); | |
340 | assert(cp != NULL); | |
341 | assert(cp - mft < INT_MAX); | |
342 | if (asprintf(&nfile, "%.*s/%s", (int)(cp - mft), mft, file->file) == -1) | |
337 | queue_add_from_mft(const char *path, const struct mftfile *file, | |
338 | struct repo *rp) | |
339 | { | |
340 | char *nfile, *npath = NULL; | |
341 | ||
342 | if (path != NULL) | |
343 | if ((npath = strdup(path)) == NULL) | |
344 | err(1, NULL); | |
345 | if ((nfile = strdup(file->file)) == NULL) | |
343 | 346 | err(1, NULL); |
344 | 347 | |
345 | /* | |
346 | * Since we're from the same directory as the MFT file, we know | |
347 | * that the repository has already been loaded. | |
348 | */ | |
349 | ||
350 | entityq_add(nfile, type, NULL, NULL, 0, -1); | |
348 | entityq_add(npath, nfile, file->type, file->location, rp, NULL, 0, -1); | |
351 | 349 | } |
352 | 350 | |
353 | 351 | /* |
359 | 357 | * check the suffix anyway). |
360 | 358 | */ |
361 | 359 | static void |
362 | queue_add_from_mft_set(const struct mft *mft) | |
363 | { | |
364 | size_t i, sz; | |
360 | queue_add_from_mft_set(const struct mft *mft, const char *name, struct repo *rp) | |
361 | { | |
362 | size_t i; | |
365 | 363 | const struct mftfile *f; |
366 | 364 | |
367 | 365 | for (i = 0; i < mft->filesz; i++) { |
368 | 366 | f = &mft->files[i]; |
369 | sz = strlen(f->file); | |
370 | assert(sz > 4); | |
371 | if (strcasecmp(f->file + sz - 4, ".crl") != 0) | |
367 | if (f->type != RTYPE_CRL) | |
372 | 368 | continue; |
373 | queue_add_from_mft(mft->file, f, RTYPE_CRL); | |
369 | queue_add_from_mft(mft->path, f, rp); | |
374 | 370 | } |
375 | 371 | |
376 | 372 | for (i = 0; i < mft->filesz; i++) { |
377 | 373 | f = &mft->files[i]; |
378 | sz = strlen(f->file); | |
379 | assert(sz > 4); | |
380 | if (strcasecmp(f->file + sz - 4, ".crl") == 0) | |
374 | switch (f->type) { | |
375 | case RTYPE_CER: | |
376 | case RTYPE_ROA: | |
377 | case RTYPE_GBR: | |
378 | queue_add_from_mft(mft->path, f, rp); | |
379 | break; | |
380 | case RTYPE_CRL: | |
381 | 381 | continue; |
382 | else if (strcasecmp(f->file + sz - 4, ".cer") == 0) | |
383 | queue_add_from_mft(mft->file, f, RTYPE_CER); | |
384 | else if (strcasecmp(f->file + sz - 4, ".roa") == 0) | |
385 | queue_add_from_mft(mft->file, f, RTYPE_ROA); | |
386 | else if (strcasecmp(f->file + sz - 4, ".gbr") == 0) | |
387 | queue_add_from_mft(mft->file, f, RTYPE_GBR); | |
388 | else | |
389 | logx("%s: unsupported file type: %s", mft->file, | |
390 | f->file); | |
391 | } | |
392 | } | |
393 | ||
394 | /* | |
395 | * Add a local TAL file (RFC 7730) to the queue of files to fetch. | |
382 | default: | |
383 | warnx("%s: unsupported file: %s", name, f->file); | |
384 | } | |
385 | } | |
386 | } | |
387 | ||
388 | /* | |
389 | * Add a local file to the queue of files to fetch. | |
396 | 390 | */ |
397 | 391 | static void |
398 | queue_add_tal(const char *file, int id) | |
399 | { | |
400 | unsigned char *buf; | |
392 | queue_add_file(const char *file, enum rtype type, int talid) | |
393 | { | |
394 | unsigned char *buf = NULL; | |
401 | 395 | char *nfile; |
402 | size_t len; | |
396 | size_t len = 0; | |
397 | ||
398 | if (!filemode || strncmp(file, "rsync://", strlen("rsync://")) != 0) { | |
399 | buf = load_file(file, &len); | |
400 | if (buf == NULL) | |
401 | err(1, "%s", file); | |
402 | } | |
403 | 403 | |
404 | 404 | if ((nfile = strdup(file)) == NULL) |
405 | 405 | err(1, NULL); |
406 | buf = load_file(file, &len); | |
407 | if (buf == NULL) { | |
408 | warn("%s", file); | |
409 | return; | |
410 | } | |
411 | ||
412 | 406 | /* Not in a repository, so directly add to queue. */ |
413 | entityq_add(nfile, RTYPE_TAL, NULL, buf, len, id); | |
407 | entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid); | |
414 | 408 | } |
415 | 409 | |
416 | 410 | /* |
421 | 415 | { |
422 | 416 | struct repo *repo; |
423 | 417 | unsigned char *data; |
418 | char *nfile; | |
424 | 419 | |
425 | 420 | assert(tal->urisz); |
426 | 421 | |
427 | 422 | if ((taldescs[tal->id] = strdup(tal->descr)) == NULL) |
428 | 423 | err(1, NULL); |
429 | 424 | |
425 | /* figure out the TA filename, must be done before repo lookup */ | |
426 | nfile = strrchr(tal->uri[0], '/'); | |
427 | assert(nfile != NULL); | |
428 | if ((nfile = strdup(nfile + 1)) == NULL) | |
429 | err(1, NULL); | |
430 | ||
430 | 431 | /* Look up the repository. */ |
431 | 432 | repo = ta_lookup(tal->id, tal); |
432 | if (repo == NULL) | |
433 | if (repo == NULL) { | |
434 | free(nfile); | |
433 | 435 | return; |
436 | } | |
434 | 437 | |
435 | 438 | /* steal the pkey from the tal structure */ |
436 | 439 | data = tal->pkey; |
437 | 440 | tal->pkey = NULL; |
438 | entityq_add(NULL, RTYPE_CER, repo, data, | |
441 | entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data, | |
439 | 442 | tal->pkeysz, tal->id); |
440 | 443 | } |
441 | 444 | |
446 | 449 | queue_add_from_cert(const struct cert *cert) |
447 | 450 | { |
448 | 451 | struct repo *repo; |
449 | char *nfile; | |
452 | char *nfile, *npath; | |
453 | const char *uri, *repouri, *file; | |
454 | size_t repourisz; | |
450 | 455 | |
451 | 456 | repo = repo_lookup(cert->talid, cert->repo, |
452 | 457 | rrdpon ? cert->notify : NULL); |
453 | 458 | if (repo == NULL) |
454 | 459 | return; |
455 | 460 | |
456 | if ((nfile = strdup(cert->mft)) == NULL) | |
457 | err(1, NULL); | |
458 | entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, -1); | |
461 | /* | |
462 | * Figure out the cert filename and path by chopping up the | |
463 | * MFT URI in the cert based on the repo base URI. | |
464 | */ | |
465 | uri = cert->mft; | |
466 | repouri = repo_uri(repo); | |
467 | repourisz = strlen(repouri); | |
468 | if (strncmp(repouri, cert->mft, repourisz) != 0) { | |
469 | warnx("%s: URI %s outside of repository", repouri, uri); | |
470 | return; | |
471 | } | |
472 | uri += repourisz + 1; /* skip base and '/' */ | |
473 | file = strrchr(uri, '/'); | |
474 | if (file == NULL) { | |
475 | npath = NULL; | |
476 | if ((nfile = strdup(uri)) == NULL) | |
477 | err(1, NULL); | |
478 | } else { | |
479 | if ((npath = strndup(uri, file - uri)) == NULL) | |
480 | err(1, NULL); | |
481 | if ((nfile = strdup(file + 1)) == NULL) | |
482 | err(1, NULL); | |
483 | } | |
484 | ||
485 | entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0, -1); | |
459 | 486 | } |
460 | 487 | |
461 | 488 | /* |
473 | 500 | struct cert *cert; |
474 | 501 | struct mft *mft; |
475 | 502 | struct roa *roa; |
503 | char *file; | |
476 | 504 | int c; |
477 | 505 | |
478 | 506 | /* |
482 | 510 | * We follow that up with whether the resources didn't parse. |
483 | 511 | */ |
484 | 512 | io_read_buf(b, &type, sizeof(type)); |
513 | io_read_str(b, &file); | |
514 | ||
515 | /* in filemode messages can be ignored, only the accounting matters */ | |
516 | if (filemode) | |
517 | goto done; | |
518 | ||
519 | if (filepath_add(&fpt, file) == 0) { | |
520 | warnx("%s: File already visited", file); | |
521 | goto done; | |
522 | } | |
485 | 523 | |
486 | 524 | switch (type) { |
487 | 525 | case RTYPE_TAL: |
521 | 559 | break; |
522 | 560 | } |
523 | 561 | mft = mft_read(b); |
524 | if (mft->stale) | |
562 | if (!mft->stale) | |
563 | queue_add_from_mft_set(mft, file, | |
564 | repo_byid(mft->repoid)); | |
565 | else | |
525 | 566 | st->mfts_stale++; |
526 | queue_add_from_mft_set(mft); | |
527 | 567 | mft_free(mft); |
528 | 568 | break; |
529 | 569 | case RTYPE_CRL: |
546 | 586 | case RTYPE_GBR: |
547 | 587 | st->gbrs++; |
548 | 588 | break; |
589 | case RTYPE_FILE: | |
590 | break; | |
549 | 591 | default: |
550 | 592 | errx(1, "unknown entity type %d", type); |
551 | 593 | } |
552 | 594 | |
595 | done: | |
596 | free(file); | |
553 | 597 | entity_queue--; |
554 | 598 | } |
555 | 599 | |
561 | 605 | struct rrdp_session s; |
562 | 606 | char *uri, *last_mod, *data; |
563 | 607 | char hash[SHA256_DIGEST_LENGTH]; |
564 | size_t dsz, id; | |
608 | size_t dsz; | |
609 | unsigned int id; | |
565 | 610 | int ok; |
566 | 611 | |
567 | 612 | io_read_buf(b, &type, sizeof(type)); |
599 | 644 | free(uri); |
600 | 645 | free(data); |
601 | 646 | break; |
647 | case RRDP_CLEAR: | |
648 | rrdp_clear(id); | |
649 | break; | |
602 | 650 | default: |
603 | 651 | errx(1, "unexpected rrdp response"); |
604 | 652 | } |
648 | 696 | |
649 | 697 | if (fs.f_bavail < minsize / fs.f_frsize || fs.f_favail < minnode) { |
650 | 698 | fprintf(stderr, "WARNING: rpki-client may need more than " |
651 | "the availabe disk space\n" | |
699 | "the available disk space\n" | |
652 | 700 | "on the file-system holding %s.\n", cachedir); |
653 | 701 | fprintf(stderr, "available space: %lldkB, " |
654 | 702 | "suggested minimum %lldkB\n", |
672 | 720 | int |
673 | 721 | main(int argc, char *argv[]) |
674 | 722 | { |
675 | int rc, c, st, proc, rsync, http, rrdp, ok, hangup = 0; | |
723 | int rc, c, st, proc, rsync, http, rrdp, hangup = 0; | |
676 | 724 | int fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK; |
677 | size_t i, id; | |
725 | size_t i; | |
678 | 726 | pid_t pid, procpid, rsyncpid, httppid, rrdppid; |
679 | 727 | int fd[2]; |
680 | 728 | struct pollfd pfd[NPFD]; |
685 | 733 | char *bind_addr = NULL; |
686 | 734 | const char *cachedir = NULL, *outputdir = NULL; |
687 | 735 | const char *errs, *name; |
688 | const char *file = NULL; | |
689 | 736 | struct vrp_tree vrps = RB_INITIALIZER(&vrps); |
690 | 737 | struct brk_tree brks = RB_INITIALIZER(&brks); |
691 | 738 | struct rusage ru; |
707 | 754 | } |
708 | 755 | cachedir = RPKI_PATH_BASE_DIR; |
709 | 756 | outputdir = RPKI_PATH_OUT_DIR; |
757 | repo_timeout = timeout / 4; | |
710 | 758 | |
711 | 759 | if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd " |
712 | 760 | "proc exec unveil", NULL) == -1) |
713 | 761 | err(1, "pledge"); |
714 | 762 | |
715 | while ((c = getopt(argc, argv, "b:Bcd:e:f:jnorRs:t:T:vV")) != -1) | |
763 | while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:t:T:vV")) != -1) | |
716 | 764 | switch (c) { |
717 | 765 | case 'b': |
718 | 766 | bind_addr = optarg; |
730 | 778 | rsync_prog = optarg; |
731 | 779 | break; |
732 | 780 | case 'f': |
733 | file = optarg; | |
781 | filemode = 1; | |
734 | 782 | noop = 1; |
735 | 783 | break; |
736 | 784 | case 'j': |
752 | 800 | timeout = strtonum(optarg, 0, 24*60*60, &errs); |
753 | 801 | if (errs) |
754 | 802 | errx(1, "-s: %s", errs); |
803 | if (timeout == 0) | |
804 | repo_timeout = 24*60*60; | |
805 | else if (timeout < 1) | |
806 | errx(1, "-s: %i too small", timeout); | |
807 | else | |
808 | repo_timeout = timeout / 4; | |
755 | 809 | break; |
756 | 810 | case 't': |
757 | 811 | if (talsz >= TALSZ_MAX) |
775 | 829 | |
776 | 830 | argv += optind; |
777 | 831 | argc -= optind; |
778 | if (argc == 1) | |
779 | outputdir = argv[0]; | |
780 | else if (argc > 1) | |
781 | goto usage; | |
782 | ||
783 | signal(SIGPIPE, SIG_IGN); | |
832 | ||
833 | if (!filemode) { | |
834 | if (argc == 1) | |
835 | outputdir = argv[0]; | |
836 | else if (argc > 1) | |
837 | goto usage; | |
838 | ||
839 | if (outputdir == NULL) { | |
840 | warnx("output directory required"); | |
841 | goto usage; | |
842 | } | |
843 | } else { | |
844 | if (argc == 0) | |
845 | goto usage; | |
846 | outputdir = NULL; | |
847 | } | |
784 | 848 | |
785 | 849 | if (cachedir == NULL) { |
786 | 850 | warnx("cache directory required"); |
787 | 851 | goto usage; |
788 | 852 | } |
789 | if (outputdir == NULL) { | |
790 | warnx("output directory required"); | |
791 | goto usage; | |
792 | } | |
853 | ||
854 | signal(SIGPIPE, SIG_IGN); | |
793 | 855 | |
794 | 856 | if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1) |
795 | 857 | err(1, "cache directory %s", cachedir); |
796 | if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1) | |
797 | err(1, "output directory %s", outputdir); | |
858 | if (outputdir != NULL) { | |
859 | if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1) | |
860 | err(1, "output directory %s", outputdir); | |
861 | if (outformats == 0) | |
862 | outformats = FORMAT_OPENBGPD; | |
863 | } | |
798 | 864 | |
799 | 865 | check_fs_size(cachefd, cachedir); |
800 | 866 | |
1003 | 1069 | */ |
1004 | 1070 | |
1005 | 1071 | for (i = 0; i < talsz; i++) |
1006 | queue_add_tal(tals[i], i); | |
1072 | queue_add_file(tals[i], RTYPE_TAL, i); | |
1073 | ||
1074 | if (filemode) { | |
1075 | while (*argv != NULL) | |
1076 | queue_add_file(*argv++, RTYPE_FILE, 0); | |
1077 | } | |
1007 | 1078 | |
1008 | 1079 | /* change working directory to the cache directory */ |
1009 | 1080 | if (fchdir(cachefd) == -1) |
1018 | 1089 | pfd[i].events |= POLLOUT; |
1019 | 1090 | } |
1020 | 1091 | |
1021 | polltim = repo_next_timeout(INFTIM); | |
1092 | polltim = repo_check_timeout(INFTIM); | |
1022 | 1093 | |
1023 | 1094 | if ((c = poll(pfd, NPFD, polltim)) == -1) { |
1024 | 1095 | if (errno == EINTR) |
1050 | 1121 | if (hangup) |
1051 | 1122 | break; |
1052 | 1123 | |
1053 | repo_check_timeout(); | |
1054 | ||
1055 | 1124 | /* |
1056 | 1125 | * Check the rsync and http process. |
1057 | 1126 | * This means that one of our modules has completed |
1062 | 1131 | if ((pfd[1].revents & POLLIN)) { |
1063 | 1132 | b = io_buf_read(rsync, &rsyncbuf); |
1064 | 1133 | if (b != NULL) { |
1134 | unsigned int id; | |
1135 | int ok; | |
1136 | ||
1065 | 1137 | io_read_buf(b, &id, sizeof(id)); |
1066 | 1138 | io_read_buf(b, &ok, sizeof(ok)); |
1067 | 1139 | rsync_finish(id, ok); |
1072 | 1144 | if ((pfd[2].revents & POLLIN)) { |
1073 | 1145 | b = io_buf_read(http, &httpbuf); |
1074 | 1146 | if (b != NULL) { |
1147 | unsigned int id; | |
1075 | 1148 | enum http_result res; |
1076 | 1149 | char *last_mod; |
1077 | 1150 | |
1161 | 1234 | /* processing did not finish because of error */ |
1162 | 1235 | if (entity_queue != 0) |
1163 | 1236 | errx(1, "not all files processed, giving up"); |
1237 | ||
1238 | /* if processing in filemode the process is done, no cleanup */ | |
1239 | if (filemode) | |
1240 | return rc; | |
1164 | 1241 | |
1165 | 1242 | logx("all files parsed: generating output"); |
1166 | 1243 | |
1201 | 1278 | logx("Certificate revocation lists: %zu", stats.crls); |
1202 | 1279 | logx("Ghostbuster records: %zu", stats.gbrs); |
1203 | 1280 | logx("Repositories: %zu", stats.repos); |
1204 | logx("Cleanup: removed %zu files, %zu directories", | |
1205 | stats.del_files, stats.del_dirs); | |
1281 | logx("Cleanup: removed %zu files, %zu directories, %zu superfluous", | |
1282 | stats.del_files, stats.del_dirs, stats.extra_files); | |
1206 | 1283 | logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs); |
1207 | 1284 | |
1208 | 1285 | /* Memory cleanup. */ |
1215 | 1292 | "usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]" |
1216 | 1293 | " [-e rsync_prog]\n" |
1217 | 1294 | " [-s timeout] [-T table] [-t tal]" |
1218 | " [outputdir]\n"); | |
1295 | " [outputdir]\n" | |
1296 | " rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n"); | |
1219 | 1297 | return 1; |
1220 | 1298 | } |
0 | /* $OpenBSD: mft.c,v 1.42 2021/10/28 13:51:42 job Exp $ */ | |
0 | /* $OpenBSD: mft.c,v 1.52 2022/01/28 15:30:23 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
15 | 15 | */ |
16 | 16 | |
17 | 17 | #include <assert.h> |
18 | #include <ctype.h> | |
18 | 19 | #include <err.h> |
19 | 20 | #include <limits.h> |
20 | 21 | #include <stdarg.h> |
21 | 22 | #include <stdint.h> |
22 | #include <fcntl.h> | |
23 | 23 | #include <stdlib.h> |
24 | 24 | #include <string.h> |
25 | 25 | #include <unistd.h> |
39 | 39 | struct mft *res; /* result object */ |
40 | 40 | }; |
41 | 41 | |
42 | static ASN1_OBJECT *mft_oid; | |
43 | ||
44 | static const char * | |
45 | gentime2str(const ASN1_GENERALIZEDTIME *time) | |
46 | { | |
47 | static char buf[64]; | |
48 | BIO *mem; | |
49 | ||
50 | if ((mem = BIO_new(BIO_s_mem())) == NULL) | |
51 | cryptoerrx("BIO_new"); | |
52 | if (!ASN1_GENERALIZEDTIME_print(mem, time)) | |
53 | cryptoerrx("ASN1_GENERALIZEDTIME_print"); | |
54 | if (BIO_gets(mem, buf, sizeof(buf)) < 0) | |
55 | cryptoerrx("BIO_gets"); | |
56 | ||
57 | BIO_free(mem); | |
58 | return buf; | |
59 | } | |
42 | extern ASN1_OBJECT *mft_oid; | |
60 | 43 | |
61 | 44 | /* |
62 | 45 | * Convert an ASN1_GENERALIZEDTIME to a struct tm. |
78 | 61 | |
79 | 62 | /* |
80 | 63 | * Validate and verify the time validity of the mft. |
81 | * Returns 1 if all is good, 0 if mft is stale, any other case -1. | |
64 | * Returns 1 if all is good and for any other case 0. | |
82 | 65 | */ |
83 | 66 | static int |
84 | check_validity(const ASN1_GENERALIZEDTIME *from, | |
85 | const ASN1_GENERALIZEDTIME *until, const char *fn) | |
86 | { | |
87 | time_t now = time(NULL); | |
88 | struct tm tm_from, tm_until, tm_now; | |
89 | ||
90 | if (gmtime_r(&now, &tm_now) == NULL) { | |
91 | warnx("%s: could not get current time", fn); | |
92 | return -1; | |
93 | } | |
67 | mft_parse_time(const ASN1_GENERALIZEDTIME *from, | |
68 | const ASN1_GENERALIZEDTIME *until, struct parse *p) | |
69 | { | |
70 | struct tm tm_from, tm_until; | |
94 | 71 | |
95 | 72 | if (!generalizedtime_to_tm(from, &tm_from)) { |
96 | warnx("%s: embedded from time format invalid", fn); | |
97 | return -1; | |
73 | warnx("%s: embedded from time format invalid", p->fn); | |
74 | return 0; | |
98 | 75 | } |
99 | 76 | if (!generalizedtime_to_tm(until, &tm_until)) { |
100 | warnx("%s: embedded until time format invalid", fn); | |
101 | return -1; | |
77 | warnx("%s: embedded until time format invalid", p->fn); | |
78 | return 0; | |
102 | 79 | } |
103 | 80 | |
104 | 81 | /* check that until is not before from */ |
105 | 82 | if (ASN1_time_tm_cmp(&tm_until, &tm_from) < 0) { |
106 | warnx("%s: bad update interval", fn); | |
107 | return -1; | |
108 | } | |
109 | /* check that now is not before from */ | |
110 | if (ASN1_time_tm_cmp(&tm_from, &tm_now) > 0) { | |
111 | warnx("%s: mft not yet valid %s", fn, gentime2str(from)); | |
112 | return -1; | |
113 | } | |
114 | /* check that now is not after until */ | |
115 | if (ASN1_time_tm_cmp(&tm_until, &tm_now) < 0) { | |
116 | warnx("%s: mft expired on %s", fn, gentime2str(until)); | |
83 | warnx("%s: bad update interval", p->fn); | |
117 | 84 | return 0; |
118 | 85 | } |
119 | 86 | |
87 | if ((p->res->valid_from = mktime(&tm_from)) == -1 || | |
88 | (p->res->valid_until = mktime(&tm_until)) == -1) | |
89 | errx(1, "%s: mktime failed", p->fn); | |
90 | ||
120 | 91 | return 1; |
92 | } | |
93 | ||
94 | /* | |
95 | * Determine rtype corresponding to file extension. Returns RTYPE_INVALID | |
96 | * on error or unkown extension. | |
97 | */ | |
98 | enum rtype | |
99 | rtype_from_file_extension(const char *fn) | |
100 | { | |
101 | size_t sz; | |
102 | ||
103 | sz = strlen(fn); | |
104 | if (sz < 5) | |
105 | return RTYPE_INVALID; | |
106 | ||
107 | if (strcasecmp(fn + sz - 4, ".tal") == 0) | |
108 | return RTYPE_TAL; | |
109 | if (strcasecmp(fn + sz - 4, ".cer") == 0) | |
110 | return RTYPE_CER; | |
111 | if (strcasecmp(fn + sz - 4, ".crl") == 0) | |
112 | return RTYPE_CRL; | |
113 | if (strcasecmp(fn + sz - 4, ".mft") == 0) | |
114 | return RTYPE_MFT; | |
115 | if (strcasecmp(fn + sz - 4, ".roa") == 0) | |
116 | return RTYPE_ROA; | |
117 | if (strcasecmp(fn + sz - 4, ".gbr") == 0) | |
118 | return RTYPE_GBR; | |
119 | ||
120 | return RTYPE_INVALID; | |
121 | } | |
122 | ||
123 | /* | |
124 | * Validate that a filename listed on a Manifest only contains characters | |
125 | * permitted in draft-ietf-sidrops-6486bis section 4.2.2 | |
126 | */ | |
127 | static int | |
128 | valid_filename(const char *fn, size_t len) | |
129 | { | |
130 | const unsigned char *c; | |
131 | size_t i; | |
132 | ||
133 | for (c = fn, i = 0; i < len; i++, c++) | |
134 | if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.') | |
135 | return 0; | |
136 | ||
137 | c = memchr(fn, '.', len); | |
138 | if (c == NULL || c != memrchr(fn, '.', len)) | |
139 | return 0; | |
140 | ||
141 | return 1; | |
142 | } | |
143 | ||
144 | /* | |
145 | * Check that the file is a CER, CRL, GBR or a ROA. | |
146 | * Returns corresponding rtype or RTYPE_INVALID on error. | |
147 | */ | |
148 | static enum rtype | |
149 | rtype_from_mftfile(const char *fn) | |
150 | { | |
151 | enum rtype type; | |
152 | ||
153 | type = rtype_from_file_extension(fn); | |
154 | switch (type) { | |
155 | case RTYPE_CER: | |
156 | case RTYPE_CRL: | |
157 | case RTYPE_GBR: | |
158 | case RTYPE_ROA: | |
159 | return type; | |
160 | default: | |
161 | return RTYPE_INVALID; | |
162 | } | |
121 | 163 | } |
122 | 164 | |
123 | 165 | /* |
155 | 197 | p->fn, ASN1_tag2str(file->type), file->type); |
156 | 198 | goto out; |
157 | 199 | } |
200 | if (!valid_filename(file->value.ia5string->data, | |
201 | file->value.ia5string->length)) { | |
202 | warnx("%s: RFC 6486 section 4.2.2: bad filename", p->fn); | |
203 | goto out; | |
204 | } | |
158 | 205 | fn = strndup((const char *)file->value.ia5string->data, |
159 | 206 | file->value.ia5string->length); |
160 | 207 | if (fn == NULL) |
161 | 208 | err(1, NULL); |
162 | ||
163 | /* | |
164 | * Make sure we're just a pathname and either an ROA or CER. | |
165 | * I don't think that the RFC specifically mentions this, but | |
166 | * it's in practical use and would really screw things up | |
167 | * (arbitrary filenames) otherwise. | |
168 | */ | |
169 | ||
170 | if (strchr(fn, '/') != NULL) { | |
171 | warnx("%s: path components disallowed in filename: %s", | |
172 | p->fn, fn); | |
173 | goto out; | |
174 | } else if (strlen(fn) <= 4) { | |
175 | warnx("%s: filename must be large enough for suffix part: %s", | |
176 | p->fn, fn); | |
177 | goto out; | |
178 | } | |
179 | 209 | |
180 | 210 | /* Now hash value. */ |
181 | 211 | |
197 | 227 | /* Insert the filename and hash value. */ |
198 | 228 | fent = &p->res->files[p->res->filesz++]; |
199 | 229 | |
230 | fent->type = rtype_from_mftfile(fn); | |
200 | 231 | fent->file = fn; |
201 | 232 | fn = NULL; |
202 | 233 | memcpy(fent->hash, hash->value.bit_string->data, SHA256_DIGEST_LENGTH); |
256 | 287 | |
257 | 288 | /* |
258 | 289 | * Handle the eContent of the manifest object, RFC 6486 sec. 4.2. |
259 | * Returns <0 on failure, 0 on stale, >0 on success. | |
290 | * Returns 0 on failure and 1 on success. | |
260 | 291 | */ |
261 | 292 | static int |
262 | 293 | mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) |
266 | 297 | const ASN1_GENERALIZEDTIME *from, *until; |
267 | 298 | long mft_version; |
268 | 299 | BIGNUM *mft_seqnum = NULL; |
269 | int i = 0, rc = -1; | |
300 | int i = 0, rc = 0; | |
270 | 301 | |
271 | 302 | if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) { |
272 | 303 | cryptowarnx("%s: RFC 6486 section 4.2: Manifest: " |
365 | 396 | } |
366 | 397 | until = t->value.generalizedtime; |
367 | 398 | |
368 | rc = check_validity(from, until, p->fn); | |
369 | if (rc != 1) | |
370 | goto out; | |
371 | ||
372 | /* The mft is valid. Reset rc so later 'goto out' return failure. */ | |
373 | rc = -1; | |
399 | if (!mft_parse_time(from, until, p)) | |
400 | goto out; | |
374 | 401 | |
375 | 402 | /* File list algorithm. */ |
376 | 403 | |
377 | 404 | t = sk_ASN1_TYPE_value(seq, i++); |
378 | 405 | if (t->type != V_ASN1_OBJECT) { |
379 | 406 | warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: " |
380 | "want ASN.1 object time, have %s (NID %d)", | |
407 | "want ASN.1 object, have %s (NID %d)", | |
381 | 408 | p->fn, ASN1_tag2str(t->type), t->type); |
382 | 409 | goto out; |
383 | } else if (OBJ_obj2nid(t->value.object) != NID_sha256) { | |
410 | } | |
411 | if (OBJ_obj2nid(t->value.object) != NID_sha256) { | |
384 | 412 | warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: " |
385 | 413 | "want SHA256 object, have %s (NID %d)", p->fn, |
386 | 414 | ASN1_tag2str(OBJ_obj2nid(t->value.object)), |
396 | 424 | "want ASN.1 sequence, have %s (NID %d)", |
397 | 425 | p->fn, ASN1_tag2str(t->type), t->type); |
398 | 426 | goto out; |
399 | } else if (!mft_parse_flist(p, t->value.octet_string)) | |
427 | } | |
428 | ||
429 | if (!mft_parse_flist(p, t->value.octet_string)) | |
400 | 430 | goto out; |
401 | 431 | |
402 | 432 | rc = 1; |
417 | 447 | mft_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len) |
418 | 448 | { |
419 | 449 | struct parse p; |
420 | int c, rc = 0; | |
421 | size_t i, cmsz; | |
450 | int rc = 0; | |
451 | size_t cmsz; | |
422 | 452 | unsigned char *cms; |
423 | 453 | |
424 | 454 | memset(&p, 0, sizeof(struct parse)); |
425 | 455 | p.fn = fn; |
426 | ||
427 | if (mft_oid == NULL) { | |
428 | mft_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.26", 1); | |
429 | if (mft_oid == NULL) | |
430 | errx(1, "OBJ_txt2obj for %s failed", | |
431 | "1.2.840.113549.1.9.16.1.26"); | |
432 | } | |
433 | 456 | |
434 | 457 | cms = cms_parse_validate(x509, fn, der, len, mft_oid, &cmsz); |
435 | 458 | if (cms == NULL) |
437 | 460 | assert(*x509 != NULL); |
438 | 461 | |
439 | 462 | if ((p.res = calloc(1, sizeof(struct mft))) == NULL) |
440 | err(1, NULL); | |
441 | if ((p.res->file = strdup(fn)) == NULL) | |
442 | 463 | err(1, NULL); |
443 | 464 | |
444 | 465 | p.res->aia = x509_get_aia(*x509, fn); |
450 | 471 | goto out; |
451 | 472 | } |
452 | 473 | |
453 | /* | |
454 | * If we're stale, then remove all of the files that the MFT | |
455 | * references as well as marking it as stale. | |
456 | */ | |
457 | ||
458 | if ((c = mft_parse_econtent(cms, cmsz, &p)) == 0) { | |
459 | /* | |
460 | * FIXME: it should suffice to just mark this as stale | |
461 | * and have the logic around mft_read() simply ignore | |
462 | * the contents of stale entries, just like it does for | |
463 | * invalid ROAs or certificates. | |
464 | */ | |
465 | ||
466 | p.res->stale = 1; | |
467 | if (p.res->files != NULL) | |
468 | for (i = 0; i < p.res->filesz; i++) | |
469 | free(p.res->files[i].file); | |
470 | free(p.res->files); | |
471 | p.res->filesz = 0; | |
472 | p.res->files = NULL; | |
473 | } else if (c == -1) | |
474 | if (mft_parse_econtent(cms, cmsz, &p) == 0) | |
474 | 475 | goto out; |
475 | 476 | |
476 | 477 | rc = 1; |
486 | 487 | } |
487 | 488 | |
488 | 489 | /* |
489 | * Check all files and their hashes in a MFT structure. | |
490 | * Return zero on failure, non-zero on success. | |
491 | */ | |
492 | int | |
493 | mft_check(const char *fn, struct mft *p) | |
494 | { | |
495 | size_t i; | |
496 | int rc = 1; | |
497 | char *cp, *h, *path = NULL; | |
498 | ||
499 | /* Check hash of file now, but first build path for it */ | |
500 | cp = strrchr(fn, '/'); | |
501 | assert(cp != NULL); | |
502 | assert(cp - fn < INT_MAX); | |
503 | ||
504 | for (i = 0; i < p->filesz; i++) { | |
505 | const struct mftfile *m = &p->files[i]; | |
506 | if (!valid_filename(m->file)) { | |
507 | if (base64_encode(m->hash, sizeof(m->hash), &h) == -1) | |
508 | errx(1, "base64_encode failed in %s", __func__); | |
509 | warnx("%s: unsupported filename for %s", fn, h); | |
510 | free(h); | |
511 | continue; | |
512 | } | |
513 | if (asprintf(&path, "%.*s/%s", (int)(cp - fn), fn, | |
514 | m->file) == -1) | |
515 | err(1, NULL); | |
516 | if (!valid_filehash(path, m->hash, sizeof(m->hash))) { | |
517 | warnx("%s: bad message digest for %s", fn, m->file); | |
518 | rc = 0; | |
519 | } | |
520 | free(path); | |
521 | } | |
522 | ||
523 | return rc; | |
524 | } | |
525 | ||
526 | /* | |
527 | 490 | * Free an MFT pointer. |
528 | 491 | * Safe to call with NULL. |
529 | 492 | */ |
542 | 505 | free(p->aia); |
543 | 506 | free(p->aki); |
544 | 507 | free(p->ski); |
545 | free(p->file); | |
508 | free(p->path); | |
546 | 509 | free(p->files); |
547 | 510 | free(p->seqnum); |
548 | 511 | free(p); |
557 | 520 | { |
558 | 521 | size_t i; |
559 | 522 | |
560 | io_simple_buffer(b, &p->stale, sizeof(int)); | |
561 | io_str_buffer(b, p->file); | |
562 | io_simple_buffer(b, &p->filesz, sizeof(size_t)); | |
563 | ||
564 | for (i = 0; i < p->filesz; i++) { | |
565 | io_str_buffer(b, p->files[i].file); | |
566 | io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH); | |
567 | } | |
523 | io_simple_buffer(b, &p->stale, sizeof(p->stale)); | |
524 | io_simple_buffer(b, &p->repoid, sizeof(p->repoid)); | |
525 | io_str_buffer(b, p->path); | |
568 | 526 | |
569 | 527 | io_str_buffer(b, p->aia); |
570 | 528 | io_str_buffer(b, p->aki); |
571 | 529 | io_str_buffer(b, p->ski); |
530 | ||
531 | io_simple_buffer(b, &p->filesz, sizeof(size_t)); | |
532 | for (i = 0; i < p->filesz; i++) { | |
533 | io_str_buffer(b, p->files[i].file); | |
534 | io_simple_buffer(b, &p->files[i].type, | |
535 | sizeof(p->files[i].type)); | |
536 | io_simple_buffer(b, &p->files[i].location, | |
537 | sizeof(p->files[i].location)); | |
538 | io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH); | |
539 | } | |
572 | 540 | } |
573 | 541 | |
574 | 542 | /* |
584 | 552 | if ((p = calloc(1, sizeof(struct mft))) == NULL) |
585 | 553 | err(1, NULL); |
586 | 554 | |
587 | io_read_buf(b, &p->stale, sizeof(int)); | |
588 | io_read_str(b, &p->file); | |
589 | io_read_buf(b, &p->filesz, sizeof(size_t)); | |
590 | ||
591 | assert(p->file); | |
592 | if ((p->files = calloc(p->filesz, sizeof(struct mftfile))) == NULL) | |
593 | err(1, NULL); | |
594 | ||
595 | for (i = 0; i < p->filesz; i++) { | |
596 | io_read_str(b, &p->files[i].file); | |
597 | io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH); | |
598 | } | |
555 | io_read_buf(b, &p->stale, sizeof(p->stale)); | |
556 | io_read_buf(b, &p->repoid, sizeof(p->repoid)); | |
557 | io_read_str(b, &p->path); | |
599 | 558 | |
600 | 559 | io_read_str(b, &p->aia); |
601 | 560 | io_read_str(b, &p->aki); |
602 | 561 | io_read_str(b, &p->ski); |
603 | 562 | assert(p->aia && p->aki && p->ski); |
604 | 563 | |
564 | io_read_buf(b, &p->filesz, sizeof(size_t)); | |
565 | if ((p->files = calloc(p->filesz, sizeof(struct mftfile))) == NULL) | |
566 | err(1, NULL); | |
567 | ||
568 | for (i = 0; i < p->filesz; i++) { | |
569 | io_read_str(b, &p->files[i].file); | |
570 | io_read_buf(b, &p->files[i].type, sizeof(p->files[i].type)); | |
571 | io_read_buf(b, &p->files[i].location, | |
572 | sizeof(p->files[i].location)); | |
573 | io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH); | |
574 | } | |
575 | ||
605 | 576 | return p; |
606 | 577 | } |
578 | ||
579 | /* | |
580 | * Compare two MFT files, returns 1 if first MFT is preferred and 0 if second | |
581 | * MFT should be used. | |
582 | */ | |
583 | int | |
584 | mft_compare(const struct mft *a, const struct mft *b) | |
585 | { | |
586 | int r; | |
587 | ||
588 | if (b == NULL) | |
589 | return 1; | |
590 | if (a == NULL) | |
591 | return 0; | |
592 | ||
593 | r = strlen(a->seqnum) - strlen(b->seqnum); | |
594 | if (r > 0) /* seqnum in a is longer -> higher */ | |
595 | return 1; | |
596 | if (r < 0) /* seqnum in a is shorter -> smaller */ | |
597 | return 0; | |
598 | ||
599 | r = strcmp(a->seqnum, b->seqnum); | |
600 | if (r >= 0) /* a is greater or equal, prefer a */ | |
601 | return 1; | |
602 | return 0; | |
603 | } |
0 | /* $OpenBSD: output-json.c,v 1.22 2021/11/04 11:32:55 claudio Exp $ */ | |
0 | /* $OpenBSD: output-json.c,v 1.23 2022/01/14 15:00:23 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * |
77 | 77 | "\t\t\"vrps\": %zu,\n" |
78 | 78 | "\t\t\"uniquevrps\": %zu,\n" |
79 | 79 | "\t\t\"cachedir_del_files\": %zu,\n" |
80 | "\t\t\"cachedir_superfluous_files\": %zu,\n" | |
80 | 81 | "\t\t\"cachedir_del_dirs\": %zu\n" |
81 | 82 | "\t},\n\n", |
82 | 83 | st->mfts, st->mfts_fail, st->mfts_stale, |
84 | 85 | st->gbrs, |
85 | 86 | st->repos, |
86 | 87 | st->vrps, st->uniqs, |
87 | st->del_files, st->del_dirs) < 0) | |
88 | st->del_files, st->extra_files, st->del_dirs) < 0) | |
88 | 89 | return -1; |
89 | 90 | return 0; |
90 | 91 | } |
0 | /* $OpenBSD: parser.c,v 1.28 2021/11/04 18:26:48 claudio Exp $ */ | |
0 | /* $OpenBSD: parser.c,v 1.60 2022/02/04 16:29:43 tb Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
21 | 21 | |
22 | 22 | #include <assert.h> |
23 | 23 | #include <err.h> |
24 | #include <fcntl.h> | |
24 | 25 | #include <poll.h> |
25 | 26 | #include <stdio.h> |
26 | 27 | #include <stdlib.h> |
33 | 34 | #include <openssl/err.h> |
34 | 35 | #include <openssl/evp.h> |
35 | 36 | #include <openssl/x509.h> |
37 | #include <openssl/x509v3.h> | |
36 | 38 | |
37 | 39 | #include "extern.h" |
38 | 40 | |
41 | 43 | static void build_crls(const struct crl *, STACK_OF(X509_CRL) **); |
42 | 44 | |
43 | 45 | static X509_STORE_CTX *ctx; |
44 | static struct auth_tree auths = RB_INITIALIZER(&auths); | |
46 | static struct auth_tree auths = RB_INITIALIZER(&auths); | |
45 | 47 | static struct crl_tree crlt = RB_INITIALIZER(&crlt); |
48 | ||
49 | extern ASN1_OBJECT *certpol_oid; | |
50 | ||
51 | struct parse_repo { | |
52 | RB_ENTRY(parse_repo) entry; | |
53 | char *path; | |
54 | char *validpath; | |
55 | unsigned int id; | |
56 | }; | |
57 | ||
58 | static RB_HEAD(repo_tree, parse_repo) repos = RB_INITIALIZER(&repos); | |
59 | ||
60 | static inline int | |
61 | repocmp(struct parse_repo *a, struct parse_repo *b) | |
62 | { | |
63 | return a->id - b->id; | |
64 | } | |
65 | ||
66 | RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp); | |
67 | ||
68 | static struct parse_repo * | |
69 | repo_get(unsigned int id) | |
70 | { | |
71 | struct parse_repo needle = { .id = id }; | |
72 | ||
73 | return RB_FIND(repo_tree, &repos, &needle); | |
74 | } | |
75 | ||
76 | static void | |
77 | repo_add(unsigned int id, char *path, char *validpath) | |
78 | { | |
79 | struct parse_repo *rp; | |
80 | ||
81 | if ((rp = calloc(1, sizeof(*rp))) == NULL) | |
82 | err(1, NULL); | |
83 | rp->id = id; | |
84 | if (path != NULL) | |
85 | if ((rp->path = strdup(path)) == NULL) | |
86 | err(1, NULL); | |
87 | if (validpath != NULL) | |
88 | if ((rp->validpath = strdup(validpath)) == NULL) | |
89 | err(1, NULL); | |
90 | ||
91 | if (RB_INSERT(repo_tree, &repos, rp) != NULL) | |
92 | errx(1, "repository already added: id %d, %s", id, path); | |
93 | } | |
94 | ||
95 | static char * | |
96 | time2str(time_t t) | |
97 | { | |
98 | static char buf[64]; | |
99 | struct tm tm; | |
100 | ||
101 | if (gmtime_r(&t, &tm) == NULL) | |
102 | return "could not convert time"; | |
103 | ||
104 | strftime(buf, sizeof(buf), "%h %d %T %Y %Z", &tm); | |
105 | return buf; | |
106 | } | |
107 | ||
108 | /* | |
109 | * Build access path to file based on repoid, path, location and file values. | |
110 | */ | |
111 | static char * | |
112 | parse_filepath(unsigned int repoid, const char *path, const char *file, | |
113 | enum location loc) | |
114 | { | |
115 | struct parse_repo *rp; | |
116 | char *fn, *repopath; | |
117 | ||
118 | /* build file path based on repoid, entity path and filename */ | |
119 | rp = repo_get(repoid); | |
120 | if (rp == NULL) | |
121 | return NULL; | |
122 | ||
123 | if (loc == DIR_VALID) | |
124 | repopath = rp->validpath; | |
125 | else | |
126 | repopath = rp->path; | |
127 | ||
128 | if (repopath == NULL) | |
129 | return NULL; | |
130 | ||
131 | if (path == NULL) { | |
132 | if (asprintf(&fn, "%s/%s", repopath, file) == -1) | |
133 | err(1, NULL); | |
134 | } else { | |
135 | if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1) | |
136 | err(1, NULL); | |
137 | } | |
138 | return fn; | |
139 | } | |
140 | ||
141 | /* | |
142 | * Callback for X509_verify_cert() to handle critical extensions in old | |
143 | * LibreSSL libraries or OpenSSL libs without RFC3779 support. | |
144 | */ | |
145 | static int | |
146 | verify_cb(int ok, X509_STORE_CTX *store_ctx) | |
147 | { | |
148 | X509 *cert; | |
149 | const STACK_OF(X509_EXTENSION) *exts; | |
150 | X509_EXTENSION *ext; | |
151 | ASN1_OBJECT *obj; | |
152 | char *file; | |
153 | int depth, error, i, nid; | |
154 | ||
155 | error = X509_STORE_CTX_get_error(store_ctx); | |
156 | depth = X509_STORE_CTX_get_error_depth(store_ctx); | |
157 | ||
158 | if (error != X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) | |
159 | return ok; | |
160 | ||
161 | if ((file = X509_STORE_CTX_get_app_data(store_ctx)) == NULL) | |
162 | cryptoerrx("X509_STORE_CTX_get_app_data"); | |
163 | ||
164 | if ((cert = X509_STORE_CTX_get_current_cert(store_ctx)) == NULL) { | |
165 | warnx("%s: got no current cert", file); | |
166 | return 0; | |
167 | } | |
168 | if ((exts = X509_get0_extensions(cert)) == NULL) { | |
169 | warnx("%s: got no cert extensions", file); | |
170 | return 0; | |
171 | } | |
172 | ||
173 | for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { | |
174 | ext = sk_X509_EXTENSION_value(exts, i); | |
175 | ||
176 | /* skip over non-critical and known extensions */ | |
177 | if (!X509_EXTENSION_get_critical(ext)) | |
178 | continue; | |
179 | if (X509_supported_extension(ext)) | |
180 | continue; | |
181 | ||
182 | if ((obj = X509_EXTENSION_get_object(ext)) == NULL) { | |
183 | warnx("%s: got no extension object", file); | |
184 | return 0; | |
185 | } | |
186 | ||
187 | nid = OBJ_obj2nid(obj); | |
188 | switch (nid) { | |
189 | case NID_sbgp_ipAddrBlock: | |
190 | case NID_sbgp_autonomousSysNum: | |
191 | continue; | |
192 | default: | |
193 | warnx("%s: depth %d: unknown extension: nid %d", | |
194 | file, depth, nid); | |
195 | return 0; | |
196 | } | |
197 | } | |
198 | ||
199 | return 1; | |
200 | } | |
201 | ||
202 | /* | |
203 | * Validate the X509 certificate. If crl is NULL don't check CRL. | |
204 | * Returns 1 for valid certificates, returns 0 if there is a verify error | |
205 | */ | |
206 | static int | |
207 | valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl, | |
208 | unsigned long flags, int nowarn) | |
209 | { | |
210 | X509_VERIFY_PARAM *params; | |
211 | ASN1_OBJECT *cp_oid; | |
212 | STACK_OF(X509) *chain; | |
213 | STACK_OF(X509_CRL) *crls = NULL; | |
214 | int c; | |
215 | ||
216 | build_chain(a, &chain); | |
217 | build_crls(crl, &crls); | |
218 | ||
219 | assert(x509 != NULL); | |
220 | if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL)) | |
221 | cryptoerrx("X509_STORE_CTX_init"); | |
222 | ||
223 | if ((params = X509_STORE_CTX_get0_param(ctx)) == NULL) | |
224 | cryptoerrx("X509_STORE_CTX_get0_param"); | |
225 | if ((cp_oid = OBJ_dup(certpol_oid)) == NULL) | |
226 | cryptoerrx("OBJ_dup"); | |
227 | if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid)) | |
228 | cryptoerrx("X509_VERIFY_PARAM_add0_policy"); | |
229 | ||
230 | X509_STORE_CTX_set_verify_cb(ctx, verify_cb); | |
231 | if (!X509_STORE_CTX_set_app_data(ctx, file)) | |
232 | cryptoerrx("X509_STORE_CTX_set_app_data"); | |
233 | flags |= X509_V_FLAG_EXPLICIT_POLICY; | |
234 | flags |= X509_V_FLAG_INHIBIT_MAP; | |
235 | X509_STORE_CTX_set_flags(ctx, flags); | |
236 | X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH); | |
237 | X509_STORE_CTX_set0_trusted_stack(ctx, chain); | |
238 | X509_STORE_CTX_set0_crls(ctx, crls); | |
239 | ||
240 | if (X509_verify_cert(ctx) <= 0) { | |
241 | c = X509_STORE_CTX_get_error(ctx); | |
242 | if (!nowarn || verbose > 1) | |
243 | warnx("%s: %s", file, X509_verify_cert_error_string(c)); | |
244 | X509_STORE_CTX_cleanup(ctx); | |
245 | sk_X509_free(chain); | |
246 | sk_X509_CRL_free(crls); | |
247 | return 0; | |
248 | } | |
249 | ||
250 | X509_STORE_CTX_cleanup(ctx); | |
251 | sk_X509_free(chain); | |
252 | sk_X509_CRL_free(crls); | |
253 | return 1; | |
254 | } | |
46 | 255 | |
47 | 256 | /* |
48 | 257 | * Parse and validate a ROA. |
50 | 259 | * Returns the roa on success, NULL on failure. |
51 | 260 | */ |
52 | 261 | static struct roa * |
53 | proc_parser_roa(struct entity *entp, const unsigned char *der, size_t len) | |
262 | proc_parser_roa(char *file, const unsigned char *der, size_t len) | |
54 | 263 | { |
55 | 264 | struct roa *roa; |
265 | struct crl *crl; | |
266 | struct auth *a; | |
56 | 267 | X509 *x509; |
57 | int c; | |
58 | struct auth *a; | |
59 | STACK_OF(X509) *chain; | |
60 | STACK_OF(X509_CRL) *crls; | |
61 | struct crl *crl; | |
62 | ||
63 | if ((roa = roa_parse(&x509, entp->file, der, len)) == NULL) | |
64 | return NULL; | |
65 | ||
66 | a = valid_ski_aki(entp->file, &auths, roa->ski, roa->aki); | |
67 | build_chain(a, &chain); | |
268 | ||
269 | if ((roa = roa_parse(&x509, file, der, len)) == NULL) | |
270 | return NULL; | |
271 | ||
272 | a = valid_ski_aki(file, &auths, roa->ski, roa->aki); | |
68 | 273 | crl = get_crl(a); |
69 | build_crls(crl, &crls); | |
70 | ||
71 | assert(x509 != NULL); | |
72 | if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL)) | |
73 | cryptoerrx("X509_STORE_CTX_init"); | |
74 | X509_STORE_CTX_set_flags(ctx, | |
75 | X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK); | |
76 | X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH); | |
77 | X509_STORE_CTX_set0_trusted_stack(ctx, chain); | |
78 | X509_STORE_CTX_set0_crls(ctx, crls); | |
79 | ||
80 | if (X509_verify_cert(ctx) <= 0) { | |
81 | c = X509_STORE_CTX_get_error(ctx); | |
82 | X509_STORE_CTX_cleanup(ctx); | |
83 | if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL) | |
84 | warnx("%s: %s", entp->file, | |
85 | X509_verify_cert_error_string(c)); | |
274 | ||
275 | if (!valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) { | |
86 | 276 | X509_free(x509); |
87 | 277 | roa_free(roa); |
88 | sk_X509_free(chain); | |
89 | sk_X509_CRL_free(crls); | |
90 | return NULL; | |
91 | } | |
92 | X509_STORE_CTX_cleanup(ctx); | |
278 | return NULL; | |
279 | } | |
280 | X509_free(x509); | |
281 | ||
282 | roa->talid = a->cert->talid; | |
283 | ||
284 | /* | |
285 | * If the ROA isn't valid, we accept it anyway and depend upon | |
286 | * the code around roa_read() to check the "valid" field itself. | |
287 | */ | |
288 | ||
289 | if (valid_roa(file, a, roa)) | |
290 | roa->valid = 1; | |
93 | 291 | |
94 | 292 | /* |
95 | 293 | * Check CRL to figure out the soonest transitive expiry moment |
106 | 304 | roa->expires = a->cert->expires; |
107 | 305 | } |
108 | 306 | |
109 | /* | |
110 | * If the ROA isn't valid, we accept it anyway and depend upon | |
111 | * the code around roa_read() to check the "valid" field itself. | |
112 | */ | |
113 | ||
114 | if (valid_roa(entp->file, &auths, roa)) | |
115 | roa->valid = 1; | |
116 | ||
117 | sk_X509_free(chain); | |
118 | sk_X509_CRL_free(crls); | |
119 | X509_free(x509); | |
120 | ||
121 | 307 | return roa; |
122 | 308 | } |
123 | 309 | |
124 | 310 | /* |
125 | * Parse and validate a manifest file. | |
311 | * Check all files and their hashes in a MFT structure. | |
312 | * Return zero on failure, non-zero on success. | |
313 | */ | |
314 | static int | |
315 | proc_parser_mft_check(const char *fn, struct mft *p) | |
316 | { | |
317 | const enum location loc[2] = { DIR_TEMP, DIR_VALID }; | |
318 | size_t i; | |
319 | int rc = 1; | |
320 | char *path; | |
321 | ||
322 | for (i = 0; i < p->filesz; i++) { | |
323 | struct mftfile *m = &p->files[i]; | |
324 | int try, fd = -1, noent = 0, valid = 0; | |
325 | for (try = 0; try < 2 && !valid; try++) { | |
326 | if ((path = parse_filepath(p->repoid, p->path, m->file, | |
327 | loc[try])) == NULL) | |
328 | continue; | |
329 | fd = open(path, O_RDONLY); | |
330 | if (fd == -1 && errno == ENOENT) | |
331 | noent++; | |
332 | free(path); | |
333 | ||
334 | /* remember which path was checked */ | |
335 | m->location = loc[try]; | |
336 | valid = valid_filehash(fd, m->hash, sizeof(m->hash)); | |
337 | } | |
338 | ||
339 | if (!valid) { | |
340 | /* silently skip not-existing unknown files */ | |
341 | if (m->type == RTYPE_INVALID && noent == 2) | |
342 | continue; | |
343 | warnx("%s: bad message digest for %s", fn, m->file); | |
344 | rc = 0; | |
345 | continue; | |
346 | } | |
347 | } | |
348 | ||
349 | return rc; | |
350 | } | |
351 | ||
352 | /* | |
353 | * Parse and validate a manifest file. Skip checking the fileandhash | |
354 | * this is done in the post check. After this step we know the mft is | |
355 | * valid and can be compared. | |
126 | 356 | * Here we *don't* validate against the list of CRLs, because the |
127 | 357 | * certificate used to sign the manifest may specify a CRL that the root |
128 | 358 | * certificate didn't, and we haven't scanned for it yet. |
132 | 362 | * Return the mft on success or NULL on failure. |
133 | 363 | */ |
134 | 364 | static struct mft * |
135 | proc_parser_mft(struct entity *entp, const unsigned char *der, size_t len) | |
365 | proc_parser_mft_pre(char *file, const unsigned char *der, size_t len) | |
136 | 366 | { |
137 | 367 | struct mft *mft; |
138 | 368 | X509 *x509; |
139 | int c; | |
140 | 369 | struct auth *a; |
141 | STACK_OF(X509) *chain; | |
142 | ||
143 | if ((mft = mft_parse(&x509, entp->file, der, len)) == NULL) | |
144 | return NULL; | |
145 | ||
146 | a = valid_ski_aki(entp->file, &auths, mft->ski, mft->aki); | |
147 | build_chain(a, &chain); | |
148 | ||
149 | if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL)) | |
150 | cryptoerrx("X509_STORE_CTX_init"); | |
151 | ||
152 | /* CRL checked disabled here because CRL is referenced from mft */ | |
153 | X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_IGNORE_CRITICAL); | |
154 | X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH); | |
155 | X509_STORE_CTX_set0_trusted_stack(ctx, chain); | |
156 | ||
157 | if (X509_verify_cert(ctx) <= 0) { | |
158 | c = X509_STORE_CTX_get_error(ctx); | |
159 | X509_STORE_CTX_cleanup(ctx); | |
160 | warnx("%s: %s", entp->file, X509_verify_cert_error_string(c)); | |
370 | ||
371 | if ((mft = mft_parse(&x509, file, der, len)) == NULL) | |
372 | return NULL; | |
373 | ||
374 | a = valid_ski_aki(file, &auths, mft->ski, mft->aki); | |
375 | ||
376 | /* CRL checks disabled here because CRL is referenced from mft */ | |
377 | if (!valid_x509(file, x509, a, NULL, 0, 1)) { | |
161 | 378 | mft_free(mft); |
162 | 379 | X509_free(x509); |
163 | sk_X509_free(chain); | |
164 | return NULL; | |
165 | } | |
166 | ||
167 | X509_STORE_CTX_cleanup(ctx); | |
168 | sk_X509_free(chain); | |
380 | return NULL; | |
381 | } | |
169 | 382 | X509_free(x509); |
170 | 383 | |
171 | if (!mft_check(entp->file, mft)) { | |
172 | mft_free(mft); | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | 384 | return mft; |
385 | } | |
386 | ||
387 | /* | |
388 | * Do the end of manifest validation. | |
389 | * Return the mft on success or NULL on failure. | |
390 | */ | |
391 | static struct mft * | |
392 | proc_parser_mft_post(char *file, struct mft *mft, const char *path, | |
393 | unsigned int repoid) | |
394 | { | |
395 | /* check that now is not before from */ | |
396 | time_t now = time(NULL); | |
397 | ||
398 | if (mft == NULL) { | |
399 | warnx("%s: no valid mft available", file); | |
400 | return NULL; | |
401 | } | |
402 | ||
403 | /* check that now is not before from */ | |
404 | if (now < mft->valid_from) { | |
405 | warnx("%s: mft not yet valid %s", file, | |
406 | time2str(mft->valid_from)); | |
407 | mft->stale = 1; | |
408 | } | |
409 | /* check that now is not after until */ | |
410 | if (now > mft->valid_until) { | |
411 | warnx("%s: mft expired on %s", file, | |
412 | time2str(mft->valid_until)); | |
413 | mft->stale = 1; | |
414 | } | |
415 | ||
416 | mft->repoid = repoid; | |
417 | if (path != NULL) | |
418 | if ((mft->path = strdup(path)) == NULL) | |
419 | err(1, NULL); | |
420 | ||
421 | if (!mft->stale) | |
422 | if (!proc_parser_mft_check(file, mft)) { | |
423 | mft_free(mft); | |
424 | return NULL; | |
425 | } | |
426 | ||
427 | return mft; | |
428 | } | |
429 | ||
430 | /* | |
431 | * Validate a certificate, if invalid free the resouces and return NULL. | |
432 | */ | |
433 | static struct cert * | |
434 | proc_parser_cert_validate(char *file, struct cert *cert) | |
435 | { | |
436 | struct auth *a; | |
437 | struct crl *crl; | |
438 | ||
439 | a = valid_ski_aki(file, &auths, cert->ski, cert->aki); | |
440 | crl = get_crl(a); | |
441 | ||
442 | if (!valid_x509(file, cert->x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) { | |
443 | cert_free(cert); | |
444 | return NULL; | |
445 | } | |
446 | ||
447 | cert->talid = a->cert->talid; | |
448 | ||
449 | /* Validate the cert */ | |
450 | if (!valid_cert(file, a, cert)) { | |
451 | cert_free(cert); | |
452 | return NULL; | |
453 | } | |
454 | ||
455 | /* | |
456 | * Add validated CA certs to the RPKI auth tree. | |
457 | */ | |
458 | if (cert->purpose == CERT_PURPOSE_CA) | |
459 | auth_insert(&auths, cert, a); | |
460 | ||
461 | return cert; | |
177 | 462 | } |
178 | 463 | |
179 | 464 | /* |
184 | 469 | * parse failure. |
185 | 470 | */ |
186 | 471 | static struct cert * |
187 | proc_parser_cert(const struct entity *entp, const unsigned char *der, | |
188 | size_t len) | |
189 | { | |
190 | struct cert *cert; | |
191 | X509 *x509; | |
192 | int c; | |
193 | struct auth *a = NULL; | |
194 | STACK_OF(X509) *chain; | |
195 | STACK_OF(X509_CRL) *crls; | |
196 | ||
197 | assert(!entp->has_data); | |
198 | ||
199 | /* Extract certificate data and X509. */ | |
200 | ||
201 | cert = cert_parse(&x509, entp->file, der, len); | |
472 | proc_parser_cert(char *file, const unsigned char *der, size_t len) | |
473 | { | |
474 | struct cert *cert; | |
475 | ||
476 | /* Extract certificate data. */ | |
477 | ||
478 | cert = cert_parse(file, der, len); | |
202 | 479 | if (cert == NULL) |
203 | 480 | return NULL; |
204 | 481 | |
205 | a = valid_ski_aki(entp->file, &auths, cert->ski, cert->aki); | |
206 | build_chain(a, &chain); | |
207 | build_crls(get_crl(a), &crls); | |
208 | ||
209 | assert(x509 != NULL); | |
210 | if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL)) | |
211 | cryptoerrx("X509_STORE_CTX_init"); | |
212 | ||
213 | X509_STORE_CTX_set_flags(ctx, | |
214 | X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK); | |
215 | X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH); | |
216 | X509_STORE_CTX_set0_trusted_stack(ctx, chain); | |
217 | X509_STORE_CTX_set0_crls(ctx, crls); | |
218 | ||
219 | if (X509_verify_cert(ctx) <= 0) { | |
220 | c = X509_STORE_CTX_get_error(ctx); | |
221 | warnx("%s: %s", entp->file, | |
222 | X509_verify_cert_error_string(c)); | |
223 | X509_STORE_CTX_cleanup(ctx); | |
224 | cert_free(cert); | |
225 | sk_X509_free(chain); | |
226 | sk_X509_CRL_free(crls); | |
227 | X509_free(x509); | |
228 | return NULL; | |
229 | } | |
230 | ||
231 | X509_STORE_CTX_cleanup(ctx); | |
232 | sk_X509_free(chain); | |
233 | sk_X509_CRL_free(crls); | |
234 | X509_free(x509); | |
235 | ||
236 | cert->talid = a->cert->talid; | |
237 | ||
238 | /* Validate the cert to get the parent */ | |
239 | if (!valid_cert(entp->file, &auths, cert)) { | |
240 | cert_free(cert); | |
241 | return NULL; | |
242 | } | |
243 | ||
244 | /* | |
245 | * Add validated CA certs to the RPKI auth tree. | |
246 | */ | |
247 | if (cert->purpose == CERT_PURPOSE_CA) { | |
248 | if (!auth_insert(&auths, cert, a)) { | |
249 | cert_free(cert); | |
250 | return NULL; | |
251 | } | |
252 | } | |
253 | ||
482 | cert = proc_parser_cert_validate(file, cert); | |
254 | 483 | return cert; |
255 | 484 | } |
256 | 485 | |
257 | 486 | /* |
258 | 487 | * Root certificates come from TALs (has a pkey and is self-signed). |
259 | * Parse the certificate, ensure that it's public key matches the | |
488 | * Parse the certificate, ensure that its public key matches the | |
260 | 489 | * known public key from the TAL, and then validate the RPKI |
261 | 490 | * content. |
262 | 491 | * |
264 | 493 | * parse failure. |
265 | 494 | */ |
266 | 495 | static struct cert * |
267 | proc_parser_root_cert(const struct entity *entp, const unsigned char *der, | |
268 | size_t len) | |
269 | { | |
270 | char subject[256]; | |
271 | ASN1_TIME *notBefore, *notAfter; | |
272 | X509_NAME *name; | |
496 | proc_parser_root_cert(char *file, const unsigned char *der, size_t len, | |
497 | unsigned char *pkey, size_t pkeysz, int talid) | |
498 | { | |
273 | 499 | struct cert *cert; |
274 | X509 *x509; | |
275 | ||
276 | assert(entp->has_data); | |
277 | ||
278 | /* Extract certificate data and X509. */ | |
279 | ||
280 | cert = ta_parse(&x509, entp->file, der, len, entp->data, entp->datasz); | |
500 | ||
501 | /* Extract certificate data. */ | |
502 | ||
503 | cert = ta_parse(file, der, len, pkey, pkeysz); | |
281 | 504 | if (cert == NULL) |
282 | 505 | return NULL; |
283 | 506 | |
284 | if ((name = X509_get_subject_name(x509)) == NULL) { | |
285 | warnx("%s Unable to get certificate subject", entp->file); | |
286 | goto badcert; | |
287 | } | |
288 | if (X509_NAME_oneline(name, subject, sizeof(subject)) == NULL) { | |
289 | warnx("%s: Unable to parse certificate subject name", | |
290 | entp->file); | |
291 | goto badcert; | |
292 | } | |
293 | if ((notBefore = X509_get_notBefore(x509)) == NULL) { | |
294 | warnx("%s: certificate has invalid notBefore, subject='%s'", | |
295 | entp->file, subject); | |
296 | goto badcert; | |
297 | } | |
298 | if ((notAfter = X509_get_notAfter(x509)) == NULL) { | |
299 | warnx("%s: certificate has invalid notAfter, subject='%s'", | |
300 | entp->file, subject); | |
301 | goto badcert; | |
302 | } | |
303 | if (X509_cmp_current_time(notBefore) != -1) { | |
304 | warnx("%s: certificate not yet valid, subject='%s'", entp->file, | |
305 | subject); | |
306 | goto badcert; | |
307 | } | |
308 | if (X509_cmp_current_time(notAfter) != 1) { | |
309 | warnx("%s: certificate has expired, subject='%s'", entp->file, | |
310 | subject); | |
311 | goto badcert; | |
312 | } | |
313 | if (!valid_ta(entp->file, &auths, cert)) { | |
314 | warnx("%s: certificate not a valid ta, subject='%s'", | |
315 | entp->file, subject); | |
316 | goto badcert; | |
317 | } | |
318 | ||
319 | X509_free(x509); | |
320 | ||
321 | cert->talid = entp->talid; | |
507 | if (!valid_ta(file, &auths, cert)) { | |
508 | warnx("%s: certificate not a valid ta", file); | |
509 | cert_free(cert); | |
510 | return NULL; | |
511 | } | |
512 | ||
513 | cert->talid = talid; | |
322 | 514 | |
323 | 515 | /* |
324 | 516 | * Add valid roots to the RPKI auth tree. |
325 | 517 | */ |
326 | if (!auth_insert(&auths, cert, NULL)) { | |
327 | cert_free(cert); | |
328 | return NULL; | |
329 | } | |
518 | auth_insert(&auths, cert, NULL); | |
330 | 519 | |
331 | 520 | return cert; |
332 | ||
333 | badcert: | |
334 | X509_free(x509); | |
335 | cert_free(cert); | |
336 | return NULL; | |
337 | 521 | } |
338 | 522 | |
339 | 523 | /* |
343 | 527 | * CRL tree. |
344 | 528 | */ |
345 | 529 | static void |
346 | proc_parser_crl(struct entity *entp, const unsigned char *der, size_t len) | |
530 | proc_parser_crl(char *file, const unsigned char *der, size_t len) | |
347 | 531 | { |
348 | 532 | X509_CRL *x509_crl; |
349 | 533 | struct crl *crl; |
350 | 534 | const ASN1_TIME *at; |
351 | 535 | struct tm expires_tm; |
352 | 536 | |
353 | if ((x509_crl = crl_parse(entp->file, der, len)) != NULL) { | |
537 | if ((x509_crl = crl_parse(file, der, len)) != NULL) { | |
354 | 538 | if ((crl = malloc(sizeof(*crl))) == NULL) |
355 | 539 | err(1, NULL); |
356 | if ((crl->aki = x509_crl_get_aki(x509_crl, entp->file)) == | |
357 | NULL) { | |
540 | if ((crl->aki = x509_crl_get_aki(x509_crl, file)) == NULL) { | |
358 | 541 | warnx("x509_crl_get_aki failed"); |
359 | 542 | goto err; |
360 | 543 | } |
364 | 547 | /* extract expire time for later use */ |
365 | 548 | at = X509_CRL_get0_nextUpdate(x509_crl); |
366 | 549 | if (at == NULL) { |
367 | warnx("%s: X509_CRL_get0_nextUpdate failed", | |
368 | entp->file); | |
550 | warnx("%s: X509_CRL_get0_nextUpdate failed", file); | |
369 | 551 | goto err; |
370 | 552 | } |
371 | 553 | memset(&expires_tm, 0, sizeof(expires_tm)); |
372 | 554 | if (ASN1_time_parse(at->data, at->length, &expires_tm, |
373 | 555 | 0) == -1) { |
374 | warnx("%s: ASN1_time_parse failed", entp->file); | |
556 | warnx("%s: ASN1_time_parse failed", file); | |
375 | 557 | goto err; |
376 | 558 | } |
377 | 559 | if ((crl->expires = mktime(&expires_tm)) == -1) |
378 | errx(1, "%s: mktime failed", entp->file); | |
560 | errx(1, "%s: mktime failed", file); | |
379 | 561 | |
380 | 562 | if (RB_INSERT(crl_tree, &crlt, crl) != NULL) { |
381 | warnx("%s: duplicate AKI %s", entp->file, crl->aki); | |
563 | if (!filemode) | |
564 | warnx("%s: duplicate AKI %s", file, crl->aki); | |
382 | 565 | goto err; |
383 | 566 | } |
384 | 567 | } |
391 | 574 | * Parse a ghostbuster record |
392 | 575 | */ |
393 | 576 | static void |
394 | proc_parser_gbr(struct entity *entp, const unsigned char *der, size_t len) | |
577 | proc_parser_gbr(char *file, const unsigned char *der, size_t len) | |
395 | 578 | { |
396 | 579 | struct gbr *gbr; |
397 | 580 | X509 *x509; |
398 | int c; | |
399 | 581 | struct auth *a; |
400 | STACK_OF(X509) *chain; | |
401 | STACK_OF(X509_CRL) *crls; | |
402 | ||
403 | if ((gbr = gbr_parse(&x509, entp->file, der, len)) == NULL) | |
582 | struct crl *crl; | |
583 | ||
584 | if ((gbr = gbr_parse(&x509, file, der, len)) == NULL) | |
404 | 585 | return; |
405 | 586 | |
406 | a = valid_ski_aki(entp->file, &auths, gbr->ski, gbr->aki); | |
407 | ||
408 | build_chain(a, &chain); | |
409 | build_crls(get_crl(a), &crls); | |
410 | ||
411 | assert(x509 != NULL); | |
412 | if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL)) | |
413 | cryptoerrx("X509_STORE_CTX_init"); | |
414 | X509_STORE_CTX_set_flags(ctx, | |
415 | X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK); | |
416 | X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH); | |
417 | X509_STORE_CTX_set0_trusted_stack(ctx, chain); | |
418 | X509_STORE_CTX_set0_crls(ctx, crls); | |
419 | ||
420 | if (X509_verify_cert(ctx) <= 0) { | |
421 | c = X509_STORE_CTX_get_error(ctx); | |
422 | if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL) | |
423 | warnx("%s: %s", entp->file, | |
424 | X509_verify_cert_error_string(c)); | |
425 | } | |
426 | ||
427 | X509_STORE_CTX_cleanup(ctx); | |
428 | sk_X509_free(chain); | |
429 | sk_X509_CRL_free(crls); | |
587 | a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki); | |
588 | crl = get_crl(a); | |
589 | ||
590 | /* return value can be ignored since nothing happens here */ | |
591 | valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0); | |
592 | ||
430 | 593 | X509_free(x509); |
431 | 594 | gbr_free(gbr); |
432 | 595 | } |
487 | 650 | err(1, "sk_X509_CRL_push"); |
488 | 651 | } |
489 | 652 | |
653 | /* | |
654 | * Load the file specified by the entity information. | |
655 | */ | |
656 | static char * | |
657 | parse_load_file(struct entity *entp, unsigned char **f, size_t *flen) | |
658 | { | |
659 | char *file; | |
660 | ||
661 | file = parse_filepath(entp->repoid, entp->path, entp->file, | |
662 | entp->location); | |
663 | if (file == NULL) | |
664 | errx(1, "no path to file"); | |
665 | ||
666 | *f = load_file(file, flen); | |
667 | if (*f == NULL) | |
668 | warn("parse file %s", file); | |
669 | ||
670 | return file; | |
671 | } | |
672 | ||
673 | static char * | |
674 | parse_load_mft(struct entity *entp, struct mft **mft) | |
675 | { | |
676 | struct mft *mft1 = NULL, *mft2 = NULL; | |
677 | char *f, *file1, *file2; | |
678 | size_t flen; | |
679 | ||
680 | file1 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID); | |
681 | file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_TEMP); | |
682 | ||
683 | if (file1 != NULL) { | |
684 | f = load_file(file1, &flen); | |
685 | if (f == NULL && errno != ENOENT) | |
686 | warn("parse file %s", file1); | |
687 | mft1 = proc_parser_mft_pre(file1, f, flen); | |
688 | free(f); | |
689 | } | |
690 | ||
691 | if (file2 != NULL) { | |
692 | f = load_file(file2, &flen); | |
693 | if (f == NULL && errno != ENOENT) | |
694 | warn("parse file %s", file2); | |
695 | mft2 = proc_parser_mft_pre(file2, f, flen); | |
696 | free(f); | |
697 | } | |
698 | ||
699 | if (mft_compare(mft1, mft2) == 1) { | |
700 | mft_free(mft2); | |
701 | free(file2); | |
702 | *mft = mft1; | |
703 | return file1; | |
704 | } else { | |
705 | mft_free(mft1); | |
706 | free(file1); | |
707 | *mft = mft2; | |
708 | return file2; | |
709 | } | |
710 | } | |
711 | ||
712 | /* | |
713 | * Process an entity and responing to parent process. | |
714 | */ | |
490 | 715 | static void |
491 | 716 | parse_entity(struct entityq *q, struct msgbuf *msgq) |
492 | 717 | { |
498 | 723 | struct ibuf *b; |
499 | 724 | unsigned char *f; |
500 | 725 | size_t flen; |
726 | char *file; | |
501 | 727 | int c; |
502 | 728 | |
503 | 729 | while ((entp = TAILQ_FIRST(q)) != NULL) { |
504 | 730 | TAILQ_REMOVE(q, entp, entries); |
505 | 731 | |
732 | /* handle RTYPE_REPO first */ | |
733 | if (entp->type == RTYPE_REPO) { | |
734 | repo_add(entp->repoid, entp->path, entp->file); | |
735 | entity_free(entp); | |
736 | continue; | |
737 | } | |
738 | ||
739 | /* pass back at least type, repoid and filename */ | |
506 | 740 | b = io_new_buffer(); |
507 | 741 | io_simple_buffer(b, &entp->type, sizeof(entp->type)); |
508 | 742 | |
743 | file = NULL; | |
509 | 744 | f = NULL; |
510 | if (entp->type != RTYPE_TAL) { | |
511 | f = load_file(entp->file, &flen); | |
512 | if (f == NULL) | |
513 | warn("%s", entp->file); | |
514 | } | |
515 | ||
516 | 745 | switch (entp->type) { |
517 | 746 | case RTYPE_TAL: |
747 | io_str_buffer(b, entp->file); | |
518 | 748 | if ((tal = tal_parse(entp->file, entp->data, |
519 | 749 | entp->datasz)) == NULL) |
520 | 750 | errx(1, "%s: could not parse tal file", |
524 | 754 | tal_free(tal); |
525 | 755 | break; |
526 | 756 | case RTYPE_CER: |
527 | if (entp->has_data) | |
528 | cert = proc_parser_root_cert(entp, f, flen); | |
757 | file = parse_load_file(entp, &f, &flen); | |
758 | io_str_buffer(b, file); | |
759 | if (entp->data != NULL) | |
760 | cert = proc_parser_root_cert(file, | |
761 | f, flen, entp->data, entp->datasz, | |
762 | entp->talid); | |
529 | 763 | else |
530 | cert = proc_parser_cert(entp, f, flen); | |
764 | cert = proc_parser_cert(file, f, flen); | |
531 | 765 | c = (cert != NULL); |
532 | 766 | io_simple_buffer(b, &c, sizeof(int)); |
533 | 767 | if (cert != NULL) |
535 | 769 | /* |
536 | 770 | * The parsed certificate data "cert" is now |
537 | 771 | * managed in the "auths" table, so don't free |
538 | * it here (see the loop after "out"). | |
772 | * it here. | |
539 | 773 | */ |
540 | 774 | break; |
541 | 775 | case RTYPE_CRL: |
542 | proc_parser_crl(entp, f, flen); | |
776 | file = parse_load_file(entp, &f, &flen); | |
777 | io_str_buffer(b, file); | |
778 | proc_parser_crl(file, f, flen); | |
543 | 779 | break; |
544 | 780 | case RTYPE_MFT: |
545 | mft = proc_parser_mft(entp, f, flen); | |
781 | file = parse_load_mft(entp, &mft); | |
782 | ||
783 | mft = proc_parser_mft_post(file, mft, | |
784 | entp->path, entp->repoid); | |
785 | ||
786 | io_str_buffer(b, file); | |
546 | 787 | c = (mft != NULL); |
547 | 788 | io_simple_buffer(b, &c, sizeof(int)); |
548 | 789 | if (mft != NULL) |
550 | 791 | mft_free(mft); |
551 | 792 | break; |
552 | 793 | case RTYPE_ROA: |
553 | roa = proc_parser_roa(entp, f, flen); | |
794 | file = parse_load_file(entp, &f, &flen); | |
795 | io_str_buffer(b, file); | |
796 | roa = proc_parser_roa(file, f, flen); | |
554 | 797 | c = (roa != NULL); |
555 | 798 | io_simple_buffer(b, &c, sizeof(int)); |
556 | 799 | if (roa != NULL) |
558 | 801 | roa_free(roa); |
559 | 802 | break; |
560 | 803 | case RTYPE_GBR: |
561 | proc_parser_gbr(entp, f, flen); | |
804 | file = parse_load_file(entp, &f, &flen); | |
805 | io_str_buffer(b, file); | |
806 | proc_parser_gbr(file, f, flen); | |
562 | 807 | break; |
563 | 808 | default: |
564 | abort(); | |
809 | errx(1, "unhandled entity type %d", entp->type); | |
565 | 810 | } |
566 | 811 | |
567 | 812 | free(f); |
813 | free(file); | |
814 | io_close_buffer(msgq, b); | |
815 | entity_free(entp); | |
816 | } | |
817 | } | |
818 | ||
819 | /* | |
820 | * Use the X509 CRL Distribution Points to locate the CRL needed for | |
821 | * verification. | |
822 | */ | |
823 | static void | |
824 | parse_load_crl(char *uri) | |
825 | { | |
826 | char *f; | |
827 | size_t flen; | |
828 | ||
829 | if (uri == NULL) | |
830 | return; | |
831 | if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) { | |
832 | warnx("bad CRL distribution point URI %s", uri); | |
833 | return; | |
834 | } | |
835 | uri += strlen("rsync://"); | |
836 | ||
837 | f = load_file(uri, &flen); | |
838 | if (f == NULL) { | |
839 | warn("parse file %s", uri); | |
840 | return; | |
841 | } | |
842 | ||
843 | proc_parser_crl(uri, f, flen); | |
844 | ||
845 | free(f); | |
846 | } | |
847 | ||
848 | /* | |
849 | * Parse the cert pointed at by the AIA URI while doing that also load | |
850 | * the CRL of this cert. While the CRL is validated the returned cert | |
851 | * is not. The caller needs to make sure it is validated once all | |
852 | * necessary certs were loaded. Returns NULL on failure. | |
853 | */ | |
854 | static struct cert * | |
855 | parse_load_cert(char *uri) | |
856 | { | |
857 | struct cert *cert = NULL; | |
858 | char *f; | |
859 | size_t flen; | |
860 | ||
861 | if (uri == NULL) | |
862 | return NULL; | |
863 | ||
864 | if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) { | |
865 | warnx("bad authority information access URI %s", uri); | |
866 | return NULL; | |
867 | } | |
868 | uri += strlen("rsync://"); | |
869 | ||
870 | f = load_file(uri, &flen); | |
871 | if (f == NULL) { | |
872 | warn("parse file %s", uri); | |
873 | goto done; | |
874 | } | |
875 | ||
876 | cert = cert_parse(uri, f, flen); | |
877 | free(f); | |
878 | ||
879 | if (cert == NULL) | |
880 | goto done; | |
881 | if (cert->purpose != CERT_PURPOSE_CA) { | |
882 | warnx("AIA reference to bgpsec cert %s", uri); | |
883 | goto done; | |
884 | } | |
885 | /* try to load the CRL of this cert */ | |
886 | parse_load_crl(cert->crl); | |
887 | ||
888 | return cert; | |
889 | ||
890 | done: | |
891 | cert_free(cert); | |
892 | return NULL; | |
893 | } | |
894 | ||
895 | /* | |
896 | * Build the certificate chain by using the Authority Information Access. | |
897 | * This requires that the TA are already validated and added to the auths | |
898 | * tree. Once the TA is located in the chain the chain is validated in | |
899 | * reverse order. | |
900 | */ | |
901 | static void | |
902 | parse_load_certchain(char *uri) | |
903 | { | |
904 | struct cert *stack[MAX_CERT_DEPTH]; | |
905 | char *filestack[MAX_CERT_DEPTH]; | |
906 | struct cert *cert; | |
907 | int i, failed; | |
908 | ||
909 | for (i = 0; i < MAX_CERT_DEPTH; i++) { | |
910 | cert = parse_load_cert(uri); | |
911 | if (cert == NULL) { | |
912 | warnx("failed to build authority chain"); | |
913 | return; | |
914 | } | |
915 | if (auth_find(&auths, cert->ski) != NULL) { | |
916 | assert(i == 0); | |
917 | cert_free(cert); | |
918 | return; /* cert already added */ | |
919 | } | |
920 | stack[i] = cert; | |
921 | filestack[i] = uri; | |
922 | if (auth_find(&auths, cert->aki) != NULL) | |
923 | break; /* found chain to TA */ | |
924 | uri = cert->aia; | |
925 | } | |
926 | ||
927 | if (i >= MAX_CERT_DEPTH) { | |
928 | warnx("authority chain exceeds max depth of %d", | |
929 | MAX_CERT_DEPTH); | |
930 | for (i = 0; i < MAX_CERT_DEPTH; i++) | |
931 | cert_free(stack[i]); | |
932 | return; | |
933 | } | |
934 | ||
935 | /* TA found play back the stack and add all certs */ | |
936 | for (failed = 0; i >= 0; i--) { | |
937 | cert = stack[i]; | |
938 | uri = filestack[i]; | |
939 | ||
940 | if (failed) | |
941 | cert_free(cert); | |
942 | else if (proc_parser_cert_validate(uri, cert) == NULL) | |
943 | failed = 1; | |
944 | } | |
945 | } | |
946 | ||
947 | static void | |
948 | parse_load_ta(struct tal *tal) | |
949 | { | |
950 | const char *file; | |
951 | char *nfile, *f; | |
952 | size_t flen; | |
953 | ||
954 | /* does not matter which URI, all end with same filename */ | |
955 | file = strrchr(tal->uri[0], '/'); | |
956 | assert(file); | |
957 | ||
958 | if (asprintf(&nfile, "ta/%s%s", tal->descr, file) == -1) | |
959 | err(1, NULL); | |
960 | ||
961 | f = load_file(nfile, &flen); | |
962 | if (f == NULL) { | |
963 | warn("parse file %s", nfile); | |
964 | free(nfile); | |
965 | return; | |
966 | } | |
967 | ||
968 | /* if TA is valid it was added as a root which is all we need */ | |
969 | proc_parser_root_cert(nfile, f, flen, tal->pkey, tal->pkeysz, tal->id); | |
970 | free(nfile); | |
971 | free(f); | |
972 | } | |
973 | ||
974 | /* | |
975 | * Parse file passed with -f option. | |
976 | */ | |
977 | static void | |
978 | proc_parser_file(char *file, unsigned char *buf, size_t len) | |
979 | { | |
980 | static int num; | |
981 | X509 *x509 = NULL; | |
982 | struct cert *cert = NULL; | |
983 | struct mft *mft = NULL; | |
984 | struct roa *roa = NULL; | |
985 | struct gbr *gbr = NULL; | |
986 | struct tal *tal = NULL; | |
987 | enum rtype type; | |
988 | char *aia = NULL, *aki = NULL; | |
989 | unsigned long verify_flags = X509_V_FLAG_CRL_CHECK; | |
990 | ||
991 | if (num++ > 0) | |
992 | printf("--\n"); | |
993 | ||
994 | if (strncmp(file, "rsync://", strlen("rsync://")) == 0) { | |
995 | file += strlen("rsync://"); | |
996 | buf = load_file(file, &len); | |
997 | if (buf == NULL) { | |
998 | warn("parse file %s", file); | |
999 | return; | |
1000 | } | |
1001 | } | |
1002 | ||
1003 | printf("File: %s\n", file); | |
1004 | ||
1005 | type = rtype_from_file_extension(file); | |
1006 | ||
1007 | switch (type) { | |
1008 | case RTYPE_CER: | |
1009 | cert = cert_parse(file, buf, len); | |
1010 | if (cert == NULL) | |
1011 | break; | |
1012 | cert_print(cert); | |
1013 | aia = cert->aia; | |
1014 | aki = cert->aki; | |
1015 | x509 = cert->x509; | |
1016 | if (X509_up_ref(x509) == 0) | |
1017 | errx(1, "%s: X509_up_ref failed", __func__); | |
1018 | break; | |
1019 | case RTYPE_MFT: | |
1020 | mft = mft_parse(&x509, file, buf, len); | |
1021 | if (mft == NULL) | |
1022 | break; | |
1023 | mft_print(mft); | |
1024 | aia = mft->aia; | |
1025 | aki = mft->aki; | |
1026 | verify_flags = 0; | |
1027 | break; | |
1028 | case RTYPE_ROA: | |
1029 | roa = roa_parse(&x509, file, buf, len); | |
1030 | if (roa == NULL) | |
1031 | break; | |
1032 | roa_print(roa); | |
1033 | aia = roa->aia; | |
1034 | aki = roa->aki; | |
1035 | break; | |
1036 | case RTYPE_GBR: | |
1037 | gbr = gbr_parse(&x509, file, buf, len); | |
1038 | if (gbr == NULL) | |
1039 | break; | |
1040 | gbr_print(gbr); | |
1041 | aia = gbr->aia; | |
1042 | aki = gbr->aki; | |
1043 | break; | |
1044 | case RTYPE_TAL: | |
1045 | tal = tal_parse(file, buf, len); | |
1046 | if (tal == NULL) | |
1047 | break; | |
1048 | tal_print(tal); | |
1049 | break; | |
1050 | case RTYPE_CRL: /* XXX no printer yet */ | |
1051 | default: | |
1052 | printf("%s: unsupported file type\n", file); | |
1053 | break; | |
1054 | } | |
1055 | ||
1056 | if (aia != NULL) { | |
1057 | struct auth *a; | |
1058 | struct crl *crl; | |
1059 | char *c; | |
1060 | ||
1061 | c = x509_get_crl(x509, file); | |
1062 | parse_load_crl(c); | |
1063 | free(c); | |
1064 | parse_load_certchain(aia); | |
1065 | a = auth_find(&auths, aki); | |
1066 | crl = get_crl(a); | |
1067 | ||
1068 | if (valid_x509(file, x509, a, crl, verify_flags, 0)) | |
1069 | printf("Validation: OK\n"); | |
1070 | else | |
1071 | printf("Validation: Failed\n"); | |
1072 | } | |
1073 | ||
1074 | X509_free(x509); | |
1075 | cert_free(cert); | |
1076 | mft_free(mft); | |
1077 | roa_free(roa); | |
1078 | gbr_free(gbr); | |
1079 | tal_free(tal); | |
1080 | } | |
1081 | ||
1082 | /* | |
1083 | * Process a file request, in general don't send anything back. | |
1084 | */ | |
1085 | static void | |
1086 | parse_file(struct entityq *q, struct msgbuf *msgq) | |
1087 | { | |
1088 | struct entity *entp; | |
1089 | struct ibuf *b; | |
1090 | struct tal *tal; | |
1091 | ||
1092 | while ((entp = TAILQ_FIRST(q)) != NULL) { | |
1093 | TAILQ_REMOVE(q, entp, entries); | |
1094 | ||
1095 | switch (entp->type) { | |
1096 | case RTYPE_FILE: | |
1097 | proc_parser_file(entp->file, entp->data, entp->datasz); | |
1098 | break; | |
1099 | case RTYPE_TAL: | |
1100 | if ((tal = tal_parse(entp->file, entp->data, | |
1101 | entp->datasz)) == NULL) | |
1102 | errx(1, "%s: could not parse tal file", | |
1103 | entp->file); | |
1104 | tal->id = entp->talid; | |
1105 | parse_load_ta(tal); | |
1106 | tal_free(tal); | |
1107 | break; | |
1108 | default: | |
1109 | errx(1, "unhandled entity type %d", entp->type); | |
1110 | } | |
1111 | ||
1112 | b = io_new_buffer(); | |
1113 | io_simple_buffer(b, &entp->type, sizeof(entp->type)); | |
1114 | io_str_buffer(b, entp->file); | |
568 | 1115 | io_close_buffer(msgq, b); |
569 | 1116 | entity_free(entp); |
570 | 1117 | } |
589 | 1136 | ERR_load_crypto_strings(); |
590 | 1137 | OpenSSL_add_all_ciphers(); |
591 | 1138 | OpenSSL_add_all_digests(); |
1139 | x509_init_oid(); | |
592 | 1140 | |
593 | 1141 | if ((ctx = X509_STORE_CTX_new()) == NULL) |
594 | 1142 | cryptoerrx("X509_STORE_CTX_new"); |
605 | 1153 | if (msgq.queued) |
606 | 1154 | pfd.events |= POLLOUT; |
607 | 1155 | |
608 | if (poll(&pfd, 1, INFTIM) == -1) | |
1156 | if (poll(&pfd, 1, INFTIM) == -1) { | |
1157 | if (errno == EINTR) | |
1158 | continue; | |
609 | 1159 | err(1, "poll"); |
1160 | } | |
610 | 1161 | if ((pfd.revents & (POLLERR|POLLNVAL))) |
611 | 1162 | errx(1, "poll: bad descriptor"); |
612 | 1163 | |
636 | 1187 | } |
637 | 1188 | } |
638 | 1189 | |
639 | parse_entity(&q, &msgq); | |
1190 | if (!filemode) | |
1191 | parse_entity(&q, &msgq); | |
1192 | else | |
1193 | parse_file(&q, &msgq); | |
640 | 1194 | } |
641 | 1195 | |
642 | 1196 | while ((entp = TAILQ_FIRST(&q)) != NULL) { |
0 | /* $OpenBSD: print.c,v 1.3 2021/12/22 09:35:14 claudio Exp $ */ | |
1 | /* | |
2 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> | |
3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include <sys/types.h> | |
19 | #include <sys/socket.h> | |
20 | #include <arpa/inet.h> | |
21 | ||
22 | #include <err.h> | |
23 | #include <stdio.h> | |
24 | #include <string.h> | |
25 | #include <time.h> | |
26 | ||
27 | #include "extern.h" | |
28 | ||
29 | static const char * | |
30 | pretty_key_id(char *hex) | |
31 | { | |
32 | static char buf[128]; /* bigger than SHA_DIGEST_LENGTH * 3 */ | |
33 | size_t i; | |
34 | ||
35 | for (i = 0; i < sizeof(buf) && *hex != '\0'; i++) { | |
36 | if (i % 3 == 2 && *hex != '\0') | |
37 | buf[i] = ':'; | |
38 | else | |
39 | buf[i] = *hex++; | |
40 | } | |
41 | if (i == sizeof(buf)) | |
42 | memcpy(buf + sizeof(buf) - 4, "...", 4); | |
43 | return buf; | |
44 | } | |
45 | ||
46 | void | |
47 | tal_print(const struct tal *p) | |
48 | { | |
49 | size_t i; | |
50 | ||
51 | for (i = 0; i < p->urisz; i++) | |
52 | printf("%5zu: URI: %s\n", i + 1, p->uri[i]); | |
53 | } | |
54 | ||
55 | void | |
56 | cert_print(const struct cert *p) | |
57 | { | |
58 | size_t i; | |
59 | char buf1[64], buf2[64]; | |
60 | int sockt; | |
61 | char tbuf[21]; | |
62 | ||
63 | printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); | |
64 | if (p->aki != NULL) | |
65 | printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); | |
66 | if (p->aia != NULL) | |
67 | printf("Authority info access: %s\n", p->aia); | |
68 | if (p->mft != NULL) | |
69 | printf("Manifest: %s\n", p->mft); | |
70 | if (p->repo != NULL) | |
71 | printf("caRepository: %s\n", p->repo); | |
72 | if (p->notify != NULL) | |
73 | printf("Notify URL: %s\n", p->notify); | |
74 | if (p->pubkey != NULL) | |
75 | printf("BGPsec P-256 ECDSA public key: %s\n", p->pubkey); | |
76 | strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires)); | |
77 | printf("Valid until: %s\n", tbuf); | |
78 | ||
79 | printf("Subordinate Resources:\n"); | |
80 | ||
81 | for (i = 0; i < p->asz; i++) | |
82 | switch (p->as[i].type) { | |
83 | case CERT_AS_ID: | |
84 | printf("%5zu: AS: %u\n", i + 1, p->as[i].id); | |
85 | break; | |
86 | case CERT_AS_INHERIT: | |
87 | printf("%5zu: AS: inherit\n", i + 1); | |
88 | break; | |
89 | case CERT_AS_RANGE: | |
90 | printf("%5zu: AS: %u -- %u\n", i + 1, | |
91 | p->as[i].range.min, p->as[i].range.max); | |
92 | break; | |
93 | } | |
94 | ||
95 | for (i = 0; i < p->ipsz; i++) | |
96 | switch (p->ips[i].type) { | |
97 | case CERT_IP_INHERIT: | |
98 | printf("%5zu: IP: inherit\n", i + 1); | |
99 | break; | |
100 | case CERT_IP_ADDR: | |
101 | ip_addr_print(&p->ips[i].ip, | |
102 | p->ips[i].afi, buf1, sizeof(buf1)); | |
103 | printf("%5zu: IP: %s\n", i + 1, buf1); | |
104 | break; | |
105 | case CERT_IP_RANGE: | |
106 | sockt = (p->ips[i].afi == AFI_IPV4) ? | |
107 | AF_INET : AF_INET6; | |
108 | inet_ntop(sockt, p->ips[i].min, buf1, sizeof(buf1)); | |
109 | inet_ntop(sockt, p->ips[i].max, buf2, sizeof(buf2)); | |
110 | printf("%5zu: IP: %s -- %s\n", i + 1, buf1, buf2); | |
111 | break; | |
112 | } | |
113 | ||
114 | } | |
115 | ||
116 | void | |
117 | mft_print(const struct mft *p) | |
118 | { | |
119 | size_t i; | |
120 | char *hash; | |
121 | ||
122 | printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); | |
123 | printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); | |
124 | printf("Authority info access: %s\n", p->aia); | |
125 | printf("Manifest Number: %s\n", p->seqnum); | |
126 | for (i = 0; i < p->filesz; i++) { | |
127 | if (base64_encode(p->files[i].hash, sizeof(p->files[i].hash), | |
128 | &hash) == -1) | |
129 | errx(1, "base64_encode failure"); | |
130 | printf("%5zu: %s\n", i + 1, p->files[i].file); | |
131 | printf("\thash %s\n", hash); | |
132 | free(hash); | |
133 | } | |
134 | } | |
135 | ||
136 | void | |
137 | roa_print(const struct roa *p) | |
138 | { | |
139 | char buf[128]; | |
140 | size_t i; | |
141 | char tbuf[21]; | |
142 | ||
143 | printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); | |
144 | printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); | |
145 | printf("Authority info access: %s\n", p->aia); | |
146 | strftime(tbuf, sizeof(tbuf), "%FT%TZ", gmtime(&p->expires)); | |
147 | printf("ROA valid until: %s\n", tbuf); | |
148 | ||
149 | printf("asID: %u\n", p->asid); | |
150 | for (i = 0; i < p->ipsz; i++) { | |
151 | ip_addr_print(&p->ips[i].addr, | |
152 | p->ips[i].afi, buf, sizeof(buf)); | |
153 | printf("%5zu: %s maxlen: %hhu\n", i + 1, | |
154 | buf, p->ips[i].maxlength); | |
155 | } | |
156 | } | |
157 | ||
158 | void | |
159 | gbr_print(const struct gbr *p) | |
160 | { | |
161 | printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); | |
162 | printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); | |
163 | printf("Authority info access: %s\n", p->aia); | |
164 | printf("vcard:\n%s", p->vcard); | |
165 | } |
0 | /* $OpenBSD: repo.c,v 1.11 2021/11/09 11:03:39 claudio Exp $ */ | |
0 | /* $OpenBSD: repo.c,v 1.30 2022/02/02 15:13:00 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
39 | 39 | extern struct stats stats; |
40 | 40 | extern int noop; |
41 | 41 | extern int rrdpon; |
42 | extern int repo_timeout; | |
42 | 43 | |
43 | 44 | enum repo_state { |
44 | 45 | REPO_LOADING = 0, |
56 | 57 | SLIST_ENTRY(rrdprepo) entry; |
57 | 58 | char *notifyuri; |
58 | 59 | char *basedir; |
59 | char *temp; | |
60 | struct filepath_tree added; | |
61 | 60 | struct filepath_tree deleted; |
62 | size_t id; | |
61 | unsigned int id; | |
63 | 62 | enum repo_state state; |
64 | 63 | }; |
65 | SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos); | |
64 | static SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos); | |
66 | 65 | |
67 | 66 | struct rsyncrepo { |
68 | 67 | SLIST_ENTRY(rsyncrepo) entry; |
69 | 68 | char *repouri; |
70 | 69 | char *basedir; |
71 | size_t id; | |
70 | unsigned int id; | |
72 | 71 | enum repo_state state; |
73 | 72 | }; |
74 | SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos); | |
73 | static SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos); | |
75 | 74 | |
76 | 75 | struct tarepo { |
77 | 76 | SLIST_ENTRY(tarepo) entry; |
81 | 80 | char **uri; |
82 | 81 | size_t urisz; |
83 | 82 | size_t uriidx; |
84 | size_t id; | |
83 | unsigned int id; | |
85 | 84 | enum repo_state state; |
86 | 85 | }; |
87 | SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos); | |
88 | ||
89 | struct repo { | |
86 | static SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos); | |
87 | ||
88 | struct repo { | |
90 | 89 | SLIST_ENTRY(repo) entry; |
91 | 90 | char *repouri; |
92 | 91 | char *notifyuri; |
92 | char *basedir; | |
93 | 93 | const struct rrdprepo *rrdp; |
94 | 94 | const struct rsyncrepo *rsync; |
95 | 95 | const struct tarepo *ta; |
96 | 96 | struct entityq queue; /* files waiting for repo */ |
97 | 97 | time_t alarm; /* sync timeout */ |
98 | 98 | int talid; |
99 | size_t id; /* identifier */ | |
99 | unsigned int id; /* identifier */ | |
100 | 100 | }; |
101 | SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos); | |
101 | static SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos); | |
102 | 102 | |
103 | 103 | /* counter for unique repo id */ |
104 | size_t repoid; | |
104 | unsigned int repoid; | |
105 | ||
106 | static struct rsyncrepo *rsync_get(const char *, const char *); | |
107 | static void remove_contents(char *); | |
105 | 108 | |
106 | 109 | /* |
107 | 110 | * Database of all file path accessed during a run. |
148 | 151 | static struct filepath * |
149 | 152 | filepath_find(struct filepath_tree *tree, char *file) |
150 | 153 | { |
151 | struct filepath needle; | |
152 | ||
153 | needle.file = file; | |
154 | struct filepath needle = { .file = file }; | |
155 | ||
154 | 156 | return RB_FIND(filepath_tree, tree, &needle); |
155 | 157 | } |
156 | 158 | |
161 | 163 | filepath_exists(struct filepath_tree *tree, char *file) |
162 | 164 | { |
163 | 165 | return filepath_find(tree, file) != NULL; |
164 | } | |
165 | ||
166 | /* | |
167 | * Return true if a filepath entry exists that starts with path. | |
168 | */ | |
169 | static int | |
170 | filepath_dir_exists(struct filepath_tree *tree, char *path) | |
171 | { | |
172 | struct filepath needle; | |
173 | struct filepath *res; | |
174 | ||
175 | needle.file = path; | |
176 | res = RB_NFIND(filepath_tree, tree, &needle); | |
177 | while (res != NULL && strstr(res->file, path) == res->file) { | |
178 | /* make sure that filepath actually is in that path */ | |
179 | if (res->file[strlen(path)] == '/') | |
180 | return 1; | |
181 | res = RB_NEXT(filepath_tree, tree, res); | |
182 | } | |
183 | return 0; | |
184 | 166 | } |
185 | 167 | |
186 | 168 | /* |
210 | 192 | |
211 | 193 | /* |
212 | 194 | * Function to hash a string into a unique directory name. |
213 | * prefixed with dir. | |
195 | * Returned hash needs to be freed. | |
214 | 196 | */ |
215 | 197 | static char * |
216 | hash_dir(const char *uri, const char *dir) | |
217 | { | |
218 | const char hex[] = "0123456789abcdef"; | |
198 | hash_dir(const char *uri) | |
199 | { | |
219 | 200 | unsigned char m[SHA256_DIGEST_LENGTH]; |
220 | char hash[SHA256_DIGEST_LENGTH * 2 + 1]; | |
221 | char *out; | |
222 | size_t i; | |
223 | 201 | |
224 | 202 | SHA256(uri, strlen(uri), m); |
225 | for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { | |
226 | hash[i * 2] = hex[m[i] >> 4]; | |
227 | hash[i * 2 + 1] = hex[m[i] & 0xf]; | |
228 | } | |
229 | hash[SHA256_DIGEST_LENGTH * 2] = '\0'; | |
230 | ||
231 | asprintf(&out, "%s/%s", dir, hash); | |
232 | return out; | |
203 | return hex_encode(m, sizeof(m)); | |
233 | 204 | } |
234 | 205 | |
235 | 206 | /* |
237 | 208 | * as prefix. Skip the proto:// in URI but keep everything else. |
238 | 209 | */ |
239 | 210 | static char * |
240 | rsync_dir(const char *uri, const char *dir) | |
241 | { | |
242 | char *local, *out; | |
243 | ||
244 | local = strchr(uri, ':') + strlen("://"); | |
245 | ||
246 | asprintf(&out, "%s/%s", dir, local); | |
211 | repo_dir(const char *uri, const char *dir, int hash) | |
212 | { | |
213 | const char *local; | |
214 | char *out, *hdir = NULL; | |
215 | ||
216 | if (hash) { | |
217 | local = hdir = hash_dir(uri); | |
218 | } else { | |
219 | local = strchr(uri, ':'); | |
220 | if (local != NULL) | |
221 | local += strlen("://"); | |
222 | else | |
223 | local = uri; | |
224 | } | |
225 | ||
226 | if (dir == NULL) { | |
227 | if ((out = strdup(local)) == NULL) | |
228 | err(1, NULL); | |
229 | } else { | |
230 | if (asprintf(&out, "%s/%s", dir, local) == -1) | |
231 | err(1, NULL); | |
232 | } | |
233 | ||
234 | free(hdir); | |
247 | 235 | return out; |
248 | 236 | } |
249 | 237 | |
269 | 257 | } |
270 | 258 | |
271 | 259 | /* |
260 | * Return the state of a repository. | |
261 | */ | |
262 | static enum repo_state | |
263 | repo_state(struct repo *rp) | |
264 | { | |
265 | if (rp->ta) | |
266 | return rp->ta->state; | |
267 | if (rp->rsync) | |
268 | return rp->rsync->state; | |
269 | if (rp->rrdp) | |
270 | return rp->rrdp->state; | |
271 | /* No backend so sync is by definition done. */ | |
272 | return REPO_DONE; | |
273 | } | |
274 | ||
275 | /* | |
276 | * Function called once a repository is done with the sync. Either | |
277 | * successfully or after failure. | |
278 | */ | |
279 | static void | |
280 | repo_done(const void *vp, int ok) | |
281 | { | |
282 | struct repo *rp; | |
283 | ||
284 | SLIST_FOREACH(rp, &repos, entry) { | |
285 | if (vp == rp->ta) | |
286 | entityq_flush(&rp->queue, rp); | |
287 | if (vp == rp->rsync) | |
288 | entityq_flush(&rp->queue, rp); | |
289 | if (vp == rp->rrdp) { | |
290 | if (!ok) { | |
291 | /* try to fall back to rsync */ | |
292 | rp->rrdp = NULL; | |
293 | rp->rsync = rsync_get(rp->repouri, | |
294 | rp->basedir); | |
295 | /* need to check if it was already loaded */ | |
296 | if (repo_state(rp) != REPO_LOADING) | |
297 | entityq_flush(&rp->queue, rp); | |
298 | } else | |
299 | entityq_flush(&rp->queue, rp); | |
300 | } | |
301 | } | |
302 | } | |
303 | ||
304 | /* | |
272 | 305 | * Build TA file name based on the repo info. |
273 | 306 | * If temp is set add Xs for mkostemp. |
274 | 307 | */ |
288 | 321 | |
289 | 322 | return nfile; |
290 | 323 | } |
291 | ||
292 | /* | |
293 | * Build local file name base on the URI and the rrdprepo info. | |
294 | */ | |
295 | static char * | |
296 | rrdp_filename(const struct rrdprepo *rr, const char *uri, int temp) | |
297 | { | |
298 | char *nfile; | |
299 | char *dir = rr->basedir; | |
300 | ||
301 | if (temp) | |
302 | dir = rr->temp; | |
303 | ||
304 | if (!valid_uri(uri, strlen(uri), "rsync://")) { | |
305 | warnx("%s: bad URI %s", rr->basedir, uri); | |
306 | return NULL; | |
307 | } | |
308 | ||
309 | uri += strlen("rsync://"); /* skip proto */ | |
310 | if (asprintf(&nfile, "%s/%s", dir, uri) == -1) | |
311 | err(1, NULL); | |
312 | return nfile; | |
313 | } | |
314 | ||
315 | /* | |
316 | * Build RRDP state file name based on the repo info. | |
317 | * If temp is set add Xs for mkostemp. | |
318 | */ | |
319 | static char * | |
320 | rrdp_state_filename(const struct rrdprepo *rr, int temp) | |
321 | { | |
322 | char *nfile; | |
323 | ||
324 | if (asprintf(&nfile, "%s/.state%s", rr->basedir, | |
325 | temp ? ".XXXXXXXX": "") == -1) | |
326 | err(1, NULL); | |
327 | ||
328 | return nfile; | |
329 | } | |
330 | ||
331 | ||
332 | 324 | |
333 | 325 | static void |
334 | 326 | ta_fetch(struct tarepo *tr) |
342 | 334 | } |
343 | 335 | |
344 | 336 | if (tr->uriidx >= tr->urisz) { |
345 | struct repo *rp; | |
346 | ||
347 | 337 | tr->state = REPO_FAILED; |
348 | 338 | logx("ta/%s: fallback to cache", tr->descr); |
349 | 339 | |
350 | SLIST_FOREACH(rp, &repos, entry) | |
351 | if (rp->ta == tr) | |
352 | entityq_flush(&rp->queue, rp); | |
340 | repo_done(tr, 0); | |
353 | 341 | return; |
354 | 342 | } |
355 | 343 | |
360 | 348 | * Create destination location. |
361 | 349 | * Build up the tree to this point. |
362 | 350 | */ |
363 | rsync_fetch(tr->id, tr->uri[tr->uriidx], tr->basedir); | |
351 | rsync_fetch(tr->id, tr->uri[tr->uriidx], tr->basedir, NULL); | |
364 | 352 | } else { |
365 | 353 | int fd; |
366 | 354 | |
385 | 373 | |
386 | 374 | /* no need to look for possible other repo */ |
387 | 375 | |
388 | if (tal->urisz == 0) | |
389 | errx(1, "TAL %s has no URI", tal->descr); | |
390 | ||
391 | 376 | if ((tr = calloc(1, sizeof(*tr))) == NULL) |
392 | 377 | err(1, NULL); |
393 | 378 | tr->id = ++repoid; |
395 | 380 | |
396 | 381 | if ((tr->descr = strdup(tal->descr)) == NULL) |
397 | 382 | err(1, NULL); |
398 | if (asprintf(&tr->basedir, "ta/%s", tal->descr) == -1) | |
399 | err(1, NULL); | |
383 | tr->basedir = repo_dir(tal->descr, "ta", 0); | |
400 | 384 | |
401 | 385 | /* steal URI infromation from TAL */ |
402 | 386 | tr->urisz = tal->urisz; |
404 | 388 | tal->urisz = 0; |
405 | 389 | tal->uri = NULL; |
406 | 390 | |
407 | if (noop) { | |
408 | tr->state = REPO_DONE; | |
409 | logx("ta/%s: using cache", tr->descr); | |
410 | /* there is nothing in the queue so no need to flush */ | |
411 | } else { | |
412 | /* try to create base directory */ | |
413 | if (mkpath(tr->basedir) == -1) | |
414 | warn("mkpath %s", tr->basedir); | |
415 | ||
416 | ta_fetch(tr); | |
417 | } | |
391 | ta_fetch(tr); | |
418 | 392 | |
419 | 393 | return tr; |
420 | 394 | } |
421 | 395 | |
422 | 396 | static struct tarepo * |
423 | ta_find(size_t id) | |
397 | ta_find(unsigned int id) | |
424 | 398 | { |
425 | 399 | struct tarepo *tr; |
426 | 400 | |
446 | 420 | } |
447 | 421 | |
448 | 422 | static struct rsyncrepo * |
449 | rsync_get(const char *uri) | |
423 | rsync_get(const char *uri, const char *validdir) | |
450 | 424 | { |
451 | 425 | struct rsyncrepo *rr; |
452 | 426 | char *repo; |
467 | 441 | SLIST_INSERT_HEAD(&rsyncrepos, rr, entry); |
468 | 442 | |
469 | 443 | rr->repouri = repo; |
470 | rr->basedir = rsync_dir(repo, "rsync"); | |
471 | ||
472 | if (noop) { | |
473 | rr->state = REPO_DONE; | |
474 | logx("%s: using cache", rr->basedir); | |
475 | /* there is nothing in the queue so no need to flush */ | |
476 | } else { | |
477 | /* create base directory */ | |
478 | if (mkpath(rr->basedir) == -1) { | |
479 | warn("mkpath %s", rr->basedir); | |
480 | rsync_finish(rr->id, 0); | |
481 | return rr; | |
482 | } | |
483 | ||
484 | logx("%s: pulling from %s", rr->basedir, rr->repouri); | |
485 | rsync_fetch(rr->id, rr->repouri, rr->basedir); | |
486 | } | |
444 | rr->basedir = repo_dir(repo, ".rsync", 0); | |
445 | ||
446 | /* create base directory */ | |
447 | if (mkpath(rr->basedir) == -1) { | |
448 | warn("mkpath %s", rr->basedir); | |
449 | rsync_finish(rr->id, 0); | |
450 | return rr; | |
451 | } | |
452 | ||
453 | logx("%s: pulling from %s", rr->basedir, rr->repouri); | |
454 | rsync_fetch(rr->id, rr->repouri, rr->basedir, validdir); | |
487 | 455 | |
488 | 456 | return rr; |
489 | 457 | } |
490 | 458 | |
491 | 459 | static struct rsyncrepo * |
492 | rsync_find(size_t id) | |
460 | rsync_find(unsigned int id) | |
493 | 461 | { |
494 | 462 | struct rsyncrepo *rr; |
495 | 463 | |
512 | 480 | } |
513 | 481 | } |
514 | 482 | |
515 | static int rrdprepo_fetch(struct rrdprepo *); | |
483 | /* | |
484 | * Build local file name base on the URI and the rrdprepo info. | |
485 | */ | |
486 | static char * | |
487 | rrdp_filename(const struct rrdprepo *rr, const char *uri, int valid) | |
488 | { | |
489 | char *nfile; | |
490 | const char *dir = rr->basedir; | |
491 | ||
492 | if (!valid_uri(uri, strlen(uri), "rsync://")) | |
493 | errx(1, "%s: bad URI %s", rr->basedir, uri); | |
494 | uri += strlen("rsync://"); /* skip proto */ | |
495 | if (valid) { | |
496 | if ((nfile = strdup(uri)) == NULL) | |
497 | err(1, NULL); | |
498 | } else { | |
499 | if (asprintf(&nfile, "%s/%s", dir, uri) == -1) | |
500 | err(1, NULL); | |
501 | } | |
502 | return nfile; | |
503 | } | |
504 | ||
505 | /* | |
506 | * Build RRDP state file name based on the repo info. | |
507 | * If temp is set add Xs for mkostemp. | |
508 | */ | |
509 | static char * | |
510 | rrdp_state_filename(const struct rrdprepo *rr, int temp) | |
511 | { | |
512 | char *nfile; | |
513 | ||
514 | if (asprintf(&nfile, "%s/.state%s", rr->basedir, | |
515 | temp ? ".XXXXXXXX": "") == -1) | |
516 | err(1, NULL); | |
517 | ||
518 | return nfile; | |
519 | } | |
516 | 520 | |
517 | 521 | static struct rrdprepo * |
518 | rrdp_get(const char *uri) | |
519 | { | |
520 | struct rrdprepo *rr; | |
521 | ||
522 | SLIST_FOREACH(rr, &rrdprepos, entry) | |
523 | if (strcmp(rr->notifyuri, uri) == 0) { | |
524 | if (rr->state == REPO_FAILED) | |
525 | return NULL; | |
526 | return rr; | |
527 | } | |
528 | ||
529 | if ((rr = calloc(1, sizeof(*rr))) == NULL) | |
530 | err(1, NULL); | |
531 | ||
532 | rr->id = ++repoid; | |
533 | SLIST_INSERT_HEAD(&rrdprepos, rr, entry); | |
534 | ||
535 | if ((rr->notifyuri = strdup(uri)) == NULL) | |
536 | err(1, NULL); | |
537 | rr->basedir = hash_dir(uri, "rrdp"); | |
538 | ||
539 | RB_INIT(&rr->added); | |
540 | RB_INIT(&rr->deleted); | |
541 | ||
542 | if (noop) { | |
543 | rr->state = REPO_DONE; | |
544 | logx("%s: using cache", rr->notifyuri); | |
545 | /* there is nothing in the queue so no need to flush */ | |
546 | } else { | |
547 | /* create base directory */ | |
548 | if (mkpath(rr->basedir) == -1) { | |
549 | warn("mkpath %s", rr->basedir); | |
550 | rrdp_finish(rr->id, 0); | |
551 | return rr; | |
552 | } | |
553 | if (rrdprepo_fetch(rr) == -1) { | |
554 | rrdp_finish(rr->id, 0); | |
555 | return rr; | |
556 | } | |
557 | ||
558 | logx("%s: pulling from %s", rr->notifyuri, "network"); | |
559 | } | |
560 | ||
561 | return rr; | |
562 | } | |
563 | ||
564 | static struct rrdprepo * | |
565 | rrdp_find(size_t id) | |
522 | rrdp_find(unsigned int id) | |
566 | 523 | { |
567 | 524 | struct rrdprepo *rr; |
568 | 525 | |
582 | 539 | |
583 | 540 | free(rr->notifyuri); |
584 | 541 | free(rr->basedir); |
585 | free(rr->temp); | |
586 | ||
587 | filepath_free(&rr->added); | |
542 | ||
588 | 543 | filepath_free(&rr->deleted); |
589 | 544 | |
590 | 545 | free(rr); |
591 | 546 | } |
592 | 547 | } |
593 | 548 | |
594 | static struct rrdprepo * | |
595 | rrdp_basedir(const char *dir) | |
549 | /* | |
550 | * Check if a directory is an active rrdp repository. | |
551 | * Returns 1 if found else 0. | |
552 | */ | |
553 | static int | |
554 | rrdp_is_active(const char *dir) | |
596 | 555 | { |
597 | 556 | struct rrdprepo *rr; |
598 | 557 | |
599 | 558 | SLIST_FOREACH(rr, &rrdprepos, entry) |
600 | if (strcmp(dir, rr->basedir) == 0) { | |
601 | if (rr->state == REPO_FAILED) | |
602 | return NULL; | |
603 | return rr; | |
604 | } | |
605 | ||
606 | return NULL; | |
559 | if (strcmp(dir, rr->basedir) == 0) | |
560 | return rr->state != REPO_FAILED; | |
561 | ||
562 | return 0; | |
563 | } | |
564 | ||
565 | /* | |
566 | * Check if the URI is actually covered by one of the repositories | |
567 | * that depend on this RRDP repository. | |
568 | * Returns 1 if the URI is valid, 0 if no repouri matches the URI. | |
569 | */ | |
570 | static int | |
571 | rrdp_uri_valid(struct rrdprepo *rr, const char *uri) | |
572 | { | |
573 | struct repo *rp; | |
574 | ||
575 | SLIST_FOREACH(rp, &repos, entry) { | |
576 | if (rp->rrdp != rr) | |
577 | continue; | |
578 | if (strncmp(uri, rp->repouri, strlen(rp->repouri)) == 0) | |
579 | return 1; | |
580 | } | |
581 | return 0; | |
607 | 582 | } |
608 | 583 | |
609 | 584 | /* |
614 | 589 | { |
615 | 590 | struct repo *rp; |
616 | 591 | |
617 | if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) { | |
618 | if (talrepocnt[talid] == MAX_REPO_PER_TAL) | |
619 | warnx("too many repositories under %s", tals[talid]); | |
620 | return NULL; | |
621 | } | |
622 | ||
623 | 592 | if ((rp = calloc(1, sizeof(*rp))) == NULL) |
624 | 593 | err(1, NULL); |
625 | 594 | |
626 | 595 | rp->id = ++repoid; |
627 | 596 | rp->talid = talid; |
628 | rp->alarm = getmonotime() + MAX_REPO_TIMEOUT; | |
597 | rp->alarm = getmonotime() + repo_timeout; | |
629 | 598 | TAILQ_INIT(&rp->queue); |
630 | 599 | SLIST_INSERT_HEAD(&repos, rp, entry); |
631 | 600 | |
632 | 601 | stats.repos++; |
633 | 602 | return rp; |
634 | } | |
635 | ||
636 | /* | |
637 | * Return the state of a repository. | |
638 | */ | |
639 | static enum repo_state | |
640 | repo_state(struct repo *rp) | |
641 | { | |
642 | if (rp->ta) | |
643 | return rp->ta->state; | |
644 | if (rp->rrdp) | |
645 | return rp->rrdp->state; | |
646 | if (rp->rsync) | |
647 | return rp->rsync->state; | |
648 | errx(1, "%s: bad repo", rp->repouri); | |
649 | 603 | } |
650 | 604 | |
651 | 605 | /* |
715 | 669 | * Carefully write the RRDP session state file back. |
716 | 670 | */ |
717 | 671 | void |
718 | rrdp_save_state(size_t id, struct rrdp_session *state) | |
672 | rrdp_save_state(unsigned int id, struct rrdp_session *state) | |
719 | 673 | { |
720 | 674 | struct rrdprepo *rr; |
721 | 675 | char *temp, *file; |
724 | 678 | |
725 | 679 | rr = rrdp_find(id); |
726 | 680 | if (rr == NULL) |
727 | errx(1, "non-existant rrdp repo %zu", id); | |
681 | errx(1, "non-existant rrdp repo %u", id); | |
728 | 682 | |
729 | 683 | file = rrdp_state_filename(rr, 0); |
730 | 684 | temp = rrdp_state_filename(rr, 1); |
767 | 721 | free(file); |
768 | 722 | } |
769 | 723 | |
724 | static struct rrdprepo * | |
725 | rrdp_get(const char *uri) | |
726 | { | |
727 | struct rrdp_session state = { 0 }; | |
728 | struct rrdprepo *rr; | |
729 | ||
730 | SLIST_FOREACH(rr, &rrdprepos, entry) | |
731 | if (strcmp(rr->notifyuri, uri) == 0) { | |
732 | if (rr->state == REPO_FAILED) | |
733 | return NULL; | |
734 | return rr; | |
735 | } | |
736 | ||
737 | if ((rr = calloc(1, sizeof(*rr))) == NULL) | |
738 | err(1, NULL); | |
739 | ||
740 | rr->id = ++repoid; | |
741 | SLIST_INSERT_HEAD(&rrdprepos, rr, entry); | |
742 | ||
743 | if ((rr->notifyuri = strdup(uri)) == NULL) | |
744 | err(1, NULL); | |
745 | rr->basedir = repo_dir(uri, ".rrdp", 1); | |
746 | ||
747 | RB_INIT(&rr->deleted); | |
748 | ||
749 | ||
750 | /* create base directory */ | |
751 | if (mkpath(rr->basedir) == -1) { | |
752 | warn("mkpath %s", rr->basedir); | |
753 | rrdp_finish(rr->id, 0); | |
754 | return rr; | |
755 | } | |
756 | ||
757 | /* parse state and start the sync */ | |
758 | rrdp_parse_state(rr, &state); | |
759 | rrdp_fetch(rr->id, rr->notifyuri, rr->notifyuri, &state); | |
760 | free(state.session_id); | |
761 | free(state.last_mod); | |
762 | ||
763 | logx("%s: pulling from %s", rr->notifyuri, "network"); | |
764 | ||
765 | return rr; | |
766 | } | |
767 | ||
768 | /* | |
769 | * Remove RRDP repo and start over. | |
770 | */ | |
771 | void | |
772 | rrdp_clear(unsigned int id) | |
773 | { | |
774 | struct rrdprepo *rr; | |
775 | ||
776 | rr = rrdp_find(id); | |
777 | if (rr == NULL) | |
778 | errx(1, "non-existant rrdp repo %u", id); | |
779 | ||
780 | /* remove rrdp repository contents */ | |
781 | remove_contents(rr->basedir); | |
782 | } | |
783 | ||
770 | 784 | /* |
771 | 785 | * Write a file into the temporary RRDP dir but only after checking |
772 | 786 | * its hash (if required). The function also makes sure that the file |
774 | 788 | * Returns 1 on success, 0 if the repo is corrupt, -1 on IO error |
775 | 789 | */ |
776 | 790 | int |
777 | rrdp_handle_file(size_t id, enum publish_type pt, char *uri, | |
791 | rrdp_handle_file(unsigned int id, enum publish_type pt, char *uri, | |
778 | 792 | char *hash, size_t hlen, char *data, size_t dlen) |
779 | 793 | { |
780 | 794 | struct rrdprepo *rr; |
781 | 795 | struct filepath *fp; |
782 | 796 | ssize_t s; |
783 | char *fn; | |
784 | int fd = -1; | |
797 | char *fn = NULL; | |
798 | int fd = -1, try = 0; | |
785 | 799 | |
786 | 800 | rr = rrdp_find(id); |
787 | 801 | if (rr == NULL) |
788 | errx(1, "non-existant rrdp repo %zu", id); | |
802 | errx(1, "non-existant rrdp repo %u", id); | |
789 | 803 | if (rr->state == REPO_FAILED) |
790 | 804 | return -1; |
791 | 805 | |
806 | /* check hash of original file for updates and deletes */ | |
792 | 807 | if (pt == PUB_UPD || pt == PUB_DEL) { |
793 | 808 | if (filepath_exists(&rr->deleted, uri)) { |
794 | 809 | warnx("%s: already deleted", uri); |
795 | 810 | return 0; |
796 | 811 | } |
797 | fp = filepath_find(&rr->added, uri); | |
798 | if (fp == NULL) { | |
799 | if ((fn = rrdp_filename(rr, uri, 0)) == NULL) | |
812 | /* try to open file first in rrdp then in valid repo */ | |
813 | do { | |
814 | free(fn); | |
815 | if ((fn = rrdp_filename(rr, uri, try++)) == NULL) | |
800 | 816 | return 0; |
801 | } else { | |
802 | filepath_put(&rr->added, fp); | |
803 | if ((fn = rrdp_filename(rr, uri, 1)) == NULL) | |
804 | return 0; | |
805 | } | |
806 | if (!valid_filehash(fn, hash, hlen)) { | |
807 | warnx("%s: bad message digest", fn); | |
817 | fd = open(fn, O_RDONLY); | |
818 | } while (fd == -1 && try < 2); | |
819 | ||
820 | if (!valid_filehash(fd, hash, hlen)) { | |
821 | warnx("%s: bad file digest for %s", rr->notifyuri, fn); | |
808 | 822 | free(fn); |
809 | 823 | return 0; |
810 | 824 | } |
811 | 825 | free(fn); |
812 | 826 | } |
813 | 827 | |
828 | /* write new content or mark uri as deleted. */ | |
814 | 829 | if (pt == PUB_DEL) { |
815 | 830 | filepath_add(&rr->deleted, uri); |
816 | 831 | } else { |
818 | 833 | if (fp != NULL) |
819 | 834 | filepath_put(&rr->deleted, fp); |
820 | 835 | |
821 | /* add new file to temp dir */ | |
822 | if ((fn = rrdp_filename(rr, uri, 1)) == NULL) | |
836 | /* add new file to rrdp dir */ | |
837 | if ((fn = rrdp_filename(rr, uri, 0)) == NULL) | |
823 | 838 | return 0; |
824 | 839 | |
825 | 840 | if (repo_mkpath(fn) == -1) |
839 | 854 | if ((size_t)s != dlen) /* impossible */ |
840 | 855 | errx(1, "short write %s", fn); |
841 | 856 | free(fn); |
842 | filepath_add(&rr->added, uri); | |
843 | 857 | } |
844 | 858 | |
845 | 859 | return 1; |
853 | 867 | } |
854 | 868 | |
855 | 869 | /* |
856 | * Initiate a RRDP sync, create the required temporary directory and | |
857 | * parse a possible state file before sending the request to the RRDP process. | |
858 | */ | |
859 | static int | |
860 | rrdprepo_fetch(struct rrdprepo *rr) | |
861 | { | |
862 | struct rrdp_session state = { 0 }; | |
863 | ||
864 | if (asprintf(&rr->temp, "%s.XXXXXXXX", rr->basedir) == -1) | |
865 | err(1, NULL); | |
866 | if (mkdtemp(rr->temp) == NULL) { | |
867 | warn("mkdtemp %s", rr->temp); | |
868 | return -1; | |
869 | } | |
870 | ||
871 | rrdp_parse_state(rr, &state); | |
872 | rrdp_fetch(rr->id, rr->notifyuri, rr->notifyuri, &state); | |
873 | ||
874 | free(state.session_id); | |
875 | free(state.last_mod); | |
876 | ||
877 | return 0; | |
878 | } | |
879 | ||
880 | static int | |
881 | rrdp_merge_repo(struct rrdprepo *rr) | |
882 | { | |
883 | struct filepath *fp, *nfp; | |
884 | char *fn, *rfn; | |
885 | ||
886 | RB_FOREACH_SAFE(fp, filepath_tree, &rr->added, nfp) { | |
887 | fn = rrdp_filename(rr, fp->file, 1); | |
888 | rfn = rrdp_filename(rr, fp->file, 0); | |
889 | ||
890 | if (fn == NULL || rfn == NULL) | |
891 | errx(1, "bad filepath"); /* should not happen */ | |
892 | ||
893 | if (repo_mkpath(rfn) == -1) { | |
894 | goto fail; | |
895 | } | |
896 | ||
897 | if (rename(fn, rfn) == -1) { | |
898 | warn("rename %s", rfn); | |
899 | goto fail; | |
900 | } | |
901 | ||
902 | free(rfn); | |
903 | free(fn); | |
904 | filepath_put(&rr->added, fp); | |
905 | } | |
906 | ||
907 | return 1; | |
908 | ||
909 | fail: | |
910 | free(rfn); | |
911 | free(fn); | |
912 | return 0; | |
913 | } | |
914 | ||
915 | static void | |
916 | rrdp_clean_temp(struct rrdprepo *rr) | |
917 | { | |
918 | struct filepath *fp, *nfp; | |
919 | char *fn; | |
920 | ||
921 | filepath_free(&rr->deleted); | |
922 | ||
923 | RB_FOREACH_SAFE(fp, filepath_tree, &rr->added, nfp) { | |
924 | if ((fn = rrdp_filename(rr, fp->file, 1)) != NULL) { | |
925 | if (unlink(fn) == -1) | |
926 | warn("unlink %s", fn); | |
927 | free(fn); | |
928 | } | |
929 | filepath_put(&rr->added, fp); | |
930 | } | |
931 | } | |
932 | ||
933 | /* | |
934 | 870 | * RSYNC sync finished, either with or without success. |
935 | 871 | */ |
936 | 872 | void |
937 | rsync_finish(size_t id, int ok) | |
873 | rsync_finish(unsigned int id, int ok) | |
938 | 874 | { |
939 | 875 | struct rsyncrepo *rr; |
940 | 876 | struct tarepo *tr; |
941 | struct repo *rp; | |
942 | 877 | |
943 | 878 | tr = ta_find(id); |
944 | 879 | if (tr != NULL) { |
949 | 884 | logx("ta/%s: loaded from network", tr->descr); |
950 | 885 | stats.rsync_repos++; |
951 | 886 | tr->state = REPO_DONE; |
887 | repo_done(tr, 1); | |
952 | 888 | } else { |
953 | 889 | logx("ta/%s: load from network failed", tr->descr); |
954 | 890 | stats.rsync_fails++; |
955 | 891 | tr->uriidx++; |
956 | 892 | ta_fetch(tr); |
957 | return; | |
958 | } | |
959 | SLIST_FOREACH(rp, &repos, entry) | |
960 | if (rp->ta == tr) | |
961 | entityq_flush(&rp->queue, rp); | |
962 | ||
893 | } | |
963 | 894 | return; |
964 | 895 | } |
965 | 896 | |
966 | 897 | rr = rsync_find(id); |
967 | 898 | if (rr == NULL) |
968 | errx(1, "unknown rsync repo %zu", id); | |
969 | ||
899 | errx(1, "unknown rsync repo %u", id); | |
970 | 900 | /* repository changed state already, ignore request */ |
971 | 901 | if (rr->state != REPO_LOADING) |
972 | 902 | return; |
903 | ||
973 | 904 | if (ok) { |
974 | 905 | logx("%s: loaded from network", rr->basedir); |
975 | 906 | stats.rsync_repos++; |
979 | 910 | rr->basedir); |
980 | 911 | stats.rsync_fails++; |
981 | 912 | rr->state = REPO_FAILED; |
982 | } | |
983 | ||
984 | SLIST_FOREACH(rp, &repos, entry) | |
985 | if (rp->rsync == rr) | |
986 | entityq_flush(&rp->queue, rp); | |
913 | /* clear rsync repo since it failed */ | |
914 | remove_contents(rr->basedir); | |
915 | } | |
916 | ||
917 | repo_done(rr, ok); | |
987 | 918 | } |
988 | 919 | |
989 | 920 | /* |
990 | 921 | * RRDP sync finshed, either with or without success. |
991 | 922 | */ |
992 | 923 | void |
993 | rrdp_finish(size_t id, int ok) | |
924 | rrdp_finish(unsigned int id, int ok) | |
994 | 925 | { |
995 | 926 | struct rrdprepo *rr; |
996 | struct repo *rp; | |
997 | 927 | |
998 | 928 | rr = rrdp_find(id); |
999 | 929 | if (rr == NULL) |
1000 | errx(1, "unknown RRDP repo %zu", id); | |
930 | errx(1, "unknown RRDP repo %u", id); | |
1001 | 931 | /* repository changed state already, ignore request */ |
1002 | 932 | if (rr->state != REPO_LOADING) |
1003 | 933 | return; |
1004 | 934 | |
1005 | if (ok && rrdp_merge_repo(rr)) { | |
935 | if (ok) { | |
1006 | 936 | logx("%s: loaded from network", rr->notifyuri); |
937 | stats.rrdp_repos++; | |
1007 | 938 | rr->state = REPO_DONE; |
1008 | stats.rrdp_repos++; | |
1009 | SLIST_FOREACH(rp, &repos, entry) | |
1010 | if (rp->rrdp == rr) | |
1011 | entityq_flush(&rp->queue, rp); | |
1012 | } else if (!ok) { | |
1013 | rrdp_clean_temp(rr); | |
939 | } else { | |
940 | logx("%s: load from network failed, fallback to rsync", | |
941 | rr->notifyuri); | |
1014 | 942 | stats.rrdp_fails++; |
1015 | 943 | rr->state = REPO_FAILED; |
1016 | logx("%s: load from network failed, fallback to rsync", | |
1017 | rr->notifyuri); | |
1018 | SLIST_FOREACH(rp, &repos, entry) | |
1019 | if (rp->rrdp == rr) { | |
1020 | rp->rrdp = NULL; | |
1021 | rp->rsync = rsync_get(rp->repouri); | |
1022 | /* need to check if it was already loaded */ | |
1023 | if (repo_state(rp) != REPO_LOADING) | |
1024 | entityq_flush(&rp->queue, rp); | |
1025 | } | |
1026 | } else { | |
1027 | rrdp_clean_temp(rr); | |
1028 | stats.rrdp_fails++; | |
1029 | rr->state = REPO_FAILED; | |
1030 | logx("%s: load from network failed", rr->notifyuri); | |
1031 | SLIST_FOREACH(rp, &repos, entry) | |
1032 | if (rp->rrdp == rr) | |
1033 | entityq_flush(&rp->queue, rp); | |
1034 | } | |
944 | /* clear the RRDP repo since it failed */ | |
945 | remove_contents(rr->basedir); | |
946 | /* also clear the list of deleted files */ | |
947 | filepath_free(&rr->deleted); | |
948 | } | |
949 | ||
950 | repo_done(rr, ok); | |
1035 | 951 | } |
1036 | 952 | |
1037 | 953 | /* |
1040 | 956 | * over to the rrdp process. |
1041 | 957 | */ |
1042 | 958 | void |
1043 | http_finish(size_t id, enum http_result res, const char *last_mod) | |
959 | http_finish(unsigned int id, enum http_result res, const char *last_mod) | |
1044 | 960 | { |
1045 | 961 | struct tarepo *tr; |
1046 | struct repo *rp; | |
1047 | 962 | |
1048 | 963 | tr = ta_find(id); |
1049 | 964 | if (tr == NULL) { |
1068 | 983 | logx("ta/%s: loaded from network", tr->descr); |
1069 | 984 | tr->state = REPO_DONE; |
1070 | 985 | stats.http_repos++; |
986 | repo_done(tr, 1); | |
1071 | 987 | } else { |
1072 | 988 | if (unlink(tr->temp) == -1 && errno != ENOENT) |
1073 | 989 | warn("unlink %s", tr->temp); |
1075 | 991 | tr->uriidx++; |
1076 | 992 | logx("ta/%s: load from network failed", tr->descr); |
1077 | 993 | ta_fetch(tr); |
1078 | return; | |
1079 | } | |
1080 | ||
1081 | SLIST_FOREACH(rp, &repos, entry) | |
1082 | if (rp->ta == tr) | |
1083 | entityq_flush(&rp->queue, rp); | |
994 | } | |
1084 | 995 | } |
1085 | 996 | |
1086 | 997 | |
1092 | 1003 | ta_lookup(int id, struct tal *tal) |
1093 | 1004 | { |
1094 | 1005 | struct repo *rp; |
1006 | ||
1007 | if (tal->urisz == 0) | |
1008 | errx(1, "TAL %s has no URI", tal->descr); | |
1095 | 1009 | |
1096 | 1010 | /* Look up in repository table. (Lookup should actually fail here) */ |
1097 | 1011 | SLIST_FOREACH(rp, &repos, entry) { |
1100 | 1014 | } |
1101 | 1015 | |
1102 | 1016 | rp = repo_alloc(id); |
1103 | if (rp == NULL) | |
1104 | return NULL; | |
1105 | ||
1017 | rp->basedir = repo_dir(tal->descr, "ta", 0); | |
1106 | 1018 | if ((rp->repouri = strdup(tal->descr)) == NULL) |
1107 | 1019 | err(1, NULL); |
1020 | ||
1021 | /* try to create base directory */ | |
1022 | if (mkpath(rp->basedir) == -1) | |
1023 | warn("mkpath %s", rp->basedir); | |
1024 | ||
1025 | /* check if sync disabled ... */ | |
1026 | if (noop) { | |
1027 | logx("ta/%s: using cache", rp->repouri); | |
1028 | entityq_flush(&rp->queue, rp); | |
1029 | return rp; | |
1030 | } | |
1031 | ||
1108 | 1032 | rp->ta = ta_get(tal); |
1109 | 1033 | |
1034 | /* need to check if it was already loaded */ | |
1035 | if (repo_state(rp) != REPO_LOADING) | |
1036 | entityq_flush(&rp->queue, rp); | |
1037 | ||
1110 | 1038 | return rp; |
1111 | 1039 | } |
1112 | 1040 | |
1114 | 1042 | * Look up a repository, queueing it for discovery if not found. |
1115 | 1043 | */ |
1116 | 1044 | struct repo * |
1117 | repo_lookup(int id, const char *uri, const char *notify) | |
1045 | repo_lookup(int talid, const char *uri, const char *notify) | |
1118 | 1046 | { |
1119 | 1047 | struct repo *rp; |
1120 | 1048 | char *repouri; |
1049 | int nofetch = 0; | |
1121 | 1050 | |
1122 | 1051 | if ((repouri = rsync_base_uri(uri)) == NULL) |
1123 | 1052 | errx(1, "bad caRepository URI: %s", uri); |
1138 | 1067 | return rp; |
1139 | 1068 | } |
1140 | 1069 | |
1141 | rp = repo_alloc(id); | |
1142 | if (rp == NULL) { | |
1143 | free(repouri); | |
1144 | return NULL; | |
1145 | } | |
1146 | ||
1070 | rp = repo_alloc(talid); | |
1071 | rp->basedir = repo_dir(repouri, NULL, 0); | |
1147 | 1072 | rp->repouri = repouri; |
1148 | 1073 | if (notify != NULL) |
1149 | 1074 | if ((rp->notifyuri = strdup(notify)) == NULL) |
1150 | 1075 | err(1, NULL); |
1151 | 1076 | |
1152 | /* try RRDP first if available */ | |
1077 | if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) { | |
1078 | if (talrepocnt[talid] == MAX_REPO_PER_TAL) | |
1079 | warnx("too many repositories under %s", tals[talid]); | |
1080 | nofetch = 1; | |
1081 | } | |
1082 | ||
1083 | /* try to create base directory */ | |
1084 | if (mkpath(rp->basedir) == -1) | |
1085 | warn("mkpath %s", rp->basedir); | |
1086 | ||
1087 | /* check if sync disabled ... */ | |
1088 | if (noop || nofetch) { | |
1089 | logx("%s: using cache", rp->basedir); | |
1090 | entityq_flush(&rp->queue, rp); | |
1091 | return rp; | |
1092 | } | |
1093 | ||
1094 | /* ... else try RRDP first if available then rsync */ | |
1153 | 1095 | if (notify != NULL) |
1154 | 1096 | rp->rrdp = rrdp_get(notify); |
1155 | 1097 | if (rp->rrdp == NULL) |
1156 | rp->rsync = rsync_get(uri); | |
1098 | rp->rsync = rsync_get(uri, rp->basedir); | |
1099 | ||
1100 | /* need to check if it was already loaded */ | |
1101 | if (repo_state(rp) != REPO_LOADING) | |
1102 | entityq_flush(&rp->queue, rp); | |
1157 | 1103 | |
1158 | 1104 | return rp; |
1159 | 1105 | } |
1160 | 1106 | |
1161 | 1107 | /* |
1162 | * Build local file name base on the URI and the repo info. | |
1108 | * Find repository by identifier. | |
1109 | */ | |
1110 | struct repo * | |
1111 | repo_byid(unsigned int id) | |
1112 | { | |
1113 | struct repo *rp; | |
1114 | ||
1115 | SLIST_FOREACH(rp, &repos, entry) { | |
1116 | if (rp->id == id) | |
1117 | return rp; | |
1118 | } | |
1119 | return NULL; | |
1120 | } | |
1121 | ||
1122 | /* | |
1123 | * Return the repository base or alternate directory. | |
1124 | * Returned string must be freed by caller. | |
1163 | 1125 | */ |
1164 | 1126 | char * |
1165 | repo_filename(const struct repo *rp, const char *uri) | |
1166 | { | |
1167 | char *nfile; | |
1168 | char *dir, *repouri; | |
1169 | ||
1170 | if (uri == NULL && rp->ta) | |
1171 | return ta_filename(rp->ta, 0); | |
1172 | ||
1173 | assert(uri != NULL); | |
1174 | if (rp->rrdp) | |
1175 | return rrdp_filename(rp->rrdp, uri, 0); | |
1176 | ||
1177 | /* must be rsync */ | |
1178 | dir = rp->rsync->basedir; | |
1179 | repouri = rp->rsync->repouri; | |
1180 | ||
1181 | if (strstr(uri, repouri) != uri) { | |
1182 | warnx("%s: URI %s outside of repository", repouri, uri); | |
1183 | return NULL; | |
1184 | } | |
1185 | ||
1186 | uri += strlen(repouri) + 1; /* skip base and '/' */ | |
1187 | ||
1188 | if (asprintf(&nfile, "%s/%s", dir, uri) == -1) | |
1189 | err(1, NULL); | |
1190 | return nfile; | |
1127 | repo_basedir(const struct repo *rp, int wantvalid) | |
1128 | { | |
1129 | char *path = NULL; | |
1130 | ||
1131 | if (!wantvalid) { | |
1132 | if (rp->ta) { | |
1133 | if ((path = strdup(rp->ta->basedir)) == NULL) | |
1134 | err(1, NULL); | |
1135 | } else if (rp->rsync) { | |
1136 | if ((path = strdup(rp->rsync->basedir)) == NULL) | |
1137 | err(1, NULL); | |
1138 | } else if (rp->rrdp) { | |
1139 | path = rrdp_filename(rp->rrdp, rp->repouri, 0); | |
1140 | } else | |
1141 | path = NULL; /* only valid repo available */ | |
1142 | } else if (rp->basedir != NULL) { | |
1143 | if ((path = strdup(rp->basedir)) == NULL) | |
1144 | err(1, NULL); | |
1145 | } | |
1146 | ||
1147 | return path; | |
1148 | } | |
1149 | ||
1150 | /* | |
1151 | * Return the repository identifier. | |
1152 | */ | |
1153 | unsigned int | |
1154 | repo_id(const struct repo *rp) | |
1155 | { | |
1156 | return rp->id; | |
1157 | } | |
1158 | ||
1159 | /* | |
1160 | * Return the repository URI. | |
1161 | */ | |
1162 | const char * | |
1163 | repo_uri(const struct repo *rp) | |
1164 | { | |
1165 | return rp->repouri; | |
1191 | 1166 | } |
1192 | 1167 | |
1193 | 1168 | int |
1200 | 1175 | return 0; |
1201 | 1176 | } |
1202 | 1177 | |
1203 | int | |
1204 | repo_next_timeout(int timeout) | |
1205 | { | |
1206 | struct repo *rp; | |
1207 | time_t now; | |
1208 | ||
1209 | now = getmonotime(); | |
1210 | /* Look up in repository table. (Lookup should actually fail here) */ | |
1211 | SLIST_FOREACH(rp, &repos, entry) { | |
1212 | if (repo_state(rp) == REPO_LOADING) { | |
1213 | int diff = rp->alarm - now; | |
1214 | diff *= 1000; | |
1215 | if (timeout == INFTIM || diff < timeout) | |
1216 | timeout = diff; | |
1217 | } | |
1218 | } | |
1219 | return timeout; | |
1220 | } | |
1221 | ||
1222 | 1178 | static void |
1223 | 1179 | repo_fail(struct repo *rp) |
1224 | 1180 | { |
1225 | 1181 | /* reset the alarm since code may fallback to rsync */ |
1226 | rp->alarm = getmonotime() + MAX_REPO_TIMEOUT; | |
1182 | rp->alarm = getmonotime() + repo_timeout; | |
1227 | 1183 | |
1228 | 1184 | if (rp->ta) |
1229 | 1185 | http_finish(rp->ta->id, HTTP_FAILED, NULL); |
1186 | else if (rp->rsync) | |
1187 | rsync_finish(rp->rsync->id, 0); | |
1230 | 1188 | else if (rp->rrdp) |
1231 | 1189 | rrdp_finish(rp->rrdp->id, 0); |
1232 | else if (rp->rsync) | |
1233 | rsync_finish(rp->rsync->id, 0); | |
1234 | 1190 | else |
1235 | 1191 | errx(1, "%s: bad repo", rp->repouri); |
1236 | 1192 | } |
1237 | 1193 | |
1238 | void | |
1239 | repo_check_timeout(void) | |
1194 | int | |
1195 | repo_check_timeout(int timeout) | |
1240 | 1196 | { |
1241 | 1197 | struct repo *rp; |
1242 | 1198 | time_t now; |
1249 | 1205 | warnx("%s: synchronisation timeout", |
1250 | 1206 | rp->repouri); |
1251 | 1207 | repo_fail(rp); |
1208 | } else { | |
1209 | int diff = rp->alarm - now; | |
1210 | diff *= 1000; | |
1211 | if (timeout == INFTIM || diff < timeout) | |
1212 | timeout = diff; | |
1252 | 1213 | } |
1253 | 1214 | } |
1254 | 1215 | } |
1216 | return timeout; | |
1255 | 1217 | } |
1256 | 1218 | |
1257 | 1219 | static char ** |
1268 | 1230 | return del; |
1269 | 1231 | } |
1270 | 1232 | |
1233 | /* | |
1234 | * Delayed delete of files from RRDP. Since RRDP has no security built-in | |
1235 | * this code needs to check if this RRDP repository is actually allowed to | |
1236 | * remove the file referenced by the URI. | |
1237 | */ | |
1271 | 1238 | static char ** |
1272 | repo_rrdp_cleanup(struct filepath_tree *tree, struct rrdprepo *rr, | |
1273 | char **del, size_t *delsz) | |
1274 | { | |
1239 | repo_cleanup_rrdp(struct filepath_tree *tree, char **del, size_t *delsz) | |
1240 | { | |
1241 | struct rrdprepo *rr; | |
1275 | 1242 | struct filepath *fp, *nfp; |
1276 | 1243 | char *fn; |
1277 | ||
1278 | RB_FOREACH_SAFE(fp, filepath_tree, &rr->deleted, nfp) { | |
1279 | fn = rrdp_filename(rr, fp->file, 0); | |
1280 | /* temp dir will be cleaned up by repo_cleanup() */ | |
1281 | ||
1282 | if (fn == NULL) | |
1283 | errx(1, "bad filepath"); /* should not happen */ | |
1284 | ||
1285 | if (!filepath_exists(tree, fn)) | |
1244 | ||
1245 | SLIST_FOREACH(rr, &rrdprepos, entry) { | |
1246 | RB_FOREACH_SAFE(fp, filepath_tree, &rr->deleted, nfp) { | |
1247 | if (!rrdp_uri_valid(rr, fp->file)) { | |
1248 | warnx("%s: external URI %s", rr->notifyuri, | |
1249 | fp->file); | |
1250 | filepath_put(&rr->deleted, fp); | |
1251 | continue; | |
1252 | } | |
1253 | /* try to remove file from rrdp repo ... */ | |
1254 | fn = rrdp_filename(rr, fp->file, 0); | |
1286 | 1255 | del = add_to_del(del, delsz, fn); |
1287 | else | |
1288 | warnx("%s: referenced file supposed to be deleted", fn); | |
1289 | ||
1290 | free(fn); | |
1291 | filepath_put(&rr->deleted, fp); | |
1256 | free(fn); | |
1257 | ||
1258 | /* ... and from the valid repository if unused. */ | |
1259 | fn = rrdp_filename(rr, fp->file, 1); | |
1260 | if (!filepath_exists(tree, fn)) | |
1261 | del = add_to_del(del, delsz, fn); | |
1262 | else | |
1263 | warnx("%s: referenced file supposed to be " | |
1264 | "deleted", fn); | |
1265 | ||
1266 | free(fn); | |
1267 | filepath_put(&rr->deleted, fp); | |
1268 | } | |
1292 | 1269 | } |
1293 | 1270 | |
1294 | 1271 | return del; |
1272 | } | |
1273 | ||
1274 | /* | |
1275 | * All files in tree are valid and should be moved to the valid repository | |
1276 | * if not already there. Rename the files to the new path and readd the | |
1277 | * filepath entry with the new path if successful. | |
1278 | */ | |
1279 | static void | |
1280 | repo_move_valid(struct filepath_tree *tree) | |
1281 | { | |
1282 | struct filepath *fp, *nfp; | |
1283 | size_t rsyncsz = strlen(".rsync/"); | |
1284 | size_t rrdpsz = strlen(".rrdp/"); | |
1285 | char *fn, *base; | |
1286 | ||
1287 | RB_FOREACH_SAFE(fp, filepath_tree, tree, nfp) { | |
1288 | if (strncmp(fp->file, ".rsync/", rsyncsz) != 0 && | |
1289 | strncmp(fp->file, ".rrdp/", rrdpsz) != 0) | |
1290 | continue; /* not a temporary file path */ | |
1291 | ||
1292 | if (strncmp(fp->file, ".rsync/", rsyncsz) == 0) { | |
1293 | fn = fp->file + rsyncsz; | |
1294 | } else { | |
1295 | base = strchr(fp->file + rrdpsz, '/'); | |
1296 | assert(base != NULL); | |
1297 | fn = base + 1; | |
1298 | } | |
1299 | ||
1300 | if (repo_mkpath(fn) == -1) | |
1301 | continue; | |
1302 | ||
1303 | if (rename(fp->file, fn) == -1) { | |
1304 | warn("rename %s", fp->file); | |
1305 | continue; | |
1306 | } | |
1307 | ||
1308 | /* switch filepath node to new path */ | |
1309 | RB_REMOVE(filepath_tree, tree, fp); | |
1310 | base = fp->file; | |
1311 | if ((fp->file = strdup(fn)) == NULL) | |
1312 | err(1, NULL); | |
1313 | free(base); | |
1314 | if (RB_INSERT(filepath_tree, tree, fp) != NULL) | |
1315 | errx(1, "%s: both possibilities of file present", | |
1316 | fp->file); | |
1317 | } | |
1318 | } | |
1319 | ||
1320 | #define BASE_DIR (void *)0x62617365 | |
1321 | #define RSYNC_DIR (void *)0x73796e63 | |
1322 | #define RRDP_DIR (void *)0x52524450 | |
1323 | ||
1324 | static inline char * | |
1325 | skip_dotslash(char *in) | |
1326 | { | |
1327 | if (memcmp(in, "./", 2) == 0) | |
1328 | return in + 2; | |
1329 | return in; | |
1295 | 1330 | } |
1296 | 1331 | |
1297 | 1332 | void |
1299 | 1334 | { |
1300 | 1335 | size_t i, cnt, delsz = 0, dirsz = 0; |
1301 | 1336 | char **del = NULL, **dir = NULL; |
1302 | char *argv[4] = { "ta", "rsync", "rrdp", NULL }; | |
1303 | struct rrdprepo *rr; | |
1337 | char *argv[2] = { ".", NULL }; | |
1304 | 1338 | FTS *fts; |
1305 | 1339 | FTSENT *e; |
1340 | ||
1341 | /* first move temp files which have been used to valid dir */ | |
1342 | repo_move_valid(tree); | |
1343 | /* then delete files requested by rrdp */ | |
1344 | del = repo_cleanup_rrdp(tree, del, &delsz); | |
1306 | 1345 | |
1307 | 1346 | if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL) |
1308 | 1347 | err(1, "fts_open"); |
1309 | 1348 | errno = 0; |
1310 | 1349 | while ((e = fts_read(fts)) != NULL) { |
1350 | char *path = skip_dotslash(e->fts_path); | |
1311 | 1351 | switch (e->fts_info) { |
1312 | 1352 | case FTS_NSOK: |
1313 | if (!filepath_exists(tree, e->fts_path)) | |
1314 | del = add_to_del(del, &delsz, | |
1315 | e->fts_path); | |
1353 | if (filepath_exists(tree, path)) { | |
1354 | e->fts_parent->fts_number++; | |
1355 | break; | |
1356 | } | |
1357 | if (e->fts_parent->fts_pointer == RRDP_DIR) { | |
1358 | e->fts_parent->fts_number++; | |
1359 | /* handle rrdp .state files explicitly */ | |
1360 | if (e->fts_level == 3 && | |
1361 | strcmp(e->fts_name, ".state") == 0) | |
1362 | break; | |
1363 | /* can't delete these extra files */ | |
1364 | stats.extra_files++; | |
1365 | if (verbose > 1) | |
1366 | logx("superfluous %s", path); | |
1367 | break; | |
1368 | } | |
1369 | if (e->fts_parent->fts_pointer == RSYNC_DIR) { | |
1370 | /* no need to keep rsync files */ | |
1371 | stats.extra_files++; | |
1372 | if (verbose > 1) | |
1373 | logx("superfluous %s", path); | |
1374 | } | |
1375 | del = add_to_del(del, &delsz, path); | |
1316 | 1376 | break; |
1317 | 1377 | case FTS_D: |
1318 | /* special cleanup for rrdp directories */ | |
1319 | if ((rr = rrdp_basedir(e->fts_path)) != NULL) { | |
1320 | del = repo_rrdp_cleanup(tree, rr, del, &delsz); | |
1321 | if (fts_set(fts, e, FTS_SKIP) == -1) | |
1322 | err(1, "fts_set"); | |
1378 | if (e->fts_level == 1) { | |
1379 | if (strcmp(".rsync", e->fts_name) == 0) | |
1380 | e->fts_pointer = RSYNC_DIR; | |
1381 | else if (strcmp(".rrdp", e->fts_name) == 0) | |
1382 | e->fts_pointer = RRDP_DIR; | |
1383 | else | |
1384 | e->fts_pointer = BASE_DIR; | |
1385 | } else | |
1386 | e->fts_pointer = e->fts_parent->fts_pointer; | |
1387 | ||
1388 | /* | |
1389 | * special handling for rrdp directories, | |
1390 | * clear them if they are not used anymore but | |
1391 | * only if rrdp is active. | |
1392 | */ | |
1393 | if (e->fts_pointer == RRDP_DIR && !noop && | |
1394 | e->fts_level == 2) { | |
1395 | if (!rrdp_is_active(path)) | |
1396 | e->fts_pointer = NULL; | |
1323 | 1397 | } |
1324 | 1398 | break; |
1325 | 1399 | case FTS_DP: |
1326 | if (!filepath_dir_exists(tree, e->fts_path)) | |
1327 | dir = add_to_del(dir, &dirsz, | |
1328 | e->fts_path); | |
1400 | if (e->fts_level == FTS_ROOTLEVEL) | |
1401 | break; | |
1402 | if (e->fts_level == 1) | |
1403 | /* do not remove .rsync and .rrdp */ | |
1404 | if (e->fts_pointer == RRDP_DIR || | |
1405 | e->fts_pointer == RSYNC_DIR) | |
1406 | break; | |
1407 | if (e->fts_number == 0) | |
1408 | dir = add_to_del(dir, &dirsz, path); | |
1409 | ||
1410 | e->fts_parent->fts_number += e->fts_number; | |
1329 | 1411 | break; |
1330 | 1412 | case FTS_SL: |
1331 | 1413 | case FTS_SLNONE: |
1332 | warnx("symlink %s", e->fts_path); | |
1333 | del = add_to_del(del, &delsz, e->fts_path); | |
1414 | warnx("symlink %s", path); | |
1415 | del = add_to_del(del, &delsz, path); | |
1334 | 1416 | break; |
1335 | 1417 | case FTS_NS: |
1336 | 1418 | case FTS_ERR: |
1337 | 1419 | if (e->fts_errno == ENOENT && |
1338 | (strcmp(e->fts_path, "rsync") == 0 || | |
1339 | strcmp(e->fts_path, "rrdp") == 0)) | |
1420 | e->fts_level == FTS_ROOTLEVEL) | |
1340 | 1421 | continue; |
1341 | warnx("fts_read %s: %s", e->fts_path, | |
1422 | warnx("fts_read %s: %s", path, | |
1342 | 1423 | strerror(e->fts_errno)); |
1343 | 1424 | break; |
1344 | 1425 | default: |
1345 | warnx("unhandled[%x] %s", e->fts_info, | |
1346 | e->fts_path); | |
1426 | warnx("fts_read %s: unhandled[%x]", path, | |
1427 | e->fts_info); | |
1347 | 1428 | break; |
1348 | 1429 | } |
1349 | 1430 | |
1367 | 1448 | free(del[i]); |
1368 | 1449 | } |
1369 | 1450 | free(del); |
1370 | stats.del_files = cnt; | |
1451 | stats.del_files += cnt; | |
1371 | 1452 | |
1372 | 1453 | cnt = 0; |
1373 | 1454 | for (i = 0; i < dirsz; i++) { |
1378 | 1459 | free(dir[i]); |
1379 | 1460 | } |
1380 | 1461 | free(dir); |
1381 | stats.del_dirs = cnt; | |
1462 | stats.del_dirs += cnt; | |
1382 | 1463 | } |
1383 | 1464 | |
1384 | 1465 | void |
1389 | 1470 | while ((rp = SLIST_FIRST(&repos)) != NULL) { |
1390 | 1471 | SLIST_REMOVE_HEAD(&repos, entry); |
1391 | 1472 | free(rp->repouri); |
1473 | free(rp->notifyuri); | |
1474 | free(rp->basedir); | |
1392 | 1475 | free(rp); |
1393 | 1476 | } |
1394 | 1477 | |
1396 | 1479 | rrdp_free(); |
1397 | 1480 | rsync_free(); |
1398 | 1481 | } |
1482 | ||
1483 | /* | |
1484 | * Remove all files and directories under base but do not remove base itself. | |
1485 | */ | |
1486 | static void | |
1487 | remove_contents(char *base) | |
1488 | { | |
1489 | char *argv[2] = { base, NULL }; | |
1490 | FTS *fts; | |
1491 | FTSENT *e; | |
1492 | ||
1493 | if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL) | |
1494 | err(1, "fts_open"); | |
1495 | errno = 0; | |
1496 | while ((e = fts_read(fts)) != NULL) { | |
1497 | switch (e->fts_info) { | |
1498 | case FTS_NSOK: | |
1499 | case FTS_SL: | |
1500 | case FTS_SLNONE: | |
1501 | if (unlink(e->fts_accpath) == -1) | |
1502 | warn("unlink %s", e->fts_path); | |
1503 | break; | |
1504 | case FTS_D: | |
1505 | break; | |
1506 | case FTS_DP: | |
1507 | /* keep root directory */ | |
1508 | if (e->fts_level == FTS_ROOTLEVEL) | |
1509 | break; | |
1510 | if (rmdir(e->fts_accpath) == -1) | |
1511 | warn("rmdir %s", e->fts_path); | |
1512 | break; | |
1513 | case FTS_NS: | |
1514 | case FTS_ERR: | |
1515 | warnx("fts_read %s: %s", e->fts_path, | |
1516 | strerror(e->fts_errno)); | |
1517 | break; | |
1518 | default: | |
1519 | warnx("unhandled[%x] %s", e->fts_info, | |
1520 | e->fts_path); | |
1521 | break; | |
1522 | } | |
1523 | errno = 0; | |
1524 | } | |
1525 | if (errno) | |
1526 | err(1, "fts_read"); | |
1527 | if (fts_close(fts) == -1) | |
1528 | err(1, "fts_close"); | |
1529 | } |
0 | /* $OpenBSD: roa.c,v 1.32 2021/11/05 10:50:41 claudio Exp $ */ | |
0 | /* $OpenBSD: roa.c,v 1.37 2022/01/18 16:29:06 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
35 | 35 | struct roa *res; /* results */ |
36 | 36 | }; |
37 | 37 | |
38 | static ASN1_OBJECT *roa_oid; | |
38 | extern ASN1_OBJECT *roa_oid; | |
39 | 39 | |
40 | 40 | /* |
41 | 41 | * Parse IP address (ROAIPAddress), RFC 6482, section 3.3. |
49 | 49 | size_t dsz = os->length; |
50 | 50 | int rc = 0; |
51 | 51 | const ASN1_TYPE *t; |
52 | const ASN1_INTEGER *maxlength = NULL; | |
52 | const ASN1_INTEGER *maxlength; | |
53 | 53 | long maxlen; |
54 | 54 | struct ip_addr addr; |
55 | 55 | struct roa_ip *res; |
82 | 82 | "invalid IP address", p->fn); |
83 | 83 | goto out; |
84 | 84 | } |
85 | maxlen = addr.prefixlen; | |
85 | 86 | |
86 | 87 | if (sk_ASN1_TYPE_num(seq) == 2) { |
87 | 88 | t = sk_ASN1_TYPE_value(seq, 1); |
114 | 115 | |
115 | 116 | res->addr = addr; |
116 | 117 | res->afi = afi; |
117 | res->maxlength = (maxlength == NULL) ? addr.prefixlen : maxlen; | |
118 | res->maxlength = maxlen; | |
118 | 119 | ip_roa_compose_ranges(res); |
119 | 120 | |
120 | 121 | rc = 1; |
179 | 180 | } |
180 | 181 | |
181 | 182 | /* will be called multiple times so use recallocarray */ |
183 | if (p->res->ipsz + sk_ASN1_TYPE_num(sseq) >= MAX_IP_SIZE) { | |
184 | warnx("%s: too many IPAddress entries: limit %d", | |
185 | p->fn, MAX_IP_SIZE); | |
186 | goto out; | |
187 | } | |
182 | 188 | p->res->ips = recallocarray(p->res->ips, p->res->ipsz, |
183 | 189 | p->res->ipsz + sk_ASN1_TYPE_num(sseq), sizeof(struct roa_ip)); |
184 | 190 | if (p->res->ips == NULL) |
338 | 344 | |
339 | 345 | memset(&p, 0, sizeof(struct parse)); |
340 | 346 | p.fn = fn; |
341 | ||
342 | /* OID from section 2, RFC 6482. */ | |
343 | if (roa_oid == NULL) { | |
344 | roa_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.24", 1); | |
345 | if (roa_oid == NULL) | |
346 | errx(1, "OBJ_txt2obj for %s failed", | |
347 | "1.2.840.113549.1.9.16.1.24"); | |
348 | } | |
349 | 347 | |
350 | 348 | cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz); |
351 | 349 | if (cms == NULL) |
0 | .\" $OpenBSD: rpki-client.8,v 1.49 2021/10/26 13:26:53 claudio Exp $ | |
0 | .\" $OpenBSD: rpki-client.8,v 1.56 2022/01/26 14:42:39 claudio 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: October 26 2021 $ | |
16 | .Dd $Mdocdate: January 26 2022 $ | |
17 | 17 | .Dt RPKI-CLIENT 8 |
18 | 18 | .Os |
19 | 19 | .Sh NAME |
29 | 29 | .Op Fl T Ar table |
30 | 30 | .Op Fl t Ar tal |
31 | 31 | .Op Ar outputdir |
32 | .Nm | |
33 | .Op Fl Vv | |
34 | .Op Fl d Ar cachedir | |
35 | .Op Fl t Ar tal | |
36 | .Fl f | |
37 | .Ar | |
32 | 38 | .Sh DESCRIPTION |
33 | 39 | The |
34 | 40 | .Nm |
39 | 45 | .Em Trust Anchor . |
40 | 46 | .Nm |
41 | 47 | subsequently validates each |
42 | .Em Route Origin Authorization Pq ROA | |
48 | .Em Signed Object | |
43 | 49 | by constructing and verifying a certification path for the certificate |
44 | associated with the ROA (including checking relevant CRLs). | |
50 | associated with the Object (including checking relevant CRLs). | |
45 | 51 | .Nm |
46 | 52 | produces lists of the |
47 | 53 | .Em Validated ROA Payloads Pq VRPs |
54 | and | |
55 | .Em BGPsec Router Keys Pq BRKs | |
48 | 56 | in various formats. |
49 | 57 | .Pp |
50 | 58 | The options are as follows: |
89 | 97 | and |
90 | 98 | .Fl -address |
91 | 99 | flags and connect with rsync-protocol locations. |
100 | .It Fl f Ar | |
101 | Validate the | |
102 | .Em Signed Object | |
103 | in | |
104 | .Ar file | |
105 | against the RPKI cache stored in | |
106 | .Ar cachedir | |
107 | and print human-readable information about the object. | |
108 | If | |
109 | .Ar file | |
110 | is an rsync:// URI the corresponding file from the cache will be used. | |
111 | This option implies | |
112 | .Fl n . | |
92 | 113 | .It Fl j |
93 | 114 | Create output in the file |
94 | 115 | .Pa json |
130 | 151 | .Xr cron 8 . |
131 | 152 | Disable by specifying 0. |
132 | 153 | Defaults to 1 hour. |
154 | Individual Publication Points are timed out after one fourth of | |
155 | .Em timeout . | |
133 | 156 | .It Fl T Ar table |
134 | 157 | For BIRD output generated with the |
135 | 158 | .Fl B |
238 | 261 | .It RFC 8630 |
239 | 262 | Resource Public Key Infrastructure (RPKI) Trust Anchor Locator. |
240 | 263 | .El |
241 | .\" .Sh HISTORY | |
264 | .Sh HISTORY | |
265 | .Nm | |
266 | first appeared in | |
267 | .Ox 6.7 . | |
242 | 268 | .Sh AUTHORS |
243 | 269 | The |
244 | 270 | .Nm |
0 | /* $OpenBSD: rrdp.c,v 1.17 2021/10/29 09:27:36 claudio Exp $ */ | |
0 | /* $OpenBSD: rrdp.c,v 1.21 2022/01/23 12:09:24 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> |
3 | 3 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
18 | 18 | #include <sys/stat.h> |
19 | 19 | |
20 | 20 | #include <assert.h> |
21 | #include <ctype.h> | |
22 | 21 | #include <err.h> |
23 | 22 | #include <errno.h> |
24 | 23 | #include <fcntl.h> |
49 | 48 | |
50 | 49 | struct rrdp { |
51 | 50 | TAILQ_ENTRY(rrdp) entry; |
52 | size_t id; | |
51 | unsigned int id; | |
53 | 52 | char *notifyuri; |
54 | 53 | char *local; |
55 | 54 | char *last_mod; |
75 | 74 | |
76 | 75 | TAILQ_HEAD(,rrdp) states = TAILQ_HEAD_INITIALIZER(states); |
77 | 76 | |
78 | struct publish_xml { | |
79 | char *uri; | |
80 | char *data; | |
81 | char hash[SHA256_DIGEST_LENGTH]; | |
82 | size_t data_length; | |
83 | enum publish_type type; | |
84 | }; | |
85 | ||
86 | 77 | char * |
87 | 78 | xstrdup(const char *s) |
88 | 79 | { |
93 | 84 | } |
94 | 85 | |
95 | 86 | /* |
96 | * Hex decode hexstring into the supplied buffer. | |
97 | * Return 0 on success else -1, if buffer too small or bad encoding. | |
98 | */ | |
99 | int | |
100 | hex_decode(const char *hexstr, char *buf, size_t len) | |
101 | { | |
102 | unsigned char ch, r; | |
103 | size_t pos = 0; | |
104 | int i; | |
105 | ||
106 | while (*hexstr) { | |
107 | r = 0; | |
108 | for (i = 0; i < 2; i++) { | |
109 | ch = hexstr[i]; | |
110 | if (isdigit(ch)) | |
111 | ch -= '0'; | |
112 | else if (islower(ch)) | |
113 | ch -= ('a' - 10); | |
114 | else if (isupper(ch)) | |
115 | ch -= ('A' - 10); | |
116 | else | |
117 | return -1; | |
118 | if (ch > 0xf) | |
119 | return -1; | |
120 | r = r << 4 | ch; | |
121 | } | |
122 | if (pos < len) | |
123 | buf[pos++] = r; | |
124 | else | |
125 | return -1; | |
126 | ||
127 | hexstr += 2; | |
128 | } | |
129 | return 0; | |
130 | } | |
131 | ||
132 | /* | |
133 | 87 | * Report back that a RRDP request finished. |
134 | 88 | * ok should only be set to 1 if the cache is now up-to-date. |
135 | 89 | */ |
136 | 90 | static void |
137 | rrdp_done(size_t id, int ok) | |
91 | rrdp_done(unsigned int id, int ok) | |
138 | 92 | { |
139 | 93 | enum rrdp_msg type = RRDP_END; |
140 | 94 | struct ibuf *b; |
155 | 109 | * should be set to NULL, else it should point to a proper date string. |
156 | 110 | */ |
157 | 111 | static void |
158 | rrdp_http_req(size_t id, const char *uri, const char *last_mod) | |
112 | rrdp_http_req(unsigned int id, const char *uri, const char *last_mod) | |
159 | 113 | { |
160 | 114 | enum rrdp_msg type = RRDP_HTTP_REQ; |
161 | 115 | struct ibuf *b; |
186 | 140 | io_close_buffer(&msgq, b); |
187 | 141 | } |
188 | 142 | |
143 | /* | |
144 | * Inform parent to clear the RRDP repository before start of snapshot. | |
145 | */ | |
146 | static void | |
147 | rrdp_clear_repo(struct rrdp *s) | |
148 | { | |
149 | enum rrdp_msg type = RRDP_CLEAR; | |
150 | struct ibuf *b; | |
151 | ||
152 | b = io_new_buffer(); | |
153 | io_simple_buffer(b, &type, sizeof(type)); | |
154 | io_simple_buffer(b, &s->id, sizeof(s->id)); | |
155 | io_close_buffer(&msgq, b); | |
156 | } | |
157 | ||
158 | /* | |
159 | * Send a blob of data to the main process to store it in the repository. | |
160 | */ | |
161 | void | |
162 | rrdp_publish_file(struct rrdp *s, struct publish_xml *pxml, | |
163 | unsigned char *data, size_t datasz) | |
164 | { | |
165 | enum rrdp_msg type = RRDP_FILE; | |
166 | struct ibuf *b; | |
167 | ||
168 | /* only send files if the fetch did not fail already */ | |
169 | if (s->file_failed == 0) { | |
170 | b = io_new_buffer(); | |
171 | io_simple_buffer(b, &type, sizeof(type)); | |
172 | io_simple_buffer(b, &s->id, sizeof(s->id)); | |
173 | io_simple_buffer(b, &pxml->type, sizeof(pxml->type)); | |
174 | if (pxml->type != PUB_ADD) | |
175 | io_simple_buffer(b, &pxml->hash, sizeof(pxml->hash)); | |
176 | io_str_buffer(b, pxml->uri); | |
177 | io_buf_buffer(b, data, datasz); | |
178 | io_close_buffer(&msgq, b); | |
179 | s->file_pending++; | |
180 | } | |
181 | } | |
182 | ||
189 | 183 | static struct rrdp * |
190 | rrdp_new(size_t id, char *local, char *notify, char *session_id, | |
184 | rrdp_new(unsigned int id, char *local, char *notify, char *session_id, | |
191 | 185 | long long serial, char *last_mod) |
192 | 186 | { |
193 | 187 | struct rrdp *s; |
243 | 237 | } |
244 | 238 | |
245 | 239 | static struct rrdp * |
246 | rrdp_get(size_t id) | |
240 | rrdp_get(unsigned int id) | |
247 | 241 | { |
248 | 242 | struct rrdp *s; |
249 | 243 | |
256 | 250 | static void |
257 | 251 | rrdp_failed(struct rrdp *s) |
258 | 252 | { |
259 | size_t id = s->id; | |
253 | unsigned int id = s->id; | |
260 | 254 | |
261 | 255 | /* reset file state before retrying */ |
262 | 256 | s->file_failed = 0; |
266 | 260 | /* fallback to a snapshot as per RFC8182 */ |
267 | 261 | free_delta_xml(s->dxml); |
268 | 262 | s->dxml = NULL; |
263 | rrdp_clear_repo(s); | |
269 | 264 | s->sxml = new_snapshot_xml(s->parser, &s->current, s); |
270 | 265 | s->task = SNAPSHOT; |
271 | 266 | s->state = RRDP_STATE_REQ; |
284 | 279 | static void |
285 | 280 | rrdp_finished(struct rrdp *s) |
286 | 281 | { |
287 | size_t id = s->id; | |
282 | unsigned int id = s->id; | |
288 | 283 | |
289 | 284 | /* check if all parts of the process have finished */ |
290 | 285 | if ((s->state & RRDP_STATE_DONE) != RRDP_STATE_DONE) |
335 | 330 | break; |
336 | 331 | case SNAPSHOT: |
337 | 332 | logx("%s: downloading snapshot", s->local); |
333 | rrdp_clear_repo(s); | |
338 | 334 | s->sxml = new_snapshot_xml(p, &s->current, s); |
339 | 335 | s->state = RRDP_STATE_REQ; |
340 | 336 | break; |
385 | 381 | enum rrdp_msg type; |
386 | 382 | enum http_result res; |
387 | 383 | long long serial; |
388 | size_t id; | |
384 | unsigned int id; | |
389 | 385 | int ok; |
390 | 386 | |
391 | 387 | b = io_buf_recvfd(fd, &inbuf); |
412 | 408 | errx(1, "expected fd not received"); |
413 | 409 | s = rrdp_get(id); |
414 | 410 | if (s == NULL) |
415 | errx(1, "rrdp session %zu does not exist", id); | |
411 | errx(1, "rrdp session %u does not exist", id); | |
416 | 412 | if (s->state != RRDP_STATE_WAIT) |
417 | 413 | errx(1, "%s: bad internal state", s->local); |
418 | 414 | |
427 | 423 | |
428 | 424 | s = rrdp_get(id); |
429 | 425 | if (s == NULL) |
430 | errx(1, "rrdp session %zu does not exist", id); | |
426 | errx(1, "rrdp session %u does not exist", id); | |
431 | 427 | if (!(s->state & RRDP_STATE_PARSE)) |
432 | 428 | errx(1, "%s: bad internal state", s->local); |
433 | 429 | |
439 | 435 | case RRDP_FILE: |
440 | 436 | s = rrdp_get(id); |
441 | 437 | if (s == NULL) |
442 | errx(1, "rrdp session %zu does not exist", id); | |
438 | errx(1, "rrdp session %u does not exist", id); | |
443 | 439 | if (b->fd != -1) |
444 | 440 | errx(1, "received unexpected fd"); |
445 | 441 | io_read_buf(b, &ok, sizeof(ok)); |
557 | 553 | if (msgq.queued) |
558 | 554 | pfds[0].events |= POLLOUT; |
559 | 555 | |
560 | if (poll(pfds, i, INFTIM) == -1) | |
556 | if (poll(pfds, i, INFTIM) == -1) { | |
557 | if (errno == EINTR) | |
558 | continue; | |
561 | 559 | err(1, "poll"); |
560 | } | |
562 | 561 | |
563 | 562 | if (pfds[0].revents & POLLHUP) |
564 | 563 | break; |
583 | 582 | |
584 | 583 | exit(0); |
585 | 584 | } |
586 | ||
587 | /* | |
588 | * Both snapshots and deltas use publish_xml to store the publish and | |
589 | * withdraw records. Once all the content is added the request is sent | |
590 | * to the main process where it is processed. | |
591 | */ | |
592 | struct publish_xml * | |
593 | new_publish_xml(enum publish_type type, char *uri, char *hash, size_t hlen) | |
594 | { | |
595 | struct publish_xml *pxml; | |
596 | ||
597 | if ((pxml = calloc(1, sizeof(*pxml))) == NULL) | |
598 | err(1, "%s", __func__); | |
599 | ||
600 | pxml->type = type; | |
601 | pxml->uri = uri; | |
602 | if (hlen > 0) { | |
603 | assert(hlen == sizeof(pxml->hash)); | |
604 | memcpy(pxml->hash, hash, hlen); | |
605 | } | |
606 | ||
607 | return pxml; | |
608 | } | |
609 | ||
610 | void | |
611 | free_publish_xml(struct publish_xml *pxml) | |
612 | { | |
613 | if (pxml == NULL) | |
614 | return; | |
615 | ||
616 | free(pxml->uri); | |
617 | free(pxml->data); | |
618 | free(pxml); | |
619 | } | |
620 | ||
621 | /* | |
622 | * Add buf to the base64 data string, ensure that this remains a proper | |
623 | * string by NUL-terminating the string. | |
624 | */ | |
625 | int | |
626 | publish_add_content(struct publish_xml *pxml, const char *buf, int length) | |
627 | { | |
628 | size_t newlen, outlen; | |
629 | ||
630 | /* | |
631 | * optmisiation, this often gets called with '\n' as the | |
632 | * only data... seems wasteful | |
633 | */ | |
634 | if (length == 1 && buf[0] == '\n') | |
635 | return 0; | |
636 | ||
637 | /* append content to data */ | |
638 | if (SIZE_MAX - length - 1 <= pxml->data_length) | |
639 | return -1; | |
640 | newlen = pxml->data_length + length; | |
641 | if (base64_decode_len(newlen, &outlen) == -1 || | |
642 | outlen > MAX_FILE_SIZE) | |
643 | return -1; | |
644 | ||
645 | pxml->data = realloc(pxml->data, newlen + 1); | |
646 | if (pxml->data == NULL) | |
647 | err(1, "%s", __func__); | |
648 | ||
649 | memcpy(pxml->data + pxml->data_length, buf, length); | |
650 | pxml->data[newlen] = '\0'; | |
651 | pxml->data_length = newlen; | |
652 | return 0; | |
653 | } | |
654 | ||
655 | /* | |
656 | * Base64 decode the data blob and send the file to the main process | |
657 | * where the hash is validated and the file stored in the repository. | |
658 | * Increase the file_pending counter to ensure the RRDP process waits | |
659 | * until all files have been processed before moving to the next stage. | |
660 | * Returns 0 on success or -1 on errors (base64 decode failed). | |
661 | */ | |
662 | int | |
663 | publish_done(struct rrdp *s, struct publish_xml *pxml) | |
664 | { | |
665 | enum rrdp_msg type = RRDP_FILE; | |
666 | struct ibuf *b; | |
667 | unsigned char *data = NULL; | |
668 | size_t datasz = 0; | |
669 | ||
670 | if (pxml->data_length > 0) | |
671 | if ((base64_decode(pxml->data, pxml->data_length, | |
672 | &data, &datasz)) == -1) | |
673 | return -1; | |
674 | ||
675 | /* only send files if the fetch did not fail already */ | |
676 | if (s->file_failed == 0) { | |
677 | b = io_new_buffer(); | |
678 | io_simple_buffer(b, &type, sizeof(type)); | |
679 | io_simple_buffer(b, &s->id, sizeof(s->id)); | |
680 | io_simple_buffer(b, &pxml->type, sizeof(pxml->type)); | |
681 | if (pxml->type != PUB_ADD) | |
682 | io_simple_buffer(b, &pxml->hash, sizeof(pxml->hash)); | |
683 | io_str_buffer(b, pxml->uri); | |
684 | io_buf_buffer(b, data, datasz); | |
685 | io_close_buffer(&msgq, b); | |
686 | s->file_pending++; | |
687 | } | |
688 | ||
689 | free(data); | |
690 | free_publish_xml(pxml); | |
691 | return 0; | |
692 | } |
0 | /* $OpenBSD: rrdp.h,v 1.6 2021/10/29 09:27:36 claudio Exp $ */ | |
0 | /* $OpenBSD: rrdp.h,v 1.8 2022/02/03 18:19:32 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> |
3 | 3 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
17 | 17 | #ifndef _RRDPH_ |
18 | 18 | #define _RRDPH_ |
19 | 19 | |
20 | #define RRDP_XMLNS "http://www.ripe.net/rpki/rrdp" | |
20 | 21 | #define MAX_VERSION 1 |
21 | 22 | |
22 | 23 | #define log_debuginfo(format, ...) logx(format, ##__VA_ARGS__) |
34 | 35 | DELTA, |
35 | 36 | }; |
36 | 37 | |
38 | struct rrdp; | |
39 | ||
40 | struct publish_xml { | |
41 | char *uri; | |
42 | char *data; | |
43 | char hash[SHA256_DIGEST_LENGTH]; | |
44 | size_t data_length; | |
45 | enum publish_type type; | |
46 | }; | |
47 | ||
37 | 48 | /* rrdp generic */ |
38 | char *xstrdup(const char *); | |
39 | int hex_decode(const char *, char *, size_t); | |
49 | char *xstrdup(const char *); | |
50 | void rrdp_publish_file(struct rrdp *, struct publish_xml *, | |
51 | unsigned char *, size_t); | |
40 | 52 | |
41 | /* publish or withdraw element */ | |
42 | struct rrdp; | |
43 | struct publish_xml; | |
44 | ||
53 | /* rrdp util */ | |
45 | 54 | struct publish_xml *new_publish_xml(enum publish_type, char *, |
46 | 55 | char *, size_t); |
47 | 56 | void free_publish_xml(struct publish_xml *); |
0 | /* $OpenBSD: rrdp_delta.c,v 1.6 2021/11/09 11:01:04 claudio Exp $ */ | |
0 | /* $OpenBSD: rrdp_delta.c,v 1.7 2022/02/03 18:19:32 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> |
3 | 3 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
65 | 65 | "parse failed - entered delta elem unexpectedely"); |
66 | 66 | for (i = 0; attr[i]; i += 2) { |
67 | 67 | const char *errstr; |
68 | if (strcmp("xmlns", attr[i]) == 0) { | |
68 | if (strcmp("xmlns", attr[i]) == 0 && | |
69 | strcmp(RRDP_XMLNS, attr[i + 1]) == 0) { | |
69 | 70 | has_xmlns = 1; |
70 | 71 | continue; |
71 | 72 | } |
0 | /* $OpenBSD: rrdp_notification.c,v 1.11 2021/11/09 11:01:04 claudio Exp $ */ | |
0 | /* $OpenBSD: rrdp_notification.c,v 1.13 2022/02/03 18:19:32 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> |
3 | 3 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
119 | 119 | "parse failed - entered notification elem unexpectedely"); |
120 | 120 | for (i = 0; attr[i]; i += 2) { |
121 | 121 | const char *errstr; |
122 | if (strcmp("xmlns", attr[i]) == 0) { | |
122 | if (strcmp("xmlns", attr[i]) == 0 && | |
123 | strcmp(RRDP_XMLNS, attr[i + 1]) == 0) { | |
123 | 124 | has_xmlns = 1; |
124 | 125 | continue; |
125 | 126 | } |
463 | 464 | void |
464 | 465 | log_notification_xml(struct notification_xml *nxml) |
465 | 466 | { |
467 | struct delta_item *d; | |
468 | char *hash; | |
469 | ||
466 | 470 | logx("session_id: %s, serial: %lld", nxml->session_id, nxml->serial); |
467 | 471 | logx("snapshot_uri: %s", nxml->snapshot_uri); |
468 | } | |
472 | hash = hex_encode(nxml->snapshot_hash, sizeof(nxml->snapshot_hash)); | |
473 | logx("snapshot hash: %s", hash); | |
474 | free(hash); | |
475 | ||
476 | TAILQ_FOREACH(d, &nxml->delta_q, q) { | |
477 | logx("delta serial %lld uri: %s", d->serial, d->uri); | |
478 | hash = hex_encode(d->hash, sizeof(d->hash)); | |
479 | logx("delta hash: %s", hash); | |
480 | free(hash); | |
481 | } | |
482 | } |
0 | /* $OpenBSD: rrdp_snapshot.c,v 1.5 2021/11/09 11:01:04 claudio Exp $ */ | |
0 | /* $OpenBSD: rrdp_snapshot.c,v 1.6 2022/02/03 18:19:32 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> |
3 | 3 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
57 | 57 | "parse failed - entered snapshot elem unexpectedely"); |
58 | 58 | for (i = 0; attr[i]; i += 2) { |
59 | 59 | const char *errstr; |
60 | if (strcmp("xmlns", attr[i]) == 0) { | |
60 | if (strcmp("xmlns", attr[i]) == 0 && | |
61 | strcmp(RRDP_XMLNS, attr[i + 1]) == 0) { | |
61 | 62 | has_xmlns = 1; |
62 | 63 | continue; |
63 | 64 | } |
0 | /* $OpenBSD: rrdp_util.c,v 1.1 2021/11/24 15:24:16 claudio Exp $ */ | |
1 | /* | |
2 | * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com> | |
3 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | #include <assert.h> | |
18 | #include <err.h> | |
19 | #include <stdlib.h> | |
20 | #include <string.h> | |
21 | ||
22 | #include <expat.h> | |
23 | #include <openssl/sha.h> | |
24 | ||
25 | #include "extern.h" | |
26 | #include "rrdp.h" | |
27 | ||
28 | /* | |
29 | * Both snapshots and deltas use publish_xml to store the publish and | |
30 | * withdraw records. Once all the content is added the request is sent | |
31 | * to the main process where it is processed. | |
32 | */ | |
33 | struct publish_xml * | |
34 | new_publish_xml(enum publish_type type, char *uri, char *hash, size_t hlen) | |
35 | { | |
36 | struct publish_xml *pxml; | |
37 | ||
38 | if ((pxml = calloc(1, sizeof(*pxml))) == NULL) | |
39 | err(1, "%s", __func__); | |
40 | ||
41 | pxml->type = type; | |
42 | pxml->uri = uri; | |
43 | if (hlen > 0) { | |
44 | assert(hlen == sizeof(pxml->hash)); | |
45 | memcpy(pxml->hash, hash, hlen); | |
46 | } | |
47 | ||
48 | return pxml; | |
49 | } | |
50 | ||
51 | void | |
52 | free_publish_xml(struct publish_xml *pxml) | |
53 | { | |
54 | if (pxml == NULL) | |
55 | return; | |
56 | ||
57 | free(pxml->uri); | |
58 | free(pxml->data); | |
59 | free(pxml); | |
60 | } | |
61 | ||
62 | /* | |
63 | * Add buf to the base64 data string, ensure that this remains a proper | |
64 | * string by NUL-terminating the string. | |
65 | */ | |
66 | int | |
67 | publish_add_content(struct publish_xml *pxml, const char *buf, int length) | |
68 | { | |
69 | size_t newlen, outlen; | |
70 | ||
71 | /* | |
72 | * optmisiation, this often gets called with '\n' as the | |
73 | * only data... seems wasteful | |
74 | */ | |
75 | if (length == 1 && buf[0] == '\n') | |
76 | return 0; | |
77 | ||
78 | /* append content to data */ | |
79 | if (SIZE_MAX - length - 1 <= pxml->data_length) | |
80 | return -1; | |
81 | newlen = pxml->data_length + length; | |
82 | if (base64_decode_len(newlen, &outlen) == -1 || | |
83 | outlen > MAX_FILE_SIZE) | |
84 | return -1; | |
85 | ||
86 | pxml->data = realloc(pxml->data, newlen + 1); | |
87 | if (pxml->data == NULL) | |
88 | err(1, "%s", __func__); | |
89 | ||
90 | memcpy(pxml->data + pxml->data_length, buf, length); | |
91 | pxml->data[newlen] = '\0'; | |
92 | pxml->data_length = newlen; | |
93 | return 0; | |
94 | } | |
95 | ||
96 | /* | |
97 | * Base64 decode the data blob and send the file to the main process | |
98 | * where the hash is validated and the file stored in the repository. | |
99 | * Increase the file_pending counter to ensure the RRDP process waits | |
100 | * until all files have been processed before moving to the next stage. | |
101 | * Returns 0 on success or -1 on errors (base64 decode failed). | |
102 | */ | |
103 | int | |
104 | publish_done(struct rrdp *s, struct publish_xml *pxml) | |
105 | { | |
106 | unsigned char *data = NULL; | |
107 | size_t datasz = 0; | |
108 | ||
109 | if (pxml->data_length > 0) | |
110 | if ((base64_decode(pxml->data, pxml->data_length, | |
111 | &data, &datasz)) == -1) | |
112 | return -1; | |
113 | ||
114 | rrdp_publish_file(s, pxml, data, datasz); | |
115 | ||
116 | free(data); | |
117 | free_publish_xml(pxml); | |
118 | return 0; | |
119 | } |
0 | /* $OpenBSD: rsync.c,v 1.30 2021/11/03 14:59:37 claudio Exp $ */ | |
0 | /* $OpenBSD: rsync.c,v 1.32 2022/01/13 11:50:29 claudio Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
41 | 41 | * of which process maps to which request. |
42 | 42 | */ |
43 | 43 | struct rsyncproc { |
44 | char *uri; /* uri of this rsync proc */ | |
45 | size_t id; /* identity of request */ | |
46 | pid_t pid; /* pid of process or 0 if unassociated */ | |
44 | char *uri; /* uri of this rsync proc */ | |
45 | unsigned int id; /* identity of request */ | |
46 | pid_t pid; /* pid of process or 0 if unassociated */ | |
47 | 47 | }; |
48 | 48 | |
49 | 49 | /* |
96 | 96 | if ((base_uri = strndup(uri, rest - uri)) == NULL) |
97 | 97 | err(1, NULL); |
98 | 98 | return base_uri; |
99 | } | |
100 | ||
101 | /* | |
102 | * The directory passed as --compare-dest needs to be relative to | |
103 | * the destination directory. This function takes care of that. | |
104 | */ | |
105 | static char * | |
106 | rsync_fixup_dest(char *destdir, char *compdir) | |
107 | { | |
108 | const char *dotdot = "../../../../../../"; /* should be enough */ | |
109 | int dirs = 1; | |
110 | char *fn; | |
111 | char c; | |
112 | ||
113 | while ((c = *destdir++) != '\0') | |
114 | if (c == '/') | |
115 | dirs++; | |
116 | ||
117 | if (dirs > 6) | |
118 | /* too deep for us */ | |
119 | return NULL; | |
120 | ||
121 | if ((asprintf(&fn, "%.*s%s", dirs * 3, dotdot, compdir)) == -1) | |
122 | err(1, NULL); | |
123 | return fn; | |
99 | 124 | } |
100 | 125 | |
101 | 126 | static void |
180 | 205 | err(1, NULL); |
181 | 206 | |
182 | 207 | for (;;) { |
183 | char *uri = NULL, *dst = NULL; | |
184 | size_t id; | |
208 | char *uri, *dst, *compdst; | |
209 | unsigned int id; | |
185 | 210 | pid_t pid; |
186 | 211 | int st; |
187 | 212 | |
208 | 233 | for (i = 0; i < idsz; i++) |
209 | 234 | if (ids[i].pid == pid) |
210 | 235 | break; |
211 | assert(i < idsz); | |
236 | if (i >= idsz) | |
237 | errx(1, "waitpid: %d unexpected", pid); | |
212 | 238 | |
213 | 239 | if (!WIFEXITED(st)) { |
214 | 240 | warnx("rsync %s terminated abnormally", |
221 | 247 | } |
222 | 248 | |
223 | 249 | b = io_new_buffer(); |
224 | io_simple_buffer(b, &ids[i].id, sizeof(size_t)); | |
250 | io_simple_buffer(b, &ids[i].id, | |
251 | sizeof(ids[i].id)); | |
225 | 252 | io_simple_buffer(b, &ok, sizeof(ok)); |
226 | 253 | io_close_buffer(&msgq, b); |
227 | 254 | |
259 | 286 | /* Read host and module. */ |
260 | 287 | io_read_buf(b, &id, sizeof(id)); |
261 | 288 | io_read_str(b, &dst); |
289 | io_read_str(b, &compdst); | |
262 | 290 | io_read_str(b, &uri); |
263 | 291 | |
264 | 292 | ibuf_free(b); |
273 | 301 | |
274 | 302 | if (pid == 0) { |
275 | 303 | char *args[32]; |
304 | char *reldst; | |
276 | 305 | |
277 | 306 | if (pledge("stdio exec", NULL) == -1) |
278 | 307 | err(1, "pledge"); |
293 | 322 | args[i++] = "--address"; |
294 | 323 | args[i++] = (char *)bind_addr; |
295 | 324 | } |
325 | if (compdst != NULL && | |
326 | (reldst = rsync_fixup_dest(dst, compdst)) != NULL) { | |
327 | args[i++] = "--compare-dest"; | |
328 | args[i++] = reldst; | |
329 | } | |
296 | 330 | args[i++] = uri; |
297 | 331 | args[i++] = dst; |
298 | 332 | args[i] = NULL; |
321 | 355 | /* Clean up temporary values. */ |
322 | 356 | |
323 | 357 | free(dst); |
358 | free(compdst); | |
324 | 359 | } |
325 | 360 | |
326 | 361 | /* No need for these to be hanging around. */ |
0 | /* $OpenBSD: validate.c,v 1.22 2021/11/04 11:32:55 claudio Exp $ */ | |
0 | /* $OpenBSD: validate.c,v 1.29 2022/02/04 13:50:32 job Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
3 | 3 | * |
57 | 57 | |
58 | 58 | /* |
59 | 59 | * Walk up the chain of certificates (really just the last one, but in |
60 | * the case of inheritence, the ones before) making sure that our IP | |
60 | * the case of inheritance, the ones before) making sure that our IP | |
61 | 61 | * prefix is covered in the first non-inheriting specification. |
62 | 62 | * Returns 1 if covered or 0 if not. |
63 | 63 | */ |
142 | 142 | * Returns 1 if valid, 0 otherwise. |
143 | 143 | */ |
144 | 144 | int |
145 | valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert) | |
146 | { | |
147 | struct auth *a; | |
145 | valid_cert(const char *fn, struct auth *a, const struct cert *cert) | |
146 | { | |
148 | 147 | size_t i; |
149 | 148 | uint32_t min, max; |
150 | 149 | char buf1[64], buf2[64]; |
151 | ||
152 | a = valid_ski_aki(fn, auths, cert->ski, cert->aki); | |
153 | if (a == NULL) | |
154 | return 0; | |
155 | 150 | |
156 | 151 | for (i = 0; i < cert->asz; i++) { |
157 | 152 | if (cert->as[i].type == CERT_AS_INHERIT) { |
201 | 196 | } |
202 | 197 | |
203 | 198 | /* |
204 | * Validate our ROA: check that the SKI is unique, the AKI exists, and | |
205 | * the IP prefix is also contained. | |
206 | * Returns 1 if valid, 0 otherwise. | |
207 | */ | |
208 | int | |
209 | valid_roa(const char *fn, struct auth_tree *auths, struct roa *roa) | |
210 | { | |
211 | struct auth *a; | |
199 | * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained. | |
200 | * Returns 1 if valid, 0 otherwise. | |
201 | */ | |
202 | int | |
203 | valid_roa(const char *fn, struct auth *a, struct roa *roa) | |
204 | { | |
212 | 205 | size_t i; |
213 | 206 | char buf[64]; |
214 | ||
215 | a = valid_ski_aki(fn, auths, roa->ski, roa->aki); | |
216 | if (a == NULL) | |
217 | return 0; | |
218 | ||
219 | roa->talid = a->cert->talid; | |
220 | 207 | |
221 | 208 | for (i = 0; i < roa->ipsz; i++) { |
222 | 209 | if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min, |
233 | 220 | } |
234 | 221 | |
235 | 222 | /* |
236 | * Validate a filename listed on a Manifest. | |
237 | * draft-ietf-sidrops-6486bis section 4.2.2 | |
238 | * Returns 1 if filename is valid, otherwise 0. | |
239 | */ | |
240 | int | |
241 | valid_filename(const char *fn) | |
242 | { | |
243 | size_t sz; | |
244 | const unsigned char *c; | |
245 | ||
246 | sz = strlen(fn); | |
247 | if (sz < 5) | |
248 | return 0; | |
249 | ||
250 | for (c = fn; *c != '\0'; ++c) | |
251 | if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.') | |
252 | return 0; | |
253 | ||
254 | if (strchr(fn, '.') != strrchr(fn, '.')) | |
255 | return 0; | |
256 | ||
257 | if (strcasecmp(fn + sz - 4, ".cer") == 0) | |
258 | return 1; | |
259 | if (strcasecmp(fn + sz - 4, ".crl") == 0) | |
260 | return 1; | |
261 | if (strcasecmp(fn + sz - 4, ".gbr") == 0) | |
262 | return 1; | |
263 | if (strcasecmp(fn + sz - 4, ".roa") == 0) | |
264 | return 1; | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | /* | |
270 | 223 | * Validate a file by verifying the SHA256 hash of that file. |
271 | * Returns 1 if valid, 0 otherwise. | |
272 | */ | |
273 | int | |
274 | valid_filehash(const char *fn, const char *hash, size_t hlen) | |
224 | * The file to check is passed as a file descriptor. | |
225 | * Returns 1 if hash matched, 0 otherwise. Closes fd when done. | |
226 | */ | |
227 | int | |
228 | valid_filehash(int fd, const char *hash, size_t hlen) | |
275 | 229 | { |
276 | 230 | SHA256_CTX ctx; |
277 | 231 | char filehash[SHA256_DIGEST_LENGTH]; |
278 | 232 | char buffer[8192]; |
279 | 233 | ssize_t nr; |
280 | int fd; | |
281 | 234 | |
282 | 235 | if (hlen != sizeof(filehash)) |
283 | 236 | errx(1, "bad hash size"); |
284 | 237 | |
285 | if ((fd = open(fn, O_RDONLY)) == -1) | |
238 | if (fd == -1) | |
286 | 239 | return 0; |
287 | 240 | |
288 | 241 | SHA256_Init(&ctx); |
289 | 242 | while ((nr = read(fd, buffer, sizeof(buffer))) > 0) |
290 | 243 | SHA256_Update(&ctx, buffer, nr); |
291 | 244 | close(fd); |
292 | ||
293 | 245 | SHA256_Final(filehash, &ctx); |
246 | ||
294 | 247 | if (memcmp(hash, filehash, sizeof(filehash)) != 0) |
295 | 248 | return 0; |
296 | 249 |
0 | /* $OpenBSD: version.h,v 1.7 2021/11/07 20:57:27 benno Exp $ */ | |
0 | /* $OpenBSD: version.h,v 1.8 2022/02/03 17:26:17 claudio Exp $ */ | |
1 | 1 | |
2 | #define RPKI_VERSION "7.5" | |
2 | #define RPKI_VERSION "7.6" |
0 | /* $OpenBSD: x509.c,v 1.29 2021/10/28 09:02:19 beck Exp $ */ | |
0 | /* $OpenBSD: x509.c,v 1.34 2022/02/04 16:08:53 tb Exp $ */ | |
1 | 1 | /* |
2 | 2 | * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> |
3 | 3 | * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> |
29 | 29 | |
30 | 30 | #include "extern.h" |
31 | 31 | |
32 | static ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router */ | |
33 | ||
34 | static void | |
35 | init_oid(void) | |
36 | { | |
32 | ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ | |
33 | ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ | |
34 | ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ | |
35 | ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ | |
36 | ASN1_OBJECT *roa_oid; /* id-ct-routeOriginAuthz CMS content type */ | |
37 | ASN1_OBJECT *mft_oid; /* id-ct-rpkiManifest CMS content type */ | |
38 | ASN1_OBJECT *gbr_oid; /* id-ct-rpkiGhostbusters CMS content type */ | |
39 | ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router Key Purpose */ | |
40 | ||
41 | void | |
42 | x509_init_oid(void) | |
43 | { | |
44 | ||
45 | if ((certpol_oid = OBJ_txt2obj("1.3.6.1.5.5.7.14.2", 1)) == NULL) | |
46 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.14.2"); | |
47 | if ((carepo_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.5", 1)) == NULL) | |
48 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.5"); | |
49 | if ((manifest_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.10", 1)) == NULL) | |
50 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.10"); | |
51 | if ((notify_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.13", 1)) == NULL) | |
52 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.13"); | |
53 | if ((roa_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.24", 1)) == NULL) | |
54 | errx(1, "OBJ_txt2obj for %s failed", | |
55 | "1.2.840.113549.1.9.16.1.24"); | |
56 | if ((mft_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.26", 1)) == NULL) | |
57 | errx(1, "OBJ_txt2obj for %s failed", | |
58 | "1.2.840.113549.1.9.16.1.26"); | |
59 | if ((gbr_oid = OBJ_txt2obj("1.2.840.113549.1.9.16.1.35", 1)) == NULL) | |
60 | errx(1, "OBJ_txt2obj for %s failed", | |
61 | "1.2.840.113549.1.9.16.1.35"); | |
37 | 62 | if ((bgpsec_oid = OBJ_txt2obj("1.3.6.1.5.5.7.3.30", 1)) == NULL) |
38 | 63 | errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.3.30"); |
39 | 64 | } |
165 | 190 | sk_ASN1_OBJECT_num(eku)); |
166 | 191 | goto out; |
167 | 192 | } |
168 | ||
169 | if (bgpsec_oid == NULL) | |
170 | init_oid(); | |
171 | 193 | |
172 | 194 | if (OBJ_cmp(bgpsec_oid, sk_ASN1_OBJECT_value(eku, 0)) == 0) { |
173 | 195 | purpose = CERT_PURPOSE_BGPSEC_ROUTER; |
196 | 218 | |
197 | 219 | pkey = X509_get0_pubkey(x); |
198 | 220 | if (pkey == NULL) { |
199 | warnx("%s: X509_get_pubkey failed in %s", fn, __func__); | |
221 | warnx("%s: X509_get0_pubkey failed in %s", fn, __func__); | |
200 | 222 | goto out; |
201 | 223 | } |
202 | 224 | if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { |
330 | 352 | /* |
331 | 353 | * Parse the very specific subset of information in the CRL distribution |
332 | 354 | * point extension. |
333 | * See RFC 6487, sectoin 4.8.6 for details. | |
355 | * See RFC 6487, section 4.8.6 for details. | |
334 | 356 | * Returns NULL on failure, the crl URI on success which has to be freed |
335 | 357 | * after use. |
336 | 358 | */ |