83 Commits

Author SHA1 Message Date
oysteikt 58b4b1f06e nix: fix package, test, and module with systemd integration 2026-07-22 15:56:38 +09:00
oysteikt 583408b3e3 nix/nixosTest: fix 2026-07-22 15:26:23 +09:00
oysteikt f8cc75b9c6 Set up nix tooling 2026-07-22 15:26:22 +09:00
oysteikt 69e74be224 kadmind: add support for systemd socket activation
Adds support for systemd's fd-passing socket activation, letting systemd
listen for connections before starting the service. This might enable
quicker startup on systems with dependent services, since they will now
only need to wait for the socket, which holds connections until kdc is
finished starting up. It also enables use of the `PrivateNetwork`
directive, sandboxing kadmind into it's own network namespace.
2026-07-22 15:14:09 +09:00
oysteikt f6ec5e5f9a kpasswd: add support for systemd socket activation
Adds support for systemd's fd-passing socket activation, letting systemd
listen for connections before starting the service. This might enable
quicker startup on systems with dependent services, since they will now
only need to wait for the socket, which holds connections until kdc is
finished starting up. It also enables use of the `PrivateNetwork`
directive, sandboxing kpasswd into it's own network namespace.
2026-07-22 15:14:09 +09:00
oysteikt 049748c182 kdc: add support for systemd socket activation
Adds support for systemd's fd-passing socket activation, letting systemd
listen for connections before starting the service. This might enable
quicker startup on systems with dependent services, since they will now
only need to wait for the socket, which holds connections until kdc is
finished starting up. It also enables use of the `PrivateNetwork`
directive, sandboxing KDC into it's own network namespace.
2026-07-22 15:14:08 +09:00
oysteikt 85b816b5bc kadmind: add sd_notify start/stop signals
This commit adds optional integration with systemd's state
notifification system.

When built with libsystemd, kadmind notifies systemd once it is
ready to serve and when it begins a clean shutdown, as well as
publishing a status line reporting the number of accepted connections.
2026-07-22 15:10:16 +09:00
oysteikt b795025613 kpasswd: add sd_notify start/stop signals
This commit adds optional integration with systemd's state
notifification system.

When built with libsystemd, kpasswdd notifies systemd once it is
ready to serve and when it begins a clean shutdown, as well as
publishing a status line reporting how many password change requests
have been processed.
2026-07-22 15:10:15 +09:00
oysteikt 4cba7c91d1 kdc: add sd_notify start/stop signals
This commit adds optional integration with systemd's state
notifification system.

When built with libsystemd, the KDC notifies systemd once it is
ready to serve and when it begins a clean shutdown, as well as
publishing a status line reporting how many worker processes are
running.
2026-07-22 15:10:15 +09:00
Roland C. Dowdeswell 6bb4ff842d lib/roken: fix hex digit table initializer 2026-07-06 09:06:35 -05:00
Daniil Sarafannikov 5b90bc8285 roken:strsep_copy: Fix out-of-bounds write in strsep_copy
In case len < (size_t)(*stringp - save) and len > 0
access to buf[l] leads to out-of-bounds write as
l = len and len means the length of buffer.

Change evaluation of l: only len - 1 elements of
buffer can be used for memcpy and terminator
should be written to buf[len - 1] (in case l = len - 1).
Also, this value of l is not used when len == 0,
so we calculate it only when len > 0.

Pair-Programmed-With: Dmitry Mikhalchenko <tascad@altlinux.org>
Signed-off-by: Daniil Sarafannikov <sarafannikovda@sgu.ru>
2026-06-30 10:19:03 +01:00
Nicolas Williams 22e73b6fcb Better fix for #1399 2026-06-30 10:16:16 +01:00
Linar Galimov ac1c2d05bc krb5: Fix a double free when running into ENOMEM
In cred_delete(), sp is freed after returning from krb5_storage_to_data().
Between this point and the subsequent assignment to sp via krb_storage_emem()
there are two jumps to out, both are executed in an ENOMEM scenario: malloc fail
for cred_data_in_file and krb5_principal_set_realm() fail. In out, sp is freed
again.

This patch fixes the issue by freeing sp right before the krb5_storage_emem()
call.

Signed-off-by: Linar Galimov <galimovlz@sgu.ru>
Signed-off-by: Dmitry Mikhalchenko <tascad@altlinux.org>
2026-06-23 15:34:32 +01:00
Roland C. Dowdeswell 37f93f85dd gss-token: add local user authorization check 2026-06-22 18:43:44 +01:00
Daniil Sarafannikov 6386d8ff82 kdc: Fix possible double free of ac pointer
This fixes possible double free of ac pointer. In the function
'krb5_auth_con_free' pointer ac (auth_context) is freed. In case
'ac != NULL', 'ac != tgs_ac', 'ac->remote_subkey == NULL' this
function is called twice (when logging "FAST AP-REQ remote subkey
missing" and at label 'out').

Pair-Programmed-With: Dmitry Mikhalchenko <tascad@altlinux.org>
Signed-off-by: Daniil Sarafannikov <sarafannikovda@sgu.ru>
2026-06-19 13:00:22 -05:00
mikhailofff afc4c486a1 lib/asn1: fix USE_AFTER_FREE in der_print_hex_heim_integer
Set *p to NULL on asprintf failure to prevent a dangling pointer
and subsequent USE_AFTER_FREE when the caller ignores ENOMEM.

Pair-Programmed-With: Dmitry Mikhalchenko <tascad@altlinux.org>
Signed-off-by: Egor Mikhailov <mikhailovev@sgu.ru>
2026-06-18 17:23:24 -05:00
Roland C. Dowdeswell 9df6b9e13a GHA: add Debian i386 build 2026-06-16 11:02:29 -05:00
Roland C. Dowdeswell 13d0215c54 configure: pass year2038 flags in CPPFLAGS 2026-06-16 11:02:29 -05:00
Roland C. Dowdeswell 759f9f228b NEWS: mention 32-bit time_t ASN.1 clamp 2026-06-16 11:02:29 -05:00
Roland C. Dowdeswell 5ac91f2dc9 hx509: preserve received certificate encodings
Keep the original DER encoding around when decoding certificates so hx509_cert_binary() does not rewrite certificates unnecessarily.

Add regression coverage for direct certificate binary output and keyless stores.
2026-06-16 11:02:29 -05:00
Roland C. Dowdeswell d67a2c36c4 tests: avoid ephemeral port range
On our MacOS X CI job, provjobd2 sometimes held local TCP port 49195,
colliding with check-iprop.  And so we move all listening ports in the
test setup out of the ephemeral port ranges on Linux and Mac.
2026-06-16 09:46:42 -05:00
Roland C. Dowdeswell 9cf1b20313 asn1: clamp far-future times on 32-bit time_t
Compute DER generalized time conversion in uint64_t and clamp to the
local time_t range before returning.  This avoids wrapping far-future
ASN.1 times on 32-bit time_t platforms.  We do not address time_t
being a non-integral type.
2026-06-15 14:09:41 -05:00
Roland C. Dowdeswell 97b07c5632 krb5: skip vanished keyring ccache keys 2026-06-10 17:26:54 -05:00
Roland C. Dowdeswell 8a0fc8d032 Add credential cache coverage tests 2026-06-10 17:26:54 -05:00
Roland C. Dowdeswell 34ab0b7c77 asn1: fix open type alignment on ILP32
Do not assume that the open-type payload needs 8-byte alignment.
Align to pointer size instead, which avoids reading the wrong location
on ILP32 layouts.
2026-06-10 10:38:43 -05:00
Roland C. Dowdeswell 9bb80f4747 hx509: choose certificate time encoding portably
Select UTCTime versus GeneralizedTime with a helper that only performs
the 2050 comparison when the local time_t range can represent that value.
This avoids ILP32 type-limit problems while preserving GeneralizedTime
output on 64-bit and unsigned 32-bit time_t platforms.
2026-06-10 09:59:13 -05:00
Roland C. Dowdeswell 5ebe5b4582 asn1: compare int32 default values safely
Move the int32 ptr comparison into a helper that first checks
whether the encoded pointer-sized default is representable as int32_t.
This avoids ILP32 type-limit warnings.
2026-06-10 09:57:03 -05:00
Roland C. Dowdeswell f609aae209 krb5: avoid time-difference overflow
Use krb5_time_abs() rather than subtracting time_t values before passing the result to labs().  On signed 32-bit time_t platforms, subtracting far-apart times can overflow before labs() sees the value.
2026-06-10 09:39:19 -05:00
Nicolas Williams fdeb3e6e4e Revert "README.md: Drop Coveralls badge (not updating)"
This reverts commit 2b2c71a7c1 as Coveralls
should now update.
2026-06-08 13:40:12 -05:00
Nicolas Williams 16a8e31d34 GHA: Build coverage for master branch too 2026-06-08 13:40:12 -05:00
Roland C. Dowdeswell cdc82913d5 kdc: typos in MAX_TIME macros 2026-06-08 11:38:31 -05:00
Pino Toscano 2194be6c92 asn1: Include <errno.h> before using/checking bits from it
Commit 232c936ea3 added a fallback ENOTSUP
definition. The check itself and the fallback definition rely on
<errno.h> to be included already, so in case it was not (depending on
the platform) then there will be a wrong definition of ENOTSUP.

Instead of rely on <errno.h> to be included before including a
generated header from this tool, include it manually. This way both
the ENOTSUP check and its fallback definition (if ever) will always
work.
2026-06-06 23:54:47 +01:00
Ihar Hrachyshka 2594691dfd Define HAVE_DB_185_H if db_185.h is present 2026-06-06 23:46:07 +01:00
Roland C. Dowdeswell a735b65b70 gssapi: avoid putenv use-after-free in store_cred
Fixes #1163
2026-06-06 23:38:21 +01:00
Roy Marples 1f0f31c954 roken: Don't define any global vars in the pidfile namespace.
Newer util.h from NetBSD defines pidfile_path() which conflicts
here.
2026-05-30 12:06:31 -05:00
Roland C. Dowdeswell e1ab030717 kdc: reject kx509 requests when disabled
Fixes #1378.
2026-05-28 21:30:06 -05:00
Roland C. Dowdeswell 421c40c73e kadm5: make ipropd-master listen on IPv6
Fixes #1330.
2026-05-27 14:11:04 -05:00
Roland C. Dowdeswell de7aa57362 treewide: fix many null dereference reports
Add defensive handling for several NULL allocation and formatting paths reported across issues #820-#829.

Fixes #820, fixes #821, fixes #822, fixes #823, fixes #825, fixes #828
2026-05-27 13:47:41 -05:00
Roland C. Dowdeswell 9a9da70626 krb5: clean up get_cred_kdc on send context failure
Fixes #1207
2026-05-27 12:12:03 -05:00
Roland C. Dowdeswell e3a59b65d3 kadmin: generate stronger random passwords
Generate 12 random bytes and encode them with Heimdal base64url, producing
16-character random passwords with 96 bits of entropy.

This avoids punctuation and quoting issues while still raising generated
password entropy substantially from the old roughly 55-bit generator.

Fixes #1145
2026-05-27 12:06:14 -05:00
Roland C. Dowdeswell 98d6fcacb4 krb5: fix ap_req_nofail documentation
Fixes #1371
2026-05-27 11:56:23 -05:00
Roland C. Dowdeswell 4f147f5e1b doc: trim krb5_verify_user xrefs
Fixes #1127
2026-05-27 16:01:16 +01:00
Roland C. Dowdeswell ef3860d6c3 doc: clean up krb5_init_context man page
Fixes #1125
2026-05-27 15:42:57 +01:00
Alexey Shapovalov 20d4e914e3 gss: Fix NULL minor_status arguments 2026-05-27 14:30:27 +01:00
Florian Best cdd22b6061 refactor(changepw): replace select() with poll()
Issue #1338
2026-05-27 14:16:23 +01:00
Florian Best 73acb1df8e refactor(send_to_kdc): replace select() with poll()
Issue #1338
2026-05-27 14:16:23 +01:00
Roland C. Dowdeswell abec12ef7f ipropd-slave: get a TGT before authenticating
Do not request an iprop/<master> initial ticket directly. With
name_canon_rules = as-is: this can leave the acquired credential
mismatched with what krb5_sendauth() later asks for. Get a normal TGT
and let sendauth acquire the service ticket.

Fixes #1332.
2026-05-26 17:20:15 -05:00
Roland C. Dowdeswell 2e3bb95430 Add KDC-free GSS tests 2026-05-25 20:18:06 -05:00
Roland C. Dowdeswell a66cb84e70 In krb5.conf make underscores and dashes equivalent 2026-05-25 20:14:36 -05:00
Roland C. Dowdeswell e89417f2a1 tests: cover MEMORY ccache cursor invalidation for #547 2026-05-25 20:09:20 -05:00
Roland C. Dowdeswell a105e8e117 tests: cover MEMORY gss_store_cred storage for #132 2026-05-25 20:01:05 -05:00
Roland C. Dowdeswell 56b55e7c9b add CI/CD for libedit and readline 2026-05-25 20:00:24 -05:00
Roland C. Dowdeswell e836e36d06 Remove duplicated libedit, find/use installed version 2026-05-25 20:00:24 -05:00
Roland C. Dowdeswell 19325d4252 lib/gssapi/test_context.c: fix typo 2026-05-25 19:59:28 -05:00
Roland C. Dowdeswell 3ff4191ba9 krb5: fail krb5_verify_user() early if service key missing
Fixes #1157.
2026-05-25 19:42:40 -05:00
Roland C. Dowdeswell 73bab3fea5 tests/kdc/leaks-kill.sh: typo 2026-05-25 17:32:30 -05:00
Roland C. Dowdeswell d47f526f55 ipc: serialize mig generated files 2026-05-25 17:32:05 -05:00
Roland C. Dowdeswell 6efb8b405e roken: provide poll fallback 2026-05-25 17:31:26 -05:00
Roland C. Dowdeswell 6ce504ad84 kdc/kdc.8: move a comma 2026-05-22 20:33:08 -05:00
Jennifer Sutton 378a367c9e kdc: Allow KDC plugin to handle attempts to authenticate without using hardware authentication
Signed-off-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
2026-05-20 11:47:28 -05:00
Jennifer Sutton 6d2d9632da kdc: Check return value of pa_enc_ts_decrypt_kvno()
Signed-off-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
2026-05-20 11:47:28 -05:00
Jennifer Sutton c65cd331e4 gsskrb5: Correctly check EVP_Cipher() return value for RC4
If the flag EVP_CIPH_FLAG_CUSTOM_CIPHER is set for the cipher, EVP_Cipher()
returns the number of bytes written to ‘out’.
2026-05-20 11:46:35 -05:00
Jennifer Sutton f93aeb3f8f krb5: Correctly check if RC4 enctype is valid
krb5_enctype_valid() returns zero on success.
2026-05-20 11:45:57 -05:00
Jennifer Sutton dafc36e26c krb5: Promote AES SHA2 enctypes to preferred 2026-05-20 11:45:57 -05:00
Jennifer Sutton b7f4f62dfa krb5: Fix non‐RC4 build
The function _krb5_usage2arcfour() is only declared if Heimdal is built with
RC4. Put calls to this function behind #ifdef guards so that the build can
succeed.
2026-05-20 11:43:53 -05:00
Jennifer Sutton 31c514e3b2 kdc: Adjust error code mapping
Commit cbe156d927 mapped error code
HX509_CERT_REVOKED to KRB5_KDC_ERR_REVOKED_CERTIFICATE, so check for the latter
instead.
2026-05-20 11:43:18 -05:00
Rudi Heitbaum 356b2111ba dbutils: fix order of libraries for static build 2026-05-20 11:42:14 -05:00
Roland C. Dowdeswell 93bbac45f9 Install heim_threads.h 2026-05-19 12:02:18 -05:00
Roland C. Dowdeswell e4a885074b krb5: make KRB5_TRACE default to tracing not just debugging 2026-05-19 12:01:42 -05:00
Ivan Korytov ffb01963fc lib:roken: allow large fragmented UDP replies from glibc resolver
glibc resolver returns same answer length as buffer size when
buffer is too small for the answer.

Signed-off-by: Ivan Korytov <toreonify@altlinux.org>
2026-05-19 11:52:18 -05:00
Roland C. Dowdeswell 8dba1f4810 add a bit more logging in gss mechglue 2026-05-19 11:14:39 -05:00
Roland C. Dowdeswell e11f8a8823 Eliminate \n from _gss_mg_log() calls 2026-05-19 11:14:39 -05:00
Kacper Boström abd35b246a kdc: support pkinit_kdc_revoke for pkinit anchors
Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
2026-02-11 16:14:53 +13:00
Nicolas Williams bddc275275 ktutil: Collect entries then add/delete when renaming principals (fix #1319) 2026-02-08 01:35:58 -06:00
Nicolas Williams 609e36de13 krb5: Only lock keytabs to write to them (fix #1319) 2026-02-08 01:30:28 -06:00
Nicolas Williams 8ec31e4926 GHA: Shorten the OS X test timeout 2026-02-08 00:36:43 -06:00
Nicolas Williams 0a9f1c3f11 GHA: Get diagnostics data from hanging check-context test (OS X) 2026-02-07 23:56:02 -06:00
Nicolas Williams 4fe0ad8e2c GHA: Get diagnostics data from hanging check-context test 2026-02-07 22:45:45 -06:00
Nicolas Williams c999e5a33a GHA: Set a timeout on tests 2026-02-07 18:40:19 -06:00
Nicolas Williams ce85c64b84 iprop: Make ipropd-master not lock the log (fix #1308) 2026-02-07 17:59:03 -06:00
Nicolas Williams c76a096a28 roken: Add pread() for Windows 2026-02-07 17:59:03 -06:00
Nicolas Williams 8a22366b55 roken: Don't define flock() ops if HAVE_FLOCK (fix #1313) 2026-02-07 17:46:19 -06:00
Nicolas Williams 1a7e3c4a5c kadm5: Fix client-side double-free (fix #1315) 2026-02-07 17:46:19 -06:00
217 changed files with 6511 additions and 29743 deletions
+2
View File
@@ -3,6 +3,7 @@ name: Test Coverage
on:
push:
branches:
- 'master'
- 'coverage-*'
jobs:
@@ -36,6 +37,7 @@ jobs:
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap --prefix=$HOME/inst CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS"
make -j4
- name: Test
timeout-minutes: 40
run: |
cd build
sudo sysctl kernel.core_pattern=core.%p || true
+1 -2
View File
@@ -49,8 +49,7 @@ jobs:
cd build
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations"
ulimit -c unlimited
# We don't want to scan-build libedit nor SQLite3 because ETOOSLOW
(cd lib/libedit && make -j4)
# We don't want to scan-build SQLite3 because ETOOSLOW
(cd lib/sqlite && make -j4)
cov-build --dir cov-int make -j4
tar czvf ../heimdal.tgz cov-int
+1
View File
@@ -78,6 +78,7 @@ jobs:
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="${{ matrix.cflags }} -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" --with-mitkrb5=$HOME/mitkrb5 --with-older-heimdal=$HOME/oh5l
make -j4
- name: Test
timeout-minutes: 20
env:
CC: ${{ matrix.compiler }}
MAKEVARS: ${{ matrix.makevars }}
+98 -1
View File
@@ -5,6 +5,7 @@ on:
branches:
- 'master'
- 'heimdal-7-1-branch'
- 'test-ILP32'
paths:
- '!docs/**'
- '!**.md'
@@ -63,6 +64,7 @@ jobs:
os: ubuntu-22.04
compiler: gcc
cflags: '-Wnonnull'
configureopts: '--with-readline=yes'
steps:
- name: Clone repository
uses: actions/checkout@v4
@@ -73,7 +75,7 @@ jobs:
sudo apt-get install -y bison comerr-dev flex doxygen
sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl
sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl
sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3
sudo apt-get install -y libsqlite3-dev libkeyutils-dev libreadline-dev pkg-config python3
sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils
sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind
# Temporary workaround for:
@@ -83,6 +85,7 @@ jobs:
env:
CC: ${{ matrix.compiler }}
MAKEVARS: ${{ matrix.makevars }}
CONFIGURE_OPTS: ${{ matrix.configureopts }}
run: |
/bin/sh ./autogen.sh
mkdir build
@@ -90,6 +93,7 @@ jobs:
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="${{ matrix.cflags }} -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations"
make -j4
- name: Test
timeout-minutes: 40
env:
CC: ${{ matrix.compiler }}
MAKEVARS: ${{ matrix.makevars }}
@@ -107,6 +111,27 @@ jobs:
make DESTDIR=/tmp/h5l install
cd /tmp/h5l
tar czf $HOME/heimdal-install-linux-${{ matrix.compiler }}.tgz .
- name: Interrupted/timed out test diagnostics
if: ${{ cancelled() || failure() }}
run: |
set -x
# Show any test-related processes still running
ps auxww | grep -E 'kdc|test_context|kinit|kadmin|check-' | grep -v grep || true
# Show who's on the test port
ss -tlnp sport = :49188 || true
# Show the newest .log file (the one likely interrupted)
newest=$(find build/tests -name '*.log' -newer build/tests/gss/Makefile -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
if [ -n "$newest" ]; then
echo "=== Newest test log: $newest ==="
cat "$newest"
fi
# Also show KDC messages.log if any exist
for f in build/tests/gss/messages.log build/tests/kdc/messages.log; do
if [ -f "$f" ]; then
echo "=== $f ==="
tail -100 "$f"
fi
done
- name: Core dump stacks
if: ${{ always() }}
run: |
@@ -147,3 +172,75 @@ jobs:
with:
name: Test Logs (${{ matrix.name }})
path: '~/logs-linux-${{ matrix.compiler }}.tgz'
linux-i386:
name: linux-i386 (${{ matrix.name }})
# Run if no [only X] tag, or if [only linux] is present (check both push commits and PR titles)
if: >-
(!contains(github.event.head_commit.message, '[only ') &&
!contains(github.event.pull_request.title, '[only ')) ||
contains(github.event.head_commit.message, '[only linux]') ||
contains(github.event.pull_request.title, '[only linux]')
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- name: time32
image: i386/debian:bookworm
year2038_configure: ""
time_t_size: 4
- name: year2038
image: i386/debian:trixie
year2038_configure: --enable-year2038
time_t_size: 8
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Build and test on Debian i386
run: |
docker run --security-opt seccomp=unconfined --platform linux/386 --rm \
-v "$PWD:/src:ro" \
-e YEAR2038_CONFIGURE="${{ matrix.year2038_configure }}" \
-e EXPECT_TIME_T_SIZE="${{ matrix.time_t_size }}" \
${{ matrix.image }} \
/bin/bash -euxc '
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y --no-install-recommends \
autoconf automake bison build-essential ca-certificates \
comerr-dev curl doxygen flex gdb git iproute2 jq keyutils \
ldap-utils libcap-ng-dev libdb-dev libedit-dev libjson-perl \
libkeyutils-dev libldap2-dev liblmdb-dev libmicrohttpd-dev libncurses5-dev \
libperl4-corelibs-perl libreadline-dev libsqlite3-dev libssl-dev \
libtool make netbase pkg-config procps python3 ss-dev tar \
texinfo unzip valgrind xz-utils
cp -a /src /tmp/heimdal-src
git config --global --add safe.directory /tmp/heimdal-src
cd /tmp/heimdal-src
/bin/sh ./autogen.sh
mkdir build
cd build
../configure --srcdir=`dirname "$PWD"` \
--enable-maintainer-mode \
--enable-developer \
${YEAR2038_CONFIGURE} \
--with-ldap \
--with-readline=yes \
--with-db-type-preference=lmdb \
--prefix=/tmp/heimdal-i386-inst \
CFLAGS="-Wnonnull -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations"
printf "%s\n" \
"#include \"include/config.h\"" \
"#include <stdio.h>" \
"#include <time.h>" \
"int main(void) { unsigned long s = sizeof(time_t); printf(\"sizeof(time_t)=%lu\n\", s); return s == EXPECT_TIME_T_SIZE ? 0 : 1; }" \
> check-time-t.c
cc -I. -I.. -DEXPECT_TIME_T_SIZE="$EXPECT_TIME_T_SIZE" -o check-time-t check-time-t.c
./check-time-t
make -j4
make -C lib/asn1 check
make -C lib/hx509 check TESTS=test_cert_binary
make DESTDIR=/tmp/heimdal-i386-root install
'
+24
View File
@@ -62,6 +62,7 @@ jobs:
- name: osx-clang
os: macos-latest
compiler: clang
configureopts: '--with-libedit=yes'
steps:
- name: Install packages
run: |
@@ -93,6 +94,7 @@ jobs:
# with:
# limit-access-to-actor: true
- name: Test
timeout-minutes: 25
shell: bash
env:
CC: ${{ matrix.compiler }}
@@ -105,6 +107,27 @@ jobs:
sudo lsof -nP -i:49188 || true
cd build
make check
- name: Interrupted/timed out test diagnostics
if: ${{ cancelled() || failure() }}
run: |
set -x
# Show any test-related processes still running
ps auxww | grep -E 'kdc|test_context|kinit|kadmin|check-' | grep -v grep || true
# Show who's on the test port
sudo lsof -nP -i:49188 || true
# Show the newest .log file (the one likely interrupted)
newest=$(find build/tests -name '*.log' -newer build/tests/gss/Makefile -print0 2>/dev/null | xargs -0 stat -f '%m %N' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
if [ -n "$newest" ]; then
echo "=== Newest test log: $newest ==="
cat "$newest"
fi
# Also show KDC messages.log if any exist
for f in build/tests/gss/messages.log build/tests/kdc/messages.log; do
if [ -f "$f" ]; then
echo "=== $f ==="
tail -100 "$f"
fi
done
- name: Install
run: |
cd build || true
@@ -112,6 +135,7 @@ jobs:
cd /tmp/h5l
tar czf $HOME/heimdal-install-osx.tgz .
- name: Test logs
if: ${{ always() }}
run: |
find build -depth -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/' | cpio -o > $HOME/logs-osx.cpio
find build -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/'|xargs cat
+2 -2
View File
@@ -44,11 +44,11 @@ jobs:
cd build
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations"
ulimit -c unlimited
# We don't want to scan-build libedit nor SQLite3 because ETOOSLOW
(cd lib/libedit && make -j4)
# We don't want to scan-build SQLite3 because ETOOSLOW
(cd lib/sqlite && make -j4)
scan-build --keep-going make -j4
- name: Test
timeout-minutes: 40
env:
CC: ${{ matrix.compiler }}
MAKEVARS: ${{ matrix.makevars }}
+1
View File
@@ -90,6 +90,7 @@ jobs:
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --enable-dynamic --disable-static --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="${{ matrix.cflags }} -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" LDFLAGS="${{ matrix.ldflags }}"
make -j4
- name: Test
timeout-minutes: 80
env:
CC: ${{ matrix.compiler }}
MAKEVARS: ${{ matrix.makevars }}
+1
View File
@@ -46,6 +46,7 @@ jobs:
../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-gdwarf-4 -g -ggdb3 -O0 -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations"
make -j4
- name: Test
timeout-minutes: 120
env:
CC: ${{ matrix.compiler }}
MAKEVARS: ${{ matrix.makevars }}
+1
View File
@@ -119,6 +119,7 @@ jobs:
)
- name: Test
timeout-minutes: 20
shell: cmd
run: |
set "PATH=%PATH%;C:\msys64\usr\bin"
+3 -26
View File
@@ -64,32 +64,6 @@ asn1_*_asn1.c
/tmp.h
/ylwrap
/lib/libedit/aclocal.m4
/lib/libedit/autom4te.cache
/lib/libedit/compile
/lib/libedit/config.guess
/lib/libedit/config.h
/lib/libedit/config.log
/lib/libedit/config.status
/lib/libedit/config.sub
/lib/libedit/configure
/lib/libedit/depcomp
/lib/libedit/install-sh
/lib/libedit/libtool
/lib/libedit/ltmain.sh
/lib/libedit/missing
/lib/libedit/setupbuild.cmd
/lib/libedit/ylwrap
/lib/libedit/src/common.h
/lib/libedit/src/emacs.h
/lib/libedit/src/fcns.c
/lib/libedit/src/fcns.h
/lib/libedit/src/func.h
/lib/libedit/src/help.c
/lib/libedit/src/help.h
/lib/libedit/src/vi.h
/lib/libedit/stamp-h1
# Files in subdirectories.
/admin/ktutil
@@ -720,3 +694,6 @@ asn1_*_asn1.c
/tools/krb5-gssapi.pc
/tools/krb5.pc
/tools/krb5-config
result
result-*
-8
View File
@@ -1,8 +0,0 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{
"tab_size": 8,
"hard_tabs": false
}
+1
View File
@@ -7,6 +7,7 @@ Release Notes - Heimdal - Version Heimdal 8.0 (future)
- Errors found by the LLVM scan-build static analyzer.
- Errors found by the valgrind memory debugger.
- Fix out-of-tree SQLite3 ccache permissions / umask issues.
- Clamp far-future ASN.1 times on 32-bit time_t platforms instead of wrapping.
- iprop bugs, race conditions, and performance
- Many misc. bugs
+2
View File
@@ -1,6 +1,7 @@
[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/linux.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Alinux)
[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/osx.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Aosx)
[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/windows.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Awindows)
[![Coverage Status](https://coveralls.io/repos/github/heimdal/heimdal/badge.svg?branch=master)](https://coveralls.io/github/heimdal/heimdal?branch=master)
Heimdal
=======
@@ -33,3 +34,4 @@ Build Status
[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/linux.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Alinux)
[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/osx.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Aosx)
[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/windows.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Awindows)
[![Coverage Status](https://coveralls.io/repos/github/heimdal/heimdal/badge.svg?branch=master)](https://coveralls.io/github/heimdal/heimdal?branch=master)
+49 -26
View File
@@ -43,6 +43,9 @@ kt_rename(struct rename_options *opt, int argc, char **argv)
krb5_keytab keytab;
krb5_kt_cursor cursor;
krb5_principal from_princ, to_princ;
krb5_keytab_entry *entries = NULL;
size_t num_entries = 0;
size_t i;
ret = krb5_parse_name(context, argv[0], &from_princ);
if(ret != 0) {
@@ -63,6 +66,14 @@ kt_rename(struct rename_options *opt, int argc, char **argv)
return 1;
}
/*
* Collect matching entries first, then close the cursor before
* adding/removing. We must not call krb5_kt_add_entry() or
* krb5_kt_remove_entry() while holding the seq_get cursor because
* the cursor holds a shared file lock and the add/remove operations
* need an exclusive lock -- with per-fd locking (BSD flock, OFD locks)
* this self-deadlocks.
*/
ret = krb5_kt_start_seq_get(context, keytab, &cursor);
if(ret) {
krb5_kt_close(context, keytab);
@@ -70,41 +81,53 @@ kt_rename(struct rename_options *opt, int argc, char **argv)
krb5_free_principal(context, to_princ);
return 1;
}
while(1) {
ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
if(ret != 0) {
if(ret != KRB5_CC_END && ret != KRB5_KT_END)
krb5_warn(context, ret, "getting entry from keytab");
else
ret = 0;
break;
}
while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
if(krb5_principal_compare(context, entry.principal, from_princ)) {
krb5_free_principal(context, entry.principal);
entry.principal = to_princ;
ret = krb5_kt_add_entry(context, keytab, &entry);
if(ret) {
entry.principal = NULL;
krb5_keytab_entry *tmp;
tmp = realloc(entries, (num_entries + 1) * sizeof(*entries));
if (tmp == NULL) {
krb5_kt_free_entry(context, &entry);
krb5_warn(context, ret, "adding entry");
ret = krb5_enomem(context);
break;
}
if (opt->delete_flag) {
entry.principal = from_princ;
ret = krb5_kt_remove_entry(context, keytab, &entry);
if(ret) {
entry.principal = NULL;
krb5_kt_free_entry(context, &entry);
krb5_warn(context, ret, "removing entry");
break;
}
}
entries = tmp;
krb5_free_principal(context, entry.principal);
entry.principal = NULL;
entries[num_entries++] = entry;
} else {
krb5_kt_free_entry(context, &entry);
}
krb5_kt_free_entry(context, &entry);
}
if(ret == KRB5_CC_END || ret == KRB5_KT_END)
ret = 0;
else if(ret)
krb5_warn(context, ret, "getting entry from keytab");
krb5_kt_end_seq_get(context, keytab, &cursor);
for (i = 0; ret == 0 && i < num_entries; i++) {
entries[i].principal = to_princ;
ret = krb5_kt_add_entry(context, keytab, &entries[i]);
if(ret) {
krb5_warn(context, ret, "adding entry");
break;
}
if (opt->delete_flag) {
entries[i].principal = from_princ;
ret = krb5_kt_remove_entry(context, keytab, &entries[i]);
if(ret) {
krb5_warn(context, ret, "removing entry");
break;
}
}
}
for (i = 0; i < num_entries; i++) {
entries[i].principal = NULL;
krb5_kt_free_entry(context, &entries[i]);
}
free(entries);
krb5_free_principal(context, from_princ);
krb5_free_principal(context, to_princ);
+1 -1
View File
@@ -10,4 +10,4 @@ man_MANS = bsearch.1
EXTRA_DIST = NTMakefile $(man_MANS)
LDADD = $(LIB_roken) $(LIB_vers) $(LIB_heimbase)
LDADD = $(LIB_vers) $(LIB_heimbase) $(LIB_roken)
+3
View File
@@ -57,6 +57,9 @@ AS_IF([test "x$with_berkeley_db" != xno],
db.h \
])])
dnl detect if compat db_185.h is present
AC_CHECK_HEADERS([db_185.h])
dnl db_create is used by db3 and db4 and db5 and db6
AC_FIND_FUNC_NO_LIBS(db_create, [$dbheader] db-6 db-5 db4 db3 db, [
+72 -12
View File
@@ -9,20 +9,80 @@ AC_DEFUN([KRB_READLINE],[
dnl readline
ac_foo=no
build_editline=no
readline_requested="${with_readline-unset}"
libedit_requested="${with_libedit-unset}"
have_readline=no
rk_TEST_PACKAGE(readline,
[#include <stdio.h>
#if defined(HAVE_READLINE_READLINE_H)
#include <readline/readline.h>
#elif defined(HAVE_READLINE_H)
#include <readline.h>
#endif
],-lreadline,[$LIB_tgetent],,[READLINE],, [readline.h readline/readline.h])
rk_TEST_PACKAGE(libedit,
[#include <stdio.h>
#if defined(HAVE_EDITLINE_READLINE_H)
#include <editline/readline.h>
#elif defined(HAVE_READLINE_READLINE_H)
#include <readline/readline.h>
#elif defined(HAVE_READLINE_H)
#include <readline.h>
#endif
],-ledit,[$LIB_tgetent],,[READLINE],,
[readline.h readline/readline.h editline/readline.h])
if test "$with_readline" = yes; then
:
have_readline=yes
elif test "$with_libedit" = yes; then
LIB_readline="${LIB_libedit}"
elif test "$ac_cv_func_readline" = yes; then
:
else
build_libedit=yes
LIB_readline="\$(top_builddir)/lib/libedit/src/libheimedit.la \$(LIB_tgetent)"
INCLUDE_readline="${INCLUDE_libedit}"
LIB_readline="${LIB_libedit}"
have_readline=yes
elif test "$readline_requested" != no; then
rk_readline_header=no
AC_CHECK_HEADERS([readline/readline.h readline.h],
[rk_readline_header=yes])
if test "$rk_readline_header" = yes; then
AC_CHECK_LIB(readline, readline, [
LIB_readline="-lreadline"
if test "x$LIB_tgetent" != x; then
LIB_readline="$LIB_readline $LIB_tgetent"
fi
have_readline=yes
with_readline=yes
], [], [$LIB_tgetent])
fi
fi
AM_CONDITIONAL(LIBEDIT, test "$build_libedit" = yes)
AC_DEFINE(HAVE_READLINE, 1,
[Define if you have a readline compatible library.])dnl
if test "$have_readline" != yes && test "$libedit_requested" != no; then
rk_libedit_header=no
AC_CHECK_HEADERS([editline/readline.h readline/readline.h readline.h],
[rk_libedit_header=yes])
if test "$rk_libedit_header" = yes; then
AC_CHECK_LIB(edit, readline, [
LIB_readline="-ledit"
if test "x$LIB_tgetent" != x; then
LIB_readline="$LIB_readline $LIB_tgetent"
fi
have_readline=yes
with_libedit=yes
], [], [$LIB_tgetent])
fi
fi
if test "$have_readline" = yes; then
AC_DEFINE(HAVE_READLINE, 1,
[Define if you have a readline compatible library.])dnl
AC_DEFINE(READLINE, 1, [Define if you have the readline package.])dnl
else
INCLUDE_readline=
LIB_readline=
AC_MSG_NOTICE([readline/libedit not found; command line editing disabled])
fi
AC_SUBST(INCLUDE_readline)
AC_SUBST(LIB_readline)
])
+6
View File
@@ -19,4 +19,10 @@ if test "$enable_largefile" != no; then
[CPPFLAGS="$CPPFLAGS $ac_cv_sys_largefile_opts"])
fi
fi
if test "$enable_year2038" != no; then
if test -n "$ac_cv_sys_year2038_opts"; then
AS_CASE([$ac_cv_sys_year2038_opts],[-D_TIME_BITS=*|-D__MINGW_USE_VC2005_COMPAT],
[CPPFLAGS="$CPPFLAGS $ac_cv_sys_year2038_opts"])
fi
fi
])
+2 -1
View File
@@ -192,7 +192,6 @@ AC_CHECK_FUNCS([ \
mkdtemp \
mkostemp \
on_exit \
poll \
random \
secure_getenv \
setprogname \
@@ -360,6 +359,8 @@ AC_BROKEN([ \
mergesort \
mergesort_r \
mkstemp \
poll \
pread \
putenv \
rcmd \
readv \
+4 -4
View File
@@ -24,8 +24,8 @@ AC_ARG_WITH($1-config,
AS_HELP_STRING([--with-$1-config=path],[config program for $1]))
m4_ifval([$6],
m4_define([rk_pkgname], $6),
m4_define([rk_pkgname], AS_TR_CPP($1)))
[m4_define([rk_pkgname], [$6])],
[m4_define([rk_pkgname], [AS_TR_CPP($1)])])
AC_MSG_CHECKING(for $1)
@@ -91,7 +91,7 @@ if test "$with_$1" != no; then
if test "$[]$1_cflags" -a "$[]$1_libs"; then
CFLAGS="$[]$1_cflags $save_CFLAGS"
LIBS="$[]$1_libs $save_LIBS"
m4_ifval([$8],[AC_CHECK_HEADERS([[$8]])])
m4_ifval([$8],[AC_CHECK_HEADERS([$8])])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[$2]],[[]])],[
INCLUDE_$1="$[]$1_cflags"
LIB_$1="$[]$1_libs"
@@ -102,7 +102,7 @@ if test "$with_$1" != no; then
ires= lres=
for i in $header_dirs; do
CFLAGS="-I$i $save_CFLAGS"
m4_ifval([$8],[AC_CHECK_HEADERS([[$8]])])
m4_ifval([$8],[AC_CHECK_HEADERS([$8])])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]],[[]])],[ires=$i;break])
done
for i in $lib_dirs; do
+16 -22
View File
@@ -196,6 +196,22 @@ AM_CONDITIONAL([HAVE_CAPNG], [test "$with_capng" != "no"])
AC_SUBST([CAPNG_CFLAGS])
AC_SUBST([CAPNG_LIBS])
dnl libsystemd
AC_ARG_WITH([systemd],
AC_HELP_STRING([--with-systemd], [use libsystemd for sd_notify service notifications @<:@default=check@:>@]),
[],
[with_systemd=check])
if test "$with_systemd" != "no"; then
PKG_CHECK_MODULES([SYSTEMD], [libsystemd],
[with_systemd=yes],[with_systemd=no])
fi
if test "$with_systemd" = "yes"; then
AC_DEFINE_UNQUOTED([HAVE_SYSTEMD], 1, [whether libsystemd is available for sd_notify])
fi
AM_CONDITIONAL([HAVE_SYSTEMD], [test "$with_systemd" != "no"])
AC_SUBST([SYSTEMD_CFLAGS])
AC_SUBST([SYSTEMD_LIBS])
dnl mitdb
AC_ARG_WITH([mitdb],
AC_HELP_STRING([--with-mitdb], [Path to MIT Kerberos DB include header and shared object]),
@@ -382,28 +398,6 @@ AC_SUBST(ENABLE_AFS_STRING_TO_KEY)dnl
rk_CHECK_MAN
rk_TEST_PACKAGE(readline,
[#include <stdio.h>
#if defined(HAVE_READLINE_READLINE_H)
#include <readline/readline.h>
#elif defined(HAVE_READLINE_H)
#include <readline.h>
#endif
],-lreadline,,, READLINE,, [readline.h readline/readline.h])
rk_TEST_PACKAGE(libedit,
[#include <stdio.h>
#if defined(HAVE_READLINE_READLINE_H)
#include <readline/readline.h>
#elif defined(HAVE_READLINE_H)
#include <readline.h>
#elif defined(HAVE_EDITLINE_READLINE_H)
#include <editline/readline.h>
#endif
],-ledit,,, READLINE,, [readline.h readline/readline.h editline/readline.h])
AC_CONFIG_SUBDIRS([lib/libedit])
KRB_C_BIGENDIAN
AC_C_INLINE
-3
View File
@@ -13,9 +13,6 @@ The @code{popper} was also a Berkeley program initially.
Some of the functions in @file{libroken} also come from Berkeley by way
of NetBSD/FreeBSD.
@code{editline} was written by Simmule Turner and Rich Salz. Heimdal
contains a modifed copy.
The @code{getifaddrs} implementation for Linux was written by Hideaki
YOSHIFUJI for the Usagi project.
-42
View File
@@ -123,48 +123,6 @@ SUCH DAMAGE.
@end verbatim
@copynext
@heading The Regents of the University of California.
libedit
@verbatim
SPDX-License-Identifier: BSD-3-Clause
Copyright (c) 1992, 1993
The Regents of the University of California. All rights reserved.
This code is derived from software contributed to Berkeley by
Christos Zoulas of Cornell University.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
@end verbatim
@copynext
@copynext
@heading Doug Rabson
GSS-API mechglue layer.
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1742800061,
"narHash": "sha256-oDJGK1UMArK52vcW9S5S2apeec4rbfNELgc50LqiPNs=",
"lastModified": 1770380644,
"narHash": "sha256-P7dWMHRUWG5m4G+06jDyThXO7kwSk46C1kgjEWcybkE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1750f3c1c89488e2ffdd47cab9d05454dddfb734",
"rev": "ae67888ff7ef9dff69b3cf0cc0fbfbcd3a722abe",
"type": "github"
},
"original": {
+17 -4
View File
@@ -22,13 +22,26 @@
default = pkgs.callPackage ./nix/shell.nix { };
});
packages = forAllSystems (system: pkgs: with pkgs; {
packages = forAllSystems (system: pkgs: let
src = lib.fileset.toSource {
root = ./.;
fileset = lib.fileset.difference ./. (lib.fileset.unions [
./.github
./.gitignore
./flake.nix
./flake.lock
./nix
]);
};
in {
default = self.packages.${system}.heimdal;
heimdal = pkgs.callPackage ./nix/heimdal {
src = lib.cleanSource ./.;
src = pkgs.runCommand "heimdal-src" {} "ln -s ${src} \"$out\"";
heimdal = pkgs.callPackage ./nix/heimdal/package.nix {
inherit src;
inherit (pkgs.darwin.apple_sdk.frameworks) CoreFoundation Security SystemConfiguration;
autoreconfHook = pkgs.buildPackages.autoreconfHook269;
autoreconfHook = pkgs.buildPackages.autoreconfHook271;
};
nixosTest = pkgs.testers.runNixOSTest (import ./nix/nixosTest.nix { inherit nixpkgs; });
+3 -2
View File
@@ -9,9 +9,11 @@ CHECK_LOCAL = no-check-local
AM_CPPFLAGS += -DHOST=\"$(CANONICAL_HOST)\"
include_HEADERS = heim_threads.h
nodist_include_HEADERS = krb5-types.h
noinst_HEADERS = heimqueue.h heim_threads.h crypto-headers.h
noinst_HEADERS = heimqueue.h crypto-headers.h
EXTRA_DIST = NTMakefile krb5-types.cross config.h.w32
@@ -48,7 +50,6 @@ CLEANFILES = \
der.h \
digest_asn1.h \
digest_template_asn1.h \
editline.h \
err.h \
getarg.h \
glob.h \
+5 -2
View File
@@ -54,7 +54,7 @@ kadmind_SOURCES = \
add_random_users_SOURCES = add-random-users.c
test_util_SOURCES = test_util.c util.c
test_util_SOURCES = test_util.c util.c random_password.c
TESTS = test_util
@@ -72,7 +72,10 @@ kadmind_LDADD = $(top_builddir)/lib/kadm5/libkadm5srv.la \
../lib/gssapi/libgssapi.la \
$(LDADD_common) \
$(LIB_pidfile) \
$(LIB_dlopen)
$(LIB_dlopen) \
$(SYSTEMD_LIBS)
kadmind_CFLAGS = $(SYSTEMD_CFLAGS)
kadmin_LDADD = \
$(top_builddir)/lib/kadm5/libkadm5clnt.la \
-17
View File
@@ -68,12 +68,6 @@ do_ext_keytab(krb5_principal principal, void *data)
if (ret)
goto out;
/* Debug: record which principal was fetched and some context */
krb5_warnx(context, "do_ext_keytab: fetched principal %s mask=0x%x n_key_data=%d",
unparsed ? unparsed : "<unparsed>",
mask,
(int)princ.n_key_data);
if (!e->random_key_flag) {
if (princ.n_key_data == 0) {
krb5_warnx(context, "principal has no keys, or user lacks "
@@ -117,13 +111,6 @@ do_ext_keytab(krb5_principal principal, void *data)
keys[i].keyblock.keyvalue.data = kd->key_data_contents[0];
keys[i].timestamp = time(NULL);
n_k++;
/* Debug: log each key extracted (kvno/enctype) for the principal */
krb5_warnx(context, "do_ext_keytab: principal=%s key_index=%zu kvno=%d enctype=%d",
unparsed ? unparsed : "<unparsed>",
i,
keys[i].vno,
keys[i].keyblock.keytype);
}
} else if (e->random_key_flag) {
ret = kadm5_randkey_principal_3(e->kadm_handle, principal, e->keep,
@@ -221,10 +208,6 @@ ext_keytab(struct ext_keytab_options *opt, int argc, char **argv)
return ret;
}
/* Debug: record ext_keytab invocation details */
krb5_warnx(context, "ext_keytab: invoking foreach_principal for %zu principals, enctypes=%s",
(size_t)argc, enctypes ? enctypes : "<none>");
for(i = 0; i < argc; i++) {
ret = foreach_principal(argv[i], do_ext_keytab, "ext", &data);
if (ret)
+4 -69
View File
@@ -488,71 +488,12 @@ do_get_entry(krb5_principal principal, void *data)
e->upto--;
memset(&princ, 0, sizeof(princ));
/* Loud tracing: record which principal we are about to request from kadmind.
*
* Guard the unparse call: don't call into unparse with a NULL principal
* and only use the unparsed string if the call succeeds.
*/
{
char *want = NULL;
if (principal != NULL && krb5_unparse_name(context, principal, &want) == 0 && want != NULL) {
krb5_warnx(context, "kadmin:get: do_get_entry: requesting principal lookup for %s (mask=0x%x extra_mask=0x%x) (pid=%d)",
want, e->mask, e->extra_mask, (int)getpid());
} else {
krb5_warnx(context, "kadmin:get: do_get_entry: requesting principal lookup for <unparsed> (mask=0x%x extra_mask=0x%x) (pid=%d)",
e->mask, e->extra_mask, (int)getpid());
}
free(want);
}
/* Always request the principal field so we can safely unparse/format
* the returned entry. Some callers request only TL_DATA (eg aliases),
* and the kadm5 backend may return successful results without filling
* the principal pointer which leads to crashes when we try to use it.
*/
{
uint32_t want_mask = e->mask | e->extra_mask | KADM5_PRINCIPAL;
ret = kadm5_get_principal(e->kadm_handle, principal,
&princ,
want_mask);
}
ret = kadm5_get_principal(e->kadm_handle, principal,
&princ,
e->mask | e->extra_mask);
if (ret == 0) {
/* Success: log the fact we received a principal record and some basic info */
{
char *got = NULL;
if (krb5_unparse_name(context, princ.principal, &got) == 0) {
krb5_warnx(context, "kadmin:get: do_get_entry: kadm5_get_principal succeeded: principal=%s kvno=%d n_key_data=%d (pid=%d)",
got ? got : "<unparsed>",
princ.kvno,
princ.n_key_data,
(int)getpid());
} else {
krb5_warnx(context, "kadmin:get: do_get_entry: kadm5_get_principal succeeded: <unparsed principal> kvno=%d n_key_data=%d (pid=%d)",
princ.kvno, princ.n_key_data, (int)getpid());
}
free(got);
}
(e->format)(e, &princ);
kadm5_free_principal_ent(e->kadm_handle, &princ);
} else {
/* Failure: log explicit error so we can trace failing lookups.
*
* Guard the unparse call similarly to above.
*/
{
char *want2 = NULL;
if (principal != NULL && krb5_unparse_name(context, principal, &want2) == 0 && want2 != NULL) {
krb5_warn(context, ret, "kadmin:get: do_get_entry: kadm5_get_principal(%s) failed (pid=%d)",
want2, (int)getpid());
} else {
krb5_warn(context, ret, "kadmin:get: do_get_entry: kadm5_get_principal(<unparsed>) failed (pid=%d)",
(int)getpid());
}
free(want2);
}
}
e->n++;
@@ -686,14 +627,8 @@ getit(struct get_options *opt, const char *name, int argc, char **argv)
return 0;
}
for(i = 0; i < argc; i++) {
/* Loud tracing: announce each foreach_principal invocation */
krb5_warnx(context, "kadmin:get: getit: invoking foreach_principal for arg[%d]=%s (call %d of %d) (pid=%d)",
i, argv[i] ? argv[i] : "<null>", i+1, argc, (int)getpid());
for(i = 0; i < argc; i++)
ret = foreach_principal(argv[i], do_get_entry, name, &data);
if (ret)
krb5_warn(context, ret, "kadmin:get: getit: foreach_principal(%s) returned error", argv[i] ? argv[i] : "<null>");
}
kadm5_destroy(data.kadm_handle);
+69 -8
View File
@@ -35,6 +35,11 @@
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
/* how often (seconds) to refresh the sd_notify STATUS line while idle */
#define STATUS_INTERVAL 30
#endif
extern int daemon_child;
@@ -203,22 +208,52 @@ wait_for_connection(krb5_context contextp,
signal(SIGINT, terminate);
signal(SIGCHLD, sigchld);
{
struct timeval *tmoutp = NULL;
#ifdef HAVE_SYSTEMD
unsigned long nconns = 0;
struct timeval tmout;
tmoutp = &tmout;
sd_notify(0, "READY=1");
sd_notifyf(0, "STATUS=Serving; %lu connection(s) accepted", nconns);
#endif
while (term_flag == 0) {
read_set = orig_read_set;
e = select(max_fd + 1, &read_set, NULL, NULL, NULL);
#ifdef HAVE_SYSTEMD
tmout.tv_sec = STATUS_INTERVAL;
tmout.tv_usec = 0;
#endif
e = select(max_fd + 1, &read_set, NULL, NULL, tmoutp);
if(rk_IS_SOCKET_ERROR(e)) {
if(rk_SOCK_ERRNO != EINTR)
krb5_warn(contextp, rk_SOCK_ERRNO, "select");
} else if(e == 0)
} else if(e == 0) {
#ifdef HAVE_SYSTEMD
/* select timed out: refresh our systemd status line */
sd_notifyf(0, "STATUS=Serving; %lu connection(s) accepted", nconns);
#else
krb5_warnx(contextp, "select returned 0");
else {
#endif
} else {
for(i = 0; i < num_socks; i++) {
if(FD_ISSET(socks[i], &read_set))
if(FD_ISSET(socks[i], &read_set)) {
if(spawn_child(contextp, socks, num_socks, i) == 0)
return;
#ifdef HAVE_SYSTEMD
nconns++;
#endif
}
}
}
}
}
#ifdef HAVE_SYSTEMD
sd_notify(0, "STOPPING=1");
#endif
signal(SIGCHLD, SIG_IGN);
while ((waitpid(-1, &status, WNOHANG)) > 0)
@@ -238,12 +273,37 @@ start_server(krb5_context contextp, const char *port_str)
unsigned int num_socks = 0;
int i;
if (port_str == NULL)
port_str = "+";
#ifdef HAVE_SYSTEMD
{
char **names = NULL;
int sd_n, j;
parse_ports(contextp, port_str);
sd_n = sd_listen_fds_with_names(0, &names);
if (sd_n < 0)
krb5_err(contextp, 1, -sd_n, "sd_listen_fds_with_names");
if (sd_n > 0) {
socks = malloc(sd_n * sizeof(*socks));
if (socks == NULL)
krb5_err(contextp, 1, errno, "malloc");
for (j = 0; j < sd_n; j++) {
if (names != NULL && names[j] != NULL &&
strncmp(names[j], "kadmind", 7) == 0)
socks[num_socks++] = SD_LISTEN_FDS_START + j;
}
}
for (j = 0; names != NULL && names[j] != NULL; j++)
free(names[j]);
free(names);
}
#endif /* HAVE_SYSTEMD */
for(p = kadm_ports; p; p = p->next) {
if (num_socks == 0) {
if (port_str == NULL)
port_str = "+";
parse_ports(contextp, port_str);
for(p = kadm_ports; p; p = p->next) {
struct addrinfo hints, *ai, *ap;
char portstr[32];
memset (&hints, 0, sizeof(hints));
@@ -299,6 +359,7 @@ start_server(krb5_context contextp, const char *port_str)
socks[num_socks++] = s;
}
freeaddrinfo (ai);
}
}
if(num_socks == 0)
krb5_errx(contextp, 1, "no sockets to listen to - exiting");
+18 -119
View File
@@ -32,131 +32,30 @@
*/
#include "kadmin_locl.h"
#include <base64.h>
/* This file defines some a function that generates a random password,
that can be used when creating a large amount of principals (such
as for a batch of students). Since this is a political matter, you
should think about how secure generated passwords has to be.
Both methods defined here will give you at least 55 bits of
entropy.
*/
/* If you want OTP-style passwords, define OTP_STYLE */
#ifdef OTP_STYLE
#include <otp.h>
#else
static void generate_password(char **pw, int num_classes, ...);
#endif
#define RANDOM_PASSWORD_BYTES 12
void
random_password(char *pw, size_t len)
{
#ifdef OTP_STYLE
{
OtpKey newkey;
unsigned char random[RANDOM_PASSWORD_BYTES];
char *password = NULL;
size_t password_len;
krb5_generate_random_block(&newkey, sizeof(newkey));
otp_print_stddict (newkey, pw, len);
strlwr(pw);
}
#else
char *pass;
generate_password(&pass, 3,
"abcdefghijklmnopqrstuvwxyz", 7,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 2,
"@$%&*()-+=:,/<>1234567890", 1);
strlcpy(pw, pass, len);
len = strlen(pass);
memset_s(pass, len, 0, len);
free(pass);
#endif
}
/* some helper functions */
#ifndef OTP_STYLE
/* return a random value in range 0-127 */
static int
RND(unsigned char *key, int keylen, int *left)
{
if(*left == 0){
krb5_generate_random_block(key, keylen);
*left = keylen;
}
(*left)--;
return ((unsigned char*)key)[*left];
}
/* This a helper function that generates a random password with a
number of characters from a set of character classes.
If there are n classes, and the size of each class is Pi, and the
number of characters from each class is Ni, the number of possible
passwords are (given that the character classes are disjoint):
n n
----- / ---- \
| | Ni | \ |
| | Pi | \ Ni| !
| | ---- * | / |
| | Ni! | /___ |
i=1 \ i=1 /
Since it uses the RND function above, neither the size of each
class, nor the total length of the generated password should be
larger than 127 (without fixing RND).
*/
static void
generate_password(char **pw, int num_classes, ...)
{
struct {
const char *str;
int len;
int freq;
} *classes;
va_list ap;
int len, i;
unsigned char rbuf[8]; /* random buffer */
int rleft = 0;
*pw = NULL;
classes = malloc(num_classes * sizeof(*classes));
if(classes == NULL)
if (len == 0)
return;
va_start(ap, num_classes);
len = 0;
for(i = 0; i < num_classes; i++){
classes[i].str = va_arg(ap, const char*);
classes[i].len = strlen(classes[i].str);
classes[i].freq = va_arg(ap, int);
len += classes[i].freq;
krb5_generate_random_block(random, sizeof(random));
if (rk_base64url_encode(random, sizeof(random), &password) < 0 ||
password == NULL) {
memset_s(random, sizeof(random), 0, sizeof(random));
krb5_abortx(NULL, "Failed to encode random password");
}
va_end(ap);
*pw = malloc(len + 1);
if(*pw == NULL) {
free(classes);
return;
}
for(i = 0; i < len; i++) {
int j;
int x = RND(rbuf, sizeof(rbuf), &rleft) % (len - i);
int t = 0;
for(j = 0; j < num_classes; j++) {
if(x < t + classes[j].freq) {
(*pw)[i] = classes[j].str[RND(rbuf, sizeof(rbuf), &rleft)
% classes[j].len];
classes[j].freq--;
break;
}
t += classes[j].freq;
}
}
(*pw)[len] = '\0';
memset_s(rbuf, sizeof(rbuf), 0, sizeof(rbuf));
free(classes);
password_len = strlen(password);
strlcpy(pw, password, len);
memset_s(random, sizeof(random), 0, sizeof(random));
memset_s(password, password_len, 0, password_len);
free(password);
}
#endif
-24
View File
@@ -624,31 +624,7 @@ proc_get_principal(kadm5_server_context *contextp,
if(ret)
goto fail;
/* Loud tracing: log which client requested this GET and what principal is being looked up */
{
char *want = NULL;
(void) krb5_unparse_name(contextp->context, princ, &want);
krb5_warnx(contextp->context,
"proc_get_principal: received GET request for principal=%s mask=0x%x (pid=%d ppid=%d uid=%d)",
want ? want : "<unparsed>",
mask,
(int)getpid(),
(int)getppid(),
(int)getuid());
free(want);
}
ret = kadm5_get_principal(contextp, princ, &ent, mask);
if (ret) {
/* Extra log to make failures obvious at the call site */
char *want2 = NULL;
(void) krb5_unparse_name(contextp->context, princ, &want2);
krb5_warn(contextp->context, ret,
"proc_get_principal: kadm5_get_principal failed for principal=%s (pid=%d)",
want2 ? want2 : "<unparsed>",
(int)getpid());
free(want2);
}
fail:
krb5_warn(contextp->context, ret, "get principal principal");
-5
View File
@@ -226,8 +226,6 @@ kadmind_dispatch_int(void *kadm_handlep, krb5_boolean initial,
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail;
}
/* Debug: record which client and numeric command we received */
krb5_warnx(contextp->context, "kadmind_dispatch: received request from client=%s cmd=%d", client, cmd);
switch(cmd){
case kadm_nop:{
@@ -270,8 +268,6 @@ kadmind_dispatch_int(void *kadm_handlep, krb5_boolean initial,
mask |= KADM5_PRINCIPAL;
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
/* Debug: include mask/keys_ok context so we can correlate admin requests to keytab lookups */
krb5_warnx(contextp->context, "kadmind_dispatch: GET invoked by %s for %s (mask=0x%x, keys_ok=%d)", client, name, mask, keys_ok);
/* If the caller doesn't have KADM5_PRIV_GET, we're done. */
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ);
@@ -311,7 +307,6 @@ kadmind_dispatch_int(void *kadm_handlep, krb5_boolean initial,
}
}
krb5_warnx(contextp->context, "kadmind_dispatch: calling kadm5_get_principal for %s (mask=0x%x, keys_ok=%d)", name, mask, keys_ok);
ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask);
ret_sp = krb5_store_int32(rsp, ret);
if (ret == 0) {
+44 -1
View File
@@ -68,6 +68,49 @@ test_time(void)
return errors;
}
static int
test_random_password(void)
{
static const char alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
char pw[128];
char small[5];
char zero[1] = { 'x' };
size_t i, j;
int errors = 0;
for (i = 0; i < 128; i++) {
random_password(pw, sizeof(pw));
if (strlen(pw) != 16) {
printf("wrong random password length: %lu\n",
(unsigned long)strlen(pw));
errors++;
}
for (j = 0; pw[j] != '\0'; j++) {
if (strchr(alphabet, pw[j]) == NULL) {
printf("random password contains invalid byte: 0x%02x\n",
(unsigned char)pw[j]);
errors++;
}
}
}
random_password(small, sizeof(small));
if (strlen(small) != sizeof(small) - 1) {
printf("wrong short random password length: %lu\n",
(unsigned long)strlen(small));
errors++;
}
random_password(zero, 0);
if (zero[0] != 'x') {
printf("zero-length random password buffer was modified\n");
errors++;
}
return errors;
}
int
main(int argc, char **argv)
@@ -82,9 +125,9 @@ main(int argc, char **argv)
ret = 0;
ret += test_time();
ret += test_random_password();
krb5_free_context(context);
return ret;
}
+2 -2
View File
@@ -198,12 +198,12 @@ LDADD = $(top_builddir)/lib/hdb/libhdb.la \
$(LIB_roken) \
$(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB)
kdc_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) $(CAPNG_LIBS)
kdc_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) $(CAPNG_LIBS) $(SYSTEMD_LIBS)
if FRAMEWORK_SECURITY
kdc_LDFLAGS = -framework SystemConfiguration -framework CoreFoundation
endif
kdc_CFLAGS = $(CAPNG_CFLAGS)
kdc_CFLAGS = $(CAPNG_CFLAGS) $(SYSTEMD_CFLAGS)
kdc_replay_LDADD = libkdc.la $(LDADD) $(LIB_pidfile)
kdc_tester_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) $(LIB_heimbase)
+92 -1
View File
@@ -33,6 +33,10 @@
#include "kdc_locl.h"
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
/*
* a tuple describing on what to listen
*/
@@ -295,6 +299,69 @@ init_socket(krb5_context context,
socket_set_keepalive(d->s, 1);
}
#ifdef HAVE_SYSTEMD
/*
* Allocate descriptors for the sockets handed to us via systemd socket
* activation whose FileDescriptorName is "kdc", and return then number of
* them (0 if we were not socket-activated).
*/
static int
init_sockets_sd(krb5_context context,
krb5_kdc_configuration *config,
struct descr **desc)
{
char **names = NULL;
struct descr *d;
int n, i, num = 0;
n = sd_listen_fds_with_names(0, &names);
if (n < 0)
krb5_err(context, 1, -n, "sd_listen_fds_with_names");
if (n == 0)
return 0;
d = malloc(n * sizeof(*d));
if (d == NULL)
krb5_errx(context, 1, "malloc(%lu) failed",
(unsigned long)n * sizeof(*d));
for (i = 0; i < n; i++) {
int fd = SD_LISTEN_FDS_START + i;
int type;
socklen_t tlen = sizeof(type);
if (names == NULL || names[i] == NULL ||
strncmp(names[i], "kdc", 3) != 0)
continue;
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &tlen) < 0) {
krb5_warn(context, errno,
"getsockopt(SO_TYPE) on socket-activated fd %d", fd);
continue;
}
init_descr(&d[num]);
d[num].s = fd;
d[num].type = type;
socket_set_nonblocking(fd, 1);
kdc_log(context, config, 3, "listening on socket-activated fd %d (%s)",
fd, (type == SOCK_STREAM) ? "tcp" : "udp");
num++;
}
for (i = 0; names != NULL && names[i] != NULL; i++)
free(names[i]);
free(names);
if (num == 0) {
free(d);
return 0;
}
reinit_descrs(d, num);
*desc = d;
return num;
}
#endif /* HAVE_SYSTEMD */
/*
* Allocate descriptors for all the sockets that we should listen on
* and return the number of them.
@@ -1191,7 +1258,12 @@ start_kdc(krb5_context context,
socket_set_nonblocking(islive[1], 1);
#endif
ndescr = init_sockets(context, config, &d);
ndescr = 0;
#ifdef HAVE_SYSTEMD
ndescr = init_sockets_sd(context, config, &d);
#endif
if (ndescr <= 0)
ndescr = init_sockets(context, config, &d);
if(ndescr <= 0)
krb5_errx(context, 1, "No sockets!");
@@ -1209,6 +1281,11 @@ start_kdc(krb5_context context,
roken_detach_finish(NULL, daemon_child);
#ifdef HAVE_SYSTEMD
sd_notify(0, "READY=1");
sd_notify(0, "STATUS=Serving requests");
#endif
#ifdef HAVE_FORK
if (!testing_flag) {
/* Note that we might never execute the body of this loop */
@@ -1250,12 +1327,20 @@ start_kdc(krb5_context context,
kdc_log(context, config, 3, "KDC worker process started: %d",
pid);
num_kdcs++;
#ifdef HAVE_SYSTEMD
sd_notifyf(0, "STATUS=Serving requests; %d of %d KDC worker "
"process(es) running", num_kdcs, max_kdcs);
#endif
/* Slow down the creation of KDCs... */
select_sleep(12500);
break;
}
}
#ifdef HAVE_SYSTEMD
sd_notify(0, "STOPPING=1");
#endif
/* Closing these sockets should cause the kids to die... */
close(islive[0]);
@@ -1307,11 +1392,17 @@ start_kdc(krb5_context context,
kdc_log(context, config, 3, "KDC master process exiting");
} else {
loop(context, config, &d, &ndescr, -1);
#ifdef HAVE_SYSTEMD
sd_notify(0, "STOPPING=1");
#endif
kdc_log(context, config, 3, "KDC exiting");
}
free(pids);
#else
loop(context, config, &d, &ndescr, -1);
#ifdef HAVE_SYSTEMD
sd_notify(0, "STOPPING=1");
#endif
kdc_log(context, config, 3, "KDC exiting");
#endif
+6 -4
View File
@@ -460,6 +460,7 @@ fast_unwrap_request(astgs_request_t r,
char *armor_client_principal_name = NULL;
char *armor_server_principal_name = NULL;
PA_FX_FAST_REQUEST fxreq;
krb5_auth_context free_ac = NULL;
krb5_auth_context ac = NULL;
krb5_ticket *ticket = NULL;
krb5_flags ap_req_options;
@@ -581,7 +582,7 @@ fast_unwrap_request(astgs_request_t r,
goto out;
}
ret = krb5_verify_ap_req2(r->context, &ac,
ret = krb5_verify_ap_req2(r->context, &free_ac,
&ap_req,
armor_server_principal,
&r->armor_key->key,
@@ -593,6 +594,8 @@ fast_unwrap_request(astgs_request_t r,
if (ret)
goto out;
ac = free_ac;
ret = krb5_unparse_name(r->context, armor_server_principal,
&armor_server_principal_name);
if (ret)
@@ -621,7 +624,6 @@ fast_unwrap_request(astgs_request_t r,
"<out of memory>");
if (ac->remote_subkey == NULL) {
krb5_auth_con_free(r->context, ac);
kdc_log(r->context, r->config, 2,
"FAST AP-REQ remote subkey missing");
ret = KRB5KDC_ERR_PREAUTH_FAILED;
@@ -747,8 +749,8 @@ fast_unwrap_request(astgs_request_t r,
kdc_log(r->context, r->config, 5, "Client selected FAST");
out:
if (ac && ac != tgs_ac)
krb5_auth_con_free(r->context, ac);
if (free_ac)
krb5_auth_con_free(r->context, free_ac);
krb5_free_principal(r->context, armor_server_principal);
krb5_xfree(armor_client_principal_name);
+28 -1
View File
@@ -51,7 +51,7 @@ static const char *kdc_plugin_deps[] = {
static struct heim_plugin_data kdc_plugin_data = {
"krb5",
"kdc",
KRB5_PLUGIN_KDC_VERSION_10,
KRB5_PLUGIN_KDC_VERSION_11,
kdc_plugin_deps,
kdc_get_instance
};
@@ -239,6 +239,33 @@ _kdc_referral_policy(astgs_request_t r)
return ret;
}
static krb5_error_code KRB5_LIB_CALL
hwauth_policy(krb5_context context, const void *plug, void *plugctx, void *userctx)
{
const krb5plugin_kdc_ftable *ft = plug;
if (ft->hwauth_policy == NULL) {
return KRB5_PLUGIN_NO_HANDLE;
}
return ft->hwauth_policy(rk_UNCONST(plug), userctx);
}
krb5_error_code
_kdc_hwauth_policy(astgs_request_t r)
{
krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE;
if (have_plugin) {
ret = _krb5_plugin_run_f(r->context, &kdc_plugin_data, 0, r, hwauth_policy);
}
if (ret != KRB5_PLUGIN_NO_HANDLE) {
return ret;
}
return r->client->flags.require_hwauth ? KRB5KDC_ERR_POLICY : 0;
}
static krb5_error_code KRB5_LIB_CALL
finalize_reply(krb5_context context, const void *plug, void *plugctx, void *userctx)
{
+12 -1
View File
@@ -95,6 +95,16 @@ typedef krb5_error_code
typedef krb5_error_code
(KRB5_CALLCONV *krb5plugin_kdc_referral_policy)(void *, astgs_request_t);
/*
* A hardware authentication policy plugin can indicate what is to
* happen when a client authenticates using a method other than
* hardware authentication. It can return zero to allow the
* authentication, or an appropriate error code to deny it.
*/
typedef krb5_error_code
(KRB5_CALLCONV *krb5plugin_kdc_hwauth_policy)(void *, astgs_request_t);
/*
* Update the AS or TGS reply immediately prior to encoding.
*/
@@ -117,7 +127,7 @@ typedef krb5_error_code
* Plugins should carefully check API contract notes for changes
* between plugin API versions.
*/
#define KRB5_PLUGIN_KDC_VERSION_10 10
#define KRB5_PLUGIN_KDC_VERSION_11 11
typedef struct krb5plugin_kdc_ftable {
HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context);
@@ -125,6 +135,7 @@ typedef struct krb5plugin_kdc_ftable {
krb5plugin_kdc_pac_verify pac_verify;
krb5plugin_kdc_client_access client_access;
krb5plugin_kdc_referral_policy referral_policy;
krb5plugin_kdc_hwauth_policy hwauth_policy;
krb5plugin_kdc_finalize_reply finalize_reply;
krb5plugin_kdc_audit audit;
} krb5plugin_kdc_ftable;
+1 -1
View File
@@ -228,5 +228,5 @@ There should be a way to specify protocol, port, and address triplets,
not just addresses and protocol, port tuples.
.Sh SEE ALSO
.Xr kinit 1 ,
.Xr krb5.conf 5,
.Xr krb5.conf 5 ,
.Xr getservbyname 3
+19 -13
View File
@@ -37,16 +37,15 @@
#if SIZEOF_TIME_T == 4
#define MAX_TIME ((time_t)INT32_MAX)
#elif SIZEOF_TIME_T == 8
#define MAX_TIME ((time_t)INT32_MAX)
#define MAX_TIME ((time_t)INT64_MAX)
#else
#error "Unexpected sizeof(time_t)"
#endif
#else
#if SIZEOF_TIME_T == 4
#define MAX_TIME ((time_t)INT32_MAX)
#define MAX_TIME ((time_t)UINT32_MAX)
#else
#define MAX_TIME ((time_t)INT32_MAX)
#define MAX_TIME ((time_t)UINT64_MAX)
#endif
#endif
@@ -536,7 +535,11 @@ pa_pkinit_validate(astgs_request_t r, const PA_DATA *pa)
ret = _kdc_pk_rd_padata(r, pa, &pkp);
if (ret || pkp == NULL) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
if (ret == KRB5_KDC_ERR_REVOKED_CERTIFICATE) {
ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED;
} else {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
}
_kdc_r_log(r, 4, "Failed to decode PKINIT PA-DATA -- %s",
r->cname);
goto out;
@@ -935,6 +938,9 @@ pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa)
goto out;
}
free_EncryptedData(&enc_data);
if (ret) {
goto out;
}
ret = decode_PA_ENC_TS_ENC(ts_data.data,
ts_data.length,
&p,
@@ -946,7 +952,7 @@ pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa)
r->cname);
goto out;
}
if (labs(kdc_time - p.patimestamp) > r->context->max_skew) {
if (krb5_time_abs(kdc_time, p.patimestamp) > r->context->max_skew) {
char client_time[100];
krb5_format_time(r->context, p.patimestamp,
@@ -956,7 +962,7 @@ pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa)
_kdc_r_log(r, 4, "Too large time skew, "
"client time %s is out by %u > %u seconds -- %s",
client_time,
(unsigned)labs(kdc_time - p.patimestamp),
(unsigned)krb5_time_abs(kdc_time, p.patimestamp),
r->context->max_skew,
r->cname);
kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT,
@@ -2263,12 +2269,12 @@ _kdc_as_rep(astgs_request_t r)
ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
goto out;
}
if (r->client->flags.require_hwauth &&
!(pat[n].flags & PA_HARDWARE_AUTH)) {
kdc_log(r->context, config, 4, "Hardware authentication required for %s", r->cname);
ret = KRB5KDC_ERR_POLICY;
goto out;
if (!(pat[n].flags & PA_HARDWARE_AUTH)) {
ret = _kdc_hwauth_policy(r);
if (ret) {
kdc_log(r->context, config, 4, "Hardware authentication required for %s", r->cname);
goto out;
}
}
kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_VIS, "pa", "%s",
pat[n].name);
+12 -19
View File
@@ -399,7 +399,6 @@ mk_error_response(krb5_context context,
Kx509Response rep;
const char *msg;
char *freeme0 = NULL;
char *freeme1 = NULL;
va_list ap;
if (code != 0) {
@@ -417,9 +416,6 @@ mk_error_response(krb5_context context,
va_end(ap);
}
if (!reqctx->config->enable_kx509)
code = KRB5KDC_ERR_POLICY;
/* Make sure we only send RFC4120 and friends wire protocol error codes */
if (code) {
if (code == KX509_ERR_NONE) {
@@ -441,12 +437,6 @@ mk_error_response(krb5_context context,
msg = freeme0;
va_end(ap);
if (!reqctx->config->enable_kx509 &&
asprintf(&freeme1, "kx509 service is disabled (%s)", msg) > -1 &&
freeme1 != NULL) {
msg = freeme1;
}
rep.hash = NULL;
rep.certificate = NULL;
rep.error_code = code;
@@ -468,7 +458,6 @@ mk_error_response(krb5_context context,
free(rep.e_text);
free(rep.hash);
free(freeme0);
free(freeme1);
return ret;
}
@@ -900,14 +889,15 @@ _kdc_do_kx509(kx509_req_context r)
if (r->req.authenticator.length == 0) {
/*
* Unauthenticated kx509 service availability probe.
*
* mk_error_response() will check whether the service is enabled and
* possibly change the error code and message.
*/
is_probe = 1;
kdc_audit_addkv((kdc_request_t)r, 0, "probe", "unauthenticated");
ret = mk_error_response(r->context, r, 4, 0,
"kx509 service is available");
if (!r->config->enable_kx509)
ret = mk_error_response(r->context, r, 4, KRB5KDC_ERR_POLICY,
"kx509 service is disabled");
else
ret = mk_error_response(r->context, r, 4, 0,
"kx509 service is available");
goto out;
}
@@ -938,6 +928,12 @@ _kdc_do_kx509(kx509_req_context r)
* Provided we got the session key, errors past this point will be
* authenticated.
*/
if (ret == 0 && !r->config->enable_kx509) {
ret = mk_error_response(r->context, r, 4, KRB5KDC_ERR_POLICY,
"kx509 service is disabled");
goto out;
}
if (ret == 0)
ret = krb5_ticket_get_client(r->context, ticket, &cprincipal);
@@ -983,9 +979,6 @@ _kdc_do_kx509(kx509_req_context r)
if (r->req.pk_key.length == 0) {
/*
* The request is an authenticated kx509 service availability probe.
*
* mk_error_response() will check whether the service is enabled and
* possibly change the error code and message.
*/
is_probe = 1;
kdc_audit_addkv((kdc_request_t)r, 0, "probe", "authenticated");
+4 -2
View File
@@ -432,7 +432,7 @@ pk_check_pkauthenticator_win2k(krb5_context context,
krb5_timeofday (context, &now);
/* XXX cusec */
if (a->ctime == 0 || labs(a->ctime - now) > context->max_skew) {
if (a->ctime == 0 || krb5_time_abs(a->ctime, now) > context->max_skew) {
krb5_clear_error_message(context);
return KRB5KRB_AP_ERR_SKEW;
}
@@ -451,7 +451,7 @@ pk_check_pkauthenticator(krb5_context context,
krb5_timeofday (context, &now);
/* XXX cusec */
if (a->ctime == 0 || labs(a->ctime - now) > context->max_skew) {
if (a->ctime == 0 || krb5_time_abs(a->ctime, now) > context->max_skew) {
krb5_clear_error_message(context);
return KRB5KRB_AP_ERR_SKEW;
}
@@ -797,6 +797,8 @@ _kdc_pk_rd_padata(astgs_request_t priv,
hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors);
hx509_certs_free(&trust_anchors);
hx509_verify_attach_revoke(cp->verify_ctx, kdc_identity->revokectx);
if (config->pkinit_allow_proxy_certs)
hx509_verify_set_proxy_certificate(cp->verify_ctx, 1);
+4 -1
View File
@@ -24,7 +24,10 @@ kpasswdd_LDADD = \
$(LDADD) \
$(LIB_pidfile) \
$(LIB_dlopen) \
$(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB)
$(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) \
$(SYSTEMD_LIBS)
kpasswdd_CFLAGS = $(SYSTEMD_CFLAGS)
LDADD = $(top_builddir)/lib/krb5/libkrb5.la \
$(top_builddir)/lib/asn1/libasn1.la \
+150 -60
View File
@@ -41,6 +41,11 @@ RCSID("$Id$");
#include <hdb.h>
#include <kadm5/private.h>
#include <kadm5/kadm5_err.h>
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
/* how often (seconds) to refresh the sd_notify STATUS line while idle */
#define STATUS_INTERVAL 30
#endif
static krb5_context context;
static krb5_log_facility *log_facility;
@@ -701,82 +706,167 @@ doit(krb5_keytab keytab, int port)
fd_set real_fdset;
struct sockaddr_storage __ss;
struct sockaddr *sa = (struct sockaddr *)&__ss;
int sd_activated = 0;
if (explicit_addresses.len) {
addrs = explicit_addresses;
} else {
ret = krb5_get_all_server_addrs(context, &addrs);
if (ret)
krb5_err(context, 1, ret, "krb5_get_all_server_addrs");
}
n = addrs.len;
#ifdef HAVE_SYSTEMD
{
char **names = NULL;
int sd_n, j;
sockets = malloc(n * sizeof(*sockets));
if (sockets == NULL)
krb5_errx(context, 1, "out of memory");
maxfd = -1;
FD_ZERO(&real_fdset);
for (i = 0; i < n; ++i) {
krb5_socklen_t sa_size = sizeof(__ss);
sd_n = sd_listen_fds_with_names(0, &names);
if (sd_n < 0)
krb5_err(context, 1, -sd_n, "sd_listen_fds_with_names");
if (sd_n > 0) {
sd_activated = 1;
sockets = malloc(sd_n * sizeof(*sockets));
if (sockets == NULL)
krb5_errx(context, 1, "out of memory");
memset(&addrs, 0, sizeof(addrs));
addrs.val = malloc(sd_n * sizeof(*addrs.val));
if (addrs.val == NULL)
krb5_errx(context, 1, "out of memory");
n = 0;
maxfd = -1;
FD_ZERO(&real_fdset);
for (j = 0; j < sd_n; j++) {
int fd = SD_LISTEN_FDS_START + j;
krb5_socklen_t sa_size = sizeof(__ss);
krb5_addr2sockaddr(context, &addrs.val[i], sa, &sa_size, port);
sockets[i] = socket(__ss.ss_family, SOCK_DGRAM, 0);
if (sockets[i] < 0)
krb5_err(context, 1, errno, "socket");
if (bind(sockets[i], sa, sa_size) < 0) {
char str[128];
size_t len;
int save_errno = errno;
ret = krb5_print_address(&addrs.val[i], str, sizeof(str), &len);
if (ret)
strlcpy(str, "unknown address", sizeof(str));
krb5_warn(context, save_errno, "bind(%s)", str);
continue;
if (names == NULL || names[j] == NULL ||
strncmp(names[j], "kpasswdd", 8) != 0)
continue;
if (getsockname(fd, sa, &sa_size) < 0) {
krb5_warn(context, errno,
"getsockname on socket-activated fd %d", fd);
continue;
}
if (krb5_sockaddr2address(context, sa, &addrs.val[n]) != 0)
continue;
sockets[n] = fd;
maxfd = max(maxfd, fd);
if (maxfd >= FD_SETSIZE)
krb5_errx(context, 1, "fd too large");
FD_SET(fd, &real_fdset);
n++;
}
addrs.len = n;
}
maxfd = max(maxfd, sockets[i]);
if (maxfd >= FD_SETSIZE)
krb5_errx(context, 1, "fd too large");
FD_SET(sockets[i], &real_fdset);
for (j = 0; names != NULL && names[j] != NULL; j++)
free(names[j]);
free(names);
}
#endif /* HAVE_SYSTEMD */
if (!sd_activated) {
if (explicit_addresses.len) {
addrs = explicit_addresses;
} else {
ret = krb5_get_all_server_addrs(context, &addrs);
if (ret)
krb5_err(context, 1, ret, "krb5_get_all_server_addrs");
}
n = addrs.len;
sockets = malloc(n * sizeof(*sockets));
if (sockets == NULL)
krb5_errx(context, 1, "out of memory");
maxfd = -1;
FD_ZERO(&real_fdset);
for (i = 0; i < n; ++i) {
krb5_socklen_t sa_size = sizeof(__ss);
krb5_addr2sockaddr(context, &addrs.val[i], sa, &sa_size, port);
sockets[i] = socket(__ss.ss_family, SOCK_DGRAM, 0);
if (sockets[i] < 0)
krb5_err(context, 1, errno, "socket");
if (bind(sockets[i], sa, sa_size) < 0) {
char str[128];
size_t len;
int save_errno = errno;
ret = krb5_print_address(&addrs.val[i], str, sizeof(str), &len);
if (ret)
strlcpy(str, "unknown address", sizeof(str));
krb5_warn(context, save_errno, "bind(%s)", str);
continue;
}
maxfd = max(maxfd, sockets[i]);
if (maxfd >= FD_SETSIZE)
krb5_errx(context, 1, "fd too large");
FD_SET(sockets[i], &real_fdset);
}
}
if (maxfd == -1)
krb5_errx(context, 1, "No sockets!");
roken_detach_finish(NULL, daemon_child);
while (exit_flag == 0) {
krb5_ssize_t retx;
fd_set fdset = real_fdset;
{
struct timeval *tmoutp = NULL;
#ifdef HAVE_SYSTEMD
unsigned long nrequests = 0;
struct timeval tmout;
retx = select(maxfd + 1, &fdset, NULL, NULL, NULL);
if (retx < 0) {
if (errno == EINTR)
continue;
else
krb5_err(context, 1, errno, "select");
}
for (i = 0; i < n; ++i)
if (FD_ISSET(sockets[i], &fdset)) {
u_char buf[BUFSIZ];
socklen_t addrlen = sizeof(__ss);
tmoutp = &tmout;
sd_notify(0, "READY=1");
sd_notifyf(0, "STATUS=Serving; %lu password change request(s) processed",
nrequests);
#endif
retx = recvfrom(sockets[i], buf, sizeof(buf), 0,
sa, &addrlen);
if (retx < 0) {
if (errno == EINTR)
break;
else
krb5_err(context, 1, errno, "recvfrom");
}
while (exit_flag == 0) {
krb5_ssize_t retx;
fd_set fdset = real_fdset;
process(keytab, sockets[i],
&addrs.val[i],
sa, addrlen,
buf, retx);
#ifdef HAVE_SYSTEMD
tmout.tv_sec = STATUS_INTERVAL;
tmout.tv_usec = 0;
#endif
retx = select(maxfd + 1, &fdset, NULL, NULL, tmoutp);
if (retx < 0) {
if (errno == EINTR)
continue;
else
krb5_err(context, 1, errno, "select");
}
#ifdef HAVE_SYSTEMD
if (retx == 0) {
/* select timed out: refresh our systemd status line */
sd_notifyf(0, "STATUS=Serving; %lu password change request(s) "
"processed", nrequests);
continue;
}
#endif
for (i = 0; i < n; ++i)
if (FD_ISSET(sockets[i], &fdset)) {
u_char buf[BUFSIZ];
socklen_t addrlen = sizeof(__ss);
retx = recvfrom(sockets[i], buf, sizeof(buf), 0,
sa, &addrlen);
if (retx < 0) {
if (errno == EINTR)
break;
else
krb5_err(context, 1, errno, "recvfrom");
}
process(keytab, sockets[i],
&addrs.val[i],
sa, addrlen,
buf, retx);
#ifdef HAVE_SYSTEMD
nrequests++;
#endif
}
}
}
#ifdef HAVE_SYSTEMD
sd_notify(0, "STOPPING=1");
#endif
for (i = 0; i < n; ++i)
close(sockets[i]);
free(sockets);
+4 -2
View File
@@ -1104,7 +1104,8 @@ get_new_tickets(krb5_context context,
}
if (ticket_life != 0) {
if (labs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) {
if (krb5_time_abs(cred.times.endtime - cred.times.starttime,
ticket_life) > 30) {
char life[64];
unparse_time_approx(cred.times.endtime - cred.times.starttime,
life, sizeof(life));
@@ -1112,7 +1113,8 @@ get_new_tickets(krb5_context context,
}
}
if (renew_life) {
if (labs(cred.times.renew_till - cred.times.starttime - renew) > 30) {
if (krb5_time_abs(cred.times.renew_till - cred.times.starttime,
renew) > 30) {
char life[64];
unparse_time_approx(cred.times.renew_till - cred.times.starttime,
life, sizeof(life));
-4
View File
@@ -1,8 +1,5 @@
include $(top_srcdir)/Makefile.am.common
if LIBEDIT
dir_editline = libedit
endif
if DCE
dir_dce = kdfs
endif
@@ -21,7 +18,6 @@ SUBDIRS = \
vers \
$(dir_com_err) \
base \
$(dir_editline) \
sl \
wind \
asn1 \
+3 -1
View File
@@ -97,8 +97,10 @@ der_print_hex_heim_integer (const heim_integer *data, char **p)
if (data->negative) {
len = asprintf(&q, "-%s", *p);
free(*p);
if (len < 0)
if (len < 0) {
*p = NULL;
return ENOMEM;
}
*p = q;
}
return 0;
+3
View File
@@ -191,6 +191,7 @@ init_generate (const char *filename, const char *base)
fprintf (headerfile,
"#include <stddef.h>\n"
"#include <stdint.h>\n"
"#include <errno.h>\n"
"#include <time.h>\n\n");
fprintf (headerfile,
"#ifndef __asn1_common_definitions__\n"
@@ -599,6 +600,8 @@ generate_constant (const Symbol *s)
/* header file */
gen_upper = strdup(s->gen_name);
if (gen_upper == NULL)
errx(1, "malloc");
len = strlen(gen_upper);
for (i = 0; i < len; i++)
gen_upper[i] = toupper((unsigned char)s->gen_name[i]);
+6
View File
@@ -289,7 +289,11 @@ static struct tlist *
tlist_new(const char *name)
{
struct tlist *tl = calloc(1, sizeof(*tl));
if (tl == NULL)
errx(1, "malloc");
tl->name = strdup(name);
if (tl->name == NULL)
errx(1, "malloc");
HEIM_TAILQ_INIT(&tl->template);
return tl;
}
@@ -421,6 +425,8 @@ add_line(struct templatehead *t, const char *fmt, ...)
{
struct template *q = calloc(1, sizeof(*q));
va_list ap;
if (q == NULL)
errx(1, "malloc");
va_start(ap, fmt);
if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL)
errx(1, "malloc");
+22 -14
View File
@@ -38,12 +38,26 @@
#include <vis.h>
#include <vis-extras.h>
#include <heimbase.h>
#include <errno.h>
#ifndef ENOTSUP
/* Very old MSVC CRTs don't have ENOTSUP */
#define ENOTSUP EINVAL
#endif
static int
int32_ptr_equal(int32_t i, const void *ptr)
{
const intptr_t v = (intptr_t)ptr;
#if INTPTR_MAX > INT32_MAX || INTPTR_MIN < INT32_MIN
if (v > INT32_MAX || v < INT32_MIN)
return 0;
#endif
return i == (int32_t)v;
}
struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = {
#define el(name, type) { \
(asn1_type_encode)der_put_##name, \
@@ -1493,9 +1507,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
} else if (tdefval->tt & A1_DV_INTEGER32) {
const int32_t *i = el;
if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
(int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
*i == (int32_t)(intptr_t)tdefval->ptr)
if (int32_ptr_equal(*i, tdefval->ptr))
break;
} else if (tdefval->tt & A1_DV_INTEGER) {
const struct heim_integer *i = el;
@@ -1567,9 +1579,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
} else if (tdefval->tt & A1_DV_INTEGER32) {
const int32_t *i = data;
if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
(int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
*i == (int32_t)(intptr_t)tdefval->ptr)
if (int32_ptr_equal(*i, tdefval->ptr))
exclude = 1;
} else if (tdefval->tt & A1_DV_INTEGER) {
const struct heim_integer *i = data;
@@ -2072,9 +2082,7 @@ _asn1_length(const struct asn1_template *t, const void *data)
} else if (tdefval->tt & A1_DV_INTEGER32) {
const int32_t *i = el;
if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
(int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
*i == (int32_t)(intptr_t)tdefval->ptr)
if (int32_ptr_equal(*i, tdefval->ptr))
break;
} else if (tdefval->tt & A1_DV_INTEGER) {
const struct heim_integer *i = el;
@@ -2131,9 +2139,7 @@ _asn1_length(const struct asn1_template *t, const void *data)
} else if (tdefval->tt & A1_DV_INTEGER32) {
const int32_t *i = data;
if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX &&
(int64_t)(intptr_t)tdefval->ptr >= INT_MIN &&
*i == (int32_t)(intptr_t)tdefval->ptr)
if (int32_ptr_equal(*i, tdefval->ptr))
exclude = 1;
} else if (tdefval->tt & A1_DV_INTEGER) {
const struct heim_integer *i = data;
@@ -2483,8 +2489,10 @@ _asn1_print_open_type(const struct asn1_template *t, /* object set template */
}
if (!(t->tt & A1_OS_OT_IS_ARRAY)) {
unsigned align = 8 - ((t->offset + sizeof(*elementp)) & 0x7);
dp = DPOC(data, t->offset + sizeof(*elementp) + align);
size_t offset = t->offset + sizeof(*elementp);
offset += (sizeof(void *) - offset % sizeof(void *)) % sizeof(void *);
dp = DPOC(data, offset);
if (*dp) {
struct rk_strpool *r2 = NULL;
char *s = NULL;
+17 -2
View File
@@ -46,6 +46,21 @@ static const unsigned ndays[2][12] ={
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
static time_t
_clamp_time_t(uint64_t t)
{
#if SIZEOF_TIME_T < 8
#ifdef TIME_T_UNSIGNED
#define MAX_TIME ((UINT64_C(1) << (SIZEOF_TIME_T * 8)) - 1)
#else
#define MAX_TIME ((UINT64_C(1) << ((SIZEOF_TIME_T * 8) - 1)) - 1)
#endif
return t < MAX_TIME ? t : MAX_TIME;
#else
return t;
#endif
}
/*
* This is a simplifed version of timegm(3) that doesn't accept out of
* bound values that timegm(3) normally accepts but those are not
@@ -55,7 +70,7 @@ static const unsigned ndays[2][12] ={
time_t
_der_timegm (struct tm *tm)
{
time_t res = 0;
uint64_t res = 0;
int i;
/*
@@ -89,7 +104,7 @@ _der_timegm (struct tm *tm)
res += tm->tm_min;
res *= 60;
res += tm->tm_sec;
return res;
return _clamp_time_t(res);
}
struct tm *
+23 -3
View File
@@ -86,6 +86,26 @@ static heim_error_code parse_list(struct fileptr *f, unsigned *lineno,
heim_config_binding **parent,
const char **err_message);
static int
todash(int c)
{
if (c == '_')
return '-';
return c;
}
static int
strcmp_du(const char *s1, const char *s2)
{
while (todash((unsigned char)*s1) == todash((unsigned char)*s2)) {
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return todash((unsigned char)*s1) - todash((unsigned char)*s2);
}
heim_config_section *
heim_config_get_entry(heim_config_section **parent, const char *name, int type)
{
@@ -94,7 +114,7 @@ heim_config_get_entry(heim_config_section **parent, const char *name, int type)
for (q = parent; *q != NULL; q = &(*q)->next)
if (type == heim_config_list &&
(unsigned)type == (*q)->type &&
strcmp(name, (*q)->name) == 0)
strcmp_du(name, (*q)->name) == 0)
return *q;
*q = calloc(1, sizeof(**q));
if (*q == NULL)
@@ -788,7 +808,7 @@ vget_next(heim_context context,
const char *p = va_arg(args, const char *);
while (b != NULL) {
if (strcmp(b->name, name) == 0) {
if (strcmp_du(b->name, name) == 0) {
if (b->type == (unsigned)type && p == NULL) {
*pointer = b;
return b->u.generic;
@@ -826,7 +846,7 @@ heim_config_vget_next(heim_context context,
/* we were called again, so just look for more entries with the
same name and type */
for (b = (*pointer)->next; b != NULL; b = b->next) {
if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {
if(strcmp_du(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {
*pointer = b;
return b->u.generic;
}
+28 -9
View File
@@ -355,11 +355,12 @@ open_file(heim_context context, heim_log_facility *fac, int min, int max,
return ret;
}
heim_error_code
heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
static heim_error_code
addlog_dest(heim_context context, heim_log_facility *f,
const char *orig, int default_min, int default_max)
{
heim_error_code ret = 0;
int min = 0, max = 3, n;
int min = default_min, max = default_max, n;
char c;
const char *p = orig;
#ifdef _WIN32
@@ -393,8 +394,6 @@ heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
return HEIM_ERR_LOG_PARSE;
}
p++;
} else {
max = 5;
}
if (strcmp(p, "STDERR") == 0) {
ret = open_file(context, f, min, max, NULL, "a", stderr,
@@ -445,6 +444,12 @@ heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
return ret;
}
heim_error_code
heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
{
return addlog_dest(context, f, orig, 0, 5);
}
heim_error_code
heim_openlog(heim_context context,
const char *program,
@@ -648,9 +653,9 @@ heim_add_warn_dest(heim_context context, const char *program,
return 0;
}
heim_error_code
heim_add_debug_dest(heim_context context, const char *program,
const char *log_spec)
static heim_error_code
add_debug_dest(heim_context context, const char *program,
const char *log_spec, int default_min, int default_max)
{
heim_log_facility *fac;
heim_error_code ret;
@@ -662,12 +667,26 @@ heim_add_debug_dest(heim_context context, const char *program,
heim_set_debug_dest(context, fac);
}
ret = heim_addlog_dest(context, fac, log_spec);
ret = addlog_dest(context, fac, log_spec, default_min, default_max);
if (ret)
return ret;
return 0;
}
heim_error_code
heim_add_debug_dest(heim_context context, const char *program,
const char *log_spec)
{
return add_debug_dest(context, program, log_spec, 0, 5);
}
heim_error_code
heim_add_trace_dest(heim_context context, const char *program,
const char *log_spec)
{
return add_debug_dest(context, program, log_spec, 0, -1);
}
struct heim_audit_kv_tuple {
heim_string_t key;
heim_object_t value;
+78
View File
@@ -142,6 +142,83 @@ test_rwlock(void)
return 0;
}
static int
file_contains(const char *filename, const char *needle)
{
char buf[1024];
FILE *f;
int found = 0;
f = fopen(filename, "r");
if (f == NULL)
return 0;
while (fgets(buf, sizeof(buf), f) != NULL) {
if (strstr(buf, needle) != NULL) {
found = 1;
break;
}
}
fclose(f);
return found;
}
static int
test_log_dest(void)
{
const char *normal = "test-log-dest.log";
const char *trace = "test-trace-dest.log";
const char *explicit = "test-trace-explicit-dest.log";
heim_log_facility *fac = NULL;
heim_context context;
int ret;
unlink(normal);
unlink(trace);
unlink(explicit);
context = heim_context_init();
heim_assert(context != NULL, "heim_context_init failed");
ret = heim_initlog(context, "test_base", &fac);
heim_assert(ret == 0, "heim_initlog failed");
ret = heim_addlog_dest(context, fac, normal);
heim_assert(ret == 0, "heim_addlog_dest failed");
heim_log(context, fac, 10, "normal level 10");
heim_log(context, fac, 5, "normal level 5");
heim_closelog(context, fac);
heim_assert(!file_contains(normal, "normal level 10"),
"normal log destination traced level 10 by default");
heim_assert(file_contains(normal, "normal level 5"),
"normal log destination did not log level 5 by default");
ret = heim_add_trace_dest(context, "test_base", trace);
heim_assert(ret == 0, "heim_add_trace_dest failed");
ret = heim_add_trace_dest(context, "test_base",
"5/FILE:test-trace-explicit-dest.log");
heim_assert(ret == 0, "heim_add_trace_dest with explicit level failed");
heim_debug(context, 10, "trace level 10");
heim_debug(context, 5, "trace level 5");
heim_assert(file_contains(trace, "trace level 10"),
"trace log destination did not trace level 10 by default");
heim_assert(!file_contains(explicit, "trace level 10"),
"explicit trace destination ignored its level filter");
heim_assert(file_contains(explicit, "trace level 5"),
"explicit trace destination did not log matching level");
heim_context_free(&context);
unlink(normal);
unlink(trace);
unlink(explicit);
return 0;
}
static int
test_dict(void)
{
@@ -1365,6 +1442,7 @@ main(int argc, char **argv)
res |= test_memory();
res |= test_mutex();
res |= test_rwlock();
res |= test_log_dest();
res |= test_dict();
res |= test_auto_release();
res |= test_string();
+1
View File
@@ -10,6 +10,7 @@ HEIMDAL_BASE_1.0 {
heim_abort;
heim_abortv;
heim_add_debug_dest;
heim_add_trace_dest;
heim_add_et_list;
heim_addlog_dest;
heim_addlog_func;
+6
View File
@@ -15,6 +15,7 @@
.Fl r
.Op Fl MNln
.Op Fl C Ar ccache
.Op Fl L Ar localuser
.Op Fl S Ar maxsize
.Op Fl c count
.Op Fl m mech
@@ -35,6 +36,11 @@ write an accepted delegated credential into
This only makes sense if
.Fl r
is specified.
.It Fl L Ar localuser
try to authorize as
.Ar localuser
with
.Fn gss_authorize_localname .
.It Fl D
delegate credentials.
This only makes sense as a client, that is when
+37 -7
View File
@@ -435,11 +435,13 @@ initiate_many(gss_name_t service, int delegate, int negotiate, int memcache,
}
static int
accept_one(gss_name_t service, const char *ccname, int negotiate)
accept_one(gss_name_t service, const char *ccname, const char *localuser,
int negotiate)
{
gss_cred_id_t cred = NULL;
gss_cred_id_t deleg_creds = NULL;
gss_name_t client;
gss_name_t client = GSS_C_NO_NAME;
gss_name_t lname = GSS_C_NO_NAME;
gss_OID mech_oid;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
@@ -495,8 +497,23 @@ accept_one(gss_name_t service, const char *ccname, int negotiate)
printf("Authenticated: %.*s\n", (int)dname.length,
(char *)dname.value);
(void) gss_release_buffer(&min, &dname);
(void) gss_release_name(&min, &client);
(void) gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER);
if (localuser) {
gss_buffer_desc lnamebuf;
lnamebuf.length = strlen(localuser);
lnamebuf.value = rk_UNCONST(localuser);
maj = gss_import_name(&min, &lnamebuf,
GSS_C_NT_USER_NAME, &lname);
GBAIL("gss_import_name", maj, min);
maj = gss_authorize_localname(&min, client, lname);
GBAIL("gss_authorize_localname", maj, min);
if (!nflag)
printf("Authorized: %s\n", localuser);
}
if (ccname) {
#ifdef HAVE_GSS_STORE_CRED_INTO
@@ -532,6 +549,12 @@ bail:
gss_release_cred(&min, &cred);
if (deleg_creds)
gss_release_cred(&min, &deleg_creds);
if (lname)
gss_release_name(&min, &lname);
if (client)
gss_release_name(&min, &client);
if (ctx != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER);
free(in.value);
@@ -585,8 +608,8 @@ usage(int ecode)
{
FILE *f = ecode == 0 ? stdout : stderr;
fprintf(f, "Usage: gss-token [-DNn] [-c count] service@host\n");
fprintf(f, " gss-token -r [-Nln] [-C ccache] [-c count] "
"[service@host]\n");
fprintf(f, " gss-token -r [-Nln] [-C ccache] [-L localuser] "
"[-c count] [service@host]\n");
exit(ecode);
}
@@ -606,12 +629,14 @@ main(int argc, char **argv)
int ret = 0;
int optidx = 0;
char *ccname = NULL;
char *localuser = NULL;
char *mech = NULL;
struct getargs args[] = {
{ "help", 'h', arg_flag, &hflag, NULL, NULL },
{ "version", 0, arg_flag, &version_flag, NULL, NULL },
{ NULL, 'C', arg_string, &ccname, NULL, NULL },
{ NULL, 'D', arg_flag, &Dflag, NULL, NULL },
{ NULL, 'L', arg_string, &localuser, NULL, NULL },
{ NULL, 'M', arg_flag, &Mflag, NULL, NULL },
{ NULL, 'N', arg_flag, &Nflag, NULL, NULL },
{ NULL, 'S', arg_integer, &Sflag, NULL, NULL },
@@ -662,6 +687,11 @@ main(int argc, char **argv)
"make sense without -r.\n");
usage(1);
}
if (localuser) {
fprintf(stderr, "Specifying a local user doesn't make "
"sense without -r.\n");
usage(1);
}
ret = initiate_many(service, Dflag, Nflag, Mflag, count);
goto done;
}
@@ -673,7 +703,7 @@ main(int argc, char **argv)
}
do {
ret = accept_one(service, ccname, Nflag);
ret = accept_one(service, ccname, localuser, Nflag);
} while (lflag && !ret && !feof(stdin));
done:
+1 -1
View File
@@ -926,7 +926,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_from
NULL, time_rec, NULL, actual_mechs);
if (ret != GSS_S_COMPLETE) {
if (handle->mechanisms != NULL)
gss_release_oid_set(NULL, &handle->mechanisms);
gss_release_oid_set(minor_status, &handle->mechanisms);
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
krb5_free_principal(context, handle->principal);
free(handle);
+2 -1
View File
@@ -238,6 +238,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred_from (
failure:
if (handle) {
OM_uint32 tmp_status;
if (handle->principal)
krb5_free_principal(context, handle->principal);
if (handle->keytab)
@@ -245,7 +246,7 @@ failure:
if (handle->ccache)
krb5_cc_destroy(context, handle->ccache);
if (handle->mechanisms)
gss_release_oid_set(NULL, &handle->mechanisms);
gss_release_oid_set(&tmp_status, &handle->mechanisms);
free(handle);
}
if (cred && output_cred_handle)
+15 -15
View File
@@ -308,7 +308,7 @@ _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, p, p, 8) != 1) {
EVP_Cipher(rc4_key, p, p, 8) != 8) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -392,7 +392,7 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, (void *)k6_data, NULL, 0) != 1 ||
EVP_Cipher(rc4_key, SND_SEQ, p, 8) != 1) {
EVP_Cipher(rc4_key, SND_SEQ, p, 8) != 8) {
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
return GSS_S_FAILURE;
@@ -553,7 +553,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8 + datalen) != 1) {
EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8 + datalen) != 8 + datalen) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -581,7 +581,7 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8) != 1) {
EVP_Cipher(rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8) != 8) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -690,7 +690,7 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, SND_SEQ, p0 + 8, 8) != 1) {
EVP_Cipher(rc4_key, SND_SEQ, p0 + 8, 8) != 8) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not decrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -747,8 +747,8 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, Confounder, p0 + 24, 8) != 1 ||
EVP_Cipher(rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen) != 1) {
EVP_Cipher(rc4_key, Confounder, p0 + 24, 8) != 8 ||
EVP_Cipher(rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen) != datalen) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not decrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1149,7 +1149,7 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
/* Confounder */
EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8) != 1) {
EVP_Cipher(rc4_key, p0 + 24, p0 + 24, 8) != 8) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1166,7 +1166,7 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
}
if (EVP_Cipher(rc4_key, iov[i].buffer.value,
iov[i].buffer.value, iov[i].buffer.length) != 1) {
iov[i].buffer.value, iov[i].buffer.length) != iov[i].buffer.length) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1177,7 +1177,7 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
/* Padding */
if (padding &&
EVP_Cipher(rc4_key, padding->buffer.value,
padding->buffer.value, padding->buffer.length) != 1) {
padding->buffer.value, padding->buffer.length) != padding->buffer.length) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1206,7 +1206,7 @@ _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, p0 + 8, p0 + 8, 8) != 1 /* SND_SEQ */) {
EVP_Cipher(rc4_key, p0 + 8, p0 + 8, 8) != 8 /* SND_SEQ */) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1357,7 +1357,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
}
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
EVP_Cipher(rc4_key, snd_seq, p0 + 8, 8) != 1 /* SND_SEQ */) {
EVP_Cipher(rc4_key, snd_seq, p0 + 8, 8) != 8 /* SND_SEQ */) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not decrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1410,7 +1410,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
if (EVP_CIPHER_CTX_init(rc4_key) != 1 ||
EVP_CipherInit_ex(rc4_key, context->ossl->rc4, NULL, k6_data, NULL, 1) != 1 ||
/* Confounder */
EVP_Cipher(rc4_key, Confounder, p0 + 24, 8) != 1) {
EVP_Cipher(rc4_key, Confounder, p0 + 24, 8) != 8) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not decrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1427,7 +1427,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
}
if (EVP_Cipher(rc4_key, iov[i].buffer.value,
iov[i].buffer.value, iov[i].buffer.length) != 1) {
iov[i].buffer.value, iov[i].buffer.length) != iov[i].buffer.length) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not decrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
@@ -1438,7 +1438,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
/* Padding */
if (padding &&
EVP_Cipher(rc4_key, padding->buffer.value,
padding->buffer.value, padding->buffer.length) != 1) {
padding->buffer.value, padding->buffer.length) != padding->buffer.length) {
EVP_CIPHER_CTX_free(rc4_key);
_krb5_debug_openssl(context, 4, "Could not encrypt with RC4 with OpenSSL");
*minor_status = KRB5_CRYPTO_INTERNAL;
+4 -3
View File
@@ -100,11 +100,12 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context (
return GSS_S_COMPLETE;
failed:
{ OM_uint32 tmp_status;
if (src_name)
_gsskrb5_release_name(NULL, src_name);
_gsskrb5_release_name(&tmp_status, src_name);
if (targ_name)
_gsskrb5_release_name(NULL, targ_name);
_gsskrb5_release_name(&tmp_status, targ_name);
}
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
+2 -1
View File
@@ -40,6 +40,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_mechs_for_name (
)
{
OM_uint32 ret;
OM_uint32 tmp_status;
ret = gss_create_empty_oid_set(minor_status, mech_types);
if (ret)
@@ -49,7 +50,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_mechs_for_name (
GSS_KRB5_MECHANISM,
mech_types);
if (ret)
gss_release_oid_set(NULL, mech_types);
gss_release_oid_set(&tmp_status, mech_types);
return ret;
}
+2 -1
View File
@@ -48,6 +48,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_names_for_mech (
)
{
OM_uint32 ret;
OM_uint32 tmp_status;
int i;
*minor_status = 0;
@@ -71,7 +72,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_names_for_mech (
}
if (ret != GSS_S_COMPLETE)
gss_release_oid_set(NULL, name_types);
gss_release_oid_set(&tmp_status, name_types);
return GSS_S_COMPLETE;
}
+19 -2
View File
@@ -83,8 +83,25 @@ set_proc(OM_uint32 *minor, gss_buffer_set_t env)
#ifndef WIN32
size_t i;
for (i = 0; i < env->count; i++)
putenv(env->elements[i].value);
for (i = 0; i < env->count; i++) {
char *var = (char *)env->elements[i].value;
char *eq = strchr(var, '=');
char *val;
int e;
if (eq == NULL) {
*minor = EINVAL;
return GSS_S_FAILURE;
}
val = eq + 1;
*eq = '\0';
e = setenv(var, val, 1);
*eq = '=';
if (e != 0) {
*minor = errno ? errno : EINVAL;
return GSS_S_FAILURE;
}
}
#endif
return GSS_S_COMPLETE;
}
+10 -1
View File
@@ -265,12 +265,14 @@ gss_accept_sec_context(OM_uint32 *minor_status,
*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
_mg_buffer_zero(output_token);
_gss_mg_log(10, "gss-asc: enter ctx=%p", ctx);
if (!*context_handle) {
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
*minor_status = ENOMEM;
return (GSS_S_DEFECTIVE_TOKEN);
}
_gss_mg_log(10, "gss-asc: allocated ctx=%p", ctx);
*context_handle = (gss_ctx_id_t)ctx;
ctx->gc_initial = 1;
}
@@ -318,6 +320,9 @@ gss_accept_sec_context(OM_uint32 *minor_status,
&mech_ret_flags,
time_rec,
&delegated_mc);
_gss_mg_log(10, "gss-asc: ctx=%p tried \"%s\", "
"returned %u", ctx, m->gm_name,
major_status);
if (major_status == GSS_S_DEFECTIVE_TOKEN) {
/*
* Try to retain and output one error token for
@@ -360,6 +365,9 @@ gss_accept_sec_context(OM_uint32 *minor_status,
&mech_ret_flags,
time_rec,
&delegated_mc);
_gss_mg_log(10, "gss-asc: ctx=%p tried \"%s\", "
"returned %u", ctx, m->gm_name,
major_status);
if (major_status == GSS_S_DEFECTIVE_TOKEN) {
if (output_token->length &&
defective_token_error.length == 0) {
@@ -510,7 +518,8 @@ got_one:
}
}
_gss_mg_log(10, "gss-asc: return %d/%d", (int)major_status, (int)*minor_status);
_gss_mg_log(10, "gss-asc: ctx=%p return %d/%d", ctx,
(int)major_status, (int)*minor_status);
if (ret_flags)
*ret_flags = mech_ret_flags;
+3
View File
@@ -38,6 +38,7 @@ gss_display_name(OM_uint32 *minor_status,
struct _gss_name *name = rk_UNCONST(input_name);
struct _gss_mechanism_name *mn;
_gss_mg_log(10, "gdn: enter gss_display_name: %p", input_name);
_mg_buffer_zero(output_name_buffer);
if (output_name_type)
*output_name_type = GSS_C_NO_OID;
@@ -68,6 +69,8 @@ gss_display_name(OM_uint32 *minor_status,
return (GSS_S_COMPLETE);
} else {
HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) {
_gss_mg_log(10, "gdn: trying mech \"%s\"",
mn->gmn_mech->gm_name);
major_status = mn->gmn_mech->gm_display_name(
minor_status, mn->gmn_name,
output_name_buffer,
+34
View File
@@ -28,6 +28,8 @@
#include "mech_locl.h"
#include <vis.h>
static OM_uint32
_gss_import_export_name(OM_uint32 *minor_status,
const gss_buffer_t input_name_buffer,
@@ -44,6 +46,8 @@ _gss_import_export_name(OM_uint32 *minor_status,
gss_name_t new_canonical_name;
int composite = 0;
_gss_mg_log(10, "gin: importing exported name");
*minor_status = 0;
*output_name = 0;
@@ -169,6 +173,32 @@ _gss_import_export_name(OM_uint32 *minor_status,
return (GSS_S_COMPLETE);
}
static void
log_import_name(gss_buffer_t input_name_buffer)
{
char *name;
size_t len;
if (!_gss_mg_log_level(10))
return;
if (input_name_buffer->length > (SIZE_MAX - 1) / 4) {
_gss_mg_log(10, "gin: importing name (%zu bytes)",
input_name_buffer->length);
return;
}
len = input_name_buffer->length * 4 + 1;
name = malloc(len);
if (name == NULL)
return;
strsvisx(name, input_name_buffer->value, input_name_buffer->length,
VIS_CSTYLE | VIS_TAB | VIS_NL, "\"");
_gss_mg_log(10, "gin: importing name \"%s\"", name);
free(name);
}
/**
* Convert a GGS-API name from contiguous string to internal form.
*
@@ -230,6 +260,7 @@ gss_import_name(OM_uint32 *minor_status,
name_type, output_name);
}
log_import_name(input_name_buffer);
*minor_status = 0;
name = _gss_create_name(NULL, NULL);
@@ -262,6 +293,9 @@ gss_import_name(OM_uint32 *minor_status,
HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
int present = 0;
_gss_mg_log(10, "gin: attempting mech \"%s\"",
m->gm_mech.gm_name);
if ((m->gm_mech.gm_flags & GM_USE_MG_NAME))
continue;
+5 -2
View File
@@ -167,7 +167,8 @@ do { \
m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \
if (!m->gm_mech.gm_ ## name || \
m->gm_mech.gm_ ##name == gss_ ## name) { \
_gss_mg_log(1, "can't find symbol gss_" #name "\n"); \
_gss_mg_log(1, "can't find symbol gss_" #name \
" in %s", lib); \
goto bad; \
} \
} while (0)
@@ -334,9 +335,11 @@ _gss_load_mech(void)
/*
* Check for duplicates, already loaded mechs.
*/
_gss_mg_log(10, "loading \"%s\"", name);
found = 0;
HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech_oid)) {
_gss_mg_log(10, "duplicate mech, not loading");
found = 1;
break;
}
@@ -346,7 +349,7 @@ _gss_load_mech(void)
so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP);
if (so == NULL) {
_gss_mg_log(1, "dlopen: %s\n", dlerror());
_gss_mg_log(1, "dlopen: %s", dlerror());
goto bad;
}
+168 -21
View File
@@ -99,6 +99,8 @@ static int help_flag = 0;
static int env_flag = 0;
static int def_flag = 0;
static int overwrite_flag = 0;
static int store_cred_flag = 0;
static char *password = NULL;
static struct getargs args[] = {
{"version", 0, arg_flag, &version_flag, "print version", NULL },
@@ -109,16 +111,133 @@ static struct getargs args[] = {
"switch credential store default principal", NULL },
{"overwrite", 0, arg_flag, &overwrite_flag,
"overwrite matching credential", NULL },
{"store-cred", 0, arg_flag, &store_cred_flag,
"use gss_store_cred instead of gss_store_cred_into2", NULL },
{"password", 0, arg_string, &password,
"acquire source credential with this password", "password" },
};
static void
usage(int ret)
{
arg_printusage(args, sizeof(args)/sizeof(*args),
NULL, "from_ccache to_ccache");
NULL, "from_ccache to_ccache | source_name target_name");
exit(ret);
}
static void
add_krb5_mech(gss_OID_set *mechs)
{
OM_uint32 major, minor;
major = gss_create_empty_oid_set(&minor, mechs);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_C_NO_OID,
"failed to create OID set");
major = gss_add_oid_set_member(&minor, GSS_KRB5_MECHANISM, mechs);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_C_NO_OID,
"failed to add krb5 mechanism to OID set");
}
static void
acquire_from_password(const char *source_name,
const char *source_password,
gss_cred_id_t *cred)
{
OM_uint32 major, minor;
gss_buffer_desc namebuf, pwbuf;
gss_name_t name = GSS_C_NO_NAME;
gss_OID_set mechs = GSS_C_NO_OID_SET;
namebuf.value = rk_UNCONST(source_name);
namebuf.length = strlen(source_name);
major = gss_import_name(&minor, &namebuf, GSS_C_NT_USER_NAME, &name);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_C_NO_OID,
"failed to import source name %s", source_name);
pwbuf.value = rk_UNCONST(source_password);
pwbuf.length = strlen(source_password);
add_krb5_mech(&mechs);
major = gss_acquire_cred_with_password(&minor, name, &pwbuf,
GSS_C_INDEFINITE, mechs,
GSS_C_INITIATE, cred, NULL, NULL);
(void) gss_release_oid_set(&minor, &mechs);
(void) gss_release_name(&minor, &name);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to acquire creds with password for %s", source_name);
}
static void
check_init_sec_context(gss_cred_id_t cred, const char *target)
{
OM_uint32 major, minor;
gss_buffer_desc namebuf;
gss_buffer_desc output_token = { 0, NULL };
gss_name_t target_name = GSS_C_NO_NAME;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
namebuf.value = rk_UNCONST(target);
namebuf.length = strlen(target);
major = gss_import_name(&minor, &namebuf, GSS_C_NT_HOSTBASED_SERVICE,
&target_name);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_C_NO_OID,
"failed to import target name %s", target);
major = gss_init_sec_context(&minor, cred, &ctx, target_name,
GSS_KRB5_MECHANISM, 0, GSS_C_INDEFINITE,
GSS_C_NO_CHANNEL_BINDINGS,
GSS_C_NO_BUFFER, NULL, &output_token,
NULL, NULL);
(void) gss_release_buffer(&minor, &output_token);
(void) gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
(void) gss_release_name(&minor, &target_name);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to use source cred for %s after storing", target);
}
static void
acquire_from_ccache(const char *ccache, gss_cred_id_t *cred)
{
OM_uint32 major, minor;
gss_key_value_element_desc element;
gss_key_value_set_desc store;
element.key = "ccache";
element.value = ccache;
store.count = 1;
store.elements = &element;
major = gss_add_cred_from(&minor, GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,
GSS_KRB5_MECHANISM, GSS_C_INITIATE,
GSS_C_INDEFINITE, GSS_C_INDEFINITE,
&store, cred, NULL, NULL, NULL);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to acquire stored creds from %s", ccache);
}
static void
check_default_ccache(gss_cred_id_t from_cred, const char *target)
{
OM_uint32 minor;
const char *ccache = getenv("KRB5CCNAME");
gss_cred_id_t to_cred = GSS_C_NO_CREDENTIAL;
if (ccache == NULL)
errx(1, "KRB5CCNAME not set");
acquire_from_ccache(ccache, &to_cred);
check_init_sec_context(from_cred, target);
check_init_sec_context(to_cred, target);
(void) gss_release_cred(&minor, &to_cred);
}
int
main(int argc, char **argv)
{
@@ -157,30 +276,42 @@ main(int argc, char **argv)
if (argc > 2)
errx(1, "too many arguments");
from_elements.key = "ccache";
from_elements.value = argv[0];
from.count = 1;
from.elements = &from_elements;
if (password) {
if (!store_cred_flag)
errx(1, "--password requires --store-cred");
acquire_from_password(argv[0], password, &from_cred);
} else {
from_elements.key = "ccache";
from_elements.value = argv[0];
from.count = 1;
from.elements = &from_elements;
to_elements.key = "ccache";
to_elements.value = argv[1];
to.count = 1;
to.elements = &to_elements;
major = gss_add_cred_from(&minor, GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,
GSS_KRB5_MECHANISM, GSS_C_INITIATE,
GSS_C_INDEFINITE, GSS_C_INDEFINITE,
&from, &from_cred, NULL, NULL, NULL);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to acquire creds from %s", argv[0]);
}
major = gss_add_cred_from(&minor, GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,
GSS_KRB5_MECHANISM, GSS_C_INITIATE,
GSS_C_INDEFINITE, GSS_C_INDEFINITE,
&from, &from_cred, NULL, NULL, NULL);
if (store_cred_flag) {
major = gss_store_cred(&minor, from_cred, GSS_C_INITIATE,
GSS_KRB5_MECHANISM, overwrite_flag, def_flag,
NULL, NULL);
} else {
to_elements.key = "ccache";
to_elements.value = argv[1];
to.count = 1;
to.elements = &to_elements;
major = gss_store_cred_into2(&minor, from_cred, GSS_C_INITIATE,
GSS_KRB5_MECHANISM, store_flags, &to, NULL,
NULL, env_flag ? &env : NULL);
}
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to acquire creds from %s", argv[0]);
major = gss_store_cred_into2(&minor, from_cred, GSS_C_INITIATE,
GSS_KRB5_MECHANISM, store_flags, &to, NULL,
NULL, env_flag ? &env : NULL);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to store creds into %s", argv[1]);
"failed to store creds");
if (env_flag) {
size_t i;
@@ -204,6 +335,22 @@ main(int argc, char **argv)
"gss_store_cred_into2()");
}
if (password)
check_default_ccache(from_cred, argv[1]);
if (store_cred_flag) {
(void) gss_release_cred(&minor, &from_cred);
return 0;
}
major = gss_add_cred_from(&minor, GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,
GSS_KRB5_MECHANISM, GSS_C_INITIATE,
GSS_C_INDEFINITE, GSS_C_INDEFINITE,
&to, &to_cred, NULL, NULL, NULL);
if (major != GSS_S_COMPLETE)
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
"failed to acquire stored creds from %s", argv[1]);
(void) gss_release_cred(&minor, &from_cred);
(void) gss_release_cred(&minor, &to_cred);
+1 -1
View File
@@ -483,7 +483,7 @@ loop(gss_OID mechoid,
if (*deleg_cred != GSS_C_NO_CREDENTIAL)
errx(1, "got delegated cred but didn't expect one");
} else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
errx(1, "asked for delegarated cred but did get one");
errx(1, "asked for delegated cred but did get one");
} else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
errx(1, "got deleg_cred cred but didn't ask");
-45
View File
@@ -149,55 +149,10 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
* enctypes should work.
*/
/* Debug: record the requested principal and keytab context */
{
char *princ_name = NULL;
if (krb5_unparse_name(context, principal, &princ_name) == 0) {
krb5_warnx(context, "hkt_fetch_kvno: looking up principal=%s in keytab=%s kvno=%u flags=0x%x",
princ_name ? princ_name : "<unparsed>",
k->path ? k->path : "<unknown>",
(unsigned)kvno,
(unsigned)flags);
} else {
krb5_warnx(context, "hkt_fetch_kvno: looking up <unparsed principal> in keytab=%s kvno=%u flags=0x%x",
k->path ? k->path : "<unknown>",
(unsigned)kvno,
(unsigned)flags);
}
free(princ_name);
}
ret = krb5_kt_get_entry(context, k->keytab, principal, kvno, 0, &ktentry);
if (ret) {
char *princ_name2 = NULL;
if (krb5_unparse_name(context, principal, &princ_name2) == 0) {
krb5_warnx(context, "hkt_fetch_kvno: krb5_kt_get_entry returned %d for principal=%s keytab=%s",
ret, princ_name2 ? princ_name2 : "<unparsed>", k->path ? k->path : "<unknown>");
} else {
krb5_warnx(context, "hkt_fetch_kvno: krb5_kt_get_entry returned %d for <unparsed principal> keytab=%s",
ret, k->path ? k->path : "<unknown>");
}
free(princ_name2);
ret = HDB_ERR_NOENTRY;
goto out;
} else {
/* Success: record what the keytab returned for inspection */
{
char *entry_princ = NULL;
if (krb5_unparse_name(context, ktentry.principal, &entry_princ) == 0) {
krb5_warnx(context, "hkt_fetch_kvno: krb5_kt_get_entry succeeded: entry_principal=%s vno=%d enctype=%d keytab=%s",
entry_princ ? entry_princ : "<unparsed>",
ktentry.vno,
ktentry.keyblock.keytype,
k->path ? k->path : "<unknown>");
} else {
krb5_warnx(context, "hkt_fetch_kvno: krb5_kt_get_entry succeeded: entry_principal=<unparsed> vno=%d enctype=%d keytab=%s",
ktentry.vno,
ktentry.keyblock.keytype,
k->path ? k->path : "<unknown>");
}
free(entry_princ);
}
}
ret = krb5_copy_principal(context, principal, &entry->principal);
+5 -1
View File
@@ -169,12 +169,15 @@ fuzz_jose_SOURCES = fuzz_jose.c
fuzz_jose_LDADD = libhx509.la $(LIB_roken) $(top_builddir)/lib/base/libheimbase.la
fuzz_jose.$(OBJEXT): $(HX509_PROTOS) $(nodist_include_HEADERS)
test_expr_LDADD = libhx509.la $(LIB_roken) $(top_builddir)/lib/asn1/libasn1.la
test_cert_binary_CPPFLAGS = $(AM_CPPFLAGS) -DSRCDIR=\"$(srcdir)\"
test_cert_binary_LDADD = libhx509.la $(LIB_roken) $(top_builddir)/lib/asn1/libasn1.la
TESTS = $(SCRIPT_TESTS) $(PROGRAM_TESTS)
PROGRAM_TESTS = \
test_name \
test_expr
test_expr \
test_cert_binary
SCRIPT_TESTS = \
test_ca \
@@ -336,6 +339,7 @@ EXTRA_DIST = \
data/key2.der \
data/nist-data \
data/nist-data2 \
data/notafter-2338.pem \
data/no-proxy-test.crt \
data/no-proxy-test.key \
data/ocsp-req1.der \
+14 -2
View File
@@ -66,6 +66,18 @@ struct hx509_ca_tbs {
AlgorithmIdentifier *sigalg;
};
static int
use_utc_time(time_t t)
{
if (t < 1)
return 1;
#if SIZEOF_TIME_T > 4 || defined(TIME_T_UNSIGNED)
if ((uint64_t)t >= 2524608000ULL)
return 0;
#endif
return 1;
}
/**
* Allocate an to-be-signed certificate object that will be converted
* into an certificate.
@@ -1773,13 +1785,13 @@ ca_sign(hx509_context context,
*
* Both, ...u.generalTime and ...u..utcTime are time_t.
*/
if (notBefore < 1 || (int64_t)notBefore < 2524608000)
if (use_utc_time(notBefore))
tbsc->validity.notBefore.element = choice_Time_utcTime;
else
tbsc->validity.notBefore.element = choice_Time_generalTime;
tbsc->validity.notBefore.u.generalTime = notBefore;
if (notAfter < 1 || (int64_t)notAfter < 2524608000)
if (use_utc_time(notAfter))
tbsc->validity.notAfter.element = choice_Time_utcTime;
else
tbsc->validity.notAfter.element = choice_Time_generalTime;
+38 -1
View File
@@ -78,6 +78,7 @@ struct hx509_cert_data {
unsigned int ref;
char *friendlyname;
Certificate *data;
heim_octet_string encoding;
hx509_private_key private_key;
struct _hx509_cert_attrs attrs;
hx509_name basename;
@@ -635,6 +636,8 @@ cert_init(hx509_context context, heim_error_t *error)
cert->release = NULL;
cert->ctx = NULL;
cert->data= NULL;
cert->encoding.data = NULL;
cert->encoding.length = 0;
return cert;
}
@@ -693,7 +696,23 @@ hx509_cert_copy_no_private_key(hx509_context context,
hx509_cert src,
heim_error_t *error)
{
return hx509_cert_init(context, src->data, error);
hx509_cert cert;
int ret;
cert = hx509_cert_init(context, src->data, error);
if (cert == NULL)
return NULL;
ret = der_copy_octet_string(&src->encoding, &cert->encoding);
if (ret) {
hx509_cert_free(cert);
if (error)
*error = heim_error_create_enomem();
errno = ret;
return NULL;
}
return cert;
}
/**
@@ -747,6 +766,7 @@ hx509_cert_init_data(hx509_context context,
heim_error_t *error)
{
hx509_cert cert;
heim_octet_string os;
Certificate t;
size_t size;
int ret;
@@ -769,6 +789,19 @@ hx509_cert_init_data(hx509_context context,
cert = hx509_cert_init(context, &t, error);
free_Certificate(&t);
if (cert == NULL)
return NULL;
os.length = len;
os.data = rk_UNCONST(ptr);
ret = der_copy_octet_string(&os, &cert->encoding);
if (ret) {
hx509_cert_free(cert);
if (error)
*error = heim_error_create_enomem();
errno = ret;
return NULL;
}
return cert;
}
@@ -824,6 +857,7 @@ hx509_cert_free(hx509_cert cert)
if (cert->data)
free_Certificate(cert->data);
free(cert->data);
der_free_octet_string(&cert->encoding);
for (i = 0; i < cert->attrs.len; i++) {
der_free_octet_string(&cert->attrs.val[i]->data);
@@ -4057,6 +4091,9 @@ hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
os->data = NULL;
os->length = 0;
if (c->encoding.data != NULL)
return der_copy_octet_string(&c->encoding, os);
ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
_hx509_get_cert(c), &size, ret);
if (ret) {
+25
View File
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIFATCCAumgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUwOSBUZXN0IFJv
b3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwMloYDzIzMzgwMTE5MDMxNDA4WjAhMQsw
CQYDVQQGEwJTRTESMBAGA1UEAwwJVGVzdCBjZXJ0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEA2h1NylGd8Z/XpHpF+HWYZrLFfVPeQjV0gc0en/ND16eDf/uizjxEN4BPITam9slRdJ7i
m7+t5OtyEWQ2iLOpkWPH7jjE9YwGceUJt+tXXb/bW3IHxSnobzOzoifvH1DwVTNjQSPgsvchd0ur
nXMqu7ZOiH985cY3PrYgwVc+bVd47w1H6UHn+rYtMj9CBY1Wr/XEuG6ZGucH1aE/KX3OsjmmqwZ6
4iY52JaeO8iveT6aJE5Lsq/kBw5x3C9wJ5c8ovppm1dLxVNeKAywx1cforImD1+/00V4kFos/Gpn
M7bBfs0XwFieuoXFFVpaZ9u/LwXNONmUyZV/m2iwYv83ks/Yd77Lcj0PuYBEV8DJEAH9ByUw69hI
Ba+Y+sRkbVmmao0b1EvzB5ho47tZySH4EbSighsN6IzgpeEcccrDLZBDw+6ZLH1BSDnIAHINgDkj
oTon7QfKMo80yrudZxN9Me1K2zV6zrOJ42SdPkdO07e9qxIWELtm6Bp3TCrguRZpZhSDTkrzb6uF
anDGm86Tq3U2o6Wqn0XWon8Xx2/59ec1UaV1xQe+Js57Pyk6dGsXeU7PTAppdVjb66jd8ebMoxhT
pcWlWqHPN2qxn9PU6w8CQNKuaM68xUbj7viXiO7IpwF6oSOv8zEsKm8Sd9w8UZ1A9Joqe4UpHz7D
1TeObgkCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFBv07DRCuotn
rFXyN120aKnYXlh7MA0GCSqGSIb3DQEBBQUAA4ICAQCV9xyZckJP0726P3p1uwE6rc5re7c9XTtG
UeqaNpRwNhw7/Lqdiw1ENgitpnOCvCPt+VoJj51iEcGUfGFmH4u5Ctw6tesiVN6j5YqUEB+EUm3+
J8jly6WOqYMWlQ1sPleF4eyCBUdtKK0NhPpAoJb0hKrR4Qu3keJHTwWX+BCg6Fe97UhlVXXa5TTo
8SCV1kCMQr+02VXIMOjVztgdMGWQOevig+0RA80HwOHEkYSgl45tIuZ1dyF8MotI7dayGS6vJq19
bM4J4Xi2cmFgIpK430JrNGtfNe/x08Z/kgU80Ah3AWb3V7hl3tPSsb+TsYyjJ+bU4iubzZ2+MYJb
U91avTkFX4xW8n+bt+/mB5a/itmNu2KYht6qkcP+57unH/D9H2ymBATwwlGhkYya7vmHQjd+nCdy
WdxgqI7RgZfxFcPYqU6aCemBdjk2swih5V6XN7pDjwYacGk7/nmmXi0mBOm8X1fJ0IDCDUvHDt0E
5RVJndf/7qMcBFZ94qDTORpZvYWw61TqgYvhF5Sl/uMM0HRC7kr0ZpBJS2S8RzX1smCOdAXQptKU
tOAPSz816irgJFjBbtBlblj34ZACrkAjJemAmtKn6l38bfhFD9tTkVUyRuNqwFQKWkzoGh6mMz7+
7batz2o8L7JsR3XxKUMxacMMQlZb2biZe/8rUIc0Lg==
-----END CERTIFICATE-----
+17
View File
@@ -47,6 +47,23 @@ for a in $srcdir/data/*.crt; do
${hxtool} print --content FILE:"$a" > /dev/null 2>/dev/null
done
echo "print certificate with 2338 notAfter"
${hxtool} print --content FILE:$srcdir/data/notafter-2338.pem > cert-2338.tmp || exit 1
config=$objdir/../../include/config.h
if grep '^#define SIZEOF_TIME_T 4$' "$config" > /dev/null; then
if grep '^#define TIME_T_UNSIGNED' "$config" > /dev/null; then
notafter='notAfter 2106-02-07 06:28:15'
else
notafter='notAfter 2038-01-19 03:14:07'
fi
else
notafter='notAfter 2338-01-19 03:14:08'
fi
grep "$notafter" cert-2338.tmp > /dev/null || {
cat cert-2338.tmp
exit 1
}
echo "print NULL"
${hxtool} print --content NULL: > /dev/null || exit 1
+179
View File
@@ -0,0 +1,179 @@
#include "hx_locl.h"
#include <err.h>
#ifndef SRCDIR
#define SRCDIR "."
#endif
struct pem_cert {
heim_octet_string der;
int found;
};
static int
pem_cert_reader(hx509_context context, const char *type,
const hx509_pem_header *headers,
const void *data, size_t length, void *ctx)
{
struct pem_cert *pem = ctx;
(void)context;
(void)headers;
if (strcmp(type, "CERTIFICATE") != 0)
return 0;
if (pem->found)
return 0;
pem->der.data = malloc(length);
if (pem->der.data == NULL)
return ENOMEM;
memcpy(pem->der.data, data, length);
pem->der.length = length;
pem->found = 1;
return 0;
}
static void
read_cert_der(hx509_context context, const char *path, heim_octet_string *der)
{
struct pem_cert pem;
FILE *f;
int ret;
memset(&pem, 0, sizeof(pem));
f = fopen(path, "r");
if (f == NULL)
err(1, "fopen: %s", path);
ret = hx509_pem_read(context, f, pem_cert_reader, &pem);
fclose(f);
if (ret)
hx509_err(context, 1, ret, "hx509_pem_read: %s", path);
if (!pem.found)
errx(1, "did not find a certificate in %s", path);
*der = pem.der;
}
static void
compare_octet_string(const char *what,
const heim_octet_string *expected,
const heim_octet_string *actual)
{
if (actual->length != expected->length)
errx(1, "%s length changed from %lu to %lu",
what, (unsigned long)expected->length,
(unsigned long)actual->length);
if (memcmp(actual->data, expected->data, expected->length) != 0)
errx(1, "%s data changed", what);
}
static void
check_cert_binary(hx509_context context, const heim_octet_string *der)
{
heim_octet_string os;
hx509_cert cert;
int ret;
memset(&os, 0, sizeof(os));
cert = hx509_cert_init_data(context, der->data, der->length, NULL);
if (cert == NULL)
err(1, "hx509_cert_init_data");
ret = hx509_cert_binary(context, cert, &os);
if (ret)
hx509_err(context, 1, ret, "hx509_cert_binary");
compare_octet_string("certificate encoding", der, &os);
der_free_octet_string(&os);
hx509_cert_free(cert);
}
static char *
make_store_name(void)
{
char *store_name = NULL;
if (asprintf(&store_name, "FILE:%s/data/test.crt,%s/data/test.key",
SRCDIR, SRCDIR) == -1 || store_name == NULL)
err(1, "asprintf");
return store_name;
}
static void
check_keyless_store_cert_encoding(hx509_context context,
const heim_octet_string *der)
{
heim_octet_string os;
hx509_certs certs = NULL;
hx509_cert cert = NULL;
char *store_name;
int ret;
memset(&os, 0, sizeof(os));
ret = hx509_certs_init(context, "MEMORY:test-keyless-certs",
HX509_CERTS_NO_PRIVATE_KEYS, NULL, &certs);
if (ret)
hx509_err(context, 1, ret, "hx509_certs_init");
store_name = make_store_name();
ret = hx509_certs_append(context, certs, NULL, store_name);
free(store_name);
if (ret)
hx509_err(context, 1, ret, "hx509_certs_append");
ret = hx509_get_one_cert(context, certs, &cert);
if (ret)
hx509_err(context, 1, ret, "hx509_get_one_cert");
if (hx509_cert_have_private_key(cert))
errx(1, "HX509_CERTS_NO_PRIVATE_KEYS store kept a private key");
ret = hx509_cert_binary(context, cert, &os);
if (ret)
hx509_err(context, 1, ret, "hx509_cert_binary on keyless cert");
compare_octet_string("keyless store certificate encoding", der, &os);
der_free_octet_string(&os);
hx509_cert_free(cert);
hx509_certs_free(&certs);
}
int
main(int argc, char **argv)
{
heim_octet_string der;
hx509_context context;
char *cert_path = NULL;
int ret;
(void)argc;
(void)argv;
memset(&der, 0, sizeof(der));
ret = hx509_context_init(&context);
if (ret)
errx(1, "hx509_context_init failed with %d", ret);
if (asprintf(&cert_path, "%s/data/test.crt", SRCDIR) == -1 ||
cert_path == NULL)
err(1, "asprintf");
read_cert_der(context, cert_path, &der);
free(cert_path);
check_cert_binary(context, &der);
check_keyless_store_cert_encoding(context, &der);
der_free_octet_string(&der);
hx509_context_free(&context);
return 0;
}
+13 -3
View File
@@ -46,14 +46,23 @@ if have_gcd
# stops building on recent OS X releases unless we disable this warning.
WFLAGS += -Wno-deprecated-declarations
heim_ipc.h heim_ipcUser.c heim_ipcServer.c heim_ipcServer.h: heim_ipc.defs
heim_ipc.stamp: heim_ipc.defs
mig -header heim_ipc.h -user heim_ipcUser.c -sheader heim_ipcServer.h -server heim_ipcServer.c -I$(srcdir) $(srcdir)/heim_ipc.defs
touch $@
heim_ipc_async.h heim_ipc_asyncUser.c heim_ipc_asyncServer.c heim_ipc_asyncServer.h: heim_ipc_async.defs
heim_ipc.h heim_ipcUser.c heim_ipcServer.c heim_ipcServer.h: heim_ipc.stamp
heim_ipc_async.stamp: heim_ipc_async.defs
mig -header heim_ipc_async.h -user heim_ipc_asyncUser.c -sheader heim_ipc_asyncServer.h -server heim_ipc_asyncServer.c -I$(srcdir) $(srcdir)/heim_ipc_async.defs
touch $@
heim_ipc_reply.h heim_ipc_replyUser.c: heim_ipc_reply.defs
heim_ipc_async.h heim_ipc_asyncUser.c heim_ipc_asyncServer.c heim_ipc_asyncServer.h: heim_ipc_async.stamp
heim_ipc_reply.stamp: heim_ipc_reply.defs
mig -header heim_ipc_reply.h -user heim_ipc_replyUser.c -sheader /dev/null -server /dev/null -I$(srcdir) $(srcdir)/heim_ipc_reply.defs
touch $@
heim_ipc_reply.h heim_ipc_replyUser.c: heim_ipc_reply.stamp
built_ipcc = heim_ipc.h heim_ipcUser.c
built_ipcc += heim_ipc_asyncServer.c heim_ipc_asyncServer.h
@@ -69,6 +78,7 @@ nodist_libheim_ipcs_la_SOURCES = $(built_ipcs)
libheim_ipcs_la_LIBADD += -lbsm
CLEANFILES = $(built_ipcc) $(built_ipcs)
CLEANFILES += heim_ipc.stamp heim_ipc_async.stamp heim_ipc_reply.stamp
$(srcdir)/client.c: $(built_ipcc)
$(srcdir)/server.c: $(built_ipcs)
-2
View File
@@ -41,8 +41,6 @@
#include <sys/un.h>
#endif
#include <poll.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
+11
View File
@@ -53,6 +53,17 @@
#define LOG_VERSION_FIRST 1
#define LOG_VERSION_UBER 0
#define LOG_HEADER_SZ ((off_t)(sizeof(uint32_t) * 4))
#define LOG_TRAILER_SZ ((off_t)(sizeof(uint32_t) * 2))
#define LOG_WRAPPER_SZ ((off_t)(LOG_HEADER_SZ + LOG_TRAILER_SZ))
#define LOG_UBER_LEN ((off_t)(sizeof(uint64_t) + sizeof(uint32_t) * 2))
#define LOG_UBER_SZ ((off_t)(LOG_WRAPPER_SZ + LOG_UBER_LEN))
struct kadm5_log_snap {
char bytes;
char buf[LOG_UBER_SZ + LOG_HEADER_SZ];
};
#include <krb5.h>
#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001
+22 -154
View File
@@ -191,20 +191,6 @@ _kadm5_c_init_context(kadm5_client_context **ctx,
}
if ((*ctx)->readonly_kadmind_port == 0)
(*ctx)->readonly_kadmind_port = (*ctx)->kadmind_port;
/*
* Extra debug: emit context-level info to help trace client init-time
* decisions in test logs.
*/
krb5_warnx(context,
"_kadm5_c_init_context: realm=%s admin_server=%s readonly_admin_server=%s kadmind_port=%u readonly_port=%u (pid=%d)",
(*ctx)->realm ? (*ctx)->realm : "<null>",
(*ctx)->admin_server ? (*ctx)->admin_server : "<null>",
(*ctx)->readonly_admin_server ? (*ctx)->readonly_admin_server : "<null>",
(unsigned)ntohs((*ctx)->kadmind_port),
(unsigned)ntohs((*ctx)->readonly_kadmind_port),
(int)getpid());
return 0;
}
@@ -217,12 +203,10 @@ kadm5_c_dup_context(void *vin, void **out)
kadm5_client_context *ctx;
*out = NULL;
ctx = malloc(sizeof(*ctx));
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
return krb5_enomem(in->context);
memset(ctx, 0, sizeof(*ctx));
set_funcs(ctx);
ctx->readonly_kadmind_port = in->readonly_kadmind_port;
ctx->kadmind_port = in->kadmind_port;
@@ -240,18 +224,13 @@ kadm5_c_dup_context(void *vin, void **out)
if (in->readonly_admin_server &&
(ctx->readonly_admin_server = strdup(in->readonly_admin_server)) == NULL)
ret = krb5_enomem(context);
/* Preserve client identity and prompter behavior in duplicated context */
if (in->client_name && (ctx->client_name = strdup(in->client_name)) == NULL)
if (in->client_name != NULL &&
(ctx->client_name = strdup(in->client_name)) == NULL)
ret = krb5_enomem(context);
if (in->service_name && (ctx->service_name = strdup(in->service_name)) == NULL)
ret = krb5_enomem(context);
/* Copy the prompter pointer so duplicated contexts behave the same
with respect to prompting vs keytab-based auth. */
ctx->prompter = in->prompter;
if (in->keytab && (ctx->keytab = strdup(in->keytab)) == NULL)
ret = krb5_enomem(context);
ctx->prompter = in->prompter;
if (in->ccache) {
char *fullname = NULL;
@@ -316,24 +295,7 @@ get_new_cache(krb5_context context,
krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
/*
* Extra debug: record the inputs to credential selection so tests can
* observe why keytab vs password paths were chosen.
*/
krb5_warnx(context,
"get_new_cache: entry client=%s password_provided=%d prompter=%p keytab=%s server_name=%s (pid=%d)",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>",
password ? 1 : 0,
(void *)prompter,
keytab ? keytab : "<default>",
server_name ? server_name : "<null>",
(int)getpid());
if(password == NULL && prompter == NULL) {
/* Debug: choosing keytab-based initial credentials */
krb5_warnx(context, "get_new_cache: choosing keytab auth (keytab=%s, client=%s)",
keytab ? keytab : "<default>",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
krb5_keytab kt;
if(keytab == NULL)
ret = krb5_kt_default(context, &kt);
@@ -350,21 +312,8 @@ get_new_cache(krb5_context context,
0,
server_name,
opt);
/* Log success/failure of keytab credential attempt for diagnostics */
if (ret == 0) {
krb5_warnx(context, "get_new_cache: krb5_get_init_creds_keytab succeeded for principal=%s using keytab=%s",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>",
keytab ? keytab : "<default>");
} else {
krb5_warn(context, ret, "get_new_cache: krb5_get_init_creds_keytab failed (keytab=%s)", keytab ? keytab : "<default>");
}
krb5_kt_close(context, kt);
} else {
/* Debug: choosing password-based initial credentials */
krb5_warnx(context, "get_new_cache: choosing password auth (password_provided=%d prompter=%p client=%s)",
password ? 1 : 0,
(void *)prompter,
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
ret = krb5_get_init_creds_password (context,
&cred,
client,
@@ -374,13 +323,6 @@ get_new_cache(krb5_context context,
0,
server_name,
opt);
if (ret == 0) {
krb5_warnx(context, "get_new_cache: krb5_get_init_creds_password succeeded for principal=%s",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
} else {
krb5_warn(context, ret, "get_new_cache: krb5_get_init_creds_password failed for principal=%s",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
}
}
krb5_get_init_creds_opt_free(context, opt);
switch(ret){
@@ -509,27 +451,6 @@ _kadm5_c_get_cred_cache(krb5_context context,
if(server_name == NULL)
server_name = KADM5_ADMIN_SERVICE;
/*
* Extra debug: log the invocation and environment so we can correlate
* with test harness behavior (e.g. whether KRB5_KTNAME / KRB5CCNAME
* were set).
*/
{
const char *env_kt = secure_getenv ? secure_getenv("KRB5_KTNAME") : getenv("KRB5_KTNAME");
const char *env_cc = secure_getenv ? secure_getenv("KRB5CCNAME") : getenv("KRB5CCNAME");
krb5_warnx(context,
"_kadm5_c_get_cred_cache: called client_name=%s server_name=%s password_provided=%d prompter=%p keytab=%s ccache=%p env.KRB5_KTNAME=%s env.KRB5CCNAME=%s (pid=%d)",
client_name ? client_name : "<null>",
server_name ? server_name : "<null>",
password ? 1 : 0,
(void *)prompter,
keytab ? keytab : "<null>",
(void *)ccache,
env_kt ? env_kt : "<unset>",
env_cc ? env_cc : "<unset>",
(int)getpid());
}
if(client_name != NULL) {
ret = krb5_parse_name(context, client_name, &client);
if(ret)
@@ -537,9 +458,19 @@ _kadm5_c_get_cred_cache(krb5_context context,
}
if(ccache != NULL) {
id = ccache;
ret = krb5_cc_get_principal(context, id, &client);
if(ret)
char *fullname = NULL;
ret = krb5_cc_get_full_name(context, ccache, &fullname);
if (ret)
return ret;
ret = krb5_cc_resolve(context, fullname, &id);
free(fullname);
if (ret)
return ret;
ret = krb5_cc_get_principal(context, id, &client);
if (ret)
return ret;
} else {
/* get principal from default cache, ok if this doesn't work */
@@ -584,47 +515,26 @@ _kadm5_c_get_cred_cache(krb5_context context,
if(id && client && (default_client == NULL ||
krb5_principal_compare(context, client, default_client) != 0)) {
/* Debug: attempting to obtain kadmin ticket from existing credential cache */
krb5_warnx(context, "_kadm5_c_get_cred_cache: trying credential cache to get kadmin ticket (client=%s)",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
ret = get_kadm_ticket(context, id, client, server_name);
if(ret == 0) {
krb5_warnx(context, "_kadm5_c_get_cred_cache: got kadmin ticket from cache for client=%s",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
*ret_cache = id;
krb5_free_principal(context, default_client);
if (default_client != client)
krb5_free_principal(context, client);
return 0;
}
krb5_warn(context, ret, "_kadm5_c_get_cred_cache: get_kadm_ticket from cache failed for client=%s", client ? krb5_principal_get_comp_string(context, client, 0) : "<null>");
if(ccache != NULL)
/* couldn't get ticket from cache */
return -1;
}
/* get creds via AS request */
if(id && (id != ccache))
if (id)
krb5_cc_close(context, id);
if (client != default_client)
krb5_free_principal(context, default_client);
ret = get_new_cache(context, client, password, prompter, keytab,
server_name, ret_cache);
/*
* Extra debug: report the result of get_new_cache so caller logs
* can show why auth succeeded/failed.
*/
if (ret == 0) {
krb5_warnx(context, "_kadm5_c_get_cred_cache: get_new_cache succeeded for client=%s (pid=%d)",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>",
(int)getpid());
} else {
krb5_warn(context, ret, "_kadm5_c_get_cred_cache: get_new_cache failed for client=%s (pid=%d)",
client ? krb5_principal_get_comp_string(context, client, 0) : "<null>",
(int)getpid());
}
krb5_free_principal(context, client);
return ret;
}
@@ -648,17 +558,6 @@ kadm_connect(kadm5_client_context *ctx)
krb5_context context = ctx->context;
int writable = 0;
/*
* Extra debug: record connect intent and client context pointers
* to help correlate kadmin network activity with credential selection.
*/
krb5_warnx(context, "kadm_connect: entering (client_name=%s prompter=%p keytab=%s ccache=%p pid=%d)",
ctx->client_name ? ctx->client_name : "<null>",
(void *)ctx->prompter,
ctx->keytab ? ctx->keytab : "<null>",
(void *)ctx->ccache,
(int)getpid());
if (ctx->ac)
krb5_auth_con_free(context, ctx->ac);
ctx->ac = NULL;
@@ -772,12 +671,6 @@ out:
rk_closesocket(s);
krb5_auth_con_free(context, ctx->ac);
ctx->ac = NULL;
} else {
/* Extra debug: successful connect and auth */
krb5_warnx(context, "kadm_connect: success connected_to_writable=%d sock=%d (pid=%d)",
(int)ctx->connected_to_writable,
(int)ctx->sock,
(int)getpid());
}
return ret;
}
@@ -824,25 +717,12 @@ kadm5_c_init_with_context(krb5_context context,
kadm5_client_context *ctx = NULL;
krb5_ccache cc;
/*
* Extra debug: record initialization flags and pointers so we can later
* understand whether a prompter was provided (which affects keytab vs
* password selection) and whether a keytab or ccache was requested.
*/
krb5_warnx(context, "kadm5_c_init_with_context: client_name=%s password_provided=%d prompter=%p keytab=%s ccache=%p service_name=%s (pid=%d)",
client_name ? client_name : "<null>",
password ? 1 : 0,
(void *)prompter,
keytab ? keytab : "<null>",
(void *)ccache,
service_name ? service_name : "<null>",
(int)getpid());
ret = _kadm5_c_init_context(&ctx, realm_params, context);
if (ret)
return ret;
if (password != NULL && *password != '\0') {
if ((password != NULL && *password != '\0') ||
(client_name && !keytab)) {
ret = _kadm5_c_get_cred_cache(context,
client_name,
service_name,
@@ -870,19 +750,6 @@ kadm5_c_init_with_context(krb5_context context,
ctx->sock = -1;
*server_handle = ctx;
/*
* Extra debug: final context values after init so logs show what the
* kadm client will carry into subsequent connect attempts.
*/
krb5_warnx(context, "kadm5_c_init_with_context: done ctx=%p client_name=%s prompter=%p keytab=%s ccache=%p (pid=%d)",
(void *)ctx,
ctx->client_name ? ctx->client_name : "<null>",
(void *)ctx->prompter,
ctx->keytab ? ctx->keytab : "<null>",
(void *)ctx->ccache,
(int)getpid());
return 0;
}
@@ -1069,3 +936,4 @@ kadm5_init(char *client_name, char *pass,
{
}
#endif
+285 -176
View File
@@ -86,37 +86,46 @@ make_signal_socket (krb5_context context)
#endif
}
static int
listen_port(krb5_context context, const char *port_str)
{
int port;
if (port_str) {
port = krb5_getportbyname(context, port_str, "tcp", 0);
if (port == 0) {
char *ptr;
long num;
num = strtol(port_str, &ptr, 10);
if (num == 0 && ptr == port_str)
krb5_errx(context, 1, "bad port `%s'", port_str);
port = htons(num);
}
} else {
port = krb5_getportbyname(context, IPROP_SERVICE,
"tcp", IPROP_PORT);
}
return port;
}
static krb5_socket_t
make_listen_socket (krb5_context context, const char *port_str)
make_listen_socket(krb5_context context, int port)
{
krb5_socket_t fd;
int one = 1;
struct sockaddr_in addr;
fd = socket (AF_INET, SOCK_STREAM, 0);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (rk_IS_BAD_SOCKET(fd))
krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF_INET");
(void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
memset (&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (port_str) {
addr.sin_port = krb5_getportbyname (context,
port_str, "tcp",
0);
if (addr.sin_port == 0) {
char *ptr;
long port;
port = strtol (port_str, &ptr, 10);
if (port == 0 && ptr == port_str)
krb5_errx (context, 1, "bad port `%s'", port_str);
addr.sin_port = htons(port);
}
} else {
addr.sin_port = krb5_getportbyname (context, IPROP_SERVICE,
"tcp", IPROP_PORT);
}
if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
krb5_err (context, 1, errno, "bind");
if (listen(fd, SOMAXCONN) < 0)
@@ -124,15 +133,68 @@ make_listen_socket (krb5_context context, const char *port_str)
return fd;
}
#ifdef AF_INET6
static krb5_socket_t
make_listen_socket6(krb5_context context, int port)
{
krb5_socket_t fd;
int one = 1;
struct sockaddr_in6 addr;
fd = socket(AF_INET6, SOCK_STREAM, 0);
if (rk_IS_BAD_SOCKET(fd)) {
#ifdef EAFNOSUPPORT
if (rk_SOCK_ERRNO != EAFNOSUPPORT)
#endif
krb5_warn(context, rk_SOCK_ERRNO, "socket AF_INET6");
return rk_INVALID_SOCKET;
}
(void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
socket_set_ipv6only(fd, 1);
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = port;
addr.sin6_addr = in6addr_any;
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
krb5_warn(context, errno, "bind AF_INET6");
rk_closesocket(fd);
return rk_INVALID_SOCKET;
}
if (listen(fd, SOMAXCONN) < 0) {
krb5_warn (context, errno, "listen AF_INET6");
rk_closesocket(fd);
return rk_INVALID_SOCKET;
}
return fd;
}
#endif
static void
make_listen_sockets(krb5_context context, const char *port_str,
krb5_socket_t *fds, int *num_fds)
{
krb5_socket_t fd;
int port = listen_port(context, port_str);
*num_fds = 0;
#ifdef AF_INET6
fd = make_listen_socket6(context, port);
if (!rk_IS_BAD_SOCKET(fd))
fds[(*num_fds)++] = fd;
#endif
fds[(*num_fds)++] = make_listen_socket(context, port);
}
struct slave {
krb5_socket_t fd;
struct sockaddr_in addr;
struct sockaddr_storage addr;
char *name;
krb5_auth_context ac;
uint32_t version;
uint32_t version_tstamp;
uint32_t version_ack;
time_t seen;
unsigned long flags;
#define SLAVE_F_DEAD 0x1
@@ -376,7 +438,6 @@ add_slave (krb5_context context, krb5_keytab keytab, slave **root,
krb5_warnx (context, "connection from %s", s->name);
s->version = 0;
s->version_ack = 0;
s->flags = 0;
slave_seen(s);
s->next = *root;
@@ -862,8 +923,11 @@ diffready(krb5_context context, slave *s)
* Don't send any diffs until slave has sent an I_HAVE telling us the
* initial version number!
*/
if ((s->flags & SLAVE_F_READY) == 0)
if ((s->flags & SLAVE_F_READY) == 0) {
if (verbose)
krb5_warnx(context, "not sending diffs to not-ready slave %s", s->name);
return 0;
}
if (s->flags & SLAVE_F_DEAD) {
if (verbose)
@@ -872,8 +936,11 @@ diffready(krb5_context context, slave *s)
}
/* Write any remainder of previous write, if we can. */
if (send_tail(context, s) != 0)
if (send_tail(context, s) != 0 && have_tail(s)) {
if (verbose)
krb5_warnx(context, "not sending diffs to busy slave %s", s->name);
return 0;
}
return 1;
}
@@ -881,10 +948,6 @@ diffready(krb5_context context, slave *s)
static int
nodiffs(krb5_context context, slave *s, uint32_t current_version)
{
krb5_storage *sp;
krb5_data data;
int ret;
if (s->version < current_version)
return 0;
@@ -897,6 +960,20 @@ nodiffs(krb5_context context, slave *s, uint32_t current_version)
if (verbose)
krb5_warnx(context, "slave %s version %ld already sent", s->name,
(long)s->version);
return 1;
}
static void
send_you_have_last_version(krb5_context context, slave *s)
{
krb5_storage *sp;
krb5_data data;
int ret;
if (verbose)
krb5_warnx(context, "slave %s version %ld is latest", s->name,
(long)s->version);
sp = krb5_storage_emem();
if (sp == NULL)
krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_mem");
@@ -909,19 +986,17 @@ nodiffs(krb5_context context, slave *s, uint32_t current_version)
krb5_storage_free(sp);
if (ret == 0) {
ret = mk_priv_tail(context, s, &data);
if (ret)
krb5_err(context, IPROPD_RESTART, ret,
"sending you have last version");
krb5_data_free(&data);
}
if (ret == 0)
send_tail(context, s);
return 1;
}
/*
* Lock the log and return initial version and timestamp
*/
static int
get_first(kadm5_server_context *server_context, int log_fd,
get_first(kadm5_server_context *server_context,
uint32_t *initial_verp, uint32_t *initial_timep)
{
krb5_context context = server_context->context;
@@ -931,19 +1006,14 @@ get_first(kadm5_server_context *server_context, int log_fd,
* We don't want to perform tight retry loops on log access errors, so on
* error mark the slave dead. The slave reconnect after a delay...
*/
if (flock(log_fd, LOCK_SH) == -1) {
krb5_warn(context, errno, "could not obtain shared lock on log file");
return -1;
}
ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST,
ret = kadm5_log_get_version_fd(server_context, -1, LOG_VERSION_FIRST,
initial_verp, initial_timep);
if (ret == HEIM_ERR_EOF)
ret = kadm5_log_get_version_fd(server_context, log_fd,
if (ret == HEIM_ERR_EOF || ret == KADM5_LOG_EMPTY)
ret = kadm5_log_get_version_fd(server_context, -1,
LOG_VERSION_UBER, initial_verp,
initial_timep);
if (ret != 0) {
flock(log_fd, LOCK_UN);
krb5_warn(context, ret, "could not read initial log entry");
return -1;
}
@@ -954,17 +1024,20 @@ get_first(kadm5_server_context *server_context, int log_fd,
/*-
* Find the left end of the diffs in the log we want to send.
*
* - On success, return a positive offset to the first new entry, retaining
* a read lock on the log file.
* - On error, return a negative offset, with the lock released.
* - On success, return a positive offset to the first new entry.
* - On error, return a negative offset.
* - If we simply find no successor entry in the log, return zero
* with the lock released, which indicates that fallback to send_complete()
* is needed.
*
* The caller must use kadm5_log_snapshot()/kadm5_log_snapshot_verify() to
* ensure that the data read here is consistent because there have been only
* append writes and/or there have been no log rotations.
*/
static off_t
get_left(kadm5_server_context *server_context, slave *s, krb5_storage *sp,
int log_fd, uint32_t current_version,
uint32_t *initial_verp, uint32_t *initial_timep)
uint32_t current_version, uint32_t *initial_verp,
uint32_t *initial_timep)
{
krb5_context context = server_context->context;
off_t pos;
@@ -974,17 +1047,13 @@ get_left(kadm5_server_context *server_context, slave *s, krb5_storage *sp,
for (;;) {
uint32_t ver = s->version;
/* This acquires a read lock on success */
ret = get_first(server_context, log_fd,
initial_verp, initial_timep);
ret = get_first(server_context, initial_verp, initial_timep);
if (ret != 0)
return -1;
/* When the slave version is out of range, send the whole database. */
if (ver == 0 || ver < *initial_verp || ver > current_version) {
flock(log_fd, LOCK_UN);
if (ver == 0 || ver + 1 < *initial_verp || ver > current_version)
return 0;
}
/* Avoid seeking past the last committed record */
if (kadm5_log_goto_end(server_context, sp) != 0 ||
@@ -1016,13 +1085,12 @@ get_left(kadm5_server_context *server_context, slave *s, krb5_storage *sp,
goto err;
/*
* Drop the lock and try to find the left entry by seeking backward
* from the end of the end of the log. If we succeed, re-acquire the
* lock, update "next_diff", and retry the fast-path.
* Slow path: seek backwards, entry by entry, from the end.
*
* Try to find the left entry by seeking backward from the end of the
* end of the log. If we succeed, update "next_diff", and retry the
* fast-path.
*/
flock(log_fd, LOCK_UN);
/* Slow path: seek backwards, entry by entry, from the end */
for (;;) {
enum kadm_ops op;
uint32_t len;
@@ -1038,7 +1106,7 @@ get_left(kadm5_server_context *server_context, slave *s, krb5_storage *sp,
/*
* We don't expect to reach the slave's version, unless the log
* has been modified after we released the lock.
* has been rotated.
*/
if (ver == s->version) {
krb5_warnx(context, "iprop log truncated while sending diffs "
@@ -1060,33 +1128,28 @@ get_left(kadm5_server_context *server_context, slave *s, krb5_storage *sp,
/*
* If we loop then we're hoping to hit the fast path so we can return a
* non-zero, positive left offset with the lock held.
* non-zero, positive left offset.
*
* We just updated the fast path pre-conditions, so unless a log
* truncation event happens between the point where we dropped the lock
* and the point where we rearcuire it above, we will hit the fast
* path.
* truncation event happens again, we will hit the fast path.
*/
}
err:
flock(log_fd, LOCK_UN);
return -1;
}
static off_t
get_right(krb5_context context, int log_fd, krb5_storage *sp,
int lastver, slave *s, off_t left, uint32_t *verp)
get_right(krb5_context context, krb5_storage *sp, int lastver, slave *s,
off_t left, uint32_t *verp)
{
int ret = 0;
int i = 0;
uint32_t ver = s->version;
off_t right = krb5_storage_seek(sp, left, SEEK_SET);
if (right <= 0) {
flock(log_fd, LOCK_UN);
if (right <= 0)
return -1;
}
/* The "lastver" bound should preclude us reaching EOF */
for (; ret == 0 && i < SEND_DIFFS_MAX_RECORDS && ver < lastver; ++i) {
@@ -1101,18 +1164,23 @@ get_right(krb5_context context, int log_fd, krb5_storage *sp,
right = krb5_storage_seek(sp, 0, SEEK_CUR);
else
right = -1;
if (right <= 0) {
flock(log_fd, LOCK_UN);
if (right <= 0)
return -1;
}
*verp = ver;
return right;
}
static void
send_diffs(kadm5_server_context *server_context, slave *s, int log_fd,
/*
* This function _must_ send something to the client unless it's dead, and if
* dead it must mark it so (and so close the connection). It is an error to
* return from this function without having done so _unless_ the client is
* either dead or not ready.
*/
static kadm5_ret_t
send_diffs(kadm5_server_context *server_context, slave *s,
const char *database, uint32_t current_version)
{
struct kadm5_log_snap snap;
krb5_context context = server_context->context;
krb5_storage *sp;
uint32_t initial_version;
@@ -1122,84 +1190,122 @@ send_diffs(kadm5_server_context *server_context, slave *s, int log_fd,
off_t right = 0;
krb5_ssize_t bytes;
krb5_data data;
int ret = 0;
kadm5_ret_t ret = 0;
if (!diffready(context, s) || nodiffs(context, s, current_version))
return;
/*
* diffready() can send part of an extant buffer, and does nothing if the
* client is either dead or not ready.
*/
if (!diffready(context, s))
return 0;
/* From this point onwards we cannot return without having sent anything */
if (nodiffs(context, s, current_version)) {
if (verbose)
krb5_warnx(context, "not sending diffs to up-to-date slave %s (no diffs)", s->name);
send_you_have_last_version(context, s);
return 0;
}
if (verbose)
krb5_warnx(context, "sending diffs to live-seeming slave %s", s->name);
sp = krb5_storage_from_fd(log_fd);
ret = kadm5_log_snapshot(server_context, &snap);
if (ret) {
/*
* Here ret would be KADM5_LOG_CORRUPT. What can we do?
*/
send_you_have_last_version(context, s);
return 0;
}
sp = krb5_storage_from_fd(server_context->log_context.log_fd);
if (sp == NULL)
krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM,
"send_diffs: out of memory");
left = get_left(server_context, s, sp, log_fd, current_version,
left = get_left(server_context, s, sp, current_version,
&initial_version, &initial_tstamp);
if (left < 0) {
/* Some sort of error; fallback on full prop */
krb5_storage_free(sp);
slave_dead(context, s);
return;
if (verbose)
krb5_warnx(context, "sending full prop to slave %s "
"(could not find offset for incremental)", s->name);
send_complete(context, s, database, current_version,
initial_version, initial_tstamp);
return 0;
}
if (left == 0) {
/* Slave's version is not in the log, fall back on send_complete() */
krb5_storage_free(sp);
if (verbose)
krb5_warnx(context, "sending full prop to slave %s "
"(their version is too old)", s->name);
send_complete(context, s, database, current_version,
initial_version, initial_tstamp);
return;
return 0;
}
/* We still hold the read lock, if right > 0 */
right = get_right(server_context->context, log_fd, sp, current_version,
right = get_right(server_context->context, sp, current_version,
s, left, &ver);
if (right == left) {
flock(log_fd, LOCK_UN);
/* Shouldn't happen */
krb5_storage_free(sp);
return;
if (verbose)
krb5_warnx(context, "not sending diffs to up-to-date slave %s (weird)", s->name);
send_you_have_last_version(context, s);
return 0;
}
if (right < left) {
assert(right < 0);
krb5_storage_free(sp);
slave_dead(context, s);
return;
return 0;
}
if (krb5_storage_seek(sp, left, SEEK_SET) != left) {
ret = errno ? errno : EIO;
flock(log_fd, LOCK_UN);
krb5_warn(context, ret, "send_diffs: krb5_storage_seek");
krb5_warn(context, errno ? errno : EIO, "send_diffs: krb5_storage_seek");
krb5_storage_free(sp);
slave_dead(context, s);
return;
return 0;
}
ret = krb5_data_alloc(&data, right - left + 4);
if (ret) {
flock(log_fd, LOCK_UN);
krb5_warn(context, ret, "send_diffs: krb5_data_alloc");
krb5_storage_free(sp);
slave_dead(context, s);
return;
}
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "out of memory");
bytes = krb5_storage_read(sp, (char *)data.data + 4, data.length - 4);
flock(log_fd, LOCK_UN);
krb5_storage_free(sp);
if (bytes != data.length - 4)
krb5_errx(context, IPROPD_RESTART, "locked log truncated???");
if (bytes != data.length - 4) {
krb5_warnx(context, "send_diffs: log rotated");
return KADM5_LOG_SNAPSHOT_INVALID;
}
ret = kadm5_log_snapshot_verify(server_context, &snap);
if (ret) {
krb5_data_free(&data);
if (ret == KADM5_LOG_SNAPSHOT_INVALID) {
krb5_warnx(context, "send_diffs: log rotated");
return ret;
}
krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "out of memory");
}
sp = krb5_storage_from_data(&data);
if (sp == NULL) {
if (sp == NULL)
krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "out of memory");
return;
}
ret = krb5_store_uint32(sp, FOR_YOU);
krb5_storage_free(sp);
if (ret == 0)
if (ret == 0) {
ret = mk_priv_tail(context, s, &data);
if (ret == ENOMEM)
krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "out of memory");
}
krb5_data_free(&data);
if (ret == 0) {
/* Save the fast-path continuation */
@@ -1221,10 +1327,10 @@ send_diffs(kadm5_server_context *server_context, slave *s, int log_fd,
krb5_warn(context, ret, "send_diffs: making or sending "
"KRB-PRIV message");
slave_dead(context, s);
return;
return ret;
}
slave_seen(s);
return;
return 0;
}
/* Sensible bound on slave message size */
@@ -1299,7 +1405,7 @@ read_msg(krb5_context context, slave *s, krb5_data *out)
}
static int
process_msg(kadm5_server_context *server_context, slave *s, int log_fd,
process_msg(kadm5_server_context *server_context, slave *s,
const char *database, uint32_t current_version)
{
krb5_context context = server_context->context;
@@ -1307,6 +1413,7 @@ process_msg(kadm5_server_context *server_context, slave *s, int log_fd,
krb5_data out;
krb5_storage *sp;
uint32_t tmp;
int tries = 3;
ret = read_msg(context, s, &out);
if (ret) {
@@ -1372,9 +1479,9 @@ process_msg(kadm5_server_context *server_context, slave *s, int log_fd,
krb5_warnx(context, "slave %s ready for updates from version %u",
s->name, tmp);
}
if ((s->version_ack = tmp) < s->version)
break;
send_diffs(server_context, s, log_fd, database, current_version);
do {
ret = send_diffs(server_context, s, database, current_version);
} while (ret == KADM5_LOG_SNAPSHOT_INVALID && tries--);
break;
case I_AM_HERE :
if (verbose)
@@ -1490,7 +1597,7 @@ write_stats(krb5_context context, slave *slaves, uint32_t current_version)
} else
rtbl_add_column_entry(tbl, SLAVE_ADDRESS, "<unknown>");
snprintf(str, sizeof(str), "%u", (unsigned)slaves->version_ack);
snprintf(str, sizeof(str), "%u", (unsigned)slaves->version);
rtbl_add_column_entry(tbl, SLAVE_VERSION, str);
if (slaves->flags & SLAVE_F_DEAD)
@@ -1570,14 +1677,14 @@ main(int argc, char **argv)
void *kadm_handle;
kadm5_server_context *server_context;
kadm5_config_params conf;
krb5_socket_t signal_fd, listen_fd;
int log_fd;
krb5_socket_t signal_fd, listen_fds[2];
slave *slaves = NULL;
uint32_t current_version = 0, old_version = 0;
krb5_keytab keytab;
char **files;
int aret;
int optidx = 0;
int num_listen_fds = 0;
int restarter_fd = -1;
struct stat st;
@@ -1675,24 +1782,19 @@ main(int argc, char **argv)
server_context = (kadm5_server_context *)kadm_handle;
log_fd = open (server_context->log_context.log_file, O_RDONLY, 0);
if (log_fd < 0)
krb5_err (context, 1, errno, "open %s",
server_context->log_context.log_file);
ret = kadm5_log_init_nolock(server_context);
if (ret)
krb5_err(context, 1, ret, "Could not open iprop log file");
if (fstat(log_fd, &st) == -1)
if (fstat(server_context->log_context.log_fd, &st) == -1)
krb5_err(context, 1, errno, "stat %s",
server_context->log_context.log_file);
if (flock(log_fd, LOCK_SH) == -1)
krb5_err(context, 1, errno, "shared flock %s",
server_context->log_context.log_file);
kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
kadm5_log_get_version_fd(server_context, -1, LOG_VERSION_LAST,
&current_version, NULL);
flock(log_fd, LOCK_UN);
signal_fd = make_signal_socket (context);
listen_fd = make_listen_socket (context, port_str);
make_listen_sockets(context, port_str, listen_fds, &num_listen_fds);
krb5_warnx(context, "ipropd-master started at version: %lu",
(unsigned long)current_version);
@@ -1704,22 +1806,28 @@ main(int argc, char **argv)
slave *p;
fd_set readset, writeset;
int max_fd = 0;
int nready;
int i;
struct timeval to = {30, 0};
uint32_t vers;
struct stat st2;;
struct stat st2;
#ifndef NO_LIMIT_FD_SETSIZE
if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE ||
restarter_fd >= FD_SETSIZE)
if (signal_fd >= FD_SETSIZE || restarter_fd >= FD_SETSIZE)
krb5_errx (context, IPROPD_RESTART, "fd too large");
for (i = 0; i < num_listen_fds; i++)
if (listen_fds[i] >= FD_SETSIZE)
krb5_errx (context, IPROPD_RESTART, "fd too large");
#endif
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(signal_fd, &readset);
max_fd = max(max_fd, signal_fd);
FD_SET(listen_fd, &readset);
max_fd = max(max_fd, listen_fd);
for (i = 0; i < num_listen_fds; i++) {
FD_SET(listen_fds[i], &readset);
max_fd = max(max_fd, listen_fds[i]);
}
if (restarter_fd > -1) {
FD_SET(restarter_fd, &readset);
max_fd = max(max_fd, restarter_fd);
@@ -1741,6 +1849,7 @@ main(int argc, char **argv)
else
krb5_err (context, IPROPD_RESTART, errno, "select");
}
nready = ret;
if (stat(server_context->log_context.log_file, &st2) == -1) {
krb5_warn(context, errno, "could not stat log file by path");
@@ -1748,36 +1857,24 @@ main(int argc, char **argv)
}
if (st2.st_dev != st.st_dev || st2.st_ino != st.st_ino) {
(void) close(log_fd);
kadm5_log_end(server_context);
log_fd = open(server_context->log_context.log_file, O_RDONLY, 0);
if (log_fd < 0)
krb5_err(context, IPROPD_RESTART_SLOW, errno, "open %s",
server_context->log_context.log_file);
ret = kadm5_log_init_nolock(server_context);
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret,
"Could not re-open iprop log file");
if (fstat(log_fd, &st) == -1)
if (fstat(server_context->log_context.log_fd, &st) == -1)
krb5_err(context, IPROPD_RESTART_SLOW, errno, "stat %s",
server_context->log_context.log_file);
if (flock(log_fd, LOCK_SH) == -1)
krb5_err(context, IPROPD_RESTART, errno, "shared flock %s",
server_context->log_context.log_file);
kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
kadm5_log_get_version_fd(server_context, -1, LOG_VERSION_LAST,
&current_version, NULL);
flock(log_fd, LOCK_UN);
}
if (ret == 0) {
/* Recover from failed transactions */
if (kadm5_log_init_nb(server_context) == 0)
kadm5_log_end(server_context);
if (flock(log_fd, LOCK_SH) == -1)
krb5_err(context, IPROPD_RESTART, errno,
"could not lock log file");
kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
if (nready == 0) {
kadm5_log_get_version_fd(server_context, -1, LOG_VERSION_LAST,
&current_version, NULL);
flock(log_fd, LOCK_UN);
if (current_version > old_version) {
if (verbose)
@@ -1786,21 +1883,25 @@ main(int argc, char **argv)
(unsigned long)old_version,
(unsigned long)current_version);
for (p = slaves; p != NULL; p = p->next) {
int tries = 3;
if (p->flags & SLAVE_F_DEAD)
continue;
send_diffs(server_context, p, log_fd, database,
current_version);
do {
ret = send_diffs(server_context, p, database,
current_version);
} while (ret == KADM5_LOG_SNAPSHOT_INVALID && tries--);
}
old_version = current_version;
}
}
if (ret && FD_ISSET(restarter_fd, &readset)) {
if (nready && restarter_fd > -1 && FD_ISSET(restarter_fd, &readset)) {
exit_flag = SIGTERM;
break;
}
if (ret && FD_ISSET(signal_fd, &readset)) {
if (nready && FD_ISSET(signal_fd, &readset)) {
#ifndef NO_UNIX_SOCKETS
struct sockaddr_un peer_addr;
#else
@@ -1813,15 +1914,11 @@ main(int argc, char **argv)
krb5_warn (context, errno, "recvfrom");
continue;
}
--ret;
assert(ret >= 0);
--nready;
assert(nready >= 0);
old_version = current_version;
if (flock(log_fd, LOCK_SH) == -1)
krb5_err(context, IPROPD_RESTART, errno, "shared flock %s",
server_context->log_context.log_file);
kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
kadm5_log_get_version_fd(server_context, -1, LOG_VERSION_LAST,
&current_version, NULL);
flock(log_fd, LOCK_UN);
if (current_version != old_version) {
/*
* If current_version < old_version then the log got
@@ -1841,10 +1938,14 @@ main(int argc, char **argv)
(unsigned long)old_version,
(unsigned long)current_version);
for (p = slaves; p != NULL; p = p->next) {
int tries = 3;
if (p->flags & SLAVE_F_DEAD)
continue;
send_diffs(server_context, p, log_fd, database,
current_version);
do {
ret = send_diffs(server_context, p, database,
current_version);
} while (ret == EAGAIN && tries--);
}
} else {
if (verbose)
@@ -1859,31 +1960,39 @@ main(int argc, char **argv)
FD_ISSET(p->fd, &writeset) &&
((have_tail(p) && send_tail(context, p) == 0) ||
(!have_tail(p) && more_diffs(p)))) {
send_diffs(server_context, p, log_fd, database,
current_version);
int tries = 3;
do {
ret = send_diffs(server_context, p, database,
current_version);
} while (ret == KADM5_LOG_SNAPSHOT_INVALID && tries--);
}
}
for(p = slaves; p != NULL; p = p->next) {
if (p->flags & SLAVE_F_DEAD)
continue;
if (ret && FD_ISSET(p->fd, &readset)) {
--ret;
assert(ret >= 0);
ret = process_msg(server_context, p, log_fd, database,
if (nready && FD_ISSET(p->fd, &readset)) {
--nready;
assert(nready >= 0);
ret = process_msg(server_context, p, database,
current_version);
if (ret && ret != EWOULDBLOCK)
if (ret && ret != EWOULDBLOCK) {
krb5_warn(context, ret, "process_msg()");
slave_dead(context, p);
}
} else if (slave_gone_p (p))
slave_dead(context, p);
else if (slave_missing_p (p))
send_are_you_there (context, p);
}
if (ret && FD_ISSET(listen_fd, &readset)) {
add_slave (context, keytab, &slaves, listen_fd);
--ret;
assert(ret >= 0);
for (i = 0; nready && i < num_listen_fds; i++) {
if (FD_ISSET(listen_fds[i], &readset)) {
add_slave(context, keytab, &slaves, listen_fds[i]);
--nready;
assert(nready >= 0);
}
}
write_stats(context, slaves, current_version);
}
+6 -36
View File
@@ -124,16 +124,14 @@ connect_to_master (krb5_context context, const char *master,
}
static void
get_creds(krb5_context context, krb5_ccache *cache, const char *serverhost)
get_creds(krb5_context context, krb5_ccache *cache)
{
krb5_keytab keytab;
krb5_principal client;
krb5_error_code ret;
krb5_get_init_creds_opt *init_opts;
krb5_creds creds;
char *server;
char keytab_buf[256];
int aret;
if (no_keytab_flag) {
/* We're using an externally refreshed ccache */
@@ -176,13 +174,8 @@ get_creds(krb5_context context, krb5_ccache *cache, const char *serverhost)
ret = krb5_get_init_creds_opt_alloc(context, &init_opts);
if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
aret = asprintf (&server, "%s/%s", IPROP_NAME, serverhost);
if (aret == -1 || server == NULL)
krb5_errx (context, 1, "malloc: no memory");
ret = krb5_get_init_creds_keytab(context, &creds, client, keytab,
0, server, init_opts);
free (server);
0, NULL, init_opts);
krb5_get_init_creds_opt_free(context, init_opts);
if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds");
@@ -355,11 +348,6 @@ receive_loop(krb5_context context,
if (verbose)
krb5_warnx(context, "receiving diffs");
ret = kadm5_log_exclusivelock(server_context);
if (ret)
krb5_err(context, IPROPD_RESTART, ret,
"Failed to lock iprop log for writes");
/*
* Seek to the first entry in the message from the master that is
* past the current version of the local database.
@@ -477,9 +465,6 @@ receive(krb5_context context,
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close");
(void) kadm5_log_sharedlock(server_context);
if (verbose)
krb5_warnx(context, "downgraded iprop log lock to shared");
kadm5_log_signal_master(server_context);
if (verbose)
krb5_warnx(context, "signaled master for hierarchical iprop");
@@ -531,9 +516,6 @@ reinit_log(krb5_context context,
ret = kadm5_log_reinit(server_context, vno);
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "kadm5_log_reinit");
(void) kadm5_log_sharedlock(server_context);
if (verbose)
krb5_warnx(context, "downgraded iprop log lock to shared");
}
@@ -553,10 +535,6 @@ receive_everything(krb5_context context, int fd,
krb5_warnx(context, "receive complete database");
ret = kadm5_log_exclusivelock(server_context);
if (ret)
krb5_err(context, IPROPD_RESTART, ret,
"Failed to lock iprop log for writes");
if (server_context->db->hdb_method_name) {
ret = asprintf(&dbname, "%.*s:%s-NEW",
(int) strlen(server_context->db->hdb_method_name) - 1,
@@ -900,15 +878,12 @@ main(int argc, char **argv)
ret = kadm5_log_init(server_context);
if (ret)
krb5_err(context, 1, ret, "kadm5_log_init");
(void) kadm5_log_sharedlock(server_context);
if (verbose)
krb5_warnx(context, "downgraded iprop log lock to shared");
ret = server_context->db->hdb_close(context, server_context->db);
if (ret)
krb5_err(context, 1, ret, "db->close");
get_creds(context, &ccache, master);
get_creds(context, &ccache);
ret = krb5_sname_to_principal (context, master, IPROP_NAME,
KRB5_NT_SRV_HST, &server);
@@ -974,7 +949,7 @@ main(int argc, char **argv)
krb5_auth_con_free(context, auth_context);
auth_context = NULL;
}
get_creds(context, &ccache, master);
get_creds(context, &ccache);
if (verbose)
krb5_warnx(context, "authenticating to master");
ret = krb5_sendauth (context, &auth_context, &master_fd,
@@ -1091,9 +1066,6 @@ main(int argc, char **argv)
krb5_err(context, IPROPD_RESTART, ret, "kadm5_log_init while "
"handling a message from the master");
}
(void) kadm5_log_sharedlock(server_context);
if (verbose)
krb5_warnx(context, "downgraded iprop log lock to shared");
ret = server_context->db->hdb_close (context, server_context->db);
if (ret)
@@ -1125,7 +1097,6 @@ main(int argc, char **argv)
krb5_warnx(context, "master sent us a full dump");
ret = receive_everything(context, master_fd, server_context,
auth_context);
(void) kadm5_log_sharedlock(server_context);
if (ret == 0) {
ret = ihave(context, auth_context, master_fd,
server_context->log_context.version);
@@ -1134,8 +1105,6 @@ main(int argc, char **argv)
connected = FALSE;
else
is_up_to_date(context, status_file, server_context);
if (verbose)
krb5_warnx(context, "downgraded iprop log lock to shared");
kadm5_log_signal_master(server_context);
if (verbose)
krb5_warnx(context, "signaled master for hierarchical iprop");
@@ -1152,6 +1121,7 @@ main(int argc, char **argv)
*
* So we don't ihave() here.
*/
is_up_to_date(context, status_file, server_context);
send_im_here(context, master_fd, auth_context);
break;
case YOU_HAVE_LAST_VERSION:
@@ -1175,7 +1145,7 @@ main(int argc, char **argv)
slave_status(context, status_file, "disconnected from master");
retry:
if (connected == FALSE)
krb5_warnx (context, "disconnected for server");
krb5_warnx (context, "disconnected from server");
if (exit_flag)
krb5_warnx (context, "got an exit signal");
+2
View File
@@ -73,6 +73,8 @@ error_code OLD_SERVER_HOOK_VERSION, "KADM5 server hook is too old for this versi
error_code NEW_SERVER_HOOK_VERSION, "KADM5 server hook is too new for this version of Heimdal"
error_code READ_ONLY, "Database is read-only; try primary server"
error_code PASS_Q_GENERIC, "Unspecified password quality failure"
error_code LOG_SNAPSHOT_INVALID, "Incremental propagation log rotated; restart operation"
error_code LOG_EMPTY, "Incremental propagation log is empty"
# MIT has:
+1
View File
@@ -86,6 +86,7 @@
#include <hdb.h>
#include <der.h>
#include <parse_units.h>
#include "private.h"
#endif /* __KADM5_LOCL_H__ */
+2
View File
@@ -85,6 +85,8 @@ EXPORTS
kadm5_log_init_sharedlock
kadm5_log_next
kadm5_log_nop
kadm5_log_snapshot
kadm5_log_snapshot_verify
kadm5_log_truncate
kadm5_log_modify
_kadm5_acl_check_permission
+174 -14
View File
@@ -174,12 +174,6 @@ RCSID("$Id$");
* will deadlock with ipropd-slave -- don't do that.
*/
#define LOG_HEADER_SZ ((off_t)(sizeof(uint32_t) * 4))
#define LOG_TRAILER_SZ ((off_t)(sizeof(uint32_t) * 2))
#define LOG_WRAPPER_SZ ((off_t)(LOG_HEADER_SZ + LOG_TRAILER_SZ))
#define LOG_UBER_LEN ((off_t)(sizeof(uint64_t) + sizeof(uint32_t) * 2))
#define LOG_UBER_SZ ((off_t)(LOG_WRAPPER_SZ + LOG_UBER_LEN))
#define LOG_NOPEEK 0
#define LOG_DOPEEK 1
@@ -490,23 +484,53 @@ kadm5_log_get_version_fd(kadm5_server_context *server_context, int fd,
{
kadm5_ret_t ret = 0;
krb5_storage *sp;
enum kadm_ops op = kadm_get;
uint32_t len = 0;
uint32_t tmp;
if (fd == -1)
return 0; /* /dev/null */
if (tstamp == NULL)
tstamp = &tmp;
*ver = 0;
*tstamp = 0;
if (fd == -1)
fd = server_context->log_context.log_fd;
sp = krb5_storage_from_fd(fd);
if (sp == NULL)
return errno ? errno : ENOMEM;
ret = kadm5_log_get_version_sp(server_context, sp, which, ver, tstamp);
krb5_storage_free(sp);
return ret;
}
kadm5_ret_t
kadm5_log_get_version_sp(kadm5_server_context *server_context, krb5_storage *sp,
int which, uint32_t *ver, uint32_t *tstamp)
{
struct kadm5_log_snap snap;
kadm5_ret_t ret = 0;
enum kadm_ops op = kadm_get;
uint32_t len = 0;
uint32_t tmp;
/*
* If we're operating lock-less-ly then get a snapshot of the log so we can
* validate that what we read here is correct once we're done reading it.
*/
memset(&snap, 0, sizeof(snap));
if (server_context->log_context.lock_mode == LOCK_UN) {
ret = kadm5_log_snapshot(server_context, &snap);
if (ret)
return ret;
}
if (tstamp == NULL)
tstamp = &tmp;
*ver = 0;
*tstamp = 0;
switch (which) {
case LOG_VERSION_LAST:
ret = kadm5_log_goto_end(server_context, sp);
@@ -531,10 +555,92 @@ kadm5_log_get_version_fd(kadm5_server_context *server_context, int fd,
break;
}
krb5_storage_free(sp);
if (ret == 0 && server_context->log_context.lock_mode == LOCK_UN)
/* Validate the snapshot when operating lock-less-ly */
return kadm5_log_snapshot_verify(server_context, &snap);
return ret;
}
/*
* For lock-less reading of the log first get a snapshot, then read, then
* verify the snapshot before using the data read. If snapshot verification
* fails, start over.
*
* This will be used in ipropd-master and iprop-log to avoid needing a lock on
* the iprop log. For example, when a client says I_HAVE $ver then the server
* gets a snapshot, finds the offset to $ver and the offset to the end of the
* log, reads all that into memory, then the server veerifies the snapshot, and
* finally it sends the data to client, but if the snapshot verification fails
* then the server starts over the process of finding the offset to $ver.
*
* The way this works is that as long as the log is not rotated and truncated,
* then we can expect the header of the first record after the uber-record to
* remain the same.
*/
kadm5_ret_t
kadm5_log_snapshot(kadm5_server_context *server_context,
struct kadm5_log_snap *snap)
{
ssize_t bytes;
assert(sizeof(snap->buf) < CHAR_MAX);
snap->bytes = 0;
bytes = pread(server_context->log_context.log_fd,
snap->buf, sizeof(snap->buf), 0);
if (bytes < 0)
return errno;
if (bytes < LOG_UBER_SZ)
return KADM5_LOG_CORRUPT;
if (bytes < sizeof(snap->buf))
bytes = LOG_UBER_SZ;
snap->bytes = bytes;
return 0;
}
/*
* kadm5_log_snapshot_verify() checks that the iprop log has not been rotated
* since the given `snap` snapshot. Returns -1 if the log has been rotated.
*/
kadm5_ret_t
kadm5_log_snapshot_verify(kadm5_server_context *server_context,
struct kadm5_log_snap *snap)
{
struct kadm5_log_snap v;
kadm5_ret_t ret;
assert(sizeof(snap->buf) < CHAR_MAX);
if (snap->bytes < LOG_UBER_SZ)
return KADM5_LOG_SNAPSHOT_INVALID;
ret = kadm5_log_snapshot(server_context, &v);
if (ret)
return ret;
if (v.bytes < LOG_UBER_SZ)
return KADM5_LOG_CORRUPT;
/* The two snapshots are equal -> no log rotation, no log change at all */
if (snap->bytes == v.bytes && memcmp(snap->buf, v.buf, v.bytes) == 0)
return 0;
/*
* Both snapshots capture the first record's header past the uber record?
* Check that that first record's header is the same for both.
*/
if (snap->bytes == v.bytes && v.bytes == sizeof(v.buf) &&
memcmp(snap->buf + LOG_UBER_SZ, v.buf + LOG_UBER_SZ,
LOG_HEADER_SZ) == 0)
return 0; /* No log rotation, but the log did change */
/*
* Log rotated, or we don't have any log entries but the uber record
* changed.
*/
return KADM5_LOG_SNAPSHOT_INVALID;
}
/* Get the version of the last confirmed entry in the log */
kadm5_ret_t
kadm5_log_get_version(kadm5_server_context *server_context, uint32_t *ver)
@@ -2133,7 +2239,7 @@ kadm5_log_goto_first(kadm5_server_context *server_context, krb5_storage *sp)
if (ret)
return ret;
if (op == kadm_nop && len == LOG_UBER_LEN && seek_next(sp) == -1)
return KADM5_LOG_CORRUPT;
return KADM5_LOG_EMPTY;
return 0;
}
@@ -2503,6 +2609,13 @@ load_entries(kadm5_server_context *context, krb5_data *p,
/*
* Truncate the log, retaining at most `keep' entries and at most `maxbytes'.
* If `maxbytes' is zero, keep at most the default log size limit.
*
* I.e., rotate the log, except we don't rename a new log into place.
*
* Ensures that the log will be smaller than prior to truncation. This is
* important as it ensures that the log snapshot approach used by ipropd-master
* to read the log lock-less-ly will work. See also kadm5_log_snapshot() and
* kadm5_log_snapshot_verify().
*/
kadm5_ret_t
kadm5_log_truncate(kadm5_server_context *context, size_t keep, size_t maxbytes)
@@ -2514,7 +2627,10 @@ kadm5_log_truncate(kadm5_server_context *context, size_t keep, size_t maxbytes)
krb5_storage *sp;
ssize_t bytes;
uint64_t sz;
off_t off;
off_t off, fsz;
if ((fsz = lseek(context->log_context.log_fd, 0, SEEK_END)) < 0)
return errno;
if (maxbytes == 0)
maxbytes = get_max_log_size(context->context);
@@ -2549,6 +2665,50 @@ kadm5_log_truncate(kadm5_server_context *context, size_t keep, size_t maxbytes)
return EOVERFLOW; /* caller should ask for fewer entries */
}
/* Ensure that the iprop log will be smaller, or defer truncation */
if (sz >= fsz) {
uint32_t skip;
krb5_data_free(&entries);
if (first > last)
first = 1;
skip = (last - first) / 2;
if (skip < 2) {
/*
* There must be an entry that is just large enough, or larger,
* that it alone causes the log to exceed the log size
* limit.
*/
krb5_warnx(context->context,
"Unable to truncate log due to very large record; "
"deferring truncation");
return 0;
}
first += (last - first) / 2;
ret = load_entries(context, &entries, last - first, maxbytes, &first, &last);
if (ret)
return ret;
sz = LOG_UBER_SZ + entries.length;
off = (off_t)sz;
if (off < 0 || off != sz || sz < entries.length) {
krb5_data_free(&entries);
return EOVERFLOW; /* caller should ask for fewer entries */
}
if (sz >= fsz) {
/* Should never happen! */
krb5_data_free(&entries);
krb5_warnx(context->context,
"Unable to truncate log due to very large record; "
"deferring truncation");
return 0;
}
}
/* Truncate to zero size and seek to zero offset */
if (ftruncate(context->log_context.log_fd, 0) < 0 ||
lseek(context->log_context.log_fd, 0, SEEK_SET) < 0) {
+2
View File
@@ -87,6 +87,8 @@ HEIMDAL_KAMD5_SERVER_1.0 {
kadm5_log_init_sharedlock;
kadm5_log_next;
kadm5_log_nop;
kadm5_log_snapshot;
kadm5_log_snapshot_verify;
kadm5_log_truncate;
kadm5_log_modify;
_kadm5_acl_check_permission;
+33 -30
View File
@@ -704,25 +704,30 @@ change_password_loop (krb5_context context,
* do the SOCKS4a I/O.
*/
while (!_krb5_socks4a_connected(socks4a)) {
fd_set readfds, writefds;
struct pollfd pfd;
int nready;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
pfd.fd = sock;
pfd.events = 0;
pfd.revents = 0;
if (_krb5_socks4a_reading(socks4a))
FD_SET(sock, &readfds);
pfd.events |= POLLIN;
if (_krb5_socks4a_writing(socks4a))
FD_SET(sock, &writefds);
nready = select(sock + 1, &readfds, &writefds,
/*exceptfds*/NULL, /*timeout*/NULL);
if (nready == -1) {
pfd.events |= POLLOUT;
nready = poll(&pfd, 1, -1); /* blocking */
if (nready < 0) {
if (errno == EINTR)
continue;
ret = errno;
break;
}
if (nready <= 0) {
if (nready == 0) {
ret = EIO; /* timeout should be impossible */
break;
}
ret = _krb5_socks4a_io(socks4a);
if (ret)
break;
@@ -733,9 +738,6 @@ change_password_loop (krb5_context context,
}
for (i = 0; !done && i < 5; ++i) {
fd_set fdset;
struct timeval tv;
if (!replied) {
replied = 0;
@@ -753,27 +755,28 @@ change_password_loop (krb5_context context,
}
}
#ifndef NO_LIMIT_FD_SETSIZE
if (sock >= FD_SETSIZE) {
ret = ERANGE;
krb5_set_error_message(context, ret,
"fd %d too large", sock);
rk_closesocket (sock);
goto out;
}
#endif
struct pollfd pfd;
int timeout_ms;
timeout_ms = (1 + (1 << i)) * 1000;
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
tv.tv_usec = 0;
tv.tv_sec = 1 + (1 << i);
pfd.fd = sock;
pfd.events = POLLIN;
pfd.revents = 0;
ret = select (sock + 1, &fdset, NULL, NULL, &tv);
if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) {
rk_closesocket(sock);
goto out;
ret = poll(&pfd, 1, timeout_ms);
if (ret < 0) {
if (errno == EINTR)
continue;
rk_closesocket(sock);
ret = errno;
goto out;
}
if (ret == 1) {
if (ret == 0) {
ret = KRB5_KDC_UNREACH;
continue;
}
if (pfd.revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) {
ret = (*proc->process_rep) (context,
auth_context,
is_stream,
+4 -4
View File
@@ -489,7 +489,7 @@ init_context_from_config_file(krb5_context context)
tmp = secure_getenv("KRB5_TRACE");
if (tmp)
heim_add_debug_dest(context->hcontext, "libkrb5", tmp);
heim_add_trace_dest(context->hcontext, "libkrb5", tmp);
s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL);
if (s) {
char **p;
@@ -1108,15 +1108,15 @@ krb5_kerberos_enctypes(krb5_context context)
};
static const krb5_enctype weak[] = {
ETYPE_AES256_CTS_HMAC_SHA1_96,
ETYPE_AES128_CTS_HMAC_SHA1_96,
ETYPE_AES256_CTS_HMAC_SHA384_192,
ETYPE_AES128_CTS_HMAC_SHA256_128,
ETYPE_AES256_CTS_HMAC_SHA1_96,
ETYPE_AES128_CTS_HMAC_SHA1_96,
ETYPE_ARCFOUR_HMAC_MD5,
ETYPE_NULL
};
if (krb5_enctype_valid(context, ETYPE_ARCFOUR_HMAC_MD5))
if (krb5_enctype_valid(context, ETYPE_ARCFOUR_HMAC_MD5) == 0)
return weak;
return strong;
+16
View File
@@ -608,8 +608,12 @@ krb5_create_checksum(krb5_context context,
}
if (arcfour_checksum_p(ct, crypto)) {
#ifdef HEIM_ARCFOUR
keyusage = usage;
_krb5_usage2arcfour(context, &keyusage);
#else
return KRB5_PROG_SUMTYPE_NOSUPP;
#endif /* HEIM_ARCFOUR */
} else
keyusage = CHECKSUM_USAGE(usage);
@@ -738,8 +742,12 @@ krb5_verify_checksum(krb5_context context,
}
if (arcfour_checksum_p(ct, crypto)) {
#ifdef HEIM_ARCFOUR
keyusage = usage;
_krb5_usage2arcfour(context, &keyusage);
#else
return KRB5_PROG_SUMTYPE_NOSUPP;
#endif /* HEIM_ARCFOUR */
} else
keyusage = CHECKSUM_USAGE(usage);
@@ -2067,8 +2075,12 @@ krb5_create_checksum_iov(krb5_context context,
}
if (arcfour_checksum_p(ct, crypto)) {
#ifdef HEIM_ARCFOUR
keyusage = usage;
_krb5_usage2arcfour(context, &keyusage);
#else
return KRB5_PROG_SUMTYPE_NOSUPP;
#endif /* HEIM_ARCFOUR */
} else
keyusage = CHECKSUM_USAGE(usage);
@@ -2134,8 +2146,12 @@ krb5_verify_checksum_iov(krb5_context context,
}
if (arcfour_checksum_p(ct, crypto)) {
#ifdef HEIM_ARCFOUR
keyusage = usage;
_krb5_usage2arcfour(context, &keyusage);
#else
return KRB5_PROG_SUMTYPE_NOSUPP;
#endif /* HEIM_ARCFOUR */
} else
keyusage = CHECKSUM_USAGE(usage);
+4 -17
View File
@@ -69,22 +69,17 @@ krb5_expand_hostname (krb5_context context,
int error;
if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0 ||
krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", NULL)) {
krb5_warnx(context, "krb5_expand_hostname: DNS canonicalization disabled or blocked for hostname %s", orig_hostname);
krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", NULL))
return copy_hostname (context, orig_hostname, new_hostname);
}
memset (&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo (orig_hostname, NULL, &hints, &ai);
if (error) {
krb5_warnx(context, "krb5_expand_hostname: getaddrinfo(%s) failed: %s", orig_hostname, gai_strerror(error));
if (error)
return copy_hostname (context, orig_hostname, new_hostname);
}
for (a = ai; a != NULL; a = a->ai_next) {
if (a->ai_canonname != NULL) {
krb5_warnx(context, "krb5_expand_hostname: canonical name for %s -> %s", orig_hostname, a->ai_canonname);
*new_hostname = strdup (a->ai_canonname);
freeaddrinfo (ai);
if (*new_hostname == NULL)
@@ -94,7 +89,6 @@ krb5_expand_hostname (krb5_context context,
}
}
freeaddrinfo (ai);
krb5_warnx(context, "krb5_expand_hostname: no canonical name found for %s, falling back to copy_hostname", orig_hostname);
return copy_hostname (context, orig_hostname, new_hostname);
}
@@ -151,25 +145,20 @@ krb5_expand_hostname_realms (krb5_context context,
int error;
krb5_error_code ret = 0;
if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0) {
krb5_warnx(context, "krb5_expand_hostname_realms: DNS canonicalization disabled for hostname %s", orig_hostname);
if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0)
return vanilla_hostname (context, orig_hostname, new_hostname,
realms);
}
memset (&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo (orig_hostname, NULL, &hints, &ai);
if (error) {
krb5_warnx(context, "krb5_expand_hostname_realms: getaddrinfo(%s) failed: %s", orig_hostname, gai_strerror(error));
if (error)
return vanilla_hostname (context, orig_hostname, new_hostname,
realms);
}
for (a = ai; a != NULL; a = a->ai_next) {
if (a->ai_canonname != NULL) {
krb5_warnx(context, "krb5_expand_hostname_realms: canonical name for %s -> %s", orig_hostname, a->ai_canonname);
ret = copy_hostname (context, a->ai_canonname, new_hostname);
if (ret) {
freeaddrinfo (ai);
@@ -179,13 +168,11 @@ krb5_expand_hostname_realms (krb5_context context,
ret = krb5_get_host_realm (context, *new_hostname, realms);
if (ret == 0) {
freeaddrinfo (ai);
krb5_warnx(context, "krb5_expand_hostname_realms: host %s mapped to realm %s", *new_hostname, realms && *realms ? (*realms)[0] : "<unknown>");
return 0;
}
free (*new_hostname);
}
}
freeaddrinfo(ai);
krb5_warnx(context, "krb5_expand_hostname_realms: no canonical name/realm found for %s, falling back to vanilla_hostname", orig_hostname);
return vanilla_hostname (context, orig_hostname, new_hostname, realms);
}
+1 -1
View File
@@ -1081,7 +1081,6 @@ cred_delete(krb5_context context,
ret = krb5_storage_to_data(sp, &orig_cred_data);
if (ret)
goto out;
krb5_storage_free(sp);
cred_data_in_file = malloc(orig_cred_data.length);
if (cred_data_in_file == NULL)
@@ -1103,6 +1102,7 @@ cred_delete(krb5_context context,
goto out;
}
krb5_storage_free(sp);
sp = krb5_storage_emem();
if (sp == NULL)
goto out;
+1 -1
View File
@@ -645,7 +645,7 @@ get_cred_kdc(krb5_context context,
krb5_sendto_ctx stctx;
ret = krb5_sendto_ctx_alloc(context, &stctx);
if (ret)
return ret;
goto out;
krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
if (kdc_hostname)
+2 -114
View File
@@ -217,31 +217,6 @@ krb5_kt_resolve(krb5_context context,
residual = keytab_name(name, &type, &type_len);
/*
* Aggressive process-context logging:
* Print pid/ppid/uid/gid and the raw name string being resolved
* so test captures show which process attempted to resolve which
* keytab and with what parsed type/residual.
*
* We intentionally always emit this via krb5_warnx to make sure it
* appears in stderr/journal during tests.
*/
{
pid_t pid = getpid();
pid_t ppid = getppid();
uid_t uid = getuid();
gid_t gid = getgid();
krb5_warnx(context,
"krb5_kt_resolve: pid=%d ppid=%d uid=%d gid=%d resolving name=\"%s\" parsed_type=\"%.*s\" residual=\"%s\"",
(int)pid,
(int)ppid,
(int)uid,
(int)gid,
name ? name : "<null>",
(int)type_len, type ? type : "<null>",
residual ? residual : "<null>");
}
for(i = 0; i < context->num_kt_types; i++) {
if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
break;
@@ -276,15 +251,8 @@ static const char *default_ktname(krb5_context context)
const char *tmp = NULL;
tmp = secure_getenv("KRB5_KTNAME");
if(tmp != NULL) {
/* Aggressive logging: record environment override */
krb5_warnx(context, "default_ktname: using KRB5_KTNAME from env: \"%s\" (pid=%d)", tmp, (int)getpid());
if(tmp != NULL)
return tmp;
}
/* Aggressive logging: record context default choice as well */
krb5_warnx(context, "default_ktname: using context->default_keytab: \"%s\" (pid=%d)",
context->default_keytab ? context->default_keytab : "<null>",
(int)getpid());
return context->default_keytab;
}
@@ -629,13 +597,6 @@ _krb5_kt_principal_not_found(krb5_context context,
else
kvno_str[0] = '\0';
/* Provide a concise debug line so tests can see what principal/keytab/enctype failed */
krb5_warnx(context, "kt_principal_not_found: principal=%s kvno=%s keytab=%s enctype=%s",
princ ? princ : "<unknown>",
kvno_str[0] ? kvno_str : "<none>",
kt_name ? kt_name : "unknown keytab",
enctype_str ? enctype_str : "unknown enctype");
krb5_set_error_message(context, ret,
N_("Failed to find %s%s in keytab %s (%s)",
"principal, kvno, keytab file, enctype"),
@@ -675,81 +636,27 @@ krb5_kt_get_entry_wrapped(krb5_context context,
entry->vno = 0;
while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
/* Always-log the entry we're inspecting and what is being requested */
{
char *entry_unp = NULL;
char *want_unp = NULL;
(void) krb5_unparse_name(context, tmp.principal, &entry_unp);
(void) krb5_unparse_name(context, principal, &want_unp);
krb5_warnx(context, "krb5_kt_get_entry_wrapped: inspecting entry=%s vno=%d enctype=%d against requested=%s kvno=%u enctype=%d",
entry_unp ? entry_unp : "<unparsed>",
tmp.vno,
tmp.keyblock.keytype,
want_unp ? want_unp : "<unparsed>",
(unsigned)kvno,
(int)enctype);
free(entry_unp);
free(want_unp);
}
if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
/* the file keytab might only store the lower 8 bits of
the kvno, so only compare those bits */
if (kvno == tmp.vno
|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
/* Matched principal and kvno -> return this entry */
{
char *matched = NULL;
(void) krb5_unparse_name(context, tmp.principal, &matched);
krb5_warnx(context, "krb5_kt_get_entry_wrapped: matched entry=%s vno=%d enctype=%d -- returning",
matched ? matched : "<unparsed>",
tmp.vno,
tmp.keyblock.keytype);
free(matched);
}
krb5_kt_copy_entry_contents (context, &tmp, entry);
krb5_kt_free_entry (context, &tmp);
krb5_kt_end_seq_get(context, id, &cursor);
return 0;
} else if (kvno == 0 && tmp.vno > entry->vno) {
/* Matched principal but kvno selection logic prefers a higher vno */
{
char *matched = NULL;
(void) krb5_unparse_name(context, tmp.principal, &matched);
krb5_warnx(context, "krb5_kt_get_entry_wrapped: matched principal %s but kvno differs (entry.vno=%d tmp.vno=%d); selecting higher vno for now",
matched ? matched : "<unparsed>",
entry->vno,
tmp.vno);
free(matched);
}
if (entry->vno)
krb5_kt_free_entry (context, entry);
krb5_kt_copy_entry_contents (context, &tmp, entry);
} else {
/* Matched name but kvno didn't match and we are not in kvno-selection mode; log it. */
char *matched = NULL;
(void) krb5_unparse_name(context, tmp.principal, &matched);
krb5_warnx(context, "krb5_kt_get_entry_wrapped: matched principal %s but kvno mismatch (tmp.vno=%d requested_kvno=%u); continuing iteration",
matched ? matched : "<unparsed>",
tmp.vno,
(unsigned)kvno);
free(matched);
}
}
krb5_kt_free_entry(context, &tmp);
}
krb5_kt_end_seq_get (context, id, &cursor);
if (entry->vno == 0) {
/* No matching kvno was found in the keytab iteration; log and return */
krb5_warnx(context, "krb5_kt_get_entry_wrapped: no matching entry found -> invoking _krb5_kt_principal_not_found");
if (entry->vno == 0)
return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
id, principal, enctype, kvno);
}
krb5_warnx(context, "krb5_kt_get_entry_wrapped: returning selected entry vno=%d enctype=%d",
entry->vno, entry->keyblock.keytype);
return 0;
}
@@ -781,25 +688,6 @@ krb5_kt_get_entry(krb5_context context,
krb5_const_principal try_princ;
krb5_name_canon_iterator name_canon_iter;
/* Debug: record incoming keytab lookup request (always emitted) */
{
char *want_unp = NULL;
char *kt_full = NULL;
if (principal && krb5_unparse_name(context, principal, &want_unp) != 0)
want_unp = NULL;
(void) krb5_kt_get_full_name(context, id, &kt_full);
krb5_warnx(context, "krb5_kt_get_entry: requested principal=%s keytab=%s kvno=%u enctype=%d",
want_unp ? want_unp : "<null>",
kt_full ? kt_full : "<unknown>",
(unsigned)kvno,
(int)enctype);
free(want_unp);
free(kt_full);
}
if (!principal)
/* Use `NULL' instead of `principal' to quiet static analizers */
return krb5_kt_get_entry_wrapped(context, id, NULL, kvno, enctype,
+12 -61
View File
@@ -380,21 +380,13 @@ fkt_start_seq_get_int(krb5_context context,
d->filename, strerror(ret));
return ret;
}
/* Loud logging: record that we opened the keytab file and process info */
krb5_warnx(context, "fkt_start_seq_get_int: opened keytab \"%s\" fd=%d flags=0x%x pid=%d uid=%d",
d->filename ? d->filename : "<null>",
c->fd,
(unsigned)flags,
(int)getpid(),
(int)getuid());
rk_cloexec(c->fd);
ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
if (ret) {
krb5_warnx(context, "fkt_start_seq_get_int: failed to lock keytab \"%s\": ret=%d", d->filename ? d->filename : "<null>", ret);
close(c->fd);
return ret;
if (exclusive) {
ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
if (ret) {
close(c->fd);
return ret;
}
}
if ((flags & O_ACCMODE) == O_RDWR && (flags & O_APPEND))
stdio_mode = "ab+";
@@ -404,7 +396,6 @@ fkt_start_seq_get_int(krb5_context context,
stdio_mode = "wb";
c->sp = krb5_storage_stdio_from_fd(c->fd, stdio_mode);
if (c->sp == NULL) {
krb5_warnx(context, "fkt_start_seq_get_int: krb5_storage_stdio_from_fd returned NULL for \"%s\"", d->filename ? d->filename : "<null>");
close(c->fd);
return krb5_enomem(context);
}
@@ -414,17 +405,12 @@ fkt_start_seq_get_int(krb5_context context,
krb5_storage_free(c->sp);
close(c->fd);
krb5_clear_error_message(context);
krb5_warnx(context, "fkt_start_seq_get_int: failed reading pvno from \"%s\": ret=%d", d->filename ? d->filename : "<null>", ret);
return ret;
}
/* Log the pvno read */
krb5_warnx(context, "fkt_start_seq_get_int: keytab \"%s\" pvno=%d", d->filename ? d->filename : "<null>", (int)pvno);
if(pvno != 5) {
krb5_storage_free(c->sp);
close(c->fd);
krb5_clear_error_message (context);
krb5_warnx(context, "fkt_start_seq_get_int: keytab \"%s\" has bad vno (%d)", d->filename ? d->filename : "<null>", (int)pvno);
return KRB5_KEYTAB_BADVNO;
}
ret = krb5_ret_int8(c->sp, &tag);
@@ -432,19 +418,10 @@ fkt_start_seq_get_int(krb5_context context,
krb5_storage_free(c->sp);
close(c->fd);
krb5_clear_error_message(context);
krb5_warnx(context, "fkt_start_seq_get_int: failed reading tag from \"%s\": ret=%d", d->filename ? d->filename : "<null>", ret);
return ret;
}
/* Log the tag/version we read */
krb5_warnx(context, "fkt_start_seq_get_int: keytab \"%s\" header tag=%d", d->filename ? d->filename : "<null>", (int)tag);
id->version = tag;
storage_set_flags(context, c->sp, id->version);
/* Final confirmation log */
krb5_warnx(context, "fkt_start_seq_get_int: keytab \"%s\" opened successfully (fd=%d, version=%d)", d->filename ? d->filename : "<null>", c->fd, (int)id->version);
return 0;
}
@@ -475,50 +452,26 @@ fkt_next_entry_int(krb5_context context,
pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
loop:
ret = krb5_ret_int32(cursor->sp, &len);
if (ret) {
krb5_warnx(context, "fkt_next_entry_int: krb5_ret_int32 returned %d for keytab \"%s\" at pos=%lld", ret, d->filename ? d->filename : "<null>", (long long)pos);
if (ret)
return ret;
}
if(len < 0) {
pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
goto loop;
}
ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
if (ret) {
krb5_warnx(context, "fkt_next_entry_int: krb5_kt_ret_principal failed for keytab \"%s\" at pos=%lld: ret=%d", d->filename ? d->filename : "<null>", (long long)pos, ret);
if (ret)
goto out;
}
ret = krb5_ret_uint32(cursor->sp, &utmp32);
entry->timestamp = utmp32;
if (ret) {
krb5_warnx(context, "fkt_next_entry_int: failed reading timestamp for keytab \"%s\" at pos=%lld: ret=%d", d->filename ? d->filename : "<null>", (long long)pos, ret);
if (ret)
goto out;
}
ret = krb5_ret_int8(cursor->sp, &tmp8);
if (ret) {
krb5_warnx(context, "fkt_next_entry_int: failed reading vno (8bit) for keytab \"%s\" at pos=%lld: ret=%d", d->filename ? d->filename : "<null>", (long long)pos, ret);
if (ret)
goto out;
}
entry->vno = tmp8;
ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
if (ret) {
krb5_warnx(context, "fkt_next_entry_int: krb5_kt_ret_keyblock failed for keytab \"%s\" at pos=%lld: ret=%d", d->filename ? d->filename : "<null>", (long long)pos, ret);
if (ret)
goto out;
}
/* Log the entry we just read (principal, vno, enctype, timestamp) */
{
char *princname = NULL;
(void) krb5_unparse_name(context, entry->principal, &princname);
krb5_warnx(context, "fkt_next_entry_int: read entry principal=%s pos=%lld timestamp=%u vno=%d enctype=%d",
princname ? princname : "<unparsed>",
(long long)pos,
(unsigned)entry->timestamp,
entry->vno,
entry->keyblock.keytype);
free(princname);
}
/* there might be a 32 bit kvno here
* if it's zero, assume that the 8bit one was right,
* otherwise trust the new value */
@@ -541,10 +494,8 @@ loop:
if(start) *start = pos;
if(end) *end = pos + 4 + len;
out:
if (ret) {
krb5_warnx(context, "fkt_next_entry_int: error reading keytab \"%s\" at pos=%lld: ret=%d", d->filename ? d->filename : "<null>", (long long)pos, ret);
if (ret)
krb5_kt_free_entry(context, entry);
}
krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
return ret;
}
+6 -26
View File
@@ -35,7 +35,6 @@
.Dt KRB5_CONTEXT 3
.Os HEIMDAL
.Sh NAME
.Nm krb5_add_et_list ,
.Nm krb5_add_extra_addresses ,
.Nm krb5_add_ignore_addresses ,
.Nm krb5_context ,
@@ -48,7 +47,7 @@
.Nm krb5_get_ignore_addresses ,
.Nm krb5_get_kdc_sec_offset ,
.Nm krb5_get_max_time_skew ,
.Nm krb5_get_use_admin_kdc
.Nm krb5_get_use_admin_kdc ,
.Nm krb5_init_context ,
.Nm krb5_init_ets ,
.Nm krb5_prepend_config_files ,
@@ -59,7 +58,7 @@
.Nm krb5_set_fcache_version ,
.Nm krb5_set_ignore_addresses ,
.Nm krb5_set_max_time_skew ,
.Nm krb5_set_use_admin_kdc ,
.Nm krb5_set_use_admin_kdc
.Nd create, modify and delete krb5_context structures
.Sh LIBRARY
Kerberos 5 Library (libkrb5, -lkrb5)
@@ -81,11 +80,6 @@ Kerberos 5 Library (libkrb5, -lkrb5)
.Fa "krb5_context context"
.Fc
.Ft krb5_error_code
.Fo krb5_add_et_list
.Fa "krb5_context context"
.Fa "void (*func)(struct et_list **)"
.Fc
.Ft krb5_error_code
.Fo krb5_add_extra_addresses
.Fa "krb5_context context"
.Fa "krb5_addresses *addresses"
@@ -204,23 +198,11 @@ or that Kerberos should not be used
.Bq ENXIO .
.Pp
.Fn krb5_init_ets
adds all
.Xr com_err 3
libs to
.Fa context .
This is done by
is retained for ABI compatibility.
It does not perform any action.
Any initialization it used to provide is done by
.Fn krb5_init_context .
.Pp
.Fn krb5_add_et_list
adds a
.Xr com_err 3
error-code handler
.Fa func
to the specified
.Fa context .
The error handler must generated by the the re-rentrant version of the
.Xr compile_et 1
program.
.Fn krb5_add_extra_addresses
add a list of addresses that should be added when requesting tickets.
.Pp
@@ -302,7 +284,5 @@ and
get and sets the maximum allowed time skew between client and server.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr krb5 3 ,
.Xr krb5_config 3 ,
.Xr krb5_context 3 ,
.Xr krb5.conf 5 ,
.Xr kerberos 8
+6 -4
View File
@@ -91,11 +91,13 @@ cleans the the structure, must be used before trying to pass it in to
.Fn krb5_verify_init_creds .
.Pp
.Fn krb5_verify_init_creds_opt_set_ap_req_nofail
controls controls the behavior if
controls the behavior if
.Fa ap_req_server
doesn't exists in the local keytab or in the KDC's database, if it's
true, the error will be ignored. Note that this use is possible
insecure.
does not exist in the local keytab or in the KDC's database.
If it is true, those errors will not be ignored.
Errors from AP_REQ verification with a present key, such as an integrity
check failure, are always returned.
Note that ignoring the error is possibly insecure.
.Sh SEE ALSO
.Xr krb5 3 ,
.Xr krb5_get_init_creds 3 ,
-5
View File
@@ -231,11 +231,6 @@ main(int argc, char **argv)
}
.Ed
.Sh SEE ALSO
.Xr krb5_cc_gen_new 3 ,
.Xr krb5_cc_initialize 3 ,
.Xr krb5_cc_resolve 3 ,
.Xr krb5_err 3 ,
.Xr krb5_free_principal 3 ,
.Xr krb5_init_context 3 ,
.Xr krb5_kt_default 3 ,
.Xr krb5.conf 5

Some files were not shown because too many files have changed in this diff Show More