Browse Source

Import upstream version 10

Sergio Correia 2 years ago
parent
commit
e83ab471c3
18 changed files with 337 additions and 78 deletions
  1. 25 1
      README.md
  2. 6 3
      meson.build
  3. 9 14
      src/keys.c
  4. 2 2
      src/keys.h
  5. 1 0
      src/meson.build
  6. 3 2
      src/tang-show-keys
  7. 4 3
      src/tangd-keygen
  8. 85 0
      src/tangd-rotate-keys
  9. 38 17
      tests/adv
  10. 62 0
      tests/helpers
  11. 12 7
      tests/meson.build
  12. 10 13
      tests/rec
  13. 4 3
      tests/test-keys.c.in
  14. 12 3
      units/meson.build
  15. 47 0
      units/tangd.rc.in
  16. 0 10
      units/tangd.xinetd
  17. 4 0
      units/tangdw
  18. 13 0
      units/tangdx

+ 25 - 1
README.md

@@ -89,7 +89,31 @@ Instead of using systemd for socket activation you can use another daemon for
 spawning services like xinetd.
 
 An example of configuration file for Tang using xinetd can be found in the
-`units/` directory.
+`units/` directory as 'tangdx'.  Using that will also require installing the
+wrapper from the 'units/' directroy 'tangdw' in '/usr/libexec/tangdw'.
+
+#### FreeBSD, HardenedBSD and OPNsense
+
+Tang is also capable of running on FreeBSD Unix variants. The build is simple
+and differs only sligtly from the general instructions.
+
+    (as root) # pkg install jose git meson pkgconf jansson openssl asciidoc http-parser socat
+    $ mkdir build && cd build
+    $ meson .. --prefix=/usr/local --localstatedir=/usr/local/var
+    $ ninja
+    (as root) # ninja install
+    (as root) # mkdir -m 0700 /usr/local/var/db/tang
+    (as root) service tangd enable
+    (as root) service tangd start
+
+Once built it does not require the many packages above, but still requires
+jose, socat and http_parser. 
+
+FreeBSD, HardendedBSD, and OPNsense use inetd rather than systemd or
+xinetd. To limit the need to manage inetd configuration which has a shared
+config file, tangd is instead packaged to depend on `socat`.  Of course,
+if desired it may be configured to run instead from inetd.conf in which case
+the socat package will no longer be required.
 
 #### Docker Container
 

+ 6 - 3
meson.build

@@ -1,5 +1,5 @@
 project('tang', 'c',
-  version: '8',
+  version: '10',
   license: 'GPL3+',
   default_options: [
     'c_std=c99',
@@ -16,6 +16,9 @@ sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
 bindir = join_paths(get_option('prefix'), get_option('bindir'))
 systemunitdir = join_paths(get_option('prefix'), 'lib/systemd/system')
 licensedir = join_paths(get_option('prefix'), 'share', 'licenses', meson.project_name())
+if build_machine.system() == 'freebsd'
+  licensedir += '-'+meson.project_version()
+endif
 jwkdir = join_paths(get_option('localstatedir'), 'db', meson.project_name())
 
 data = configuration_data()
@@ -48,10 +51,10 @@ add_project_arguments(
 jose = dependency('jose', version: '>=8')
 a2x = find_program('a2x', required: false)
 compiler = meson.get_compiler('c')
-if not compiler.has_header('http_parser.h')
+if not compiler.has_header('http_parser.h',args : '-I/usr/local/include')
   error('http-parser devel files not found.')
 endif
-http_parser = compiler.find_library('http_parser')
+http_parser = compiler.find_library('http_parser',dirs:['/usr/lib','/usr/local/lib'])
 
 licenses = ['COPYING']
 libexecbins = []

+ 9 - 14
src/keys.c

@@ -32,6 +32,9 @@
 #define PATH_MAX 4096
 #endif
 
+/* Default hash to use with JWK thumbprints (S256 = SHA-256). */
+#define DEFAULT_THP_HASH "S256"
+
 static const char**
 supported_hashes(void)
 {
@@ -233,21 +236,11 @@ jwk_sign(const json_t* to_sign, const json_t* sig_keys)
     json_auto_t* sig_template = json_pack("{s:{s:s}}",
                                           "protected", "cty", "jwk-set+json");
 
-    /* Use the template with the signing keys. */
-    json_auto_t* sig_template_arr = json_array();
-    size_t arr_size = json_array_size(sig_keys);
-    for (size_t i = 0; i < arr_size; i++) {
-        if (json_array_append(sig_template_arr, sig_template) == -1) {
-            fprintf(stderr, "Unable to append sig template to array\n");
-            return NULL;
-        }
-    }
-
     __attribute__ ((__cleanup__(cleanup_str))) char* data_to_sign = json_dumps(payload, 0);
     json_auto_t* jws = json_pack("{s:o}", "payload",
                                  jose_b64_enc(data_to_sign, strlen(data_to_sign)));
 
-    if (!jose_jws_sig(NULL, jws, sig_template_arr, sig_keys)) {
+    if (!jose_jws_sig(NULL, jws, sig_template, sig_keys)) {
         fprintf(stderr, "Error trying to jose_jws_sign\n");
         return NULL;
     }
@@ -324,7 +317,6 @@ prepare_payload_and_sign(struct tang_keys_info* tki)
 static int
 create_new_keys(const char* jwkdir)
 {
-    const char** hashes = supported_hashes();
     const char* alg[] = {"ES512", "ECMR", NULL};
     char path[PATH_MAX];
     for (int i = 0; alg[i] != NULL; i++) {
@@ -332,7 +324,7 @@ create_new_keys(const char* jwkdir)
         if (!jwk) {
             return 0;
         }
-        __attribute__ ((__cleanup__(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[0]);
+        __attribute__ ((__cleanup__(cleanup_str))) char* thp = jwk_thumbprint(jwk, DEFAULT_THP_HASH);
         if (!thp) {
             return 0;
         }
@@ -392,12 +384,15 @@ load_keys(const char* jwkdir)
             json_t* arr = tki->m_keys;
             if (d->d_name[0] == '.') {
                 arr = tki->m_rotated_keys;
+                tki->m_rotated_keys_count++;
+            } else {
+                tki->m_keys_count++;
             }
+
             if (json_array_append(arr, json) == -1) {
                 fprintf(stderr, "Unable to append JSON (%s) to array; skipping\n", d->d_name);
                 continue;
             }
-            tki->m_keys_count++;
         }
     }
     closedir(dir);

+ 2 - 2
src/keys.h

@@ -34,8 +34,8 @@ struct tang_keys_info {
     json_t* m_sign;               /* Set of signing keys made from regular
                                      keys. */
 
-    size_t m_keys_count;          /* Number of keys (regular + rotated). */
-
+    size_t m_keys_count;          /* Number of regular keys. */
+    size_t m_rotated_keys_count;  /* Number of rotated keys. */
 };
 
 void cleanup_tang_keys_info(struct tang_keys_info**);

+ 1 - 0
src/meson.build

@@ -9,5 +9,6 @@ tangd = executable('tangd',
 
 bins += join_paths(meson.current_source_dir(), 'tang-show-keys')
 libexecbins += join_paths(meson.current_source_dir(), 'tangd-keygen')
+libexecbins += join_paths(meson.current_source_dir(), 'tangd-rotate-keys')
 
 # vim:set ts=2 sw=2 et:

+ 3 - 2
src/tang-show-keys

@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
 #
 # Copyright (c) 2018 Red Hat, Inc.
@@ -29,7 +29,8 @@ port=${1-80}
 
 adv=$(curl -sSf localhost:$port/adv)
 
+THP_DEFAULT_HASH=S256    # SHA-256.
 echo $adv \
     | jose fmt -j- -g payload -y -o- \
     | jose jwk use -i- -r -u verify -o- \
-    | jose jwk thp -i-
+    | jose jwk thp -i- -a "${THP_DEFAULT_HASH}"

+ 4 - 3
src/tangd-keygen

@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
 #
 # Copyright (c) 2016 Red Hat, Inc.
@@ -27,10 +27,11 @@ fi
 
 [ $# -eq 3 ] && sig=$2 && exc=$3
 
+THP_DEFAULT_HASH=S256     # SHA-256.
 jwe=`jose jwk gen -i '{"alg":"ES512"}'`
-[ -z "$sig" ] && sig=`echo "$jwe" | jose jwk thp -i-`
+[ -z "$sig" ] && sig=$(echo "$jwe" | jose jwk thp -i- -a "${THP_DEFAULT_HASH}")
 echo "$jwe" > $1/$sig.jwk
 
 jwe=`jose jwk gen -i '{"alg":"ECMR"}'`
-[ -z "$exc" ] && exc=`echo "$jwe" | jose jwk thp -i-`
+[ -z "$exc" ] && exc=$(echo "$jwe" | jose jwk thp -i- -a "${THP_DEFAULT_HASH}")
 echo "$jwe" > $1/$exc.jwk

+ 85 - 0
src/tangd-rotate-keys

@@ -0,0 +1,85 @@
+#!/bin/sh -e
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+SUMMARY="Perform rotation of tang keys"
+
+usage() {
+    local _ret="${1:-1}"
+    exec >&2
+    echo "Usage: ${0} [-h] [-v] -d <KEYDIR>"
+    echo
+    echo "${SUMMARY}"
+    echo
+    echo "  -d KEYDIR  The directory with the keys, e.g. /var/db/tang"
+    echo
+    echo "  -h         Display this usage information"
+    echo
+    echo "  -v         Verbose. Display additional info on keys created/rotated"
+    echo
+    exit "${_ret}"
+}
+
+log() {
+    local _msg="${1}"
+    local _verbose="${2:-}"
+    [ -z "${_verbose}" ] && return 0
+    echo "${_msg}" >&2
+}
+
+error() {
+    log "${1}" 1
+    usage 1
+}
+
+JWKDIR=
+VERBOSE=
+while getopts "hvd:" o; do
+    case "${o}" in
+        d) JWKDIR="${OPTARG}";;
+        h) usage 0;;
+        v) VERBOSE=1;;
+        *) usage 1;;
+    esac
+done
+
+[ -z "${JWKDIR}" ] && error "Please specify the keys directory with -d switch"
+[ -r "${JWKDIR}" ] || error "Error trying to access JWK directory '${JWKDIR}'"
+
+cd "${JWKDIR}" || error "Unable to change to keys directory '${JWKDIR}'"
+    # Disable advertisement of current keys.
+    for key in *.jwk; do
+        [ -r "${key}" ] || continue
+        mv -f -- "${key}" ."${key}"
+        log "Disabled advertisement of key ${key} -> .${key}" "${VERBOSE}"
+    done
+
+    # Create a new set of keys.
+    DEFAULT_THP_HASH="S256"
+    for alg in "ES512" "ECMR"; do
+        json="$(printf '{"alg": "%s"}' "${alg}")"
+        jwe="$(jose jwk gen --input "${json}")"
+        thp="$(printf '%s' "${jwe}" | jose jwk thp --input=- \
+                                           -a "${DEFAULT_THP_HASH}")"
+        echo "${jwe}" > "${thp}.jwk"
+        log "Created new key ${thp}.jwk" "${VERBOSE}"
+    done
+cd - >/dev/null
+
+log "Keys rotated successfully" "${VERBOSE}"

+ 38 - 17
tests/adv

@@ -1,4 +1,4 @@
-#!/bin/bash -x
+#!/bin/sh -ex
 # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
 #
 # Copyright (c) 2016 Red Hat, Inc.
@@ -18,22 +18,11 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-function fetch() {
-    curl -sfg http://127.0.0.1:$PORT$1
-}
+. helpers
 
-function ver() {
-    jose jws ver -i- -k "$1"
-}
-
-function on_exit() {
-    if [ "$PID" ]; then kill $PID; wait $PID || true; fi
-    [ -d "$TMP" ] && rm -rf $TMP
-}
+sanity_check
 
 trap 'on_exit' EXIT
-trap 'exit' ERR
-
 export TMP=`mktemp -d`
 mkdir -p $TMP/db
 
@@ -41,8 +30,8 @@ tangd-keygen $TMP/db sig exc
 jose jwk gen -i '{"alg": "ES512"}' -o $TMP/db/.sig.jwk
 jose jwk gen -i '{"alg": "ES512"}' -o $TMP/db/.oth.jwk
 
-export PORT=`shuf -i 1024-65536 -n 1`
-$SD_ACTIVATE -l "127.0.0.1:$PORT" -a $VALGRIND tangd $TMP/db &
+export PORT=$(random_port)
+start_server "${PORT}"
 export PID=$!
 sleep 0.5
 
@@ -82,4 +71,36 @@ fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` \
                -g 0 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU \
                -g 1 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU
 
-test "$(tang-show-keys $PORT)" == "$(jose jwk thp -i $TMP/db/sig.jwk)"
+THP_DEFAULT_HASH=S256     # SHA-256.
+test "$(tang-show-keys $PORT)" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i $TMP/db/sig.jwk)"
+
+# Check that new keys will be created if none exist.
+rm -rf "${TMP}/db" && mkdir -p "${TMP}/db"
+fetch /adv
+
+# Now let's make sure the new keys were named using our default thumbprint
+# hash and then rotate them and check if we still create new keys.
+cd "${TMP}/db"
+for k in *.jwk; do
+    # Check for the key name (SHA-256).
+    test "${k}" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i "${k}")".jwk
+    # Rotate the key.
+    mv -f -- "${k}" ".${k}"
+done
+cd -
+fetch /adv
+
+# Lets's now test with multiple pairs of keys.
+for i in 1 2 3 4 5 6 7 8 9; do
+    tangd-keygen "${TMP}"/db other-sig-${i} other-exc-${i}
+done
+
+# Verify the advertisement is correct.
+validate "$(fetch /adv)"
+
+# And make sure we can fetch an adv by its thumbprint.
+for jwk in "${TMP}"/db/other-sig-*.jwk; do
+    for alg in $(jose alg -k hash); do
+        fetch /adv/"$(jose jwk thp -a "${alg}" -i "${jwk}")" | ver "${jwk}"
+    done
+done

+ 62 - 0
tests/helpers

@@ -0,0 +1,62 @@
+#!/bin/sh -ex
+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2016 Red Hat, Inc.
+# Author: Nathaniel McCallum <npmccallum@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+fetch() {
+    curl -sfg "http://127.0.0.1:${PORT}${1}"
+}
+
+ver() {
+    jose jws ver -i- -k "${1}"
+}
+
+random_port() {
+    if [ -n "${TANG_BSD}" ]; then
+        jot -r 1 1024 65536
+    else
+        shuf -i 1024-65536 -n 1
+    fi
+}
+
+start_server() {
+    "${SOCAT}" TCP-LISTEN:"${1}",bind=127.0.0.1,fork SYSTEM:"${VALGRIND} tangd ${TMP}/db" &
+}
+
+on_exit() {
+    if [ "$PID" ]; then kill "${PID}"; wait "${PID}" || true; fi
+    [ -d "${TMP}" ] && rm -rf "${TMP}"
+}
+
+validate() {
+    if ! _jwks="$(jose fmt --json="${1}" -Og payload -SyOg keys \
+                 -AUo- 2>/dev/null)"; then
+        echo "Advertisement is malformed" >&2
+        exit 1
+    fi
+    _ver="$(printf '%s' "${_jwks}" | jose jwk use -i- -r -u verify -o-)"
+    if ! printf '%s' "${_ver}" | jose jws ver -i "${1}" -k- -a; then
+        echo "Advertisement is missing signatures" >&2
+        exit 1
+    fi
+}
+
+sanity_check() {
+    # Skip test if socat is not available.
+    [ -n "${SOCAT}" ] || exit 77
+}

+ 12 - 7
tests/meson.build

@@ -18,9 +18,8 @@ test_keys = executable('test-keys',
   include_directories: incdir
 )
 
-sd_activate = find_program(
-  'systemd-socket-activate',
-  'systemd-activate',
+socat = find_program(
+  'socat',
   required: false
 )
 
@@ -28,15 +27,21 @@ env = environment()
 env.prepend('PATH',
   join_paths(meson.source_root(), 'src'),
   join_paths(meson.build_root(), 'src'),
+  join_paths(meson.source_root(), 'tests'),
+  join_paths(meson.build_root(), 'tests'),
   separator: ':'
 )
 
-if sd_activate.found()
-  env.set('SD_ACTIVATE', sd_activate.path() + ' --inetd')
+if build_machine.system() == 'freebsd'
+  env.set('TANG_BSD', '1')
+endif
 
-  test('adv', find_program('adv'), env: env, timeout: 60)
-  test('rec', find_program('rec'), env: env)
+if socat.found()
+  env.set('SOCAT', socat.path())
 endif
+
+test('adv', find_program('adv'), env: env, timeout: 60)
+test('rec', find_program('rec'), env: env)
 test('test-keys', test_keys, env: env, timeout: 60)
 
 # vim:set ts=2 sw=2 et:

+ 10 - 13
tests/rec

@@ -1,4 +1,4 @@
-#!/bin/bash -x
+#!/bin/sh -ex
 # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
 #
 # Copyright (c) 2016 Red Hat, Inc.
@@ -18,14 +18,11 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-function on_exit() {
-    if [ "$PID" ]; then kill $PID; wait $PID || true; fi
-    [ -d "$TMP" ] && rm -rf $TMP
-}
+. helpers
 
-trap 'on_exit' EXIT
-trap 'exit' ERR
+sanity_check
 
+trap 'on_exit' EXIT
 export TMP=`mktemp -d`
 mkdir -p $TMP/db
 
@@ -39,19 +36,19 @@ jose jwk gen -i "$tmp" -o $TMP/exc.jwk
 jose jwk pub -i $TMP/exc.jwk -o $TMP/exc.pub.jwk
 
 # Start the server
-port=`shuf -i 1024-65536 -n 1`
-$SD_ACTIVATE -l 127.0.0.1:$port -a $VALGRIND tangd $TMP/db &
+export PORT=$(random_port)
+start_server "${PORT}"
 export PID=$!
 sleep 0.5
 
 # Make sure that GET fails
-! curl -sf http://127.0.0.1:$port/rec
-! curl -sf http://127.0.0.1:$port/rec/
+! curl -sf http://127.0.0.1:$PORT/rec
+! curl -sf http://127.0.0.1:$PORT/rec/
 
 # Make a recovery request (NOTE: this is insecure! Don't do this in real code!)
 good=`jose jwk exc -i '{"alg":"ECMR","key_ops":["deriveKey"]}' -l $TMP/exc.jwk -r $TMP/db/exc.jwk`
 test=`curl -sf -X POST \
            -H "Content-Type: application/jwk+json" \
            --data-binary @- \
-           http://127.0.0.1:$port/rec/${exc_kid} < $TMP/exc.pub.jwk`
-[ "$good" == "$test" ]
+           http://127.0.0.1:$PORT/rec/${exc_kid} < $TMP/exc.pub.jwk`
+[ "$good" = "$test" ]

+ 4 - 3
tests/test-keys.c.in

@@ -140,7 +140,7 @@ test_find_jws(void)
     json_auto_t* keys = json_deep_copy(tki->m_keys);
     ASSERT(keys);
     ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0);
-    ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count);
+    ASSERT(json_array_size(keys) == (size_t)(tki->m_keys_count + tki->m_rotated_keys_count));
 
     for (int i = 0; hashes[i]; i++) {
         json_array_foreach(keys, idx, jwk) {
@@ -203,7 +203,7 @@ test_find_jwk(void)
     json_auto_t* keys = json_deep_copy(tki->m_keys);
     ASSERT(keys);
     ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0);
-    ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count);
+    ASSERT(json_array_size(keys) == (size_t)(tki->m_keys_count + tki->m_rotated_keys_count));
 
     for (int i = 0; hashes[i]; i++) {
         json_array_foreach(keys, idx, jwk) {
@@ -230,7 +230,8 @@ test_read_keys(void)
      * - qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk
      * - -bWkGaJi0Zdvxaj4DCp28umLcRA.jwk
      */
-    ASSERT(tki->m_keys_count == 4);
+    ASSERT(tki->m_keys_count == 2);
+    ASSERT(tki->m_rotated_keys_count == 2);
     ASSERT(json_array_size(tki->m_keys) == 2);
     ASSERT(json_array_size(tki->m_rotated_keys) == 2);
 

+ 12 - 3
units/meson.build

@@ -3,8 +3,17 @@ tangd_service = configure_file(
   output: 'tangd@.service',
   configuration: data
 )
-
-units += join_paths(meson.current_source_dir(), 'tangd.socket')
-units += tangd_service
+if build_machine.system() == 'freebsd'
+  tangd_rc = configure_file(
+    input: 'tangd.rc.in',
+    output: 'tangd',
+    configuration: data,
+    install_dir: join_paths(get_option('prefix') + sysconfdir, 'rc.d'),
+    install_mode: ['rwxr-xr-x', 'root', 'wheel']
+  )
+else
+  units += join_paths(meson.current_source_dir(), 'tangd.socket')
+  units += tangd_service
+endif
 
 # vim:set ts=2 sw=2 et:

+ 47 - 0
units/tangd.rc.in

@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# Should probably in the future allow running as non-root
+# and enable multiple interfaces in some cleaner way.
+
+# PROVIDE: tangd
+# REQUIRE: NETWORKING DAEMON
+# KEYWORD: nojail
+
+. /etc/rc.subr
+
+name="tangd"
+desc="Network Presence Binding Daemon (tang)"
+rcvar="tangd_enable"
+command="/usr/local/bin/socat"
+
+load_rc_config $name
+: ${tangd_enable:=no}
+: ${tangd_ip="127.0.0.1"}
+: ${tangd_port="8888"}
+: ${tangd_jwkdir="@jwkdir@"}
+: ${tangd_logfile="/var/log/tang"}
+: ${tangd_executable="@libexecdir@/tangd"}
+
+pidfile="/var/run/${name}.pid"
+required_files="@libexecdir@/${name}"
+required_dirs="${tangd_jwkdir}"
+
+start_postcmd="${name}_poststart"
+_tangd_listen_args="TCP-LISTEN:${tangd_port},bind=${tangd_ip},fork"
+command_args="${_tangd_listen_args} SYSTEM:\"${tangd_executable} ${tangd_jwkdir} 2>> ${tangd_logfile} \" &"
+
+# Since we may not be the only socat running we can't use the built-in process
+# management, so we'll need to use a pid file and find the pid from unique arguments.
+tangd_poststart() {
+  ps_pid=`ps ax -o pid= -o command= | grep ${_tangd_listen_args} | grep -v grep | awk '{print $1}'`
+  if [ -z "$ps_pid" ]; then
+    err 1 "Cannot get pid for ${command} ${command_args}"
+  fi
+  echo $ps_pid > ${pidfile}
+  return $?
+}
+
+run_rc_command "$1"

+ 0 - 10
units/tangd.xinetd

@@ -1,10 +0,0 @@
-service tangd
-{
-    port = 80
-    server_args = /var/db/tang
-    server = /usr/libexec/tangd
-    socket_type = stream
-    protocol = tcp
-    user = root
-    wait = no
-}

+ 4 - 0
units/tangdw

@@ -0,0 +1,4 @@
+#!/bin/sh
+echo "==================================" >> /var/log/tangd.log
+echo `date`: >> /var/log/tangd.log
+/usr/libexec/tangd $1 2>> /var/log/tangd.log

+ 13 - 0
units/tangdx

@@ -0,0 +1,13 @@
+service tangd
+{
+    port            = 8888
+    server_args     = /var/db/tang
+    server          = /usr/libexec/tangdw
+    socket_type     = stream
+    user            = root
+    wait            = no
+    log_on_success  += USERID
+    log_on_failure  += USERID
+    disable         = no
+    type            = UNLISTED
+}