├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── GNUmakefile ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.md ├── THANKS ├── base64.c ├── base64.h ├── build-aux ├── ar-lib ├── compile ├── depcomp ├── git-version-gen ├── install-sh ├── m4 │ ├── ax_check_compile_flag.m4 │ ├── ax_check_enable_debug.m4 │ └── ax_is_release.m4 └── missing ├── configure.ac ├── crypto.c ├── crypto.h ├── curlwrap.c ├── curlwrap.h ├── docs ├── index.html ├── uacme.html └── ualpn.html ├── jsmn.h ├── json.c ├── json.h ├── libev ├── ev.c ├── ev.h ├── ev_epoll.c ├── ev_iouring.c ├── ev_kqueue.c ├── ev_linuxaio.c ├── ev_poll.c ├── ev_port.c ├── ev_select.c ├── ev_vars.h ├── ev_wrap.h └── libev.m4 ├── log.c ├── log.h ├── msg.c ├── msg.h ├── nsupdate.sh ├── read-file.c ├── read-file.h ├── sglib.h ├── uacme.1 ├── uacme.1.txt ├── uacme.c ├── uacme.sh ├── ualpn.1 ├── ualpn.1.txt ├── ualpn.c └── ualpn.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .version 2 | .tarball-version 3 | .deps 4 | Makefile.in 5 | Makefile 6 | aclocal.m4 7 | configure 8 | config.h 9 | config.h.in 10 | config.h.in~ 11 | config.log 12 | config.status 13 | autom4te.cache 14 | uacme 15 | ualpn 16 | *.o 17 | libev.a 18 | libev/.dirstamp 19 | stamp-h1 20 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Nicola Di Lieto 2 | * Original program author 3 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2024-12-29 Nicola Di Lieto 2 | * Release 1.7.6 3 | - Fix OpenSSL 3.x deprecated APIs 4 | - Fix cross compilation 5 | Closes https://github.com/ndilieto/uacme/issues/79 6 | - uacme: Add environment variables 7 | Closes https://github.com/ndilieto/uacme/issues/63 8 | - uacme: Add support for ACME Renewal Information (ARI) 9 | Closes https://github.com/ndilieto/uacme/issues/67 10 | - uacme: Try obtaining new Reply-Nonce if server doesn't supply one 11 | Closes https://github.com/ndilieto/uacme/issues/82 12 | - uacme: Add hook environment variables 13 | Closes https://github.com/ndilieto/uacme/issues/83 14 | - uacme: Allow matching alternative chain by Authority Key Id 15 | Closes https://github.com/ndilieto/uacme/issues/85 16 | - Documentation update 17 | - Add link to linode api hook 18 | 19 | 2024-01-28 Nicola Di Lieto 20 | * Release 1.7.5 21 | - fix ualpn exit code in client mode 22 | Fixes https://github.com/ndilieto/uacme/issues/76 23 | - fix build with autoconf version 2.71 24 | See https://github.com/ndilieto/uacme/pull/70 25 | - uacme: nsupdate.sh overhaul and DNAME redirection support 26 | - add link to deSEC.io DNS integration 27 | - minor documentation changes including copyright year 28 | 29 | 2023-02-15 Nicola Di Lieto 30 | * Release 1.7.4 31 | - uacme: Validate token from ACME server. Fixes 32 | https://github.com/ndilieto/uacme/issues/64 33 | - minor documentation changes including copyright year 34 | 35 | 2022-09-20 Nicola Di Lieto 36 | * Release 1.7.3 37 | - better compatibility with LibreSSL, require 3.4.2 or later 38 | - uacme: Enable --must-staple support with LibreSSL > 3.5.0 39 | - ualpn: Fix build issue with mbedTLS 2.x 40 | see https://github.com/ndilieto/uacme/pull/61 41 | 42 | 2022-07-20 Nicola Di Lieto 43 | * Release 1.7.2 44 | - uacme: exponential backoff for status polling instead 45 | of constant 5s delay (reduces load on server) 46 | - uacme: new -r option to allow specifying revocation code 47 | - uacme: fix silent failure in nsupdate.sh 48 | closes https://github.com/ndilieto/uacme/issues/45 49 | - uacme: replace 'echo' with 'printf' in uacme.sh 50 | closes https://github.com/ndilieto/uacme/issues/48 51 | - uacme: fix -Wsign-compare warning 52 | - compatibility with mbedTLS v3.2 53 | - compatibility with LibreSSL (with some limitations) 54 | see https://github.com/ndilieto/uacme/commit/32546c7c 55 | - embed ax_check_compile_flag.m4 from autoconf-archive as 56 | requested in https://github.com/ndilieto/uacme/pull/57 57 | - minor documentation changes including copyright year 58 | 59 | 2021-06-04 Nicola Di Lieto 60 | * Release 1.7.1 61 | - uacme: fix issue when running from inaccessible directory 62 | closes https://github.com/ndilieto/uacme/issues/41 63 | - ualpn: use default user group when -u is specified 64 | 65 | 2021-01-17 Nicola Di Lieto 66 | * Release 1.7 67 | - uacme: alternate chain selection by certificate fingerprint 68 | - uacme: print copyright with version 69 | - ualpn: print copyright with version 70 | - ualpn: add notice with version on startup 71 | - ualpn: reject duplicate options where appropriate 72 | - ualpn: make ualpn.sh always outputs to stderr 73 | - ualpn: fix compilation warning 74 | - minor changes (typos) 75 | - master branch builds must autoreconf 76 | - update copyright year 77 | 78 | 2020-12-06 Nicola Di Lieto 79 | * Release 1.6 80 | - uacme: add support for RFC8555 External Account Binding 81 | closes https://github.com/ndilieto/uacme/issues/40 82 | - uacme: fix use after free in surrogate strcasestr function 83 | - uacme: make nsupdate.sh accept quoted TXT challenge values 84 | - uacme: minor cosmetic changes to log messages 85 | 86 | 2020-07-26 Nicola Di Lieto 87 | * Release 1.5 88 | - uacme: add -l option to allow selecting alternate chain 89 | - ualpn: move signal calls to beginning 90 | - ualpn: add mbedtls_x509_crt_parse_der_with_ext_cb support 91 | fixes https://github.com/ndilieto/uacme/issues/23 92 | 93 | 2020-05-30 Nicola Di Lieto 94 | * Release 1.4.1 95 | - fix SIGPIPE of parent process in daemon mode 96 | https://github.com/ndilieto/uacme/issues/36 97 | 98 | 2020-05-30 Nicola Di Lieto 99 | * Release 1.4 100 | - fix nsupdate.sh 101 | https://github.com/ndilieto/uacme/issues/32 102 | - uacme: warn that --must-staple is ignored with CSRFILE 103 | - ualpn: swap -p and -P command line switches 104 | - ualpn: remove redundant memset 105 | - ualpn: increase key buffer size as required by OpenSSL 3.x 106 | - ualpn: fix minor OpenBSD portability issues 107 | - ualpn: fix typo in warning message 108 | - ualpn: fix library link order when using built-in libev 109 | - README.md now included in distribution 110 | 111 | 2020-05-08 Nicola Di Lieto 112 | * Release 1.3 113 | - allow signing revocation requests with certificate key 114 | - add support for issuing certificates based on a CSR 115 | - add mbedTLS implementation of OCSP check 116 | - add nsupdate.sh dns-01 authentication script 117 | - improve handling of RFC8738 with OpenSSL/mbedTLS 118 | - fix memory leak in csr_gen upon some OpenSSL errors 119 | 120 | 2020-04-25 Nicola Di Lieto 121 | * Release 1.2.4 122 | - improve mbedTLS detection in configure.ac 123 | - check format string arguments with GCC 124 | - ualpn: fix incorrect message arguments 125 | 126 | 2020-04-22 Nicola Di Lieto 127 | * Release 1.2.3 128 | - fix Content-Type header parsing 129 | https://github.com/ndilieto/uacme/issues/22 130 | 131 | 2020-04-18 Nicola Di Lieto 132 | * Release 1.2.2 133 | - fix ualpn socket type bug on uClibc based systems 134 | - fix configure.ac MAP_ANON cross-compilation test 135 | 136 | 2020-04-17 Nicola Di Lieto 137 | * Release 1.2.1 138 | - increase cert buf size to cope with long identifiers 139 | - fix gcc8 -Wstringop-truncation warning 140 | 141 | 2020-04-15 Nicola Di Lieto 142 | * Release 1.2 143 | - add uacme OCSP certificate status check 144 | - add ualpn OpenSSL/mbedTLS implementations 145 | - add key usage to ualpn challenge certificate 146 | - ensure top bit of ualpn certificate S/N is 0 with OpenSSL 147 | - fix ualpn memory leaks and corner case bugs 148 | - minor cosmetic code and documentation changes 149 | 150 | 2020-03-12 Nicola Di Lieto 151 | * Release 1.1.2 152 | - fix configure.ac typo affecting LDFLAGS 153 | - fix missing PIPE_BUF when building on hurd-386 154 | 155 | 2020-03-12 Nicola Di Lieto 156 | * Release 1.1.1 157 | - fix typo breaking build without HAVE_SPLICE 158 | - fix addr_t name collision on s390x 159 | 160 | 2020-03-11 Nicola Di Lieto 161 | * Release 1.1 162 | - added IP identifier support (RFC8738) 163 | - added tls-alpn-01 (RFC8737) challenge responder (ualpn) 164 | 165 | 2020-02-01 Nicola Di Lieto 166 | * Release 1.0.22 167 | - relax account status check (compatibility with buypass.no) 168 | - allow client challenge retry requests (RFC8555 sec. 7.1.6) 169 | - pass -L flag to a2x in order to avoid depending on xmllint 170 | - add wildcard clarification in manpage 171 | 172 | 2020-01-12 Nicola Di Lieto 173 | * Release 1.0.21 174 | - Fixed uacme.sh: https://github.com/ndilieto/uacme/pull/12 175 | - Added LFS support (AC_SYS_LARGEFILE) 176 | 177 | 2019-10-03 Nicola Di Lieto 178 | * Release 1.0.20 179 | - improved HTTP header parsing to fix problem that 180 | can happen when retrieving directory over HTTP/2 181 | 182 | 2019-09-30 Nicola Di Lieto 183 | * Release 1.0.19 184 | - Fix configure script bug when using explicit 185 | PKG_CONFIG environment variable 186 | - explicitly set key usage in certificate request 187 | 188 | 2019-08-29 Nicola Di Lieto 189 | * Release 1.0.18 190 | - support for OCSP Must-Staple (-m, --must-staple) 191 | - explicitly set key usage constraints with mbedTLS 192 | - fix compilation warning with gcc7 on solaris 193 | 194 | 2019-07-03 Nicola Di Lieto 195 | * Release 1.0.17 196 | - fix pedantic compilation warning 197 | - configure fails if pkg-config isn't found 198 | 199 | 2019-06-17 Nicola Di Lieto 200 | * Release 1.0.16 201 | - Configure script checks for libcurl HTTPS support 202 | - Minor man page corrections 203 | 204 | 2019-06-15 Nicola Di Lieto 205 | * Release 1.0.15 206 | - Exit with error if both -a and -s are specified 207 | - Avoid depending on libtasn1 if gnutls_decode_rs_value is available 208 | 209 | 2019-06-12 Nicola Di Lieto 210 | * Release 1.0.14 211 | - Fix deprecated API when building with OpenSSL v1.1.1c 212 | 213 | 2019-06-05 Nicola Di Lieto 214 | * Release 1.0.13 215 | - Disable mbedTLS runtime version check if not available 216 | 217 | 2019-05-18 Nicola Di Lieto 218 | * Release 1.0.12 219 | - Ensure EC key params are always properly padded 220 | - Improved hook_run error checking 221 | 222 | 2019-05-17 Nicola Di Lieto 223 | * Release 1.0.11 224 | - Key rollover (https://tools.ietf.org/html/rfc8555#section-7.3.5) 225 | - Revoked cert files now renamed to 'revoked-TIMESTAMP.pem' 226 | - Key auth contains SHA256 digest for tls-alpn-01 (like dns-01) 227 | - Minor logging improvements 228 | 229 | 2019-05-12 Nicola Di Lieto 230 | * Release 1.0.10 231 | - added secp384r1 EC key support 232 | - -b, --bits option accepts 256 or 384 for EC keys 233 | - enforce multiple of 8 RSA key size 234 | - improved acme_get and acme_post verbose logging 235 | - retry upon badNonce response according to RFC8555 6.5 236 | - mbedtls: fixed incorrect size of EC signature 237 | 238 | 2019-05-09 Nicola Di Lieto 239 | * Release 1.0.9 240 | - added EC key/cert support (-t, --type=EC, default RSA) 241 | - added RSA key length option (-b, --bits=BITS, default 2048) 242 | 243 | 2019-05-04 Nicola Di Lieto 244 | * Release 1.0.8 245 | - added OpenSSL support (./configure --with-openssl) 246 | - check libraries versions at both compile and run time 247 | - exit codes: 0=success, 1=cert issuance skipped, 2=error 248 | - mbedtls: dynamically grow buffers when needed 249 | 250 | 2019-04-29 Nicola Di Lieto 251 | * Release 1.0.7 252 | - added HTTP User-Agent: header to all requests 253 | - added --disable-docs configure option 254 | - manpage version now updated automatically 255 | 256 | 2019-04-27 Nicola Di Lieto 257 | * Release 1.0.6 258 | - fix uninitialized variable in authorize() 259 | 260 | 2019-04-27 Nicola Di Lieto 261 | * Release 1.0.5 262 | - add AM_MAINTAINER_MODE to configure.ac 263 | - minor cosmetic change to json primitive dump 264 | 265 | 2019-04-26 Nicola Di Lieto 266 | * Release 1.0.4 267 | - debian packaging 268 | - fix potential uninitialized var access in acme_get() 269 | - fix fprintf format string in _json_dump() 270 | - copy doc/index.html on demand only 271 | 272 | 2019-04-25 Nicola Di Lieto 273 | * Release 1.0.3 274 | - fixed more -pedantic gcc warnings 275 | - html manpage in html5; copy as doc/html for github hosting 276 | 277 | 2019-04-24 Nicola Di Lieto 278 | * Release 1.0.2 279 | - allow choosing between GnuTLS and mbedTLS at compile time 280 | - improved directory existence check 281 | - fixed -Wall -pedantic gcc warnings 282 | 283 | 2019-04-21 Nicola Di Lieto 284 | * Release 1.0.1 285 | - fix acme challenge web server path 286 | - fix spelling in help text 287 | 288 | 2019-04-21 Nicola Di Lieto 289 | * First public release (1.0) 290 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | # This makefile is used only if you run GNU Make. 2 | # It is necessary if you want to build targets usually of interest 3 | # only to the maintainer. 4 | 5 | # Copyright (C) 2001, 2003, 2006-2012 Free Software Foundation, Inc. 6 | 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | # If the user runs GNU make but has not yet run ./configure, 21 | # give them a diagnostic. 22 | _gl-Makefile := $(wildcard [M]akefile) 23 | _gl-configure := $(wildcard [c]onfigure) 24 | ifneq ($(_gl-Makefile),) 25 | 26 | # Make tar archive easier to reproduce. 27 | export TAR_OPTIONS = --owner=0 --group=0 --numeric-owner 28 | 29 | # Allow the user to add to this in the Makefile. 30 | ALL_RECURSIVE_TARGETS = 31 | 32 | include Makefile 33 | 34 | _build-aux ?= build-aux 35 | _autoreconf ?= autoreconf -v 36 | 37 | # Ensure that $(VERSION) is up to date for dist-related targets, but not 38 | # for others: rerunning autoreconf and recompiling everything isn't cheap. 39 | _have-git-version-gen := \ 40 | $(shell test -f $(srcdir)/$(_build-aux)/git-version-gen && echo yes) 41 | ifeq ($(_have-git-version-gen)0,yes$(MAKELEVEL)) 42 | _is-dist-target ?= $(filter-out %clean, \ 43 | $(filter maintainer-% dist% alpha beta stable,$(MAKECMDGOALS))) 44 | _is-install-target ?= $(filter-out %check, $(filter install%,$(MAKECMDGOALS))) 45 | ifneq (,$(_is-dist-target)$(_is-install-target)) 46 | _curr-ver := $(shell cd $(srcdir) \ 47 | && $(_build-aux)/git-version-gen \ 48 | .tarball-version \ 49 | $(git-version-gen-tag-sed-script)) 50 | ifneq ($(_curr-ver),$(VERSION)) 51 | ifeq ($(_curr-ver),UNKNOWN) 52 | $(info WARNING: unable to verify if $(VERSION) is the correct version) 53 | else 54 | ifneq (,$(_is-install-target)) 55 | # GNU Coding Standards state that 'make install' should not cause 56 | # recompilation after 'make all'. But as long as changing the version 57 | # string alters config.h, the cost of having 'make all' always have an 58 | # up-to-date version is prohibitive. So, as a compromise, we merely 59 | # warn when installing a version string that is out of date; the user 60 | # should run 'autoreconf' (or something like 'make distcheck') to 61 | # fix the version, 'make all' to propagate it, then 'make install'. 62 | $(info WARNING: version string $(VERSION) is out of date;) 63 | $(info run '$(MAKE) _version' to fix it) 64 | else 65 | $(info INFO: running autoreconf for new version string: $(_curr-ver)) 66 | GNUmakefile: _version 67 | touch GNUmakefile 68 | endif 69 | endif 70 | endif 71 | endif 72 | endif 73 | 74 | .PHONY: _version 75 | _version: 76 | cd $(srcdir) && rm -rf autom4te.cache .version && $(_autoreconf) 77 | $(MAKE) $(AM_MAKEFLAGS) Makefile 78 | 79 | else 80 | ifneq ($(_gl-configure),) 81 | .DEFAULT_GOAL := abort-due-to-no-makefile 82 | else 83 | .DEFAULT_GOAL := abort-due-to-no-configure 84 | endif 85 | 86 | srcdir = . 87 | 88 | _build-aux ?= build-aux 89 | _autoreconf ?= autoreconf -v 90 | 91 | ifeq ($(.DEFAULT_GOAL),abort-due-to-no-makefile) 92 | $(MAKECMDGOALS): abort-due-to-no-makefile 93 | endif 94 | 95 | _have-git := $(shell command -v git >/dev/null 2>&1 && echo yes) 96 | ifeq ($(_have-git),yes) 97 | REPO := $(shell git remote get-url origin) 98 | else 99 | REPO := https://github.com/ndilieto/uacme 100 | endif 101 | 102 | abort-due-to-no-makefile: 103 | @echo There seems to be no Makefile in this directory. 1>&2 104 | @echo "You must run ./configure before running 'make'." 1>&2 105 | @exit 1 106 | 107 | abort-due-to-no-configure: 108 | @echo There seems to be no configure in this directory. 1>&2 109 | @echo "You must run 'autoreconf' and ./configure before running 'make'." 1>&2 110 | @echo "Alternatively consider checking out the latest release:" 1>&2 111 | @echo " git clone -b upstream/latest $(REPO)" 1>&2 112 | @exit 1 113 | 114 | endif 115 | 116 | # Tell version 3.79 and up of GNU make to not build goals in this 117 | # directory in parallel, in case someone tries to build multiple 118 | # targets, and one of them can cause a recursive target to be invoked. 119 | 120 | # Only set this if Automake doesn't provide it. 121 | AM_RECURSIVE_TARGETS ?= $(RECURSIVE_TARGETS:-recursive=) \ 122 | $(RECURSIVE_CLEAN_TARGETS:-recursive=) \ 123 | dist distcheck tags ctags 124 | 125 | ALL_RECURSIVE_TARGETS += $(AM_RECURSIVE_TARGETS) 126 | 127 | ifneq ($(word 2, $(MAKECMDGOALS)), ) 128 | ifneq ($(filter $(ALL_RECURSIVE_TARGETS), $(MAKECMDGOALS)), ) 129 | .NOTPARALLEL: 130 | endif 131 | endif 132 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019-2024 Nicola Di Lieto 2 | # 3 | # This file is part of uacme. 4 | # 5 | # uacme is free software: you can redistribute it and/or modify it 6 | # under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # uacme is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | ACLOCAL_AMFLAGS=-I build-aux/m4 19 | ARFLAGS=cr 20 | 21 | bin_PROGRAMS = uacme 22 | 23 | if ENABLE_UALPN 24 | bin_PROGRAMS += ualpn 25 | 26 | ualpn_SOURCES = ualpn.c base64.c base64.h log.c log.h sglib.h 27 | ualpn_CPPFLAGS = -DRUNSTATEDIR="\"${runstatedir}\"" 28 | -DSYSCONFDIR="\"${sysconfdir}\"" 29 | ualpn_CFLAGS = $(WCFLAGS) 30 | if ENABLE_LIBEV 31 | ualpn_SOURCES += libev/ev.h 32 | ualpn_CPPFLAGS += -Ilibev 33 | ualpn_LDADD = libev.a $(UALPN_LDADD) 34 | 35 | noinst_LIBRARIES = libev.a 36 | libev_a_SOURCES = libev/ev.c 37 | else 38 | ualpn_LDADD = $(UALPN_LDADD) 39 | endif 40 | endif 41 | 42 | uacme_SOURCES = uacme.c base64.c base64.h crypto.c crypto.h \ 43 | curlwrap.c curlwrap.h json.c json.h jsmn.h \ 44 | msg.c msg.h 45 | uacme_CPPFLAGS = -DRUNSTATEDIR="\"${runstatedir}\"" \ 46 | -DSYSCONFDIR="\"${sysconfdir}\"" \ 47 | $(CURL_CPPFLAGS) 48 | uacme_CFLAGS = $(CURL_CFLAGS) $(WCFLAGS) 49 | uacme_LDFLAGS = $(CURL_LDFLAGS) 50 | uacme_LDADD = $(CURL_LDADD) 51 | 52 | if ENABLE_READFILE 53 | uacme_SOURCES += read-file.c read-file.h 54 | endif 55 | 56 | BUILT_SOURCES = $(top_srcdir)/.version 57 | $(top_srcdir)/.version: 58 | echo $(VERSION) > $@-t && mv $@-t $@ 59 | 60 | dist-hook: 61 | echo $(VERSION) > $(distdir)/.tarball-version 62 | 63 | dist_pkgdata_SCRIPTS = uacme.sh nsupdate.sh 64 | if ENABLE_UALPN 65 | dist_pkgdata_SCRIPTS += ualpn.sh 66 | endif 67 | 68 | if ENABLE_DOCS 69 | dist_man1_MANS = uacme.1 70 | dist_html_DATA = docs/uacme.html 71 | 72 | if ENABLE_UALPN 73 | dist_man1_MANS += ualpn.1 74 | dist_html_DATA += docs/ualpn.html 75 | 76 | ualpn.1: ualpn.1.txt $(top_srcdir)/.version 77 | $(AM_V_GEN)$(A2X) -L -d manpage -f manpage \ 78 | -a revision=$(VERSION) \ 79 | -a sysconfdir="${sysconfdir}" \ 80 | -a runstatedir="${runstatedir}" $< 81 | 82 | docs/ualpn.html: ualpn.1.txt $(top_srcdir)/.version 83 | $(AM_V_GEN)$(ASCIIDOC) -d manpage -b html5 -o $@ \ 84 | -a revision=$(VERSION) \ 85 | -a sysconfdir="${sysconfdir}" \ 86 | -a runstatedir="${runstatedir}" $< 87 | endif 88 | 89 | uacme.1: uacme.1.txt $(top_srcdir)/.version 90 | $(AM_V_GEN)$(A2X) -L -d manpage -f manpage \ 91 | -a revision=$(VERSION) \ 92 | -a sysconfdir="${sysconfdir}" \ 93 | -a runstatedir="${runstatedir}" $< 94 | 95 | docs/uacme.html: uacme.1.txt $(top_srcdir)/.version 96 | $(AM_V_GEN)$(ASCIIDOC) -d manpage -b html5 -o $@ \ 97 | -a revision=$(VERSION) \ 98 | -a sysconfdir="${sysconfdir}" \ 99 | -a runstatedir="${runstatedir}" $< 100 | endif 101 | 102 | .PHONY: valgrind 103 | valgrind: uacme 104 | valgrind --tool=memcheck --leak-check=yes --show-reachable=yes \ 105 | --num-callers=20 --track-fds=yes --log-file=valgrind.log \ 106 | $(builddir)/uacme $(VALGRIND_UACME_ARGS) 107 | 108 | EXTRA_DIST = GNUmakefile build-aux/git-version-gen uacme.sh nsupdate.sh \ 109 | uacme.1.txt uacme.1 docs/uacme.html ualpn.1.txt ualpn.1 \ 110 | docs/ualpn.html libev/ev_epoll.c libev/ev_iouring.c \ 111 | libev/ev_kqueue.c libev/ev_linuxaio.c libev/ev_poll.c \ 112 | libev/ev_port.c libev/ev_select.c libev/ev_vars.h \ 113 | libev/ev_wrap.h README.md 114 | CLEANFILES = valgrind.log 115 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | uacme NEWS 2 | Copyright (C) 2019-2024 Nicola Di Lieto 3 | 4 | ## [1.7.6] - 2024-12-29 5 | ### Changed 6 | - Fix OpenSSL 3.x deprecated APIs 7 | - Fix cross compilation 8 | Closes https://github.com/ndilieto/uacme/issues/79 9 | - uacme: Add environment variables 10 | Closes https://github.com/ndilieto/uacme/issues/63 11 | - uacme: Add support for ACME Renewal Information (ARI) 12 | Closes https://github.com/ndilieto/uacme/issues/67 13 | - uacme: Try obtaining new Reply-Nonce if server doesn't supply one 14 | Closes https://github.com/ndilieto/uacme/issues/82 15 | - uacme: Add hook environment variables 16 | Closes https://github.com/ndilieto/uacme/issues/83 17 | - uacme: Allow matching alternative chain by Authority Key Id 18 | Closes https://github.com/ndilieto/uacme/issues/85 19 | - Documentation update 20 | - Add link to linode api hook 21 | 22 | ## [1.7.5] - 2024-01-28 23 | ### Changed 24 | - fix ualpn exit code in client mode 25 | Fixes https://github.com/ndilieto/uacme/issues/76 26 | - fix build with autoconf version 2.71 27 | See https://github.com/ndilieto/uacme/pull/70 28 | - uacme: nsupdate.sh overhaul and DNAME redirection support 29 | - add link to deSEC.io DNS integration 30 | - minor documentation changes including copyright year 31 | 32 | ## [1.7.4] - 2023-02-15 33 | ### Changed 34 | - uacme: Validate token from ACME server. Fixes 35 | https://github.com/ndilieto/uacme/issues/64 36 | - minor documentation changes including copyright year 37 | 38 | ## [1.7.3] - 2022-09-20 39 | ### Changed 40 | - better compatibility with LibreSSL, require 3.4.2 or later 41 | - uacme: Enable --must-staple support with LibreSSL > 3.5.0 42 | - ualpn: Fix build issue with mbedTLS 2.x 43 | see https://github.com/ndilieto/uacme/pull/61 44 | 45 | ## [1.7.2] - 2022-07-20 46 | ### Added 47 | - uacme: exponential backoff for status polling instead of 48 | constant 5s delay, to reduce load on server 49 | - uacme: -r option to allow specifying revocation code 50 | - compatibility with mbedTLS v3.2 51 | - compatibility with LibreSSL (with some limitations, 52 | see https://github.com/ndilieto/uacme/commit/32546c7c 53 | 54 | ### Changed 55 | - uacme: fix silent failure in nsupdate.sh 56 | closes https://github.com/ndilieto/uacme/issues/45 57 | - uacme: replace 'echo' with 'printf' in uacme.sh 58 | closes https://github.com/ndilieto/uacme/issues/48 59 | - uacme: fix compilation warning 60 | - embed ax_check_compile_flag.m4 from autoconf-archive as 61 | requested in https://github.com/ndilieto/uacme/pull/57 62 | - minor documentation changes including copyright year 63 | 64 | ## [1.7.1] - 2021-06-04 65 | ### Changed 66 | - uacme: fix issue when running from inaccessible directory 67 | closes https://github.com/ndilieto/uacme/issues/41 68 | - ualpn: use default user group when -u is specified 69 | 70 | ## [1.7] - 2021-01-17 71 | ### Added 72 | - uacme: alternate chain selection by certificate fingerprint 73 | - uacme: print copyright with version 74 | - ualpn: print copyright with version 75 | - ualpn: add notice with version on startup 76 | 77 | ### Changed 78 | - ualpn: reject duplicate options where appropriate 79 | - ualpn: make ualpn.sh always outputs to stderr 80 | - ualpn: fix compilation warning 81 | - minor changes (typos) 82 | - update copyright years 83 | 84 | ## [1.6] - 2020-12-06 85 | ### Added 86 | - uacme: support for RFC8555 External Account Binding 87 | closes https://github.com/ndilieto/uacme/issues/40 88 | 89 | ### Changed 90 | - uacme: fix use after free in surrogate strcasestr function 91 | - uacme: make nsupdate.sh accept quoted TXT challenge values 92 | - uacme: minor cosmetic changes to log messages 93 | 94 | ## [1.5] - 2020-07-26 95 | ### Added 96 | - uacme: -l option to allow selecting alternate chain 97 | - ualpn: mbedtls_x509_crt_parse_der_with_ext_cb support 98 | fixes https://github.com/ndilieto/uacme/issues/23 99 | 100 | ### Changed 101 | - ualpn: move signal calls to beginning 102 | 103 | ## [1.4.1] - 2020-05-30 104 | ### Changed 105 | - fix SIGPIPE of parent process in daemon mode 106 | https://github.com/ndilieto/uacme/issues/36 107 | 108 | ## [1.4] - 2020-05-30 109 | ### Changed 110 | - fix nsupdate.sh 111 | https://github.com/ndilieto/uacme/issues/32 112 | - uacme: warn that --must-staple is ignored with CSRFILE 113 | - ualpn: swap -p and -P command line switches 114 | - ualpn: increase key buffer size as required by OpenSSL 3.x 115 | - ualpn: fix minor OpenBSD portability issues 116 | - ualpn: fix library link order when using built-in libev 117 | - minor cosmetic code/documentation changes 118 | - README.md now included in distribution 119 | 120 | ## [1.3] - 2020-05-08 121 | ### Added 122 | - support for issuing certificates based on a CSR 123 | - mbedTLS implementation of OCSP check 124 | - nsupdate.sh dns-01 authentication script 125 | 126 | ### Changed 127 | - allow signing revocation requests with certificate key 128 | - improved handling of RFC8738 with OpenSSL/mbedTLS 129 | - fix memory leak in csr_gen upon some OpenSSL errors 130 | 131 | ## [1.2.4] - 2020-04-25 132 | ### Changed 133 | - improve mbedTLS detection in configure.ac 134 | - check format string arguments with GCC 135 | - ualpn: fix incorrect message arguments 136 | 137 | ## [1.2.3] - 2020-04-22 138 | ### Changed 139 | - fix Content-Type header parsing 140 | https://github.com/ndilieto/uacme/issues/22 141 | 142 | ## [1.2.2] - 2020-04-18 143 | ### Changed 144 | - fix ualpn socket type bug on uClibc based systems 145 | - fix configure.ac MAP_ANON cross-compilation test 146 | 147 | ## [1.2.1] - 2020-04-17 148 | ### Changed 149 | - increase cert buf size to cope with long identifiers 150 | - fix gcc8 -Wstringop-truncation warning 151 | 152 | ## [1.2] - 2020-04-15 153 | ### Added 154 | - uacme OCSP certificate status check 155 | - ualpn OpenSSL/mbedTLS implementations 156 | 157 | ### Changed 158 | - add key usage to ualpn challenge certificate 159 | - ensure top bit of ualpn certificate S/N is 0 with OpenSSL 160 | - fix ualpn memory leaks and corner case bugs 161 | - minor cosmetic code/documentation changes 162 | 163 | ## [1.1.2] - 2020-03-12 164 | ### Changed 165 | - fix configure.ac typo affecting LDFLAGS 166 | - fix missing PIPE_BUF when building on hurd-386 167 | 168 | ## [1.1.1] - 2020-03-12 169 | ### Changed 170 | - fix typo breaking build without HAVE_SPLICE 171 | - fix addr_t name collision on s390x 172 | 173 | ## [1.1] - 2020-03-11 174 | ### Added 175 | - IP identifier support (RFC8738) 176 | - tls-alpn-01 (RFC8737) challenge responder (ualpn) 177 | 178 | ## [1.0.22] - 2020-02-01 179 | ### Changed 180 | - relax account status check (compatibility with buypass.no) 181 | - allow client challenge retry requests (RFC8555 section 7.1.6) 182 | - add wildcard clarification in manpage 183 | 184 | ## [1.0.21] - 2020-01-12 185 | ### Changed 186 | - Quote variables in uacme.sh 187 | - Added LFS support (AC_SYS_LARGEFILE) 188 | 189 | ## [1.0.20] - 2019-10-03 190 | ### Changed 191 | - improved HTTP header parsing to fix problem that 192 | can happen when retrieving directory over HTTP/2 193 | 194 | ## [1.0.19] - 2019-09-30 195 | ### Changed 196 | - fix configure script bug when using explicit 197 | PKG_CONFIG environment variable 198 | - explicitly set key usage in certificate request 199 | 200 | ## [1.0.18] - 2019-08-29 201 | ### Added 202 | - support for OCSP Must-Staple (-m, --must-staple) 203 | 204 | ### Changed 205 | - explicitly set key usage constraints with mbedTLS 206 | - fix compilation warning with gcc7 on solaris 207 | 208 | ## [1.0.17] - 2019-07-03 209 | ### Changed 210 | - fix pedantic compilation warning 211 | - configure fails if pkg-config isn't found 212 | 213 | ## [1.0.16] - 2019-06-17 214 | ### Changed 215 | - configure script checks for libcurl HTTPS support 216 | - minor manpage corrections 217 | 218 | ## [1.0.15] - 2019-06-15 219 | ### Changed 220 | - exit with error if both -a and -s are specified 221 | - avoid depending on libtasn1 if gnutls_decode_rs_value is 222 | available (requires gnutls 3.6.0 or later) 223 | 224 | ## [1.0.14] - 2019-06-12 225 | ### Changed 226 | - Fix deprecated API when building with OpenSSL v1.1.1c 227 | 228 | ## [1.0.13] - 2019-06-05 229 | ### Changed 230 | - Disable mbedTLS runtime version check if not available 231 | 232 | ## [1.0.12] - 2019-05-18 233 | ### Changed 234 | - Ensure EC key params are always properly padded 235 | - Improved hook_run error checking 236 | 237 | ## [1.0.11] - 2019-05-17 238 | ### Added 239 | - Key rollover (https://tools.ietf.org/html/rfc8555#section-7.3.5) 240 | 241 | ### Changed 242 | - Revoked cert files now renamed to 'revoked-TIMESTAMP.pem' 243 | - Key auth contains SHA256 digest for tls-alpn-01 (like dns-01) 244 | - Minor logging improvements 245 | 246 | ## [1.0.10] - 2019-05-12 247 | ### Added 248 | - secp384r1 EC key support 249 | 250 | ### Changed 251 | - -b, --bits option accepts 256 or 384 for EC keys 252 | - enforce multiple of 8 RSA key size 253 | - improved acme_get and acme_post verbose logging 254 | - retry upon badNonce response according to RFC8555 6.5 255 | 256 | ## [1.0.9] - 2019-05-09 257 | ### Added 258 | - EC key/cert support (-t, --type=EC, default RSA) 259 | - RSA key length option (-b, --bits=BITS, default 2048) 260 | 261 | ## [1.0.8] - 2019-05-05 262 | ### Added 263 | - OpenSSL support (./configure --with-openssl) 264 | 265 | ### Changed 266 | - exit codes: 0=success, 1=cert issuance skipped, 2=error 267 | - mbedtls: dynamically grow buffers when needed 268 | 269 | ## [1.0.7] - 2019-04-29 270 | ### Added 271 | - HTTP User-Agent: header in all requests 272 | - --disable-docs configure option 273 | 274 | ### Changed 275 | - manpage version now updated automatically 276 | 277 | ## [1.0.6] - 2019-04-27 278 | ### Changed 279 | - fixed uninitialized variable in authorize() function 280 | 281 | ## [1.0.5] - 2019-04-27 282 | ### Changed 283 | - autoconf maintainer mode 284 | - cosmetic change to json primitive dump 285 | 286 | ## [1.0.4] - 2019-04-26 287 | ### Added 288 | - debian packaging 289 | 290 | ## [1.0.3] - 2019-04-25 291 | ### Changed 292 | - fixed gcc -pedantic warnings 293 | 294 | ## [1.0.2] - 2019-04-24 295 | ### Added 296 | - support for mbedTLS (./configure --with-mbedtls) 297 | 298 | ## [1.0.1] - 2019-04-21 299 | ### Changed 300 | - minor fixes to links in documentation 301 | 302 | ## [1.0] - 2019-04-21 303 | ### Added 304 | - first public release 305 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | uacme README 2 | Copyright (C) 2019-2024 Nicola Di Lieto 3 | 4 | uacme is a client for the RFC8555 ACMEv2 protocol. Additional 5 | information can be found at 6 | and the manual pages at 7 | and 8 | 9 | 10 | README 11 | ------ 12 | This README is targeted for users of the software who build from 13 | sources but do not necessarily develop. 14 | 15 | 16 | COMPILATION 17 | ----------- 18 | A typical command sequence for building uacme is shown below. 19 | A complete list of options available for configure can be found 20 | by running './configure --help'. 21 | 22 | cd uacme- 23 | ./configure 24 | make 25 | sudo make install 26 | 27 | The software depends on libcurl and one of GnuTLS, OpenSSL or 28 | mbedTLS 29 | 30 | * libcurl: the multiprotocol file transfer library 31 | https://curl.haxx.se/libcurl 32 | * GnuTLS: for cryptographic algorithms 33 | https://gnutls.org 34 | * OpenSSL: alternative to GnuTLS 35 | https://www.openssl.org 36 | * mbedTLS: lightweight alternative to GnuTLS 37 | https://tls.mbed.org 38 | 39 | 40 | DOCUMENTATION 41 | ------------- 42 | See README.md and the manual pages included in the distribution 43 | (uacme.1 or uacme.1.html and ualpn.1 or ualpn.1.html) 44 | 45 | 46 | LICENSING 47 | --------- 48 | See the COPYING file for licensing information 49 | 50 | 51 | BUGS 52 | ---- 53 | If you believe you have found a bug, please create a new issue 54 | at https://github.com/ndilieto/uacme/issues with any applicable 55 | information. 56 | 57 | Applicable information would include why the issue is a uacme bug (if 58 | not readily apparent), output from 'uname -a', the version of uacme 59 | being used, a stack trace if available ('bt full' if under gdb or 60 | valgrind output), and perhaps a network trace. Vague queries or 61 | piecemeal messages are difficult to act upon and don't help the 62 | development effort. 63 | 64 | 65 | PATCHES 66 | ------- 67 | Patches are welcome and encouraged. Patches can be submitted by 68 | creating a pull request at https://github.com/ndilieto/uacme/pulls 69 | 70 | When submitting patches, please be sure to use sources from the git 71 | repository, and preferrably from the master branch. To create a patch 72 | for the project from a local git repository, please use the following 73 | commands. 'uacme' should be the local directory of a previous git clone. 74 | 75 | cd uacme 76 | git add the-file-you-modified.c another-file.c 77 | git commit the-file-you-modified.c another-file.c 78 | 79 | For more information on use of Git, visit http://git-scm.com/ 80 | 81 | 82 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | Thanks are due to the following 2 | 3 | * Serge Zaitsev 4 | for jsmn, the world's fastest JSON parser/tokenizer. 5 | 6 | * The authors of libsodium 7 | for the base64 encoding/decoding routines. 8 | 9 | * Marc Alexander Lehmann 10 | for libev 11 | 12 | * Marian Vittek 13 | for SGLIB 16 | for the nsupdate.sh DNS-01 challenge hook script 17 | 18 | * The authors of libcurl 19 | 20 | * The authors of GnuTLS 21 | 22 | * The authors of OpenSSL 23 | 24 | * The authors of mbedTLS 25 | 26 | (this list may not be complete, if you think something is missing 27 | please submit a pull request!) 28 | -------------------------------------------------------------------------------- /base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "base64.h" 31 | 32 | /* Base64 routines adapted from https://www.libsodium.org */ 33 | 34 | /* 35 | * ISC License 36 | * 37 | * Copyright (c) 2013-2017 38 | * Frank Denis 39 | * 40 | * Permission to use, copy, modify, and/or distribute this software for any 41 | * purpose with or without fee is hereby granted, provided that the above 42 | * copyright notice and this permission notice appear in all copies. 43 | * 44 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 45 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 46 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 47 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 48 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 49 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 50 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 51 | */ 52 | 53 | /* Derived from original code by CodesInChaos */ 54 | char *bin2hex(char *const hex, const size_t hex_maxlen, 55 | const unsigned char *const bin, const size_t bin_len) 56 | { 57 | size_t i = (size_t) 0U; 58 | unsigned int x; 59 | int b; 60 | int c; 61 | 62 | if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { 63 | errx(2, "bin2hex length wrong"); 64 | } 65 | while (i < bin_len) { 66 | c = bin[i] & 0xf; 67 | b = bin[i] >> 4; 68 | x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | 69 | (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); 70 | hex[i * 2U] = (char) x; 71 | x >>= 8; 72 | hex[i * 2U + 1U] = (char) x; 73 | i++; 74 | } 75 | hex[i * 2U] = 0U; 76 | 77 | return hex; 78 | } 79 | 80 | int hex2bin(unsigned char *const bin, const size_t bin_maxlen, 81 | const char *const hex, const size_t hex_len, 82 | const char *const ignore, size_t *const bin_len, 83 | const char **const hex_end) 84 | { 85 | size_t bin_pos = (size_t) 0U; 86 | size_t hex_pos = (size_t) 0U; 87 | int ret = 0; 88 | unsigned char c; 89 | unsigned char c_acc = 0U; 90 | unsigned char c_alpha0, c_alpha; 91 | unsigned char c_num0, c_num; 92 | unsigned char c_val; 93 | unsigned char state = 0U; 94 | 95 | while (hex_pos < hex_len) { 96 | c = (unsigned char) hex[hex_pos]; 97 | c_num = c ^ 48U; 98 | c_num0 = (c_num - 10U) >> 8; 99 | c_alpha = (c & ~32U) - 55U; 100 | c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8; 101 | if ((c_num0 | c_alpha0) == 0U) { 102 | if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) { 103 | hex_pos++; 104 | continue; 105 | } 106 | break; 107 | } 108 | c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha); 109 | if (bin_pos >= bin_maxlen) { 110 | ret = -1; 111 | errno = ERANGE; 112 | break; 113 | } 114 | if (state == 0U) { 115 | c_acc = c_val * 16U; 116 | } else { 117 | bin[bin_pos++] = c_acc | c_val; 118 | } 119 | state = ~state; 120 | hex_pos++; 121 | } 122 | if (state != 0U) { 123 | hex_pos--; 124 | errno = EINVAL; 125 | ret = -1; 126 | } 127 | if (ret != 0) { 128 | bin_pos = (size_t) 0U; 129 | } 130 | if (hex_end != NULL) { 131 | *hex_end = &hex[hex_pos]; 132 | } else if (hex_pos != hex_len) { 133 | errno = EINVAL; 134 | ret = -1; 135 | } 136 | if (bin_len != NULL) { 137 | *bin_len = bin_pos; 138 | } 139 | return ret; 140 | } 141 | 142 | /* 143 | * Some macros for constant-time comparisons. These work over values in 144 | * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". 145 | * 146 | * Original code by Thomas Pornin. 147 | */ 148 | #define EQ(x, y) \ 149 | ((((0U - ((unsigned int) (x) ^ (unsigned int) (y))) >> 8) & 0xFF) ^ 0xFF) 150 | #define GT(x, y) ((((unsigned int) (y) - (unsigned int) (x)) >> 8) & 0xFF) 151 | #define GE(x, y) (GT(y, x) ^ 0xFF) 152 | #define LT(x, y) GT(y, x) 153 | #define LE(x, y) GE(y, x) 154 | 155 | static int b64_byte_to_char(unsigned int x) 156 | { 157 | return (LT(x, 26) & (x + 'A')) | 158 | (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | 159 | (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | 160 | (EQ(x, 63) & '/'); 161 | } 162 | 163 | static unsigned int b64_char_to_byte(int c) 164 | { 165 | const unsigned int x = 166 | (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | 167 | (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | 168 | (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | 169 | (EQ(c, '/') & 63); 170 | 171 | return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); 172 | } 173 | 174 | static int b64_byte_to_urlsafe_char(unsigned int x) 175 | { 176 | return (LT(x, 26) & (x + 'A')) | 177 | (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | 178 | (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '-') | 179 | (EQ(x, 63) & '_'); 180 | } 181 | 182 | static unsigned int b64_urlsafe_char_to_byte(int c) 183 | { 184 | const unsigned x = 185 | (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | 186 | (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | 187 | (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '-') & 62) | 188 | (EQ(c, '_') & 63); 189 | 190 | return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); 191 | } 192 | 193 | #define VARIANT_NO_PADDING_MASK 0x2U 194 | #define VARIANT_URLSAFE_MASK 0x4U 195 | 196 | static void base64_check_variant(const int variant) 197 | { 198 | if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) 199 | { 200 | errx(2, "base64_check_variant: invalid variant"); 201 | } 202 | } 203 | 204 | size_t base64_encoded_len(const size_t bin_len, const int variant) 205 | { 206 | base64_check_variant(variant); 207 | return base64_ENCODED_LEN(bin_len, variant); 208 | } 209 | 210 | char *bin2base64(char * const b64, const size_t b64_maxlen, 211 | const unsigned char * const bin, const size_t bin_len, 212 | const int variant) 213 | { 214 | size_t acc_len = (size_t) 0; 215 | size_t b64_len; 216 | size_t b64_pos = (size_t) 0; 217 | size_t bin_pos = (size_t) 0; 218 | size_t nibbles; 219 | size_t remainder; 220 | unsigned int acc = 0U; 221 | 222 | base64_check_variant(variant); 223 | nibbles = bin_len / 3; 224 | remainder = bin_len - 3 * nibbles; 225 | b64_len = nibbles * 4; 226 | if (remainder != 0) { 227 | if ((((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) { 228 | b64_len += 4; 229 | } else { 230 | b64_len += 2 + (remainder >> 1); 231 | } 232 | } 233 | if (b64_maxlen <= b64_len) 234 | { 235 | errx(2, "bin2base64: maxlen < len"); 236 | } 237 | if ((((unsigned int) variant) & VARIANT_URLSAFE_MASK) != 0U) { 238 | while (bin_pos < bin_len) { 239 | acc = (acc << 8) + bin[bin_pos++]; 240 | acc_len += 8; 241 | while (acc_len >= 6) { 242 | acc_len -= 6; 243 | b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc >> acc_len) & 0x3F); 244 | } 245 | } 246 | if (acc_len > 0) { 247 | b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc << (6 - acc_len)) & 0x3F); 248 | } 249 | } else { 250 | while (bin_pos < bin_len) { 251 | acc = (acc << 8) + bin[bin_pos++]; 252 | acc_len += 8; 253 | while (acc_len >= 6) { 254 | acc_len -= 6; 255 | b64[b64_pos++] = (char) b64_byte_to_char((acc >> acc_len) & 0x3F); 256 | } 257 | } 258 | if (acc_len > 0) { 259 | b64[b64_pos++] = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); 260 | } 261 | } 262 | assert(b64_pos <= b64_len); 263 | while (b64_pos < b64_len) { 264 | b64[b64_pos++] = '='; 265 | } 266 | do { 267 | b64[b64_pos++] = 0U; 268 | } while (b64_pos < b64_maxlen); 269 | 270 | return b64; 271 | } 272 | 273 | static int _base642bin_skip_padding(const char * const b64, 274 | const size_t b64_len, size_t * const b64_pos_p, 275 | const char * const ignore, size_t padding_len) 276 | { 277 | int c; 278 | 279 | while (padding_len > 0) { 280 | if (*b64_pos_p >= b64_len) { 281 | errno = ERANGE; 282 | return -1; 283 | } 284 | c = b64[*b64_pos_p]; 285 | if (c == '=') { 286 | padding_len--; 287 | } else if (ignore == NULL || strchr(ignore, c) == NULL) { 288 | errno = EINVAL; 289 | return -1; 290 | } 291 | (*b64_pos_p)++; 292 | } 293 | return 0; 294 | } 295 | 296 | int base642bin(unsigned char * const bin, const size_t bin_maxlen, 297 | const char * const b64, const size_t b64_len, 298 | const char * const ignore, size_t * const bin_len, 299 | const char ** const b64_end, const int variant) 300 | { 301 | size_t acc_len = (size_t) 0; 302 | size_t b64_pos = (size_t) 0; 303 | size_t bin_pos = (size_t) 0; 304 | int is_urlsafe; 305 | int ret = 0; 306 | unsigned int acc = 0U; 307 | unsigned int d; 308 | char c; 309 | 310 | base64_check_variant(variant); 311 | is_urlsafe = ((unsigned int) variant) & VARIANT_URLSAFE_MASK; 312 | while (b64_pos < b64_len) { 313 | c = b64[b64_pos]; 314 | if (is_urlsafe) { 315 | d = b64_urlsafe_char_to_byte(c); 316 | } else { 317 | d = b64_char_to_byte(c); 318 | } 319 | if (d == 0xFF) { 320 | if (ignore != NULL && strchr(ignore, c) != NULL) { 321 | b64_pos++; 322 | continue; 323 | } 324 | break; 325 | } 326 | acc = (acc << 6) + d; 327 | acc_len += 6; 328 | if (acc_len >= 8) { 329 | acc_len -= 8; 330 | if (bin_pos >= bin_maxlen) { 331 | errno = ERANGE; 332 | ret = -1; 333 | break; 334 | } 335 | bin[bin_pos++] = (acc >> acc_len) & 0xFF; 336 | } 337 | b64_pos++; 338 | } 339 | if (acc_len > 4U || (acc & ((1U << acc_len) - 1U)) != 0U) { 340 | ret = -1; 341 | } else if (ret == 0 && 342 | (((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) { 343 | ret = _base642bin_skip_padding(b64, b64_len, &b64_pos, ignore, 344 | acc_len / 2); 345 | } 346 | if (ret != 0) { 347 | bin_pos = (size_t) 0U; 348 | } else if (ignore != NULL) { 349 | while (b64_pos < b64_len && strchr(ignore, b64[b64_pos]) != NULL) { 350 | b64_pos++; 351 | } 352 | } 353 | if (b64_end != NULL) { 354 | *b64_end = &b64[b64_pos]; 355 | } else if (b64_pos != b64_len) { 356 | errno = EINVAL; 357 | ret = -1; 358 | } 359 | if (bin_len != NULL) { 360 | *bin_len = bin_pos; 361 | } 362 | return ret; 363 | } 364 | 365 | char *encode_base64url(const char *str) 366 | { 367 | size_t encoded_len = base64_ENCODED_LEN(strlen(str), 368 | base64_VARIANT_URLSAFE_NO_PADDING); 369 | char *encoded = calloc(1, encoded_len); 370 | if (!encoded) 371 | return NULL; 372 | return bin2base64(encoded, encoded_len, (const unsigned char *)str, 373 | strlen(str), base64_VARIANT_URLSAFE_NO_PADDING); 374 | } 375 | 376 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef base64_H 22 | #define base64_H 23 | 24 | #include 25 | 26 | /* Base64 routines adapted from https://www.libsodium.org */ 27 | 28 | /* 29 | * ISC License 30 | * 31 | * Copyright (c) 2013-2017 32 | * Frank Denis 33 | * 34 | * Permission to use, copy, modify, and/or distribute this software for any 35 | * purpose with or without fee is hereby granted, provided that the above 36 | * copyright notice and this permission notice appear in all copies. 37 | * 38 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 39 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 41 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 42 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 43 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 44 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 45 | */ 46 | 47 | char *bin2hex(char * const hex, const size_t hex_maxlen, 48 | const unsigned char * const bin, const size_t bin_len) 49 | __attribute__ ((nonnull(1))); 50 | 51 | int hex2bin(unsigned char * const bin, const size_t bin_maxlen, 52 | const char * const hex, const size_t hex_len, 53 | const char * const ignore, size_t * const bin_len, 54 | const char ** const hex_end) 55 | __attribute__ ((nonnull(1))); 56 | 57 | #define base64_VARIANT_ORIGINAL 1 58 | #define base64_VARIANT_ORIGINAL_NO_PADDING 3 59 | #define base64_VARIANT_URLSAFE 5 60 | #define base64_VARIANT_URLSAFE_NO_PADDING 7 61 | 62 | /* 63 | * Computes the required length to encode BIN_LEN bytes as a base64 string 64 | * using the given variant. The computed length includes a trailing \0. 65 | */ 66 | #define base64_ENCODED_LEN(BIN_LEN, VARIANT) \ 67 | (((BIN_LEN) / 3U) * 4U + \ 68 | ((((BIN_LEN) - ((BIN_LEN) / 3U) * 3U) | (((BIN_LEN) - ((BIN_LEN) / 3U) * 3U) >> 1)) & 1U) * \ 69 | (4U - (~((((VARIANT) & 2U) >> 1) - 1U) & (3U - ((BIN_LEN) - ((BIN_LEN) / 3U) * 3U)))) + 1U) 70 | 71 | size_t base64_encoded_len(const size_t bin_len, const int variant); 72 | 73 | char *bin2base64(char * const b64, const size_t b64_maxlen, 74 | const unsigned char * const bin, const size_t bin_len, 75 | const int variant) __attribute__ ((nonnull(1))); 76 | 77 | int base642bin(unsigned char * const bin, const size_t bin_maxlen, 78 | const char * const b64, const size_t b64_len, 79 | const char * const ignore, size_t * const bin_len, 80 | const char ** const b64_end, const int variant) 81 | __attribute__ ((nonnull(1))); 82 | 83 | char *encode_base64url(const char *str); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /build-aux/ar-lib: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for Microsoft lib.exe 3 | 4 | me=ar-lib 5 | scriptversion=2012-03-01.08; # UTC 6 | 7 | # Copyright (C) 2010-2014 Free Software Foundation, Inc. 8 | # Written by Peter Rosin . 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | # This file is maintained in Automake, please report 29 | # bugs to or send patches to 30 | # . 31 | 32 | 33 | # func_error message 34 | func_error () 35 | { 36 | echo "$me: $1" 1>&2 37 | exit 1 38 | } 39 | 40 | file_conv= 41 | 42 | # func_file_conv build_file 43 | # Convert a $build file to $host form and store it in $file 44 | # Currently only supports Windows hosts. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv in 65 | mingw) 66 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 67 | ;; 68 | cygwin) 69 | file=`cygpath -m "$file" || echo "$file"` 70 | ;; 71 | wine) 72 | file=`winepath -w "$file" || echo "$file"` 73 | ;; 74 | esac 75 | ;; 76 | esac 77 | } 78 | 79 | # func_at_file at_file operation archive 80 | # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE 81 | # for each of them. 82 | # When interpreting the content of the @FILE, do NOT use func_file_conv, 83 | # since the user would need to supply preconverted file names to 84 | # binutils ar, at least for MinGW. 85 | func_at_file () 86 | { 87 | operation=$2 88 | archive=$3 89 | at_file_contents=`cat "$1"` 90 | eval set x "$at_file_contents" 91 | shift 92 | 93 | for member 94 | do 95 | $AR -NOLOGO $operation:"$member" "$archive" || exit $? 96 | done 97 | } 98 | 99 | case $1 in 100 | '') 101 | func_error "no command. Try '$0 --help' for more information." 102 | ;; 103 | -h | --h*) 104 | cat <. 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /build-aux/git-version-gen: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Print a version string. 3 | scriptversion=2010-10-13.20; # UTC 4 | 5 | # Copyright (C) 2007-2010 Free Software Foundation, Inc. 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | # This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. 21 | # It may be run two ways: 22 | # - from a git repository in which the "git describe" command below 23 | # produces useful output (thus requiring at least one signed tag) 24 | # - from a non-git-repo directory containing a .tarball-version file, which 25 | # presumes this script is invoked like "./git-version-gen .tarball-version". 26 | 27 | # In order to use intra-version strings in your project, you will need two 28 | # separate generated version string files: 29 | # 30 | # .tarball-version - present only in a distribution tarball, and not in 31 | # a checked-out repository. Created with contents that were learned at 32 | # the last time autoconf was run, and used by git-version-gen. Must not 33 | # be present in either $(srcdir) or $(builddir) for git-version-gen to 34 | # give accurate answers during normal development with a checked out tree, 35 | # but must be present in a tarball when there is no version control system. 36 | # Therefore, it cannot be used in any dependencies. GNUmakefile has 37 | # hooks to force a reconfigure at distribution time to get the value 38 | # correct, without penalizing normal development with extra reconfigures. 39 | # 40 | # .version - present in a checked-out repository and in a distribution 41 | # tarball. Usable in dependencies, particularly for files that don't 42 | # want to depend on config.h but do want to track version changes. 43 | # Delete this file prior to any autoconf run where you want to rebuild 44 | # files to pick up a version string change; and leave it stale to 45 | # minimize rebuild time after unrelated changes to configure sources. 46 | # 47 | # It is probably wise to add these two files to .gitignore, so that you 48 | # don't accidentally commit either generated file. 49 | # 50 | # Use the following line in your configure.ac, so that $(VERSION) will 51 | # automatically be up-to-date each time configure is run (and note that 52 | # since configure.ac no longer includes a version string, Makefile rules 53 | # should not depend on configure.ac for version updates). 54 | # 55 | # AC_INIT([GNU project], 56 | # m4_esyscmd([build-aux/git-version-gen .tarball-version]), 57 | # [bug-project@example]) 58 | # 59 | # Then use the following lines in your Makefile.am, so that .version 60 | # will be present for dependencies, and so that .tarball-version will 61 | # exist in distribution tarballs. 62 | # 63 | # BUILT_SOURCES = $(top_srcdir)/.version 64 | # $(top_srcdir)/.version: 65 | # echo $(VERSION) > $@-t && mv $@-t $@ 66 | # dist-hook: 67 | # echo $(VERSION) > $(distdir)/.tarball-version 68 | 69 | case $# in 70 | 1|2) ;; 71 | *) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version" \ 72 | '[TAG-NORMALIZATION-SED-SCRIPT]' 73 | exit 1;; 74 | esac 75 | 76 | tarball_version_file=$1 77 | tag_sed_script="${2:-s/x/x/}" 78 | nl=' 79 | ' 80 | 81 | # Avoid meddling by environment variable of the same name. 82 | v= 83 | 84 | # First see if there is a tarball-only version file. 85 | # then try "git describe", then default. 86 | if test -f $tarball_version_file 87 | then 88 | v=`cat $tarball_version_file` || exit 1 89 | case $v in 90 | *$nl*) v= ;; # reject multi-line output 91 | [0-9]*) ;; 92 | *) v= ;; 93 | esac 94 | test -z "$v" \ 95 | && echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2 96 | fi 97 | 98 | if test -n "$v" 99 | then 100 | : # use $v 101 | # Otherwise, if there is at least one git commit involving the working 102 | # directory, and "git describe" output looks sensible, use that to 103 | # derive a version string. 104 | elif test "`git log -1 --pretty=format:x . 2>&1`" = x \ 105 | && v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \ 106 | || git describe --abbrev=4 HEAD 2>/dev/null` \ 107 | && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ 108 | && case $v in 109 | v[0-9]*) ;; 110 | *) (exit 1) ;; 111 | esac 112 | then 113 | # Is this a new git that lists number of commits since the last 114 | # tag or the previous older version that did not? 115 | # Newer: v6.10-77-g0f8faeb 116 | # Older: v6.10-g0f8faeb 117 | case $v in 118 | *-*-*) : git describe is okay three part flavor ;; 119 | *-*) 120 | : git describe is older two part flavor 121 | # Recreate the number of commits and rewrite such that the 122 | # result is the same as if we were using the newer version 123 | # of git describe. 124 | vtag=`echo "$v" | sed 's/-.*//'` 125 | numcommits=`git rev-list "$vtag"..HEAD | wc -l` 126 | v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; 127 | ;; 128 | esac 129 | 130 | # Change the first '-' to '-dev-'. 131 | # Remove the "g" in git describe's output string, to save a byte. 132 | v=`echo "$v" | sed 's/-/-dev-/;s/\(.*\)-g/\1-/'`; 133 | else 134 | v=UNKNOWN 135 | fi 136 | 137 | v=`echo "$v" |sed 's/^v//'` 138 | 139 | # Don't declare a version "dirty" merely because a time stamp has changed. 140 | git update-index --refresh > /dev/null 2>&1 141 | 142 | dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty= 143 | case "$dirty" in 144 | '') ;; 145 | *) # Append the suffix only if there isn't one already. 146 | case $v in 147 | *-dirty) ;; 148 | *) v="$v-dirty" ;; 149 | esac ;; 150 | esac 151 | 152 | # Omit the trailing newline, so that m4_esyscmd can use the result directly. 153 | echo "$v" | tr -d "$nl" 154 | 155 | # Local variables: 156 | # eval: (add-hook 'write-file-hooks 'time-stamp) 157 | # time-stamp-start: "scriptversion=" 158 | # time-stamp-format: "%:y-%02m-%02d.%02H" 159 | # time-stamp-time-zone: "UTC" 160 | # time-stamp-end: "; # UTC" 161 | # End: 162 | -------------------------------------------------------------------------------- /build-aux/m4/ax_check_compile_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_COMPILE_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 4 59 | 60 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 61 | [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 65 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 66 | AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 70 | AS_VAR_IF(CACHEVAR,yes, 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_COMPILE_FLAGS 75 | -------------------------------------------------------------------------------- /build-aux/m4/ax_check_enable_debug.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for the presence of an --enable-debug option to configure, with 12 | # the specified default value used when the option is not present. Return 13 | # the value in the variable $ax_enable_debug. 14 | # 15 | # Specifying 'yes' adds '-g -O0' to the compilation flags for all 16 | # languages. Specifying 'info' adds '-g' to the compilation flags. 17 | # Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to 18 | # the linking flags. Otherwise, nothing is added. 19 | # 20 | # Define the variables listed in the second argument if debug is enabled, 21 | # defaulting to no variables. Defines the variables listed in the third 22 | # argument if debug is disabled, defaulting to NDEBUG. All lists of 23 | # variables should be space-separated. 24 | # 25 | # If debug is not enabled, ensure AC_PROG_* will not add debugging flags. 26 | # Should be invoked prior to any AC_PROG_* compiler checks. 27 | # 28 | # IS-RELEASE can be used to change the default to 'no' when making a 29 | # release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it 30 | # uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE 31 | # macro, there is no need to pass this parameter. 32 | # 33 | # AX_IS_RELEASE([git-directory]) 34 | # AX_CHECK_ENABLE_DEBUG() 35 | # 36 | # LICENSE 37 | # 38 | # Copyright (c) 2011 Rhys Ulerich 39 | # Copyright (c) 2014, 2015 Philip Withnall 40 | # 41 | # Copying and distribution of this file, with or without modification, are 42 | # permitted in any medium without royalty provided the copyright notice 43 | # and this notice are preserved. 44 | 45 | #serial 9 46 | 47 | AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ 48 | AC_BEFORE([$0],[AC_PROG_CC])dnl 49 | AC_BEFORE([$0],[AC_PROG_CXX])dnl 50 | AC_BEFORE([$0],[AC_PROG_F77])dnl 51 | AC_BEFORE([$0],[AC_PROG_FC])dnl 52 | 53 | AC_MSG_CHECKING(whether to enable debugging) 54 | 55 | ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1]))) 56 | ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],, 57 | [$ax_is_release], 58 | [$4]))) 59 | 60 | # If this is a release, override the default. 61 | AS_IF([test "$ax_enable_debug_is_release" = "yes"], 62 | [ax_enable_debug_default="no"]) 63 | 64 | m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))]) 65 | m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))]) 66 | 67 | AC_ARG_ENABLE(debug, 68 | [AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])], 69 | [],enable_debug=$ax_enable_debug_default) 70 | 71 | # empty mean debug yes 72 | AS_IF([test "x$enable_debug" = "x"], 73 | [enable_debug="yes"]) 74 | 75 | # case of debug 76 | AS_CASE([$enable_debug], 77 | [yes],[ 78 | AC_MSG_RESULT(yes) 79 | CFLAGS="${CFLAGS} -g -O0" 80 | CXXFLAGS="${CXXFLAGS} -g -O0" 81 | FFLAGS="${FFLAGS} -g -O0" 82 | FCFLAGS="${FCFLAGS} -g -O0" 83 | OBJCFLAGS="${OBJCFLAGS} -g -O0" 84 | ], 85 | [info],[ 86 | AC_MSG_RESULT(info) 87 | CFLAGS="${CFLAGS} -g" 88 | CXXFLAGS="${CXXFLAGS} -g" 89 | FFLAGS="${FFLAGS} -g" 90 | FCFLAGS="${FCFLAGS} -g" 91 | OBJCFLAGS="${OBJCFLAGS} -g" 92 | ], 93 | [profile],[ 94 | AC_MSG_RESULT(profile) 95 | CFLAGS="${CFLAGS} -g -pg" 96 | CXXFLAGS="${CXXFLAGS} -g -pg" 97 | FFLAGS="${FFLAGS} -g -pg" 98 | FCFLAGS="${FCFLAGS} -g -pg" 99 | OBJCFLAGS="${OBJCFLAGS} -g -pg" 100 | LDFLAGS="${LDFLAGS} -pg" 101 | ], 102 | [ 103 | AC_MSG_RESULT(no) 104 | dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags 105 | dnl by setting any unset environment flag variables 106 | AS_IF([test "x${CFLAGS+set}" != "xset"], 107 | [CFLAGS=""]) 108 | AS_IF([test "x${CXXFLAGS+set}" != "xset"], 109 | [CXXFLAGS=""]) 110 | AS_IF([test "x${FFLAGS+set}" != "xset"], 111 | [FFLAGS=""]) 112 | AS_IF([test "x${FCFLAGS+set}" != "xset"], 113 | [FCFLAGS=""]) 114 | AS_IF([test "x${OBJCFLAGS+set}" != "xset"], 115 | [OBJCFLAGS=""]) 116 | ]) 117 | 118 | dnl Define various variables if debugging is disabled. 119 | dnl assert.h is a NOP if NDEBUG is defined, so define it by default. 120 | AS_IF([test "x$enable_debug" = "xyes"], 121 | [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,[1],[Define if debugging is enabled])])], 122 | [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,[1],[Define if debugging is disabled])])]) 123 | ax_enable_debug=$enable_debug 124 | ]) 125 | -------------------------------------------------------------------------------- /build-aux/m4/ax_is_release.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_is_release.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_IS_RELEASE(POLICY) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Determine whether the code is being configured as a release, or from 12 | # git. Set the ax_is_release variable to 'yes' or 'no'. 13 | # 14 | # If building a release version, it is recommended that the configure 15 | # script disable compiler errors and debug features, by conditionalising 16 | # them on the ax_is_release variable. If building from git, these 17 | # features should be enabled. 18 | # 19 | # The POLICY parameter specifies how ax_is_release is determined. It can 20 | # take the following values: 21 | # 22 | # * git-directory: ax_is_release will be 'no' if a '.git' 23 | # directory or git worktree exists 24 | # * minor-version: ax_is_release will be 'no' if the minor version number 25 | # in $PACKAGE_VERSION is odd; this assumes 26 | # $PACKAGE_VERSION follows the 'major.minor.micro' scheme 27 | # * micro-version: ax_is_release will be 'no' if the micro version number 28 | # in $PACKAGE_VERSION is odd; this assumes 29 | # $PACKAGE_VERSION follows the 'major.minor.micro' scheme 30 | # * dash-version: ax_is_release will be 'no' if there is a dash '-' 31 | # in $PACKAGE_VERSION, for example 1.2-pre3, 1.2.42-a8b9 32 | # or 2.0-dirty (in particular this is suitable for use 33 | # with git-version-gen) 34 | # * always: ax_is_release will always be 'yes' 35 | # * never: ax_is_release will always be 'no' 36 | # 37 | # Other policies may be added in future. 38 | # 39 | # LICENSE 40 | # 41 | # Copyright (c) 2015 Philip Withnall 42 | # Copyright (c) 2016 Collabora Ltd. 43 | # 44 | # Copying and distribution of this file, with or without modification, are 45 | # permitted in any medium without royalty provided the copyright notice 46 | # and this notice are preserved. 47 | 48 | #serial 8 49 | 50 | AC_DEFUN([AX_IS_RELEASE],[ 51 | AC_BEFORE([AC_INIT],[$0]) 52 | 53 | m4_case([$1], 54 | [git-directory],[ 55 | # $is_release = (.git directory does not exist) 56 | AS_IF([test -d ${srcdir}/.git || (test -f ${srcdir}/.git && grep \.git/worktrees ${srcdir}/.git)],[ax_is_release=no],[ax_is_release=yes]) 57 | ], 58 | [minor-version],[ 59 | # $is_release = ($minor_version is even) 60 | minor_version=`echo "$PACKAGE_VERSION" | sed 's/[[^.]][[^.]]*.\([[^.]][[^.]]*\).*/\1/'` 61 | AS_IF([test "$(( $minor_version % 2 ))" -ne 0], 62 | [ax_is_release=no],[ax_is_release=yes]) 63 | ], 64 | [micro-version],[ 65 | # $is_release = ($micro_version is even) 66 | micro_version=`echo "$PACKAGE_VERSION" | sed 's/[[^.]]*\.[[^.]]*\.\([[^.]]*\).*/\1/'` 67 | AS_IF([test "$(( $micro_version % 2 ))" -ne 0], 68 | [ax_is_release=no],[ax_is_release=yes]) 69 | ], 70 | [dash-version],[ 71 | # $is_release = ($PACKAGE_VERSION has a dash) 72 | AS_CASE([$PACKAGE_VERSION], 73 | [*-*], [ax_is_release=no], 74 | [*], [ax_is_release=yes]) 75 | ], 76 | [always],[ax_is_release=yes], 77 | [never],[ax_is_release=no], 78 | [ 79 | AC_MSG_ERROR([Invalid policy. Valid policies: git-directory, minor-version, micro-version, dash-version, always, never.]) 80 | ]) 81 | ]) 82 | -------------------------------------------------------------------------------- /build-aux/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2013 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /crypto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef __CRYPTO_H__ 22 | #define __CRYPTO_H__ 23 | 24 | #include 25 | 26 | #if defined(USE_GNUTLS) 27 | #if defined(USE_OPENSSL) || defined(USE_MBEDTLS) 28 | #error only one of USE_GNUTLS, USE_MBEDTLS or USE_OPENSSL must be defined 29 | #endif 30 | #include 31 | 32 | typedef gnutls_privkey_t privkey_t; 33 | #define privkey_deinit gnutls_privkey_deinit 34 | 35 | #elif defined(USE_OPENSSL) 36 | #if defined(USE_GNUTLS) || defined(USE_MBEDTLS) 37 | #error only one of USE_GNUTLS, USE_MBEDTLS or USE_OPENSSL must be defined 38 | #endif 39 | #include 40 | 41 | typedef EVP_PKEY *privkey_t; 42 | #define privkey_deinit EVP_PKEY_free 43 | 44 | #elif defined(USE_MBEDTLS) 45 | #if defined(USE_OPENSSL) || defined(USE_GNUTLS) 46 | #error only one of USE_GNUTLS, USE_MBEDTLS or USE_OPENSSL must be defined 47 | #endif 48 | #include 49 | 50 | typedef mbedtls_pk_context *privkey_t; 51 | static inline void privkey_deinit(privkey_t key) 52 | { 53 | mbedtls_pk_free(key); 54 | free(key); 55 | } 56 | 57 | #else 58 | #error either USE_GNUTLS or USE_MBEDTLS or USE_OPENSSL must be defined 59 | #endif 60 | 61 | typedef enum 62 | { 63 | PK_NONE = 0, 64 | PK_RSA, 65 | PK_EC 66 | } keytype_t; 67 | 68 | bool crypto_init(void); 69 | void crypto_deinit(void); 70 | char *sha2_base64url(size_t, const char *, ...); 71 | char *hmac_base64url(size_t, const char *, const char *, ...); 72 | char *jws_jwk(privkey_t key, const char **, const char **); 73 | char *jws_protected_jwk(const char *, const char *, privkey_t); 74 | char *jws_protected_kid(const char *, const char *, const char *, privkey_t); 75 | char *jws_protected_eab(size_t, const char *, const char *); 76 | char *jws_thumbprint(privkey_t); 77 | char *jws_encode(const char *, const char *, privkey_t); 78 | char *jws_encode_hmac(const char *, const char *, size_t, const char *); 79 | keytype_t key_type(privkey_t); 80 | privkey_t key_load(keytype_t, int bits, const char *, ...); 81 | bool is_ip(const char *, unsigned char *, size_t *); 82 | char *csr_gen(char * const *, bool, bool, privkey_t); 83 | char *csr_load(const char *, char ***); 84 | char *cert_der_base64url(const char *); 85 | bool cert_valid(const char *, char * const *, const char *, int, bool); 86 | bool cert_match(const char *, unsigned char *, size_t); 87 | 88 | #if !HAVE_STRCASESTR 89 | char *strcasestr(const char *haystack, const char *needle); 90 | #endif 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /curlwrap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #include "config.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "curlwrap.h" 30 | #include "msg.h" 31 | 32 | curldata_t *curldata_calloc(void) 33 | { 34 | curldata_t *c = calloc(1, sizeof(curldata_t)); 35 | if (!c) { 36 | warn("curldata_calloc: calloc failed"); 37 | return NULL; 38 | } 39 | c->body = strdup(""); 40 | if (!c->body) { 41 | warn("curldata_calloc: strdup failed"); 42 | free(c); 43 | return NULL; 44 | } 45 | c->headers = strdup(""); 46 | if (!c->headers) { 47 | warn("curldata_calloc: strdup failed"); 48 | free(c->body); 49 | free(c); 50 | return NULL; 51 | } 52 | return c; 53 | } 54 | 55 | void curldata_free(curldata_t *c) 56 | { 57 | if (!c) 58 | return; 59 | free(c->body); 60 | free(c->headers); 61 | free(c); 62 | } 63 | 64 | static size_t curl_hcb(char *buf, size_t size, size_t n, void *userdata) 65 | { 66 | curldata_t *c = (curldata_t *)userdata; 67 | void *p = realloc(c->headers, c->headers_len + size * n + 1); 68 | if (!p) { 69 | warn("curl_hcb: realloc failed"); 70 | return 0; 71 | } 72 | c->headers = p; 73 | memcpy(c->headers + c->headers_len, buf, size * n); 74 | c->headers_len += size * n; 75 | c->headers[c->headers_len] = 0; 76 | return size * n; 77 | } 78 | 79 | static size_t curl_wcb(void *ptr, size_t size, size_t n, void *userdata) 80 | { 81 | curldata_t *c = (curldata_t *)userdata; 82 | void *p = realloc(c->body, c->body_len + size * n + 1); 83 | if (!p) { 84 | warn("curl_wcb: realloc failed"); 85 | return 0; 86 | } 87 | c->body = p; 88 | memcpy(c->body + c->body_len, ptr, size * n); 89 | c->body_len += size * n; 90 | c->body[c->body_len] = 0; 91 | return size * n; 92 | } 93 | 94 | static void curl_env(CURL *curl) 95 | { 96 | const char *cainfo = getenv("UACME_CAINFO"); 97 | const char *capath = getenv("UACME_CAPATH"); 98 | const char *dnssrv = getenv("UACME_DNS_SERVERS"); 99 | const char *iface = getenv("UACME_INTERFACE"); 100 | const char *proxy = getenv("UACME_PROXY"); 101 | 102 | curl_easy_setopt(curl, CURLOPT_USERAGENT, 103 | "uacme/" VERSION " (https://github.com/ndilieto/uacme)"); 104 | if (g_loglevel > 3) 105 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 106 | if (cainfo) 107 | curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo); 108 | if (capath) 109 | curl_easy_setopt(curl, CURLOPT_CAPATH, capath); 110 | if (dnssrv) 111 | curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, dnssrv); 112 | if (iface) 113 | curl_easy_setopt(curl, CURLOPT_INTERFACE, iface); 114 | if (proxy) 115 | curl_easy_setopt(curl, CURLOPT_PROXY, proxy); 116 | } 117 | 118 | curldata_t *curl_get(const char *url) 119 | { 120 | curldata_t *c = NULL; 121 | for (int retry = 0; retry < 3; retry++) { 122 | CURL *curl; 123 | CURLcode res; 124 | curl = curl_easy_init(); 125 | if (!curl) { 126 | warnx("curl_get: curl_easy_init failed"); 127 | return NULL; 128 | } 129 | c = curldata_calloc(); 130 | if (!c) { 131 | warnx("curl_get: curldata_calloc failed"); 132 | curl_easy_cleanup(curl); 133 | return NULL; 134 | } 135 | curl_env(curl); 136 | curl_easy_setopt(curl, CURLOPT_URL, url); 137 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_wcb); 138 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, c); 139 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_hcb); 140 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, c); 141 | res = curl_easy_perform(curl); 142 | if (res != CURLE_OK) { 143 | warnx("curl_get: GET %s failed: %s", url, 144 | curl_easy_strerror(res)); 145 | curldata_free(c); 146 | c = NULL; 147 | } else { 148 | long code = -1; 149 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); 150 | c->code = code; 151 | } 152 | curl_easy_cleanup(curl); 153 | if (c) 154 | break; 155 | else if (retry < 3) { 156 | warnx("curl_get: waiting 5 seconds before retrying"); 157 | sleep(5); 158 | } 159 | } 160 | return c; 161 | } 162 | 163 | curldata_t *curl_post(const char *url, void *post_data, size_t post_size, 164 | const char *header, ...) 165 | { 166 | va_list ap; 167 | curldata_t *c = NULL; 168 | for (int retry = 0; retry < 3; retry++) { 169 | CURL *curl; 170 | CURLcode res; 171 | struct curl_slist *list = NULL; 172 | curl = curl_easy_init(); 173 | if (!curl) { 174 | warnx("curl_post: curl_easy_init failed"); 175 | return NULL; 176 | } 177 | c = curldata_calloc(); 178 | if (!c) { 179 | warnx("curl_post: curldata_calloc failed"); 180 | curl_easy_cleanup(curl); 181 | return NULL; 182 | } 183 | curl_env(curl); 184 | curl_easy_setopt(curl, CURLOPT_URL, url); 185 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_wcb); 186 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, c); 187 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_hcb); 188 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, c); 189 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); 190 | curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_size); 191 | va_start(ap, header); 192 | while (header) { 193 | list = curl_slist_append(list, header); 194 | header = va_arg(ap, const char *); 195 | } 196 | va_end(ap); 197 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); 198 | res = curl_easy_perform(curl); 199 | curl_slist_free_all(list); 200 | if (res != CURLE_OK) { 201 | warnx("curl_post: POST %s failed: %s", url, 202 | curl_easy_strerror(res)); 203 | curldata_free(c); 204 | c = NULL; 205 | } else { 206 | long code = -1; 207 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); 208 | c->code = code; 209 | } 210 | curl_easy_cleanup(curl); 211 | if (c) 212 | break; 213 | else if (retry < 3) { 214 | warnx("curl_post: waiting 5 seconds before retrying"); 215 | sleep(5); 216 | } 217 | } 218 | return c; 219 | } 220 | 221 | char *find_header(const char *headers, const char *name) 222 | { 223 | char *regex = NULL; 224 | if (asprintf(®ex, "^%s:[ \t]*(.*)\r\n", name) < 0) { 225 | warnx("find_header: asprintf failed"); 226 | return NULL; 227 | } 228 | char *ret = NULL; 229 | regex_t reg; 230 | if (regcomp(®, regex, REG_EXTENDED | REG_ICASE | REG_NEWLINE)) { 231 | warnx("find_header: regcomp failed"); 232 | } else { 233 | regmatch_t m[2]; 234 | if (regexec(®, headers, 2, m, 0) == 0) { 235 | ret = strndup(headers + m[1].rm_so, m[1].rm_eo - m[1].rm_so); 236 | if (!ret) 237 | warn("find_header: strndup failed"); 238 | } 239 | } 240 | free(regex); 241 | regfree(®); 242 | return ret; 243 | } 244 | -------------------------------------------------------------------------------- /curlwrap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef __CURLWRAP_H__ 22 | #define __CURLWRAP_H__ 23 | #include 24 | 25 | typedef struct { 26 | char *body; 27 | size_t body_len; 28 | char *headers; 29 | size_t headers_len; 30 | int code; 31 | } curldata_t; 32 | 33 | curldata_t *curldata_calloc(void); 34 | void curldata_free(curldata_t *c); 35 | curldata_t *curl_get(const char *url); 36 | curldata_t *curl_post(const char *url, void *post_data, size_t post_size, 37 | const char *header, ...); 38 | char *find_header(const char *headers, const char *name); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Redirecting to uacme.html 4 | 5 | 6 | -------------------------------------------------------------------------------- /json.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #include "config.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "json.h" 30 | #include "jsmn.h" 31 | 32 | static int json_build(const char *js, jsmntok_t *t, size_t count, 33 | json_value_t *value) { 34 | int i, j, k; 35 | if (count <= 0) 36 | return 0; 37 | switch (t->type) { 38 | case JSMN_PRIMITIVE: 39 | value->type = JSON_PRIMITIVE; 40 | value->v.value = strndup(js+t->start, t->end - t->start); 41 | if (!value->v.value) { 42 | warn("json_build: strndup failed"); 43 | return -1; 44 | } 45 | return 1; 46 | 47 | case JSMN_STRING: 48 | value->type = JSON_STRING; 49 | value->v.value = strndup(js+t->start, t->end - t->start); 50 | if (!value->v.value) { 51 | warn("json_build: strndup failed"); 52 | return -1; 53 | } 54 | return 1; 55 | 56 | case JSMN_OBJECT: 57 | value->type = JSON_OBJECT; 58 | value->v.object.size = t->size; 59 | value->v.object.names = calloc(t->size, sizeof(json_value_t)); 60 | value->v.object.values = calloc(t->size, sizeof(json_value_t)); 61 | if (!value->v.object.names || !value->v.object.values) { 62 | warn("json_build: calloc failed"); 63 | return -1; 64 | } 65 | for (j = i = 0; i < t->size; i++) { 66 | value->v.object.names[i].parent = value; 67 | value->v.object.values[i].parent = value; 68 | k = json_build(js, t+1+j, count-j, value->v.object.names+i); 69 | if (k < 0) return k; else j += k; 70 | k = json_build(js, t+1+j, count-j, value->v.object.values+i); 71 | if (k < 0) return k; else j += k; 72 | } 73 | return j+1; 74 | 75 | case JSMN_ARRAY: 76 | value->type = JSON_ARRAY; 77 | value->v.array.size = t->size; 78 | value->v.array.values = calloc(t->size, sizeof(json_value_t)); 79 | if (!value->v.array.values) { 80 | warn("json_build: calloc failed"); 81 | return -1; 82 | } 83 | for (j = i = 0; i < t->size; i++) { 84 | value->v.array.values[i].parent = value; 85 | k = json_build(js, t+1+j, count-j, value->v.array.values+i); 86 | if (k < 0) return k; else j += k; 87 | } 88 | return j+1; 89 | 90 | default: 91 | value->type = JSON_UNDEFINED; 92 | return 0; 93 | } 94 | } 95 | 96 | static void _json_dump(FILE *f, const json_value_t *value, size_t indent) 97 | { 98 | size_t i,j; 99 | if (!value) return; 100 | switch (value->type) { 101 | case JSON_PRIMITIVE: 102 | fprintf(f, "%s", value->v.value); 103 | return; 104 | 105 | case JSON_STRING: 106 | fprintf(f, "\"%s\"", value->v.value); 107 | return; 108 | 109 | case JSON_OBJECT: 110 | fprintf(f, "{\n"); 111 | for (i = 0; i < value->v.object.size; i++) { 112 | for (j=0; j<4*(indent+1); j++) fputc(' ', f); 113 | _json_dump(f, value->v.object.names+i, indent + 1); 114 | fprintf(f, ": "); 115 | _json_dump(f, value->v.object.values+i, indent + 1); 116 | if (i < value->v.object.size - 1) fputc(',', f); 117 | fputc('\n', f); 118 | } 119 | for (j=0; j<4*indent; j++) fputc(' ', f); 120 | fputc('}', f); 121 | if (indent == 0) 122 | fputc('\n', f); 123 | return; 124 | 125 | case JSON_ARRAY: 126 | fprintf(f, "[\n"); 127 | for (i = 0; i < value->v.array.size; i++) { 128 | for (j=0; j<4*(indent+1); j++) fputc(' ', f); 129 | _json_dump(f, value->v.array.values+i, indent + 1); 130 | if (i < value->v.array.size - 1) fputc(',', f); 131 | fputc('\n', f); 132 | } 133 | for (j=0; j<4*indent; j++) fputc(' ', f); 134 | fputc(']', f); 135 | if (indent == 0) 136 | fputc('\n', f); 137 | return; 138 | 139 | default: 140 | return; 141 | } 142 | } 143 | 144 | void json_dump(FILE *f, const json_value_t *value) 145 | { 146 | _json_dump(f, value, 0); 147 | } 148 | 149 | void json_free(json_value_t *value) 150 | { 151 | size_t i; 152 | if (!value) return; 153 | switch (value->type) { 154 | case JSON_PRIMITIVE: 155 | case JSON_STRING: 156 | free(value->v.value); 157 | break; 158 | 159 | case JSON_OBJECT: 160 | for (i = 0; i < value->v.object.size; i++) { 161 | json_free(value->v.object.names+i); 162 | json_free(value->v.object.values+i); 163 | } 164 | free(value->v.object.names); 165 | free(value->v.object.values); 166 | break; 167 | 168 | case JSON_ARRAY: 169 | for (i = 0; i < value->v.array.size; i++) 170 | json_free(value->v.array.values+i); 171 | free(value->v.array.values); 172 | break; 173 | 174 | default: 175 | break; 176 | } 177 | if (!value->parent) 178 | free(value); 179 | } 180 | 181 | const json_value_t *json_find(const json_value_t *haystack, 182 | const char *needle) 183 | { 184 | if (!haystack || haystack->type != JSON_OBJECT) 185 | return NULL; 186 | for (size_t i=0; iv.object.size; i++) 187 | if (strcmp(haystack->v.object.names[i].v.value, needle) == 0) 188 | return haystack->v.object.values + i; 189 | return NULL; 190 | } 191 | 192 | const char *json_find_value(const json_value_t *haystack, 193 | const char *needle) 194 | { 195 | if (!haystack || haystack->type != JSON_OBJECT) 196 | return NULL; 197 | for (size_t i=0; iv.object.size; i++) 198 | if (haystack->v.object.values[i].type == JSON_PRIMITIVE && 199 | strcmp(haystack->v.object.names[i].v.value, needle) == 0) 200 | return haystack->v.object.values[i].v.value; 201 | return NULL; 202 | } 203 | 204 | const char *json_find_string(const json_value_t *haystack, 205 | const char *needle) 206 | { 207 | if (!haystack || haystack->type != JSON_OBJECT) 208 | return NULL; 209 | for (size_t i=0; iv.object.size; i++) 210 | if (haystack->v.object.values[i].type == JSON_STRING && 211 | strcmp(haystack->v.object.names[i].v.value, needle) == 0) 212 | return haystack->v.object.values[i].v.value; 213 | return NULL; 214 | } 215 | 216 | int json_compare_string(const json_value_t *haystack, const char *name, 217 | const char *value) 218 | { 219 | const char *tmp = json_find_string(haystack, name); 220 | if (tmp) 221 | return strcmp(tmp, value); 222 | else 223 | return INT_MIN; 224 | } 225 | 226 | json_value_t *json_parse(const char *body, size_t body_len) 227 | { 228 | json_value_t *ret = NULL; 229 | jsmn_parser parser; 230 | unsigned int tok_len = 2; 231 | jsmntok_t *tok = calloc(tok_len, sizeof(*tok)); 232 | if (!tok) { 233 | warn("json_parse: calloc failed"); 234 | return NULL; 235 | } 236 | jsmn_init(&parser); 237 | while (1) { 238 | int r = jsmn_parse(&parser, body, body_len, tok, tok_len); 239 | if (r < 0) { 240 | if (r == JSMN_ERROR_NOMEM) { 241 | void *p = realloc(tok, sizeof(*tok) * tok_len * 2); 242 | if (!p) { 243 | warn("json_parse: realloc failed"); 244 | break; 245 | } 246 | tok_len *= 2; 247 | tok = p; 248 | } else { 249 | warnx("json_parse: jsmn_parse failed with code %d", r); 250 | break; 251 | } 252 | } else { 253 | ret = calloc(1, sizeof(json_value_t)); 254 | if (!ret) { 255 | warn("json_parse: calloc failed"); 256 | break; 257 | } 258 | json_build(body, tok, parser.toknext, ret); 259 | break; 260 | } 261 | } 262 | free(tok); 263 | return ret; 264 | } 265 | -------------------------------------------------------------------------------- /json.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef __JSON_H__ 22 | #define __JSON_H__ 23 | 24 | typedef enum { 25 | JSON_UNDEFINED = 0, 26 | JSON_OBJECT = 1, 27 | JSON_ARRAY = 2, 28 | JSON_STRING = 3, 29 | JSON_PRIMITIVE = 4 30 | } json_type_t; 31 | 32 | struct json_value; 33 | 34 | typedef struct json_object { 35 | size_t size; 36 | struct json_value *names; 37 | struct json_value *values; 38 | } json_object_t; 39 | 40 | typedef struct json_array { 41 | size_t size; 42 | struct json_value *values; 43 | } json_array_t; 44 | 45 | typedef struct json_value { 46 | json_type_t type; 47 | union 48 | { 49 | json_object_t object; 50 | json_array_t array; 51 | char *value; 52 | } v; 53 | struct json_value *parent; 54 | } json_value_t; 55 | 56 | json_value_t *json_parse(const char *body, size_t body_len); 57 | void json_dump(FILE *f, const json_value_t *value); 58 | void json_free(json_value_t *value); 59 | const json_value_t *json_find(const json_value_t *haystack, 60 | const char *needle); 61 | const char *json_find_value(const json_value_t *haystack, 62 | const char *needle); 63 | const char *json_find_string(const json_value_t *haystack, 64 | const char *needle); 65 | int json_compare_string(const json_value_t *haystack, 66 | const char *name, const char *value); 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /libev/ev_epoll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev epoll fd activity backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2016,2017,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | /* 41 | * general notes about epoll: 42 | * 43 | * a) epoll silently removes fds from the fd set. as nothing tells us 44 | * that an fd has been removed otherwise, we have to continually 45 | * "rearm" fds that we suspect *might* have changed (same 46 | * problem with kqueue, but much less costly there). 47 | * b) the fact that ADD != MOD creates a lot of extra syscalls due to a) 48 | * and seems not to have any advantage. 49 | * c) the inability to handle fork or file descriptors (think dup) 50 | * limits the applicability over poll, so this is not a generic 51 | * poll replacement. 52 | * d) epoll doesn't work the same as select with many file descriptors 53 | * (such as files). while not critical, no other advanced interface 54 | * seems to share this (rather non-unixy) limitation. 55 | * e) epoll claims to be embeddable, but in practise you never get 56 | * a ready event for the epoll fd (broken: <=2.6.26, working: >=2.6.32). 57 | * f) epoll_ctl returning EPERM means the fd is always ready. 58 | * 59 | * lots of "weird code" and complication handling in this file is due 60 | * to these design problems with epoll, as we try very hard to avoid 61 | * epoll_ctl syscalls for common usage patterns and handle the breakage 62 | * ensuing from receiving events for closed and otherwise long gone 63 | * file descriptors. 64 | */ 65 | 66 | #include 67 | 68 | #define EV_EMASK_EPERM 0x80 69 | 70 | static void 71 | epoll_modify (EV_P_ int fd, int oev, int nev) 72 | { 73 | struct epoll_event ev; 74 | unsigned char oldmask; 75 | 76 | /* 77 | * we handle EPOLL_CTL_DEL by ignoring it here 78 | * on the assumption that the fd is gone anyways 79 | * if that is wrong, we have to handle the spurious 80 | * event in epoll_poll. 81 | * if the fd is added again, we try to ADD it, and, if that 82 | * fails, we assume it still has the same eventmask. 83 | */ 84 | if (!nev) 85 | return; 86 | 87 | oldmask = anfds [fd].emask; 88 | anfds [fd].emask = nev; 89 | 90 | /* store the generation counter in the upper 32 bits, the fd in the lower 32 bits */ 91 | ev.data.u64 = (uint64_t)(uint32_t)fd 92 | | ((uint64_t)(uint32_t)++anfds [fd].egen << 32); 93 | ev.events = (nev & EV_READ ? EPOLLIN : 0) 94 | | (nev & EV_WRITE ? EPOLLOUT : 0); 95 | 96 | if (ecb_expect_true (!epoll_ctl (backend_fd, oev && oldmask != nev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &ev))) 97 | return; 98 | 99 | if (ecb_expect_true (errno == ENOENT)) 100 | { 101 | /* if ENOENT then the fd went away, so try to do the right thing */ 102 | if (!nev) 103 | goto dec_egen; 104 | 105 | if (!epoll_ctl (backend_fd, EPOLL_CTL_ADD, fd, &ev)) 106 | return; 107 | } 108 | else if (ecb_expect_true (errno == EEXIST)) 109 | { 110 | /* EEXIST means we ignored a previous DEL, but the fd is still active */ 111 | /* if the kernel mask is the same as the new mask, we assume it hasn't changed */ 112 | if (oldmask == nev) 113 | goto dec_egen; 114 | 115 | if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev)) 116 | return; 117 | } 118 | else if (ecb_expect_true (errno == EPERM)) 119 | { 120 | /* EPERM means the fd is always ready, but epoll is too snobbish */ 121 | /* to handle it, unlike select or poll. */ 122 | anfds [fd].emask = EV_EMASK_EPERM; 123 | 124 | /* add fd to epoll_eperms, if not already inside */ 125 | if (!(oldmask & EV_EMASK_EPERM)) 126 | { 127 | array_needsize (int, epoll_eperms, epoll_epermmax, epoll_epermcnt + 1, array_needsize_noinit); 128 | epoll_eperms [epoll_epermcnt++] = fd; 129 | } 130 | 131 | return; 132 | } 133 | else 134 | assert (("libev: I/O watcher with invalid fd found in epoll_ctl", errno != EBADF && errno != ELOOP && errno != EINVAL)); 135 | 136 | fd_kill (EV_A_ fd); 137 | 138 | dec_egen: 139 | /* we didn't successfully call epoll_ctl, so decrement the generation counter again */ 140 | --anfds [fd].egen; 141 | } 142 | 143 | static void 144 | epoll_poll (EV_P_ ev_tstamp timeout) 145 | { 146 | int i; 147 | int eventcnt; 148 | 149 | if (ecb_expect_false (epoll_epermcnt)) 150 | timeout = EV_TS_CONST (0.); 151 | 152 | /* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */ 153 | /* the default libev max wait time, however. */ 154 | EV_RELEASE_CB; 155 | eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, EV_TS_TO_MSEC (timeout)); 156 | EV_ACQUIRE_CB; 157 | 158 | if (ecb_expect_false (eventcnt < 0)) 159 | { 160 | if (errno != EINTR) 161 | ev_syserr ("(libev) epoll_wait"); 162 | 163 | return; 164 | } 165 | 166 | for (i = 0; i < eventcnt; ++i) 167 | { 168 | struct epoll_event *ev = epoll_events + i; 169 | 170 | int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */ 171 | int want = anfds [fd].events; 172 | int got = (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0) 173 | | (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0); 174 | 175 | /* 176 | * check for spurious notification. 177 | * this only finds spurious notifications on egen updates 178 | * other spurious notifications will be found by epoll_ctl, below 179 | * we assume that fd is always in range, as we never shrink the anfds array 180 | */ 181 | if (ecb_expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32))) 182 | { 183 | /* recreate kernel state */ 184 | postfork |= 2; 185 | continue; 186 | } 187 | 188 | if (ecb_expect_false (got & ~want)) 189 | { 190 | anfds [fd].emask = want; 191 | 192 | /* 193 | * we received an event but are not interested in it, try mod or del 194 | * this often happens because we optimistically do not unregister fds 195 | * when we are no longer interested in them, but also when we get spurious 196 | * notifications for fds from another process. this is partially handled 197 | * above with the gencounter check (== our fd is not the event fd), and 198 | * partially here, when epoll_ctl returns an error (== a child has the fd 199 | * but we closed it). 200 | * note: for events such as POLLHUP, where we can't know whether it refers 201 | * to EV_READ or EV_WRITE, we might issue redundant EPOLL_CTL_MOD calls. 202 | */ 203 | ev->events = (want & EV_READ ? EPOLLIN : 0) 204 | | (want & EV_WRITE ? EPOLLOUT : 0); 205 | 206 | /* pre-2.6.9 kernels require a non-null pointer with EPOLL_CTL_DEL, */ 207 | /* which is fortunately easy to do for us. */ 208 | if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev)) 209 | { 210 | postfork |= 2; /* an error occurred, recreate kernel state */ 211 | continue; 212 | } 213 | } 214 | 215 | fd_event (EV_A_ fd, got); 216 | } 217 | 218 | /* if the receive array was full, increase its size */ 219 | if (ecb_expect_false (eventcnt == epoll_eventmax)) 220 | { 221 | ev_free (epoll_events); 222 | epoll_eventmax = array_nextsize (sizeof (struct epoll_event), epoll_eventmax, epoll_eventmax + 1); 223 | epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); 224 | } 225 | 226 | /* now synthesize events for all fds where epoll fails, while select works... */ 227 | for (i = epoll_epermcnt; i--; ) 228 | { 229 | int fd = epoll_eperms [i]; 230 | unsigned char events = anfds [fd].events & (EV_READ | EV_WRITE); 231 | 232 | if (anfds [fd].emask & EV_EMASK_EPERM && events) 233 | fd_event (EV_A_ fd, events); 234 | else 235 | { 236 | epoll_eperms [i] = epoll_eperms [--epoll_epermcnt]; 237 | anfds [fd].emask = 0; 238 | } 239 | } 240 | } 241 | 242 | static int 243 | epoll_epoll_create (void) 244 | { 245 | int fd; 246 | 247 | #if defined EPOLL_CLOEXEC && !defined __ANDROID__ 248 | fd = epoll_create1 (EPOLL_CLOEXEC); 249 | 250 | if (fd < 0 && (errno == EINVAL || errno == ENOSYS)) 251 | #endif 252 | { 253 | fd = epoll_create (256); 254 | 255 | if (fd >= 0) 256 | fcntl (fd, F_SETFD, FD_CLOEXEC); 257 | } 258 | 259 | return fd; 260 | } 261 | 262 | inline_size 263 | int 264 | epoll_init (EV_P_ int flags) 265 | { 266 | if ((backend_fd = epoll_epoll_create ()) < 0) 267 | return 0; 268 | 269 | backend_mintime = EV_TS_CONST (1e-3); /* epoll does sometimes return early, this is just to avoid the worst */ 270 | backend_modify = epoll_modify; 271 | backend_poll = epoll_poll; 272 | 273 | epoll_eventmax = 64; /* initial number of events receivable per poll */ 274 | epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); 275 | 276 | return EVBACKEND_EPOLL; 277 | } 278 | 279 | inline_size 280 | void 281 | epoll_destroy (EV_P) 282 | { 283 | ev_free (epoll_events); 284 | array_free (epoll_eperm, EMPTY); 285 | } 286 | 287 | ecb_cold 288 | static void 289 | epoll_fork (EV_P) 290 | { 291 | close (backend_fd); 292 | 293 | while ((backend_fd = epoll_epoll_create ()) < 0) 294 | ev_syserr ("(libev) epoll_create"); 295 | 296 | fd_rearm_all (EV_A); 297 | } 298 | 299 | -------------------------------------------------------------------------------- /libev/ev_kqueue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev kqueue backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2016,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | inline_speed 47 | void 48 | kqueue_change (EV_P_ int fd, int filter, int flags, int fflags) 49 | { 50 | ++kqueue_changecnt; 51 | array_needsize (struct kevent, kqueue_changes, kqueue_changemax, kqueue_changecnt, array_needsize_noinit); 52 | 53 | EV_SET (&kqueue_changes [kqueue_changecnt - 1], fd, filter, flags, fflags, 0, 0); 54 | } 55 | 56 | /* OS X at least needs this */ 57 | #ifndef EV_ENABLE 58 | # define EV_ENABLE 0 59 | #endif 60 | #ifndef NOTE_EOF 61 | # define NOTE_EOF 0 62 | #endif 63 | 64 | static void 65 | kqueue_modify (EV_P_ int fd, int oev, int nev) 66 | { 67 | if (oev != nev) 68 | { 69 | if (oev & EV_READ) 70 | kqueue_change (EV_A_ fd, EVFILT_READ , EV_DELETE, 0); 71 | 72 | if (oev & EV_WRITE) 73 | kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_DELETE, 0); 74 | } 75 | 76 | /* to detect close/reopen reliably, we have to re-add */ 77 | /* event requests even when oev == nev */ 78 | 79 | if (nev & EV_READ) 80 | kqueue_change (EV_A_ fd, EVFILT_READ , EV_ADD | EV_ENABLE, NOTE_EOF); 81 | 82 | if (nev & EV_WRITE) 83 | kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, NOTE_EOF); 84 | } 85 | 86 | static void 87 | kqueue_poll (EV_P_ ev_tstamp timeout) 88 | { 89 | int res, i; 90 | struct timespec ts; 91 | 92 | /* need to resize so there is enough space for errors */ 93 | if (kqueue_changecnt > kqueue_eventmax) 94 | { 95 | ev_free (kqueue_events); 96 | kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_changecnt); 97 | kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); 98 | } 99 | 100 | EV_RELEASE_CB; 101 | EV_TS_SET (ts, timeout); 102 | res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts); 103 | EV_ACQUIRE_CB; 104 | kqueue_changecnt = 0; 105 | 106 | if (ecb_expect_false (res < 0)) 107 | { 108 | if (errno != EINTR) 109 | ev_syserr ("(libev) kqueue kevent"); 110 | 111 | return; 112 | } 113 | 114 | for (i = 0; i < res; ++i) 115 | { 116 | int fd = kqueue_events [i].ident; 117 | 118 | if (ecb_expect_false (kqueue_events [i].flags & EV_ERROR)) 119 | { 120 | int err = kqueue_events [i].data; 121 | 122 | /* we are only interested in errors for fds that we are interested in :) */ 123 | if (anfds [fd].events) 124 | { 125 | if (err == ENOENT) /* resubmit changes on ENOENT */ 126 | kqueue_modify (EV_A_ fd, 0, anfds [fd].events); 127 | else if (err == EBADF) /* on EBADF, we re-check the fd */ 128 | { 129 | if (fd_valid (fd)) 130 | kqueue_modify (EV_A_ fd, 0, anfds [fd].events); 131 | else 132 | { 133 | assert (("libev: kqueue found invalid fd", 0)); 134 | fd_kill (EV_A_ fd); 135 | } 136 | } 137 | else /* on all other errors, we error out on the fd */ 138 | { 139 | assert (("libev: kqueue found invalid fd", 0)); 140 | fd_kill (EV_A_ fd); 141 | } 142 | } 143 | } 144 | else 145 | fd_event ( 146 | EV_A_ 147 | fd, 148 | kqueue_events [i].filter == EVFILT_READ ? EV_READ 149 | : kqueue_events [i].filter == EVFILT_WRITE ? EV_WRITE 150 | : 0 151 | ); 152 | } 153 | 154 | if (ecb_expect_false (res == kqueue_eventmax)) 155 | { 156 | ev_free (kqueue_events); 157 | kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_eventmax + 1); 158 | kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); 159 | } 160 | } 161 | 162 | inline_size 163 | int 164 | kqueue_init (EV_P_ int flags) 165 | { 166 | /* initialize the kernel queue */ 167 | kqueue_fd_pid = getpid (); 168 | if ((backend_fd = kqueue ()) < 0) 169 | return 0; 170 | 171 | fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */ 172 | 173 | backend_mintime = EV_TS_CONST (1e-9); /* apparently, they did the right thing in freebsd */ 174 | backend_modify = kqueue_modify; 175 | backend_poll = kqueue_poll; 176 | 177 | kqueue_eventmax = 64; /* initial number of events receivable per poll */ 178 | kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); 179 | 180 | kqueue_changes = 0; 181 | kqueue_changemax = 0; 182 | kqueue_changecnt = 0; 183 | 184 | return EVBACKEND_KQUEUE; 185 | } 186 | 187 | inline_size 188 | void 189 | kqueue_destroy (EV_P) 190 | { 191 | ev_free (kqueue_events); 192 | ev_free (kqueue_changes); 193 | } 194 | 195 | inline_size 196 | void 197 | kqueue_fork (EV_P) 198 | { 199 | /* some BSD kernels don't just destroy the kqueue itself, 200 | * but also close the fd, which isn't documented, and 201 | * impossible to support properly. 202 | * we remember the pid of the kqueue call and only close 203 | * the fd if the pid is still the same. 204 | * this leaks fds on sane kernels, but BSD interfaces are 205 | * notoriously buggy and rarely get fixed. 206 | */ 207 | pid_t newpid = getpid (); 208 | 209 | if (newpid == kqueue_fd_pid) 210 | close (backend_fd); 211 | 212 | kqueue_fd_pid = newpid; 213 | while ((backend_fd = kqueue ()) < 0) 214 | ev_syserr ("(libev) kqueue"); 215 | 216 | fcntl (backend_fd, F_SETFD, FD_CLOEXEC); 217 | 218 | /* re-register interest in fds */ 219 | fd_rearm_all (EV_A); 220 | } 221 | 222 | /* sys/event.h defines EV_ERROR */ 223 | #undef EV_ERROR 224 | 225 | -------------------------------------------------------------------------------- /libev/ev_poll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev poll fd activity backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2016,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #include 41 | 42 | inline_size 43 | void 44 | array_needsize_pollidx (int *base, int offset, int count) 45 | { 46 | /* using memset (.., -1, ...) is tempting, we we try 47 | * to be ultraportable 48 | */ 49 | base += offset; 50 | while (count--) 51 | *base++ = -1; 52 | } 53 | 54 | static void 55 | poll_modify (EV_P_ int fd, int oev, int nev) 56 | { 57 | int idx; 58 | 59 | if (oev == nev) 60 | return; 61 | 62 | array_needsize (int, pollidxs, pollidxmax, fd + 1, array_needsize_pollidx); 63 | 64 | idx = pollidxs [fd]; 65 | 66 | if (idx < 0) /* need to allocate a new pollfd */ 67 | { 68 | pollidxs [fd] = idx = pollcnt++; 69 | array_needsize (struct pollfd, polls, pollmax, pollcnt, array_needsize_noinit); 70 | polls [idx].fd = fd; 71 | } 72 | 73 | assert (polls [idx].fd == fd); 74 | 75 | if (nev) 76 | polls [idx].events = 77 | (nev & EV_READ ? POLLIN : 0) 78 | | (nev & EV_WRITE ? POLLOUT : 0); 79 | else /* remove pollfd */ 80 | { 81 | pollidxs [fd] = -1; 82 | 83 | if (ecb_expect_true (idx < --pollcnt)) 84 | { 85 | polls [idx] = polls [pollcnt]; 86 | pollidxs [polls [idx].fd] = idx; 87 | } 88 | } 89 | } 90 | 91 | static void 92 | poll_poll (EV_P_ ev_tstamp timeout) 93 | { 94 | struct pollfd *p; 95 | int res; 96 | 97 | EV_RELEASE_CB; 98 | res = poll (polls, pollcnt, EV_TS_TO_MSEC (timeout)); 99 | EV_ACQUIRE_CB; 100 | 101 | if (ecb_expect_false (res < 0)) 102 | { 103 | if (errno == EBADF) 104 | fd_ebadf (EV_A); 105 | else if (errno == ENOMEM && !syserr_cb) 106 | fd_enomem (EV_A); 107 | else if (errno != EINTR) 108 | ev_syserr ("(libev) poll"); 109 | } 110 | else 111 | for (p = polls; res; ++p) 112 | { 113 | assert (("libev: poll returned illegal result, broken BSD kernel?", p < polls + pollcnt)); 114 | 115 | if (ecb_expect_false (p->revents)) /* this expect is debatable */ 116 | { 117 | --res; 118 | 119 | if (ecb_expect_false (p->revents & POLLNVAL)) 120 | { 121 | assert (("libev: poll found invalid fd in poll set", 0)); 122 | fd_kill (EV_A_ p->fd); 123 | } 124 | else 125 | fd_event ( 126 | EV_A_ 127 | p->fd, 128 | (p->revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) 129 | | (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) 130 | ); 131 | } 132 | } 133 | } 134 | 135 | inline_size 136 | int 137 | poll_init (EV_P_ int flags) 138 | { 139 | backend_mintime = EV_TS_CONST (1e-3); 140 | backend_modify = poll_modify; 141 | backend_poll = poll_poll; 142 | 143 | pollidxs = 0; pollidxmax = 0; 144 | polls = 0; pollmax = 0; pollcnt = 0; 145 | 146 | return EVBACKEND_POLL; 147 | } 148 | 149 | inline_size 150 | void 151 | poll_destroy (EV_P) 152 | { 153 | ev_free (pollidxs); 154 | ev_free (polls); 155 | } 156 | 157 | -------------------------------------------------------------------------------- /libev/ev_port.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev solaris event port backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | /* useful reading: 41 | * 42 | * http://bugs.opensolaris.org/view_bug.do?bug_id=6268715 (random results) 43 | * http://bugs.opensolaris.org/view_bug.do?bug_id=6455223 (just totally broken) 44 | * http://bugs.opensolaris.org/view_bug.do?bug_id=6873782 (manpage ETIME) 45 | * http://bugs.opensolaris.org/view_bug.do?bug_id=6874410 (implementation ETIME) 46 | * http://www.mail-archive.com/networking-discuss@opensolaris.org/msg11898.html ETIME vs. nget 47 | * http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/gen/event_port.c (libc) 48 | * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/fs/portfs/port.c#1325 (kernel) 49 | */ 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | inline_speed 59 | void 60 | port_associate_and_check (EV_P_ int fd, int ev) 61 | { 62 | if (0 > 63 | port_associate ( 64 | backend_fd, PORT_SOURCE_FD, fd, 65 | (ev & EV_READ ? POLLIN : 0) 66 | | (ev & EV_WRITE ? POLLOUT : 0), 67 | 0 68 | ) 69 | ) 70 | { 71 | if (errno == EBADFD) 72 | { 73 | assert (("libev: port_associate found invalid fd", errno != EBADFD)); 74 | fd_kill (EV_A_ fd); 75 | } 76 | else 77 | ev_syserr ("(libev) port_associate"); 78 | } 79 | } 80 | 81 | static void 82 | port_modify (EV_P_ int fd, int oev, int nev) 83 | { 84 | /* we need to reassociate no matter what, as closes are 85 | * once more silently being discarded. 86 | */ 87 | if (!nev) 88 | { 89 | if (oev) 90 | port_dissociate (backend_fd, PORT_SOURCE_FD, fd); 91 | } 92 | else 93 | port_associate_and_check (EV_A_ fd, nev); 94 | } 95 | 96 | static void 97 | port_poll (EV_P_ ev_tstamp timeout) 98 | { 99 | int res, i; 100 | struct timespec ts; 101 | uint_t nget = 1; 102 | 103 | /* we initialise this to something we will skip in the loop, as */ 104 | /* port_getn can return with nget unchanged, but no indication */ 105 | /* whether it was the original value or has been updated :/ */ 106 | port_events [0].portev_source = 0; 107 | 108 | EV_RELEASE_CB; 109 | EV_TS_SET (ts, timeout); 110 | res = port_getn (backend_fd, port_events, port_eventmax, &nget, &ts); 111 | EV_ACQUIRE_CB; 112 | 113 | /* port_getn may or may not set nget on error */ 114 | /* so we rely on port_events [0].portev_source not being updated */ 115 | if (res == -1 && errno != ETIME && errno != EINTR) 116 | ev_syserr ("(libev) port_getn (see http://bugs.opensolaris.org/view_bug.do?bug_id=6268715, try LIBEV_FLAGS=3 env variable)"); 117 | 118 | for (i = 0; i < nget; ++i) 119 | { 120 | if (port_events [i].portev_source == PORT_SOURCE_FD) 121 | { 122 | int fd = port_events [i].portev_object; 123 | 124 | fd_event ( 125 | EV_A_ 126 | fd, 127 | (port_events [i].portev_events & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) 128 | | (port_events [i].portev_events & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) 129 | ); 130 | 131 | fd_change (EV_A_ fd, EV__IOFDSET); 132 | } 133 | } 134 | 135 | if (ecb_expect_false (nget == port_eventmax)) 136 | { 137 | ev_free (port_events); 138 | port_eventmax = array_nextsize (sizeof (port_event_t), port_eventmax, port_eventmax + 1); 139 | port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax); 140 | } 141 | } 142 | 143 | inline_size 144 | int 145 | port_init (EV_P_ int flags) 146 | { 147 | /* Initialize the kernel queue */ 148 | if ((backend_fd = port_create ()) < 0) 149 | return 0; 150 | 151 | assert (("libev: PORT_SOURCE_FD must not be zero", PORT_SOURCE_FD)); 152 | 153 | fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */ 154 | 155 | /* if my reading of the opensolaris kernel sources are correct, then 156 | * opensolaris does something very stupid: it checks if the time has already 157 | * elapsed and doesn't round up if that is the case, otherwise it DOES round 158 | * up. Since we can't know what the case is, we need to guess by using a 159 | * "large enough" timeout. Normally, 1e-9 would be correct. 160 | */ 161 | backend_mintime = EV_TS_CONST (1e-3); /* needed to compensate for port_getn returning early */ 162 | backend_modify = port_modify; 163 | backend_poll = port_poll; 164 | 165 | port_eventmax = 64; /* initial number of events receivable per poll */ 166 | port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax); 167 | 168 | return EVBACKEND_PORT; 169 | } 170 | 171 | inline_size 172 | void 173 | port_destroy (EV_P) 174 | { 175 | ev_free (port_events); 176 | } 177 | 178 | inline_size 179 | void 180 | port_fork (EV_P) 181 | { 182 | close (backend_fd); 183 | 184 | while ((backend_fd = port_create ()) < 0) 185 | ev_syserr ("(libev) port"); 186 | 187 | fcntl (backend_fd, F_SETFD, FD_CLOEXEC); 188 | 189 | /* re-register interest in fds */ 190 | fd_rearm_all (EV_A); 191 | } 192 | 193 | -------------------------------------------------------------------------------- /libev/ev_select.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev select fd activity backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #ifndef _WIN32 41 | /* for unix systems */ 42 | # include 43 | # ifndef __hpux 44 | /* for REAL unix systems */ 45 | # include 46 | # endif 47 | #endif 48 | 49 | #ifndef EV_SELECT_USE_FD_SET 50 | # ifdef NFDBITS 51 | # define EV_SELECT_USE_FD_SET 0 52 | # else 53 | # define EV_SELECT_USE_FD_SET 1 54 | # endif 55 | #endif 56 | 57 | #if EV_SELECT_IS_WINSOCKET 58 | # undef EV_SELECT_USE_FD_SET 59 | # define EV_SELECT_USE_FD_SET 1 60 | # undef NFDBITS 61 | # define NFDBITS 0 62 | #endif 63 | 64 | #if !EV_SELECT_USE_FD_SET 65 | # define NFDBYTES (NFDBITS / 8) 66 | #endif 67 | 68 | #include 69 | 70 | static void 71 | select_modify (EV_P_ int fd, int oev, int nev) 72 | { 73 | if (oev == nev) 74 | return; 75 | 76 | { 77 | #if EV_SELECT_USE_FD_SET 78 | 79 | #if EV_SELECT_IS_WINSOCKET 80 | SOCKET handle = anfds [fd].handle; 81 | #else 82 | int handle = fd; 83 | #endif 84 | 85 | assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE)); 86 | 87 | /* FD_SET is broken on windows (it adds the fd to a set twice or more, 88 | * which eventually leads to overflows). Need to call it only on changes. 89 | */ 90 | #if EV_SELECT_IS_WINSOCKET 91 | if ((oev ^ nev) & EV_READ) 92 | #endif 93 | if (nev & EV_READ) 94 | FD_SET (handle, (fd_set *)vec_ri); 95 | else 96 | FD_CLR (handle, (fd_set *)vec_ri); 97 | 98 | #if EV_SELECT_IS_WINSOCKET 99 | if ((oev ^ nev) & EV_WRITE) 100 | #endif 101 | if (nev & EV_WRITE) 102 | FD_SET (handle, (fd_set *)vec_wi); 103 | else 104 | FD_CLR (handle, (fd_set *)vec_wi); 105 | 106 | #else 107 | 108 | int word = fd / NFDBITS; 109 | fd_mask mask = 1UL << (fd % NFDBITS); 110 | 111 | if (ecb_expect_false (vec_max <= word)) 112 | { 113 | int new_max = word + 1; 114 | 115 | vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES); 116 | vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */ 117 | vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES); 118 | vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */ 119 | #ifdef _WIN32 120 | vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */ 121 | #endif 122 | 123 | for (; vec_max < new_max; ++vec_max) 124 | ((fd_mask *)vec_ri) [vec_max] = 125 | ((fd_mask *)vec_wi) [vec_max] = 0; 126 | } 127 | 128 | ((fd_mask *)vec_ri) [word] |= mask; 129 | if (!(nev & EV_READ)) 130 | ((fd_mask *)vec_ri) [word] &= ~mask; 131 | 132 | ((fd_mask *)vec_wi) [word] |= mask; 133 | if (!(nev & EV_WRITE)) 134 | ((fd_mask *)vec_wi) [word] &= ~mask; 135 | #endif 136 | } 137 | } 138 | 139 | static void 140 | select_poll (EV_P_ ev_tstamp timeout) 141 | { 142 | struct timeval tv; 143 | int res; 144 | int fd_setsize; 145 | 146 | EV_RELEASE_CB; 147 | EV_TV_SET (tv, timeout); 148 | 149 | #if EV_SELECT_USE_FD_SET 150 | fd_setsize = sizeof (fd_set); 151 | #else 152 | fd_setsize = vec_max * NFDBYTES; 153 | #endif 154 | 155 | memcpy (vec_ro, vec_ri, fd_setsize); 156 | memcpy (vec_wo, vec_wi, fd_setsize); 157 | 158 | #ifdef _WIN32 159 | /* pass in the write set as except set. 160 | * the idea behind this is to work around a windows bug that causes 161 | * errors to be reported as an exception and not by setting 162 | * the writable bit. this is so uncontrollably lame. 163 | */ 164 | memcpy (vec_eo, vec_wi, fd_setsize); 165 | res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv); 166 | #elif EV_SELECT_USE_FD_SET 167 | fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE; 168 | res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); 169 | #else 170 | res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); 171 | #endif 172 | EV_ACQUIRE_CB; 173 | 174 | if (ecb_expect_false (res < 0)) 175 | { 176 | #if EV_SELECT_IS_WINSOCKET 177 | errno = WSAGetLastError (); 178 | #endif 179 | #ifdef WSABASEERR 180 | /* on windows, select returns incompatible error codes, fix this */ 181 | if (errno >= WSABASEERR && errno < WSABASEERR + 1000) 182 | if (errno == WSAENOTSOCK) 183 | errno = EBADF; 184 | else 185 | errno -= WSABASEERR; 186 | #endif 187 | 188 | #ifdef _WIN32 189 | /* select on windows erroneously returns EINVAL when no fd sets have been 190 | * provided (this is documented). what microsoft doesn't tell you that this bug 191 | * exists even when the fd sets _are_ provided, so we have to check for this bug 192 | * here and emulate by sleeping manually. 193 | * we also get EINVAL when the timeout is invalid, but we ignore this case here 194 | * and assume that EINVAL always means: you have to wait manually. 195 | */ 196 | if (errno == EINVAL) 197 | { 198 | if (timeout) 199 | { 200 | unsigned long ms = EV_TS_TO_MSEC (timeout); 201 | Sleep (ms ? ms : 1); 202 | } 203 | 204 | return; 205 | } 206 | #endif 207 | 208 | if (errno == EBADF) 209 | fd_ebadf (EV_A); 210 | else if (errno == ENOMEM && !syserr_cb) 211 | fd_enomem (EV_A); 212 | else if (errno != EINTR) 213 | ev_syserr ("(libev) select"); 214 | 215 | return; 216 | } 217 | 218 | #if EV_SELECT_USE_FD_SET 219 | 220 | { 221 | int fd; 222 | 223 | for (fd = 0; fd < anfdmax; ++fd) 224 | if (anfds [fd].events) 225 | { 226 | int events = 0; 227 | #if EV_SELECT_IS_WINSOCKET 228 | SOCKET handle = anfds [fd].handle; 229 | #else 230 | int handle = fd; 231 | #endif 232 | 233 | if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ; 234 | if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE; 235 | #ifdef _WIN32 236 | if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE; 237 | #endif 238 | 239 | if (ecb_expect_true (events)) 240 | fd_event (EV_A_ fd, events); 241 | } 242 | } 243 | 244 | #else 245 | 246 | { 247 | int word, bit; 248 | for (word = vec_max; word--; ) 249 | { 250 | fd_mask word_r = ((fd_mask *)vec_ro) [word]; 251 | fd_mask word_w = ((fd_mask *)vec_wo) [word]; 252 | #ifdef _WIN32 253 | word_w |= ((fd_mask *)vec_eo) [word]; 254 | #endif 255 | 256 | if (word_r || word_w) 257 | for (bit = NFDBITS; bit--; ) 258 | { 259 | fd_mask mask = 1UL << bit; 260 | int events = 0; 261 | 262 | events |= word_r & mask ? EV_READ : 0; 263 | events |= word_w & mask ? EV_WRITE : 0; 264 | 265 | if (ecb_expect_true (events)) 266 | fd_event (EV_A_ word * NFDBITS + bit, events); 267 | } 268 | } 269 | } 270 | 271 | #endif 272 | } 273 | 274 | inline_size 275 | int 276 | select_init (EV_P_ int flags) 277 | { 278 | backend_mintime = EV_TS_CONST (1e-6); 279 | backend_modify = select_modify; 280 | backend_poll = select_poll; 281 | 282 | #if EV_SELECT_USE_FD_SET 283 | vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri); 284 | vec_ro = ev_malloc (sizeof (fd_set)); 285 | vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi); 286 | vec_wo = ev_malloc (sizeof (fd_set)); 287 | #ifdef _WIN32 288 | vec_eo = ev_malloc (sizeof (fd_set)); 289 | #endif 290 | #else 291 | vec_max = 0; 292 | vec_ri = 0; 293 | vec_ro = 0; 294 | vec_wi = 0; 295 | vec_wo = 0; 296 | #ifdef _WIN32 297 | vec_eo = 0; 298 | #endif 299 | #endif 300 | 301 | return EVBACKEND_SELECT; 302 | } 303 | 304 | inline_size 305 | void 306 | select_destroy (EV_P) 307 | { 308 | ev_free (vec_ri); 309 | ev_free (vec_ro); 310 | ev_free (vec_wi); 311 | ev_free (vec_wo); 312 | #ifdef _WIN32 313 | ev_free (vec_eo); 314 | #endif 315 | } 316 | 317 | -------------------------------------------------------------------------------- /libev/ev_vars.h: -------------------------------------------------------------------------------- 1 | /* 2 | * loop member variable declarations 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #define VARx(type,name) VAR(name, type name) 41 | 42 | VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */ 43 | VARx(ev_tstamp, mn_now) /* monotonic clock "now" */ 44 | VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */ 45 | 46 | /* for reverse feeding of events */ 47 | VARx(W *, rfeeds) 48 | VARx(int, rfeedmax) 49 | VARx(int, rfeedcnt) 50 | 51 | VAR (pendings, ANPENDING *pendings [NUMPRI]) 52 | VAR (pendingmax, int pendingmax [NUMPRI]) 53 | VAR (pendingcnt, int pendingcnt [NUMPRI]) 54 | VARx(int, pendingpri) /* highest priority currently pending */ 55 | VARx(ev_prepare, pending_w) /* dummy pending watcher */ 56 | 57 | VARx(ev_tstamp, io_blocktime) 58 | VARx(ev_tstamp, timeout_blocktime) 59 | 60 | VARx(int, backend) 61 | VARx(int, activecnt) /* total number of active events ("refcount") */ 62 | VARx(EV_ATOMIC_T, loop_done) /* signal by ev_break */ 63 | 64 | VARx(int, backend_fd) 65 | VARx(ev_tstamp, backend_mintime) /* assumed typical timer resolution */ 66 | VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev)) 67 | VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout)) 68 | 69 | VARx(ANFD *, anfds) 70 | VARx(int, anfdmax) 71 | 72 | VAR (evpipe, int evpipe [2]) 73 | VARx(ev_io, pipe_w) 74 | VARx(EV_ATOMIC_T, pipe_write_wanted) 75 | VARx(EV_ATOMIC_T, pipe_write_skipped) 76 | 77 | #if !defined(_WIN32) || EV_GENWRAP 78 | VARx(pid_t, curpid) 79 | #endif 80 | 81 | VARx(char, postfork) /* true if we need to recreate kernel state after fork */ 82 | 83 | #if EV_USE_SELECT || EV_GENWRAP 84 | VARx(void *, vec_ri) 85 | VARx(void *, vec_ro) 86 | VARx(void *, vec_wi) 87 | VARx(void *, vec_wo) 88 | #if defined(_WIN32) || EV_GENWRAP 89 | VARx(void *, vec_eo) 90 | #endif 91 | VARx(int, vec_max) 92 | #endif 93 | 94 | #if EV_USE_POLL || EV_GENWRAP 95 | VARx(struct pollfd *, polls) 96 | VARx(int, pollmax) 97 | VARx(int, pollcnt) 98 | VARx(int *, pollidxs) /* maps fds into structure indices */ 99 | VARx(int, pollidxmax) 100 | #endif 101 | 102 | #if EV_USE_EPOLL || EV_GENWRAP 103 | VARx(struct epoll_event *, epoll_events) 104 | VARx(int, epoll_eventmax) 105 | VARx(int *, epoll_eperms) 106 | VARx(int, epoll_epermcnt) 107 | VARx(int, epoll_epermmax) 108 | #endif 109 | 110 | #if EV_USE_LINUXAIO || EV_GENWRAP 111 | VARx(aio_context_t, linuxaio_ctx) 112 | VARx(int, linuxaio_iteration) 113 | VARx(struct aniocb **, linuxaio_iocbps) 114 | VARx(int, linuxaio_iocbpmax) 115 | VARx(struct iocb **, linuxaio_submits) 116 | VARx(int, linuxaio_submitcnt) 117 | VARx(int, linuxaio_submitmax) 118 | VARx(ev_io, linuxaio_epoll_w) 119 | #endif 120 | 121 | #if EV_USE_IOURING || EV_GENWRAP 122 | VARx(int, iouring_fd) 123 | VARx(unsigned, iouring_to_submit); 124 | VARx(int, iouring_entries) 125 | VARx(int, iouring_max_entries) 126 | VARx(void *, iouring_sq_ring) 127 | VARx(void *, iouring_cq_ring) 128 | VARx(void *, iouring_sqes) 129 | VARx(uint32_t, iouring_sq_ring_size) 130 | VARx(uint32_t, iouring_cq_ring_size) 131 | VARx(uint32_t, iouring_sqes_size) 132 | VARx(uint32_t, iouring_sq_head) 133 | VARx(uint32_t, iouring_sq_tail) 134 | VARx(uint32_t, iouring_sq_ring_mask) 135 | VARx(uint32_t, iouring_sq_ring_entries) 136 | VARx(uint32_t, iouring_sq_flags) 137 | VARx(uint32_t, iouring_sq_dropped) 138 | VARx(uint32_t, iouring_sq_array) 139 | VARx(uint32_t, iouring_cq_head) 140 | VARx(uint32_t, iouring_cq_tail) 141 | VARx(uint32_t, iouring_cq_ring_mask) 142 | VARx(uint32_t, iouring_cq_ring_entries) 143 | VARx(uint32_t, iouring_cq_overflow) 144 | VARx(uint32_t, iouring_cq_cqes) 145 | VARx(ev_tstamp, iouring_tfd_to) 146 | VARx(int, iouring_tfd) 147 | VARx(ev_io, iouring_tfd_w) 148 | #endif 149 | 150 | #if EV_USE_KQUEUE || EV_GENWRAP 151 | VARx(pid_t, kqueue_fd_pid) 152 | VARx(struct kevent *, kqueue_changes) 153 | VARx(int, kqueue_changemax) 154 | VARx(int, kqueue_changecnt) 155 | VARx(struct kevent *, kqueue_events) 156 | VARx(int, kqueue_eventmax) 157 | #endif 158 | 159 | #if EV_USE_PORT || EV_GENWRAP 160 | VARx(struct port_event *, port_events) 161 | VARx(int, port_eventmax) 162 | #endif 163 | 164 | #if EV_USE_IOCP || EV_GENWRAP 165 | VARx(HANDLE, iocp) 166 | #endif 167 | 168 | VARx(int *, fdchanges) 169 | VARx(int, fdchangemax) 170 | VARx(int, fdchangecnt) 171 | 172 | VARx(ANHE *, timers) 173 | VARx(int, timermax) 174 | VARx(int, timercnt) 175 | 176 | #if EV_PERIODIC_ENABLE || EV_GENWRAP 177 | VARx(ANHE *, periodics) 178 | VARx(int, periodicmax) 179 | VARx(int, periodiccnt) 180 | #endif 181 | 182 | #if EV_IDLE_ENABLE || EV_GENWRAP 183 | VAR (idles, ev_idle **idles [NUMPRI]) 184 | VAR (idlemax, int idlemax [NUMPRI]) 185 | VAR (idlecnt, int idlecnt [NUMPRI]) 186 | #endif 187 | VARx(int, idleall) /* total number */ 188 | 189 | VARx(struct ev_prepare **, prepares) 190 | VARx(int, preparemax) 191 | VARx(int, preparecnt) 192 | 193 | VARx(struct ev_check **, checks) 194 | VARx(int, checkmax) 195 | VARx(int, checkcnt) 196 | 197 | #if EV_FORK_ENABLE || EV_GENWRAP 198 | VARx(struct ev_fork **, forks) 199 | VARx(int, forkmax) 200 | VARx(int, forkcnt) 201 | #endif 202 | 203 | #if EV_CLEANUP_ENABLE || EV_GENWRAP 204 | VARx(struct ev_cleanup **, cleanups) 205 | VARx(int, cleanupmax) 206 | VARx(int, cleanupcnt) 207 | #endif 208 | 209 | #if EV_ASYNC_ENABLE || EV_GENWRAP 210 | VARx(EV_ATOMIC_T, async_pending) 211 | VARx(struct ev_async **, asyncs) 212 | VARx(int, asyncmax) 213 | VARx(int, asynccnt) 214 | #endif 215 | 216 | #if EV_USE_INOTIFY || EV_GENWRAP 217 | VARx(int, fs_fd) 218 | VARx(ev_io, fs_w) 219 | VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */ 220 | VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) 221 | #endif 222 | 223 | VARx(EV_ATOMIC_T, sig_pending) 224 | #if EV_USE_SIGNALFD || EV_GENWRAP 225 | VARx(int, sigfd) 226 | VARx(ev_io, sigfd_w) 227 | VARx(sigset_t, sigfd_set) 228 | #endif 229 | 230 | #if EV_USE_TIMERFD || EV_GENWRAP 231 | VARx(int, timerfd) /* timerfd for time jump detection */ 232 | VARx(ev_io, timerfd_w) 233 | #endif 234 | 235 | VARx(unsigned int, origflags) /* original loop flags */ 236 | 237 | #if EV_FEATURE_API || EV_GENWRAP 238 | VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ 239 | VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ 240 | 241 | VARx(void *, userdata) 242 | /* C++ doesn't support the ev_loop_callback typedef here. stinks. */ 243 | VAR (release_cb, void (*release_cb)(EV_P) EV_NOEXCEPT) 244 | VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_NOEXCEPT) 245 | VAR (invoke_cb , ev_loop_callback invoke_cb) 246 | #endif 247 | 248 | #undef VARx 249 | 250 | -------------------------------------------------------------------------------- /libev/ev_wrap.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT, automatically generated by update_ev_wrap */ 2 | #ifndef EV_WRAP_H 3 | #define EV_WRAP_H 4 | #define acquire_cb ((loop)->acquire_cb) 5 | #define activecnt ((loop)->activecnt) 6 | #define anfdmax ((loop)->anfdmax) 7 | #define anfds ((loop)->anfds) 8 | #define async_pending ((loop)->async_pending) 9 | #define asynccnt ((loop)->asynccnt) 10 | #define asyncmax ((loop)->asyncmax) 11 | #define asyncs ((loop)->asyncs) 12 | #define backend ((loop)->backend) 13 | #define backend_fd ((loop)->backend_fd) 14 | #define backend_mintime ((loop)->backend_mintime) 15 | #define backend_modify ((loop)->backend_modify) 16 | #define backend_poll ((loop)->backend_poll) 17 | #define checkcnt ((loop)->checkcnt) 18 | #define checkmax ((loop)->checkmax) 19 | #define checks ((loop)->checks) 20 | #define cleanupcnt ((loop)->cleanupcnt) 21 | #define cleanupmax ((loop)->cleanupmax) 22 | #define cleanups ((loop)->cleanups) 23 | #define curpid ((loop)->curpid) 24 | #define epoll_epermcnt ((loop)->epoll_epermcnt) 25 | #define epoll_epermmax ((loop)->epoll_epermmax) 26 | #define epoll_eperms ((loop)->epoll_eperms) 27 | #define epoll_eventmax ((loop)->epoll_eventmax) 28 | #define epoll_events ((loop)->epoll_events) 29 | #define evpipe ((loop)->evpipe) 30 | #define fdchangecnt ((loop)->fdchangecnt) 31 | #define fdchangemax ((loop)->fdchangemax) 32 | #define fdchanges ((loop)->fdchanges) 33 | #define forkcnt ((loop)->forkcnt) 34 | #define forkmax ((loop)->forkmax) 35 | #define forks ((loop)->forks) 36 | #define fs_2625 ((loop)->fs_2625) 37 | #define fs_fd ((loop)->fs_fd) 38 | #define fs_hash ((loop)->fs_hash) 39 | #define fs_w ((loop)->fs_w) 40 | #define idleall ((loop)->idleall) 41 | #define idlecnt ((loop)->idlecnt) 42 | #define idlemax ((loop)->idlemax) 43 | #define idles ((loop)->idles) 44 | #define invoke_cb ((loop)->invoke_cb) 45 | #define io_blocktime ((loop)->io_blocktime) 46 | #define iocp ((loop)->iocp) 47 | #define iouring_cq_cqes ((loop)->iouring_cq_cqes) 48 | #define iouring_cq_head ((loop)->iouring_cq_head) 49 | #define iouring_cq_overflow ((loop)->iouring_cq_overflow) 50 | #define iouring_cq_ring ((loop)->iouring_cq_ring) 51 | #define iouring_cq_ring_entries ((loop)->iouring_cq_ring_entries) 52 | #define iouring_cq_ring_mask ((loop)->iouring_cq_ring_mask) 53 | #define iouring_cq_ring_size ((loop)->iouring_cq_ring_size) 54 | #define iouring_cq_tail ((loop)->iouring_cq_tail) 55 | #define iouring_entries ((loop)->iouring_entries) 56 | #define iouring_fd ((loop)->iouring_fd) 57 | #define iouring_max_entries ((loop)->iouring_max_entries) 58 | #define iouring_sq_array ((loop)->iouring_sq_array) 59 | #define iouring_sq_dropped ((loop)->iouring_sq_dropped) 60 | #define iouring_sq_flags ((loop)->iouring_sq_flags) 61 | #define iouring_sq_head ((loop)->iouring_sq_head) 62 | #define iouring_sq_ring ((loop)->iouring_sq_ring) 63 | #define iouring_sq_ring_entries ((loop)->iouring_sq_ring_entries) 64 | #define iouring_sq_ring_mask ((loop)->iouring_sq_ring_mask) 65 | #define iouring_sq_ring_size ((loop)->iouring_sq_ring_size) 66 | #define iouring_sq_tail ((loop)->iouring_sq_tail) 67 | #define iouring_sqes ((loop)->iouring_sqes) 68 | #define iouring_sqes_size ((loop)->iouring_sqes_size) 69 | #define iouring_tfd ((loop)->iouring_tfd) 70 | #define iouring_tfd_to ((loop)->iouring_tfd_to) 71 | #define iouring_tfd_w ((loop)->iouring_tfd_w) 72 | #define iouring_to_submit ((loop)->iouring_to_submit) 73 | #define kqueue_changecnt ((loop)->kqueue_changecnt) 74 | #define kqueue_changemax ((loop)->kqueue_changemax) 75 | #define kqueue_changes ((loop)->kqueue_changes) 76 | #define kqueue_eventmax ((loop)->kqueue_eventmax) 77 | #define kqueue_events ((loop)->kqueue_events) 78 | #define kqueue_fd_pid ((loop)->kqueue_fd_pid) 79 | #define linuxaio_ctx ((loop)->linuxaio_ctx) 80 | #define linuxaio_epoll_w ((loop)->linuxaio_epoll_w) 81 | #define linuxaio_iocbpmax ((loop)->linuxaio_iocbpmax) 82 | #define linuxaio_iocbps ((loop)->linuxaio_iocbps) 83 | #define linuxaio_iteration ((loop)->linuxaio_iteration) 84 | #define linuxaio_submitcnt ((loop)->linuxaio_submitcnt) 85 | #define linuxaio_submitmax ((loop)->linuxaio_submitmax) 86 | #define linuxaio_submits ((loop)->linuxaio_submits) 87 | #define loop_count ((loop)->loop_count) 88 | #define loop_depth ((loop)->loop_depth) 89 | #define loop_done ((loop)->loop_done) 90 | #define mn_now ((loop)->mn_now) 91 | #define now_floor ((loop)->now_floor) 92 | #define origflags ((loop)->origflags) 93 | #define pending_w ((loop)->pending_w) 94 | #define pendingcnt ((loop)->pendingcnt) 95 | #define pendingmax ((loop)->pendingmax) 96 | #define pendingpri ((loop)->pendingpri) 97 | #define pendings ((loop)->pendings) 98 | #define periodiccnt ((loop)->periodiccnt) 99 | #define periodicmax ((loop)->periodicmax) 100 | #define periodics ((loop)->periodics) 101 | #define pipe_w ((loop)->pipe_w) 102 | #define pipe_write_skipped ((loop)->pipe_write_skipped) 103 | #define pipe_write_wanted ((loop)->pipe_write_wanted) 104 | #define pollcnt ((loop)->pollcnt) 105 | #define pollidxmax ((loop)->pollidxmax) 106 | #define pollidxs ((loop)->pollidxs) 107 | #define pollmax ((loop)->pollmax) 108 | #define polls ((loop)->polls) 109 | #define port_eventmax ((loop)->port_eventmax) 110 | #define port_events ((loop)->port_events) 111 | #define postfork ((loop)->postfork) 112 | #define preparecnt ((loop)->preparecnt) 113 | #define preparemax ((loop)->preparemax) 114 | #define prepares ((loop)->prepares) 115 | #define release_cb ((loop)->release_cb) 116 | #define rfeedcnt ((loop)->rfeedcnt) 117 | #define rfeedmax ((loop)->rfeedmax) 118 | #define rfeeds ((loop)->rfeeds) 119 | #define rtmn_diff ((loop)->rtmn_diff) 120 | #define sig_pending ((loop)->sig_pending) 121 | #define sigfd ((loop)->sigfd) 122 | #define sigfd_set ((loop)->sigfd_set) 123 | #define sigfd_w ((loop)->sigfd_w) 124 | #define timeout_blocktime ((loop)->timeout_blocktime) 125 | #define timercnt ((loop)->timercnt) 126 | #define timerfd ((loop)->timerfd) 127 | #define timerfd_w ((loop)->timerfd_w) 128 | #define timermax ((loop)->timermax) 129 | #define timers ((loop)->timers) 130 | #define userdata ((loop)->userdata) 131 | #define vec_eo ((loop)->vec_eo) 132 | #define vec_max ((loop)->vec_max) 133 | #define vec_ri ((loop)->vec_ri) 134 | #define vec_ro ((loop)->vec_ro) 135 | #define vec_wi ((loop)->vec_wi) 136 | #define vec_wo ((loop)->vec_wo) 137 | #else 138 | #undef EV_WRAP_H 139 | #undef acquire_cb 140 | #undef activecnt 141 | #undef anfdmax 142 | #undef anfds 143 | #undef async_pending 144 | #undef asynccnt 145 | #undef asyncmax 146 | #undef asyncs 147 | #undef backend 148 | #undef backend_fd 149 | #undef backend_mintime 150 | #undef backend_modify 151 | #undef backend_poll 152 | #undef checkcnt 153 | #undef checkmax 154 | #undef checks 155 | #undef cleanupcnt 156 | #undef cleanupmax 157 | #undef cleanups 158 | #undef curpid 159 | #undef epoll_epermcnt 160 | #undef epoll_epermmax 161 | #undef epoll_eperms 162 | #undef epoll_eventmax 163 | #undef epoll_events 164 | #undef evpipe 165 | #undef fdchangecnt 166 | #undef fdchangemax 167 | #undef fdchanges 168 | #undef forkcnt 169 | #undef forkmax 170 | #undef forks 171 | #undef fs_2625 172 | #undef fs_fd 173 | #undef fs_hash 174 | #undef fs_w 175 | #undef idleall 176 | #undef idlecnt 177 | #undef idlemax 178 | #undef idles 179 | #undef invoke_cb 180 | #undef io_blocktime 181 | #undef iocp 182 | #undef iouring_cq_cqes 183 | #undef iouring_cq_head 184 | #undef iouring_cq_overflow 185 | #undef iouring_cq_ring 186 | #undef iouring_cq_ring_entries 187 | #undef iouring_cq_ring_mask 188 | #undef iouring_cq_ring_size 189 | #undef iouring_cq_tail 190 | #undef iouring_entries 191 | #undef iouring_fd 192 | #undef iouring_max_entries 193 | #undef iouring_sq_array 194 | #undef iouring_sq_dropped 195 | #undef iouring_sq_flags 196 | #undef iouring_sq_head 197 | #undef iouring_sq_ring 198 | #undef iouring_sq_ring_entries 199 | #undef iouring_sq_ring_mask 200 | #undef iouring_sq_ring_size 201 | #undef iouring_sq_tail 202 | #undef iouring_sqes 203 | #undef iouring_sqes_size 204 | #undef iouring_tfd 205 | #undef iouring_tfd_to 206 | #undef iouring_tfd_w 207 | #undef iouring_to_submit 208 | #undef kqueue_changecnt 209 | #undef kqueue_changemax 210 | #undef kqueue_changes 211 | #undef kqueue_eventmax 212 | #undef kqueue_events 213 | #undef kqueue_fd_pid 214 | #undef linuxaio_ctx 215 | #undef linuxaio_epoll_w 216 | #undef linuxaio_iocbpmax 217 | #undef linuxaio_iocbps 218 | #undef linuxaio_iteration 219 | #undef linuxaio_submitcnt 220 | #undef linuxaio_submitmax 221 | #undef linuxaio_submits 222 | #undef loop_count 223 | #undef loop_depth 224 | #undef loop_done 225 | #undef mn_now 226 | #undef now_floor 227 | #undef origflags 228 | #undef pending_w 229 | #undef pendingcnt 230 | #undef pendingmax 231 | #undef pendingpri 232 | #undef pendings 233 | #undef periodiccnt 234 | #undef periodicmax 235 | #undef periodics 236 | #undef pipe_w 237 | #undef pipe_write_skipped 238 | #undef pipe_write_wanted 239 | #undef pollcnt 240 | #undef pollidxmax 241 | #undef pollidxs 242 | #undef pollmax 243 | #undef polls 244 | #undef port_eventmax 245 | #undef port_events 246 | #undef postfork 247 | #undef preparecnt 248 | #undef preparemax 249 | #undef prepares 250 | #undef release_cb 251 | #undef rfeedcnt 252 | #undef rfeedmax 253 | #undef rfeeds 254 | #undef rtmn_diff 255 | #undef sig_pending 256 | #undef sigfd 257 | #undef sigfd_set 258 | #undef sigfd_w 259 | #undef timeout_blocktime 260 | #undef timercnt 261 | #undef timerfd 262 | #undef timerfd_w 263 | #undef timermax 264 | #undef timers 265 | #undef userdata 266 | #undef vec_eo 267 | #undef vec_max 268 | #undef vec_ri 269 | #undef vec_ro 270 | #undef vec_wi 271 | #undef vec_wo 272 | #endif 273 | -------------------------------------------------------------------------------- /libev/libev.m4: -------------------------------------------------------------------------------- 1 | dnl this file is part of libev, do not make local modifications 2 | dnl http://software.schmorp.de/pkg/libev 3 | 4 | dnl libev support 5 | AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h port.h poll.h sys/timerfd.h) 6 | AC_CHECK_HEADERS(sys/select.h sys/eventfd.h sys/signalfd.h linux/aio_abi.h linux/fs.h) 7 | 8 | AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd signalfd) 9 | 10 | AC_CHECK_FUNCS(clock_gettime, [], [ 11 | dnl on linux, try syscall wrapper first 12 | if test $(uname) = Linux; then 13 | AC_MSG_CHECKING(for clock_gettime syscall) 14 | AC_LINK_IFELSE([AC_LANG_PROGRAM( 15 | [#include 16 | #include 17 | #include ], 18 | [struct timespec ts; int status = syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts)])], 19 | [ac_have_clock_syscall=1 20 | AC_DEFINE(HAVE_CLOCK_SYSCALL, 1, Define to 1 to use the syscall interface for clock_gettime) 21 | AC_MSG_RESULT(yes)], 22 | [AC_MSG_RESULT(no)]) 23 | fi 24 | if test -z "$LIBEV_M4_AVOID_LIBRT" && test -z "$ac_have_clock_syscall"; then 25 | AC_CHECK_LIB(rt, clock_gettime) 26 | unset ac_cv_func_clock_gettime 27 | AC_CHECK_FUNCS(clock_gettime) 28 | fi 29 | ]) 30 | 31 | AC_CHECK_FUNCS(nanosleep, [], [ 32 | if test -z "$LIBEV_M4_AVOID_LIBRT"; then 33 | AC_CHECK_LIB(rt, nanosleep) 34 | unset ac_cv_func_nanosleep 35 | AC_CHECK_FUNCS(nanosleep) 36 | fi 37 | ]) 38 | 39 | AC_CHECK_TYPE(__kernel_rwf_t, [ 40 | AC_DEFINE(HAVE_KERNEL_RWF_T, 1, Define to 1 if linux/fs.h defined kernel_rwf_t) 41 | ], [], [#include ]) 42 | 43 | if test -z "$LIBEV_M4_AVOID_LIBM"; then 44 | LIBM=m 45 | fi 46 | AC_SEARCH_LIBS(floor, $LIBM, [AC_DEFINE(HAVE_FLOOR, 1, Define to 1 if the floor function is available)]) 47 | 48 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #include "config.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "log.h" 33 | 34 | void log_stderr(int priority, const char *format, ...) 35 | { 36 | va_list ap; 37 | const char *pri; 38 | switch (priority) { 39 | case LOG_DEBUG: 40 | pri = "DEBUG"; 41 | break; 42 | case LOG_INFO: 43 | pri = "INFO"; 44 | break; 45 | case LOG_NOTICE: 46 | pri = "NOTICE"; 47 | break; 48 | case LOG_WARNING: 49 | pri = "WARNING"; 50 | break; 51 | case LOG_ERR: 52 | pri = "ERR"; 53 | break; 54 | case LOG_CRIT: 55 | pri = "CRIT"; 56 | break; 57 | default: 58 | pri = "UNKNOWN"; 59 | } 60 | fprintf(stderr, "%ld [%s] ", (long)getpid(), pri); 61 | va_start(ap, format); 62 | vfprintf(stderr, format, ap); 63 | va_end(ap); 64 | fputc('\n', stderr); 65 | } 66 | 67 | static void (*log_func)(int priority, const char *format, ...) = log_stderr; 68 | 69 | void set_log_func(void (*f)(int priority, const char *format, ...)) { 70 | log_func = f; 71 | } 72 | 73 | static void vmsgx(int priority, const char *format, va_list ap) 74 | { 75 | int errno_save = errno; 76 | char *buf = NULL; 77 | size_t buf_size = 0; 78 | FILE *f = open_memstream(&buf, &buf_size); 79 | if (!f) 80 | log_func(LOG_ERR, "vmsg(%s, ...): open_memstream: %s", 81 | format, strerror(errno)); 82 | else if (vfprintf(f, format, ap) < 0) 83 | log_func(LOG_ERR, "vmsg(%s, ...): vfprintf: %s", 84 | format, strerror(errno)); 85 | else if (fflush(f) != 0) 86 | log_func(LOG_ERR, "vmsgx(%s, ...): fflush: %s", 87 | format, strerror(errno)); 88 | else 89 | log_func(priority, "%s", buf); 90 | if (f) 91 | fclose(f); 92 | free(buf); 93 | errno = errno_save; 94 | return; 95 | } 96 | 97 | static void vmsg(int priority, const char *format, va_list ap) 98 | { 99 | int errno_save = errno; 100 | char *buf = NULL; 101 | size_t buf_size = 0; 102 | FILE *f = open_memstream(&buf, &buf_size); 103 | if (!f) 104 | log_func(LOG_ERR, "vmsg(%s, ...): open_memstream: %s", 105 | format, strerror(errno)); 106 | else if (vfprintf(f, format, ap) < 0) 107 | log_func(LOG_ERR, "vmsg(%s, ...): vfprintf: %s", 108 | format, strerror(errno)); 109 | else if (fprintf(f, ": %s", strerror(errno_save)) < 0) 110 | log_func(LOG_ERR, "vmsg(%s, ...): fprintf: %s", 111 | format, strerror(errno)); 112 | else if (fflush(f) != 0) 113 | log_func(LOG_ERR, "vmsgx(%s, ...): fflush: %s", 114 | format, strerror(errno)); 115 | else 116 | log_func(priority, "%s", buf); 117 | if (f) 118 | fclose(f); 119 | free(buf); 120 | errno = errno_save; 121 | return; 122 | } 123 | 124 | DEFINE_LOG_FUNC(debug, LOG_DEBUG) 125 | DEFINE_LOG_FUNC(info, LOG_INFO) 126 | DEFINE_LOG_FUNC(notice, LOG_NOTICE) 127 | DEFINE_LOG_FUNC(warn, LOG_WARNING) 128 | DEFINE_LOG_FUNC(err, LOG_ERR) 129 | DEFINE_LOG_FUNC(crit, LOG_CRIT) 130 | 131 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef __LOG_H__ 22 | #define __LOG_H__ 23 | #include 24 | 25 | #ifdef __GNUC__ 26 | #define DECLARE_LOG_FUNC(func, level) \ 27 | void __attribute__((format (printf, 1, 2))) \ 28 | func##x(const char *format, ...); \ 29 | void __attribute__((format (printf, 1, 2))) \ 30 | func(const char *format, ...); 31 | #else 32 | #define DECLARE_LOG_FUNC(func, level) \ 33 | void func##x(const char *format, ...); \ 34 | void func(const char *format, ...); 35 | #endif 36 | 37 | #define DEFINE_LOG_FUNC(func, level) \ 38 | void func##x(const char *format, ...) \ 39 | { \ 40 | va_list ap; \ 41 | va_start(ap, format); \ 42 | vmsgx(level, format, ap); \ 43 | va_end(ap); \ 44 | } \ 45 | void func(const char *format, ...) \ 46 | { \ 47 | va_list ap; \ 48 | va_start(ap, format); \ 49 | vmsg(level, format, ap); \ 50 | va_end(ap); \ 51 | } 52 | 53 | DECLARE_LOG_FUNC(debug, LOG_DEBUG) 54 | DECLARE_LOG_FUNC(info, LOG_INFO) 55 | DECLARE_LOG_FUNC(notice, LOG_NOTICE) 56 | DECLARE_LOG_FUNC(warn, LOG_WARNING) 57 | DECLARE_LOG_FUNC(err, LOG_ERR) 58 | DECLARE_LOG_FUNC(crit, LOG_CRIT) 59 | 60 | void log_stderr(int priority, const char *format, ...); 61 | void set_log_func(void (*f)(int priority, const char *format, ...)); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /msg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #include "config.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "msg.h" 30 | 31 | int g_loglevel = 0; 32 | 33 | void msg(int level, const char *format, ...) 34 | { 35 | va_list ap; 36 | if (level > g_loglevel) 37 | return; 38 | va_start(ap, format); 39 | vwarnx(format, ap); 40 | va_end(ap); 41 | } 42 | 43 | void msg_hd(int level, const char *prefix, const void *data, size_t len) 44 | { 45 | char *buf = NULL; 46 | size_t buf_size = 0; 47 | const unsigned char *d = data; 48 | 49 | if (level > g_loglevel) 50 | return; 51 | 52 | FILE *f = open_memstream(&buf, &buf_size); 53 | if (!f) { 54 | warn("msg_hd: open_memstream failed"); 55 | return; 56 | } 57 | 58 | for (size_t o = 0; o < len; o += 0x10) { 59 | size_t i; 60 | if (fprintf(f, "%05zx: ", o) < 0) { 61 | warn("msg_hd: fprintf failed"); 62 | fclose(f); 63 | goto out; 64 | } 65 | for (i = 0; i < 0x10; i++) { 66 | int r = o + i < len ? 67 | fprintf(f, "%02hhx %s", d[o + i], (i & 7) == 7 ? " " : "") : 68 | fprintf(f, " %s", (i & 7) == 7 ? " " : ""); 69 | if (r < 0) { 70 | warn("msg_hd: fprintf failed"); 71 | fclose(f); 72 | goto out; 73 | } 74 | } 75 | if (fprintf(f, "|") < 0) { 76 | warn("msg_hd: fprintf failed"); 77 | fclose(f); 78 | goto out; 79 | } 80 | for (i = 0; i < 0x10 && o + i < len; i++) 81 | if (fprintf(f, "%c", isprint(d[o + i]) ? d[o + i] : '.') < 0) { 82 | warn("msg_hd: fprintf failed"); 83 | fclose(f); 84 | goto out; 85 | } 86 | if (fprintf(f, "|%s", o + i < len ? "\n" : "") < 0) { 87 | warn("msg_hd: fprintf failed"); 88 | fclose(f); 89 | goto out; 90 | } 91 | } 92 | 93 | if (fclose(f)) { 94 | warn("msg_hd: fclose failed"); 95 | goto out; 96 | } 97 | 98 | warnx("%s%s", prefix, buf); 99 | 100 | out: 101 | free(buf); 102 | return; 103 | } 104 | -------------------------------------------------------------------------------- /msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2024 Nicola Di Lieto 3 | * 4 | * This file is part of uacme. 5 | * 6 | * uacme is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * uacme is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef __MSG_H__ 22 | #define __MSG_H__ 23 | 24 | #include 25 | 26 | extern int g_loglevel; 27 | 28 | #ifdef __GNUC__ 29 | void __attribute__((format (printf, 2, 3))) msg(int level, 30 | const char *format, ...); 31 | #else 32 | void msg(int level, const char *format, ...); 33 | #endif 34 | 35 | void msg_hd(int level, const char *prefix, const void *data, size_t len); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /nsupdate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2020 Michel Stam 3 | # Copyright (C) 2023 Michal Roszkowski 4 | # 5 | # This file is part of uacme. 6 | # 7 | # uacme is free software: you can redistribute it and/or modify it 8 | # under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # uacme is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | # Commands 21 | DIG=dig 22 | NSUPDATE=nsupdate 23 | 24 | # Server to which updates will be sent. If not specified it will 25 | # be obtained from MNAME in the SOA record. 26 | NSUPDATE_SERVER= 27 | 28 | # Files 29 | # {NSUPDATE,DIG}_KEY 30 | # If you wish to sign transactions using TSIG, specify the keyfile 31 | # here. If you do, also make sure named.conf specifies the 32 | # key "KEYNAME"; in the zone that must be updated (and disallow 33 | # all others for safety) 34 | NSUPDATE_KEY= 35 | DIG_KEY= 36 | 37 | ARGS=5 38 | E_BADARGS=85 39 | 40 | if [ $# -ne "$ARGS" ]; then 41 | echo "Usage: $(basename "$0") method type ident token auth" 1>&2 42 | exit $E_BADARGS 43 | fi 44 | 45 | METHOD=$1 46 | TYPE=$2 47 | IDENT=$3 48 | TOKEN=$4 49 | AUTH=$5 50 | 51 | ns_getns() 52 | { 53 | local zone=$1 54 | local answer 55 | 56 | [ -n "$zone" ] && answer=$($DIG ${DIG_KEY:+-k ${DIG_KEY}} +noall +nottl +noclass +answer "$zone" NS) || return 57 | 58 | local owner 59 | local type 60 | local rdata 61 | while read -r owner type rdata; do 62 | [ "$type" = NS ] && echo $rdata 63 | done <<-EOF 64 | $answer 65 | EOF 66 | } 67 | 68 | ns_getall() 69 | { 70 | local name=$1 71 | local answer 72 | local zone 73 | local primary 74 | 75 | [ -n "$name" ] && answer=$($DIG ${DIG_KEY:+-k ${DIG_KEY}} +noall +nottl +noclass +answer +authority "$name" SOA) || return 76 | 77 | name=${name%.}. 78 | 79 | local owner 80 | local type 81 | local rdata 82 | while read -r owner type rdata; do 83 | case "$type" in 84 | CNAME) 85 | name=$rdata 86 | ;; 87 | DNAME) 88 | name=${name%$owner}$rdata 89 | ;; 90 | SOA) 91 | zone=$owner 92 | set -- $rdata && primary=$1 93 | ;; 94 | esac 95 | done <<-EOF 96 | $answer 97 | EOF 98 | 99 | echo $name $zone $primary 100 | } 101 | 102 | ns_ispresent() 103 | { 104 | local challenge=$2 105 | set -- $(ns_getall "$1") 106 | local name=$1 107 | local nameservers=$(ns_getns "$2") 108 | local answer 109 | local target 110 | local rc=1 111 | 112 | local ns 113 | for ns in $nameservers; do 114 | answer=$($DIG ${DIG_KEY:+-k ${DIG_KEY}} +noall +nottl +noclass +answer "@$ns" "$name" TXT) || continue 115 | target= 116 | 117 | local owner 118 | local type 119 | local rdata 120 | while read -r owner type rdata; do 121 | case "$type" in 122 | CNAME) 123 | target=$rdata 124 | ;; 125 | DNAME) 126 | [ -n "$target" ] && target=${target%$owner}$rdata || target=${name%$owner}$rdata 127 | ;; 128 | TXT) 129 | [ "$rdata" = \"$challenge\" ] && rc=0 && continue 2 130 | target= 131 | ;; 132 | esac 133 | done <<-EOF 134 | $answer 135 | EOF 136 | 137 | [ -n "$target" ] && ns_ispresent "$target" "$challenge" && rc=0 || return 1 138 | done 139 | 140 | return $rc 141 | } 142 | 143 | ns_doupdate() 144 | { 145 | local action=$1 146 | local challenge=$3 147 | set -- $(ns_getall "$2") 148 | local name=$1 149 | local zone=$2 150 | local server=${NSUPDATE_SERVER:-$3} 151 | local ttl=300 152 | 153 | [ -n "$server" ] && [ -n "$zone" ] && [ -n "$name" ] && [ -n "$challenge" ] || return 1 154 | 155 | $NSUPDATE ${NSUPDATE_KEY:+-k ${NSUPDATE_KEY}} -v <<-EOF 156 | server ${server} 157 | zone ${zone} 158 | update ${action} ${name} ${ttl} IN TXT ${challenge} 159 | send 160 | EOF 161 | 162 | return $? 163 | } 164 | 165 | ns_update() 166 | { 167 | local action=$1 168 | local name=$2 169 | local challenge=$3 170 | local retries=5 171 | local delay=5 172 | local count=0 173 | 174 | ns_doupdate "$action" "$name" "$challenge" || return 1 175 | 176 | while sleep $delay; do 177 | case "$action" in 178 | add) 179 | ns_ispresent "$name" "$challenge" && break 180 | ;; 181 | del) 182 | ns_ispresent "$name" "$challenge" || break 183 | ;; 184 | *) 185 | return 1 186 | esac 187 | [ $count -lt $retries ] || return 1 188 | count=$((count + 1)) 189 | done 190 | 191 | return 0 192 | } 193 | 194 | case "$METHOD" in 195 | "begin") 196 | case "$TYPE" in 197 | dns-01) 198 | ns_update add "_acme-challenge.$IDENT" "$AUTH" 199 | exit $? 200 | ;; 201 | *) 202 | exit 1 203 | ;; 204 | esac 205 | ;; 206 | 207 | "done"|"failed") 208 | case "$TYPE" in 209 | dns-01) 210 | ns_update del "_acme-challenge.$IDENT" "$AUTH" 211 | exit $? 212 | ;; 213 | *) 214 | exit 1 215 | ;; 216 | esac 217 | ;; 218 | 219 | *) 220 | echo "$0: invalid method" 1>&2 221 | exit 1 222 | esac 223 | -------------------------------------------------------------------------------- /read-file.c: -------------------------------------------------------------------------------- 1 | /* read-file.c -- read file contents into a string 2 | Copyright (C) 2006, 2009-2015 Free Software Foundation, Inc. 3 | Written by Simon Josefsson and Bruno Haible. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3, or (at your option) 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, see . */ 17 | 18 | #include "read-file.h" 19 | 20 | /* Get fstat. */ 21 | #include 22 | 23 | /* Get ftello. */ 24 | #include 25 | 26 | /* Get SIZE_MAX. */ 27 | #include 28 | 29 | /* Get malloc, realloc, free. */ 30 | #include 31 | 32 | /* Get errno. */ 33 | #include 34 | 35 | /* Read a STREAM and return a newly allocated string with the content, 36 | and set *LENGTH to the length of the string. The string is 37 | zero-terminated, but the terminating zero byte is not counted in 38 | *LENGTH. On errors, *LENGTH is undefined, errno preserves the 39 | values set by system functions (if any), and NULL is returned. */ 40 | char * 41 | fread_file (FILE *stream, size_t *length) 42 | { 43 | char *buf = NULL; 44 | size_t alloc = BUFSIZ; 45 | 46 | /* For a regular file, allocate a buffer that has exactly the right 47 | size. This avoids the need to do dynamic reallocations later. */ 48 | { 49 | struct stat st; 50 | 51 | if (fstat (fileno (stream), &st) >= 0 && S_ISREG (st.st_mode)) 52 | { 53 | off_t pos = ftello (stream); 54 | 55 | if (pos >= 0 && pos < st.st_size) 56 | { 57 | size_t alloc_off = st.st_size - pos; 58 | 59 | /* '1' below, accounts for the trailing NUL. */ 60 | if (SIZE_MAX/2 - 1 < alloc_off) 61 | { 62 | errno = ENOMEM; 63 | return NULL; 64 | } 65 | 66 | alloc = alloc_off + 1; 67 | } 68 | } 69 | } 70 | 71 | if (!(buf = malloc (alloc))) 72 | return NULL; /* errno is ENOMEM. */ 73 | 74 | { 75 | size_t size = 0; /* number of bytes read so far */ 76 | int save_errno; 77 | 78 | for (;;) 79 | { 80 | /* This reads 1 more than the size of a regular file 81 | so that we get eof immediately. */ 82 | size_t requested = alloc - size; 83 | size_t count = fread (buf + size, 1, requested, stream); 84 | size += count; 85 | 86 | if (count != requested) 87 | { 88 | save_errno = errno; 89 | if (ferror (stream)) 90 | break; 91 | 92 | /* Shrink the allocated memory if possible. */ 93 | if (size < alloc - 1) 94 | { 95 | char *smaller_buf = realloc (buf, size + 1); 96 | if (smaller_buf != NULL) 97 | buf = smaller_buf; 98 | } 99 | 100 | buf[size] = '\0'; 101 | *length = size; 102 | return buf; 103 | } 104 | 105 | { 106 | char *new_buf; 107 | 108 | if (alloc >= SIZE_MAX/2) 109 | { 110 | save_errno = ENOMEM; 111 | break; 112 | } 113 | 114 | if (alloc < SIZE_MAX/2 - alloc / 2) 115 | alloc = alloc + alloc / 2; 116 | else 117 | alloc = SIZE_MAX/2; 118 | 119 | if (!(new_buf = realloc (buf, alloc))) 120 | { 121 | save_errno = errno; 122 | break; 123 | } 124 | 125 | buf = new_buf; 126 | } 127 | } 128 | 129 | free (buf); 130 | errno = save_errno; 131 | return NULL; 132 | } 133 | } 134 | 135 | static char * 136 | internal_read_file (const char *filename, size_t *length, const char *mode) 137 | { 138 | FILE *stream = fopen (filename, mode); 139 | char *out; 140 | int save_errno; 141 | 142 | if (!stream) 143 | return NULL; 144 | 145 | out = fread_file (stream, length); 146 | 147 | save_errno = errno; 148 | 149 | if (fclose (stream) != 0) 150 | { 151 | if (out) 152 | { 153 | save_errno = errno; 154 | free (out); 155 | } 156 | errno = save_errno; 157 | return NULL; 158 | } 159 | 160 | return out; 161 | } 162 | 163 | /* Open and read the contents of FILENAME, and return a newly 164 | allocated string with the content, and set *LENGTH to the length of 165 | the string. The string is zero-terminated, but the terminating 166 | zero byte is not counted in *LENGTH. On errors, *LENGTH is 167 | undefined, errno preserves the values set by system functions (if 168 | any), and NULL is returned. */ 169 | char * 170 | read_file (const char *filename, size_t *length) 171 | { 172 | return internal_read_file (filename, length, "r"); 173 | } 174 | 175 | /* Open (on non-POSIX systems, in binary mode) and read the contents 176 | of FILENAME, and return a newly allocated string with the content, 177 | and set LENGTH to the length of the string. The string is 178 | zero-terminated, but the terminating zero byte is not counted in 179 | the LENGTH variable. On errors, *LENGTH is undefined, errno 180 | preserves the values set by system functions (if any), and NULL is 181 | returned. */ 182 | char * 183 | read_binary_file (const char *filename, size_t *length) 184 | { 185 | return internal_read_file (filename, length, "rb"); 186 | } 187 | -------------------------------------------------------------------------------- /read-file.h: -------------------------------------------------------------------------------- 1 | /* read-file.h -- read file contents into a string 2 | Copyright (C) 2006, 2009-2015 Free Software Foundation, Inc. 3 | Written by Simon Josefsson. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3, or (at your option) 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, see . */ 17 | 18 | #ifndef READ_FILE_H 19 | #define READ_FILE_H 20 | 21 | /* Get size_t. */ 22 | #include 23 | 24 | /* Get FILE. */ 25 | #include 26 | 27 | extern char *fread_file (FILE * stream, size_t * length); 28 | 29 | extern char *read_file (const char *filename, size_t * length); 30 | 31 | extern char *read_binary_file (const char *filename, size_t * length); 32 | 33 | #endif /* READ_FILE_H */ 34 | -------------------------------------------------------------------------------- /uacme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2019-2024 Nicola Di Lieto 3 | # 4 | # This file is part of uacme. 5 | # 6 | # uacme is free software: you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # uacme is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | CHALLENGE_PATH="${UACME_CHALLENGE_PATH:-/var/www/.well-known/acme-challenge}" 20 | ARGS=5 21 | E_BADARGS=85 22 | 23 | if test $# -ne "$ARGS" 24 | then 25 | echo "Usage: $(basename "$0") method type ident token auth" 1>&2 26 | exit $E_BADARGS 27 | fi 28 | 29 | METHOD=$1 30 | TYPE=$2 31 | IDENT=$3 32 | TOKEN=$4 33 | AUTH=$5 34 | 35 | case "$METHOD" in 36 | "begin") 37 | case "$TYPE" in 38 | http-01) 39 | printf "%s" "${AUTH}" > "${CHALLENGE_PATH}/${TOKEN}" 40 | exit $? 41 | ;; 42 | *) 43 | exit 1 44 | ;; 45 | esac 46 | ;; 47 | 48 | "done"|"failed") 49 | case "$TYPE" in 50 | http-01) 51 | rm "${CHALLENGE_PATH}/${TOKEN}" 52 | exit $? 53 | ;; 54 | *) 55 | exit 1 56 | ;; 57 | esac 58 | ;; 59 | 60 | *) 61 | echo "$0: invalid method" 1>&2 62 | exit 1 63 | esac 64 | 65 | -------------------------------------------------------------------------------- /ualpn.1.txt: -------------------------------------------------------------------------------- 1 | UALPN(1) 2 | ======== 3 | :doctype: manpage 4 | :man source: ualpn 5 | :man version: {revision} 6 | :man manual: User Commands 7 | 8 | 9 | NAME 10 | ---- 11 | ualpn - lightweight proxying ACMEv2 tls-alpn-01 responder 12 | 13 | 14 | SYNOPSIS 15 | -------- 16 | *ualpn* [*-4*|*--ipv4*] [*-6*|*--ipv6*] [*-b*|*--bind* 'address'[@'port']] 17 | [*-c*|*--connect* 'address'[@'port']] [*-d*|*--daemon*] 18 | [*-l*|*--logfile* 'file'] [*-m*|*--max-auths* 'N'] 19 | [*-n*|*--num-workers* 'N'] [*-p*|*--pidfile* 'file'] 20 | [*-P*|*--proxy* 'N'] [*-r*|*--chroot* 'dir'] 21 | [*-s*|*--sock* 'path'] [*-S*|*--sock-mode* 'mode'] 22 | [*-t*|*--terminate*] [*-u*|*--user* 'user'`[:`'group']] 23 | [*-v*|*--verbose* ...] [*-V*|*--version*] [*-?*|*--help*] 24 | 25 | DESCRIPTION 26 | ----------- 27 | *ualpn* is a lightweight proxying ACMEv2 tls-alpn-01 challenge responder 28 | compliant with RFC8737 () and RFC8738 29 | (). 30 | 31 | Depending on how it is invoked, *ualpn* runs in either client or server mode. 32 | In client mode *ualpn* connects to a running server mode instance of itself 33 | through a unix domain socket, in order to add or remove ACMEv2 authorizations. 34 | See CLIENT MODE below. 35 | 36 | In server mode *ualpn* listens for incoming connections (by default on port 443, 37 | which is mandatory for tls-alpn-01 challenges). It then handles any such 38 | connection in one of two different ways: 39 | 40 | * if the connection begins with a "ClientHello" TLS handshake packet including a 41 | "acme-tls/1" RFC7301 Application Level Protocol Negotiation extension *and* a 42 | RFC6066 Server Name Indication extension matching an identifier for which it has 43 | an authorization, *ualpn* performs the tls-alpn-01 handshake and closes the 44 | connection; 45 | * otherwise *ualpn* transparently proxies the connection to one of the backend 46 | servers it is configured with. By default *ualpn* adds PROXY v1 headers 47 | () in order to 48 | safely transport connection information such as the client's address to the 49 | backend. The PROXY protocol is currently supported by apache, nginx and several 50 | other server programs. 51 | 52 | The event-driven implementation is based on libev () 53 | and considerably reduces the cost of context switches and memory usage. In 54 | addition on systems such as Linux supporting the `splice()` system call, 55 | *ualpn* is able to move network data without copying it to/from kernel/user 56 | address space. 57 | 58 | 59 | OPTIONS 60 | ------- 61 | *-4, --ipv4*:: 62 | Only listen to IPv4 connections 63 | 64 | *-6, --ipv6*:: 65 | Only listen to IPv6 connections 66 | 67 | *-b, --bind* 'address'[@'port']:: 68 | Enable server mode and listen to 'address'. The address must be 69 | specified in numeric format using the standard IPv4 or IPv6 notation. 70 | Optionally, a port number can be given (default is 443). This flag can be 71 | specified multiple times to listen to multiple IP addresses. If this flag 72 | is not specified and server mode was enabled by some other option, 73 | *ualpn* listens to the wildcard interface; otherwise it runs in client 74 | mode (see CLIENT MODE below). 75 | 76 | *-c, --connect* 'address'[@'port']:: 77 | Enable server mode and add a new backend. The backend address must be 78 | specified in numeric format using the standard IPv4 or IPv6 notation. 79 | Optionally, a port number can be given (default is 443). This flag can be 80 | specified multiple times to add multiple backends. This flag must be 81 | specified at least once in server mode. 82 | 83 | *-d, --daemon*:: 84 | Enable server mode and fork in the background 85 | 86 | *-l, --logfile* 'file':: 87 | Log to 'file'. By default *ualpn* logs to syslog if *-d, --daemon* 88 | was specified or stderr otherwise. See also *-v, --verbose* 89 | 90 | *-m, --max-auths* 'N':: 91 | Enable server mode and allow managing ACMEv2 tls-alpn-01 challenges for 92 | up to 'N' different identifiers (default 100) 93 | 94 | *-n, --num-workers* 'N':: 95 | Enable server mode and spawn 'N' worker processes (default 2) to 96 | handle connections. Note that worker processes are single threaded but 97 | thanks to the event based implementation each can handle several 98 | (potentially thousands) connections concurrently. 99 | 100 | *-p, --pidfile* 'file':: 101 | Specify pidfile location (default {runstatedir}/ualpn.pid) 102 | 103 | *-P, --proxy* 'N':: 104 | Enable server mode and disable (0) or specify (1, 2) the PROXY header 105 | version (default 1). The backend server needs to be configured accordingly: 106 | * nginx: 107 | * apache: 108 | 109 | *-r, --chroot* 'dir':: 110 | Enable server mode and specify a directory to chroot to. If logging to 111 | syslog it is necessary to ensure that a syslogd(8) socket is available 112 | at /dev/log in the chroot directory, otherwise *ualpn* will not produce 113 | any log output. 114 | 115 | *-s, --sock* 'path':: 116 | Specify unix socket path (default {runstatedir}/ualpn.sock) 117 | 118 | *-S, --sock-mode* 'mode':: 119 | Enable server mode and specify socket access permissions (default 644) 120 | 121 | *-t, --terminate*:: 122 | Try to terminate a running *ualpn* server. This is achieved by looking 123 | up the process id stored by the server in the pidfile (see *-p, --pidfile*) 124 | and signalling it to terminate. 125 | 126 | *-u, --user* 'user'`[:`'group'`]`:: 127 | Enable server mode and drop user (and optionally group) privileges to those 128 | of 'user' after binding the sockets. Also affects the ownership of the unix 129 | socket, pidfile and logfile (if any). 130 | 131 | *-v, --verbose*:: 132 | By default *ualpn* only produces logs upon errors or warnings. 133 | When this option is specified *ualpn* also logs notice messages. 134 | This option can be specified more than once to increase verbosity and 135 | include information (twice) or debug (three times) messages. 136 | 137 | *-V, --version*:: 138 | Print program version on stderr and exit. 139 | 140 | *-?, --help*:: 141 | Print a brief usage text on stderr and exit. 142 | 143 | 144 | CLIENT MODE 145 | ----------- 146 | 147 | In client mode *ualpn* pipes stdin/stdout to/from the unix socket of the 148 | running server instance of itself. The protocol is ASCII text based, 149 | case sensitive, line oriented, with two commands: 150 | 151 | *auth* 'identifier' 'authorization':: 152 | The *auth* command instructs the running *ualpn* server to handle ACMEv2 153 | tls-alpn-01 challenges for 'identifier', which can be a string representing 154 | either a domain (type `dns` according to RFC8555 section 9.7.8) or an IP 155 | address (type `ip` according to RFC8738 section 6). 156 | 'authorization' must contain the base64url encoding of the SHA-256 digest 157 | of the key authorization computed according to RFC8737 section 3 (note the 158 | *uacme* software executes hook scripts with the correct 'authorization' 159 | passed as the 5th argument). 160 | Upon successful invocation of the *auth* command *ualpn* generates a self 161 | signed certificate as required by the tls-alpn-01 challenge, and then 162 | uses it to perform tls-alpn-01 handshakes for the given 'identifier'. 163 | 164 | *unauth* 'identifier':: 165 | The *unauth* command instructs the running *ualpn* server to no longer 166 | handle ACMEv2 tls-alpn-01 challenges for 'identifier'. 167 | 168 | *ualpn* responds to both commands with a line beginning with either "OK" or 169 | "ERR", followed by a space and additional error information. 170 | 171 | 172 | EXAMPLES 173 | -------- 174 | 175 | `ualpn -vv -d -u nobody:nogroup -c 127.0.0.1@4443 -S 666`:: 176 | start *ualpn* as a daemon, binding to the default port 443 on the 177 | wildcard interface. Proxy connections to port 4443 on 127.0.0.1 178 | After opening the sockets, drop the user privileges and run as 179 | nobody:nogroup. Allow anyone on the local host to access the unix 180 | socket. Also increase the verbosity to include notice and 181 | information messages. 182 | 183 | `echo "auth www.example.com DEi0apzMOdMT2DAro57oIvn-wEzPiYcAYDh2Cvjra3I" | ualpn`:: 184 | Instruct the running *ualpn* server to handle ACMEv2 tls-alpn-01 challenges 185 | for www.example.com with the given key authorization. 186 | 187 | `echo "unauth www.example.com" | ualpn`:: 188 | Instruct the running *ualpn* server to no longer handle ACMEv2 tls-alpn-01 189 | challenges for www.example.com 190 | 191 | 192 | EXIT STATUS 193 | ----------- 194 | *0*:: 195 | Success 196 | 197 | *1*:: 198 | Failure (syntax or usage error; configuration error; 199 | processing failure; unexpected error). 200 | 201 | 202 | EXAMPLE UACME HOOK SCRIPT 203 | ------------------------- 204 | 205 | The 'ualpn.sh' hook script included in the distribution can be used 206 | to automate the certificate issuance with *uacme*, provided *ualpn* 207 | is listening on port 443 of the webserver for the domain being validated 208 | 209 | #!/bin/sh 210 | ARGS=5 211 | E_BADARGS=85 212 | 213 | if test $# -ne "$ARGS" 214 | then 215 | echo "Usage: $(basename "$0") method type ident token auth" 1>&2 216 | exit $E_BADARGS 217 | fi 218 | 219 | METHOD=$1 220 | TYPE=$2 221 | IDENT=$3 222 | TOKEN=$4 223 | AUTH=$5 224 | 225 | if [ "$TYPE" != "tls-alpn-01" ]; then 226 | exit 1 227 | fi 228 | 229 | case "$METHOD" in 230 | "begin") 231 | UALPN_OUT=$(echo "auth $IDENT $AUTH" | ualpn) 232 | if [ "x$UALPN_OUT" = "xOK" ]; then 233 | exit 0 234 | else 235 | exit 1 236 | fi 237 | ;; 238 | "done"|"failed") 239 | UALPN_OUT=$(echo "unauth $IDENT" | ualpn) 240 | if [ "x$UALPN_OUT" = "xOK" ]; then 241 | exit 0 242 | else 243 | exit 1 244 | fi 245 | ;; 246 | *) 247 | echo "$0: invalid method" 1>&2 248 | exit 1 249 | esac 250 | 251 | 252 | BUGS 253 | ---- 254 | If you believe you have found a bug, please create a new issue 255 | at https://github.com/ndilieto/uacme/issues with any applicable 256 | information. 257 | 258 | 259 | SEE ALSO 260 | -------- 261 | *uacme*(1) 262 | 263 | 264 | AUTHOR 265 | ------ 266 | *ualpn* was written by Nicola Di Lieto 267 | 268 | 269 | COPYRIGHT 270 | --------- 271 | Copyright (C) 2019-2024 Nicola Di Lieto 272 | 273 | This file is part of *uacme*. 274 | 275 | *uacme* is free software: you can redistribute it and/or modify it 276 | under the terms of the GNU General Public License as published by 277 | the Free Software Foundation, either version 3 of the License, or 278 | (at your option) any later version. 279 | 280 | *uacme* is distributed in the hope that it will be useful, but 281 | WITHOUT ANY WARRANTY; without even the implied warranty of 282 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 283 | General Public License for more details. 284 | 285 | You should have received a copy of the GNU General Public License 286 | along with this program. If not, see . 287 | 288 | -------------------------------------------------------------------------------- /ualpn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2019-2024 Nicola Di Lieto 3 | # 4 | # This file is part of uacme. 5 | # 6 | # uacme is free software: you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # uacme is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | ARGS=5 20 | E_BADARGS=85 21 | 22 | if test $# -ne "$ARGS" 23 | then 24 | echo "Usage: $(basename "$0") method type ident token auth" 1>&2 25 | exit $E_BADARGS 26 | fi 27 | 28 | METHOD=$1 29 | TYPE=$2 30 | IDENT=$3 31 | TOKEN=$4 32 | AUTH=$5 33 | 34 | if [ "$TYPE" != "tls-alpn-01" ]; then 35 | echo "skipping $TYPE" 1>&2 36 | exit 1 37 | fi 38 | 39 | case "$METHOD" in 40 | "begin") 41 | UALPN_OUT=$(echo "auth $IDENT $AUTH" | ualpn) 42 | if [ "x$UALPN_OUT" = "xOK" ]; then 43 | exit 0 44 | else 45 | exit 1 46 | fi 47 | ;; 48 | "done"|"failed") 49 | UALPN_OUT=$(echo "unauth $IDENT" | ualpn) 50 | if [ "x$UALPN_OUT" = "xOK" ]; then 51 | exit 0 52 | else 53 | exit 1 54 | fi 55 | ;; 56 | *) 57 | echo "$0: invalid method" 1>&2 58 | exit 1 59 | esac 60 | 61 | --------------------------------------------------------------------------------