/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos-keygen

  • Committer: Teddy Hogeborn
  • Date: 2015-05-23 20:18:34 UTC
  • mto: This revision was merged to the branch mainline in revision 756.
  • Revision ID: teddy@recompile.se-20150523201834-e89ex4ito93yni8x
mandos: Use multiprocessing module to run checkers.

For a long time, the Mandos server has occasionally logged the message
"ERROR: Child process vanished".  This was never a fatal error, but it
has been annoying and slightly worrying, since a definite cause was
not found.  One potential cause could be the "multiprocessing" and
"subprocess" modules conflicting w.r.t. SIGCHLD.  To avoid this,
change the running of checkers from using subprocess.Popen
asynchronously to instead first create a multiprocessing.Process()
(which is asynchronous) calling a function, and have that function
then call subprocess.call() (which is synchronous).  In this way, the
only thing using any asynchronous subprocesses is the multiprocessing
module.

This makes it necessary to change one small thing in the D-Bus API,
since the subprocesses.call() function does not expose the raw wait(2)
status value.

DBUS-API (CheckerCompleted): Change the second value provided by this
                             D-Bus signal from the raw wait(2) status
                             to the actual terminating signal number.
mandos (subprocess_call_pipe): New function to be called by
                               multiprocessing.Process (starting a
                               separate process).
(Client.last_checker signal): New attribute for signal which
                              terminated last checker.  Like
                              last_checker_status, only not accessible
                              via D-Bus.
(Client.checker_callback): Take new "connection" argument and use it
                           to get returncode; set last_checker_signal.
                           Return False so gobject does not call this
                           callback again.
(Client.start_checker): Start checker using a multiprocessing.Process
                        instead of a subprocess.Popen.
(ClientDBus.checker_callback): Take new "connection" argument.        Call
                               Client.checker_callback early to have
                               it set last_checker_status and
                               last_checker_signal; use those.  Change
                               second value provided to D-Bus signal
                               CheckerCompleted to use
                               last_checker_signal if checker was
                               terminated by signal.
mandos-monitor: Update to reflect DBus API change.
(MandosClientWidget.checker_completed): Take "signal" instead of
                                        "condition" argument.  Use it
                                        accordingly.  Remove dead code
                                        (os.WCOREDUMP case).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/bin/sh -e
2
2
3
 
# Mandos key generator - create new keys for a Mandos client
4
 
5
 
# Copyright © 2008-2019 Teddy Hogeborn
6
 
# Copyright © 2008-2019 Björn Påhlsson
7
 
8
 
# This file is part of Mandos.
9
 
#
10
 
# Mandos is free software: you can redistribute it and/or modify it
11
 
# under the terms of the GNU General Public License as published by
 
3
# Mandos key generator - create a new OpenPGP key for a Mandos client
 
4
 
5
# Copyright © 2008-2015 Teddy Hogeborn
 
6
# Copyright © 2008-2015 Björn Påhlsson
 
7
 
8
# This program is free software: you can redistribute it and/or modify
 
9
# it under the terms of the GNU General Public License as published by
12
10
# the Free Software Foundation, either version 3 of the License, or
13
11
# (at your option) any later version.
14
12
#
15
 
#     Mandos is distributed in the hope that it will be useful, but
16
 
#     WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
#     This program is distributed in the hope that it will be useful,
 
14
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
17
15
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
16
#     GNU General Public License for more details.
19
17
20
18
# You should have received a copy of the GNU General Public License
21
 
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
20
23
21
# Contact the authors at <mandos@recompile.se>.
24
22
25
23
 
26
 
VERSION="1.8.0"
 
24
VERSION="1.6.9"
27
25
 
28
26
KEYDIR="/etc/keys/mandos"
29
27
KEYTYPE=RSA
34
32
KEYEMAIL=""
35
33
KEYCOMMENT=""
36
34
KEYEXPIRE=0
37
 
TLS_KEYTYPE=ed25519
38
35
FORCE=no
39
36
SSH=yes
40
37
KEYCOMMENT_ORIG="$KEYCOMMENT"
45
42
fi
46
43
 
47
44
# Parse options
48
 
TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:T:fS \
49
 
    --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,tls-keytype:,force,no-ssh \
 
45
TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:fS \
 
46
    --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force,no-ssh \
50
47
    --name "$0" -- "$@"`
51
48
 
52
49
help(){
64
61
  -v, --version         Show program's version number and exit
65
62
  -h, --help            Show this help message and exit
66
63
  -d DIR, --dir DIR     Target directory for key files
67
 
  -t TYPE, --type TYPE  OpenPGP key type.  Default is RSA.
 
64
  -t TYPE, --type TYPE  Key type.  Default is RSA.
68
65
  -l BITS, --length BITS
69
 
                        OpenPGP key length in bits.  Default is 4096.
 
66
                        Key length in bits.  Default is 4096.
70
67
  -s TYPE, --subtype TYPE
71
 
                        OpenPGP subkey type.  Default is RSA.
 
68
                        Subkey type.  Default is RSA.
72
69
  -L BITS, --sublength BITS
73
 
                        OpenPGP subkey length in bits.  Default 4096.
 
70
                        Subkey length in bits.  Default is 4096.
74
71
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
75
72
  -e ADDRESS, --email ADDRESS
76
 
                        Email address of OpenPGP key.  Default empty.
 
73
                        Email address of key.  Default is empty.
77
74
  -c TEXT, --comment TEXT
78
 
                        Comment field for OpenPGP key.  Default empty.
 
75
                        Comment field for key.  The default is empty.
79
76
  -x TIME, --expire TIME
80
 
                        OpenPGP key expire time.  Default is none.
 
77
                        Key expire time.  Default is no expiration.
81
78
                        See gpg(1) for syntax.
82
 
  -T TYPE, --tls-keytype TYPE
83
 
                        TLS key type.  Default is ed25519.
84
79
  -f, --force           Force overwriting old key files.
85
80
 
86
81
Password creation options:
109
104
        -e|--email) KEYEMAIL="$2"; shift 2;;
110
105
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
111
106
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
112
 
        -T|--tls-keytype) TLS_KEYTYPE="$2"; shift 2;;
113
107
        -f|--force) FORCE=yes; shift;;
114
108
        -S|--no-ssh) SSH=no; shift;;
115
109
        -v|--version) echo "$0 $VERSION"; exit;;
125
119
 
126
120
SECKEYFILE="$KEYDIR/seckey.txt"
127
121
PUBKEYFILE="$KEYDIR/pubkey.txt"
128
 
TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
129
 
TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
130
122
 
131
123
# Check for some invalid values
132
124
if [ ! -d "$KEYDIR" ]; then
169
161
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
170
162
    esac
171
163
    
172
 
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
173
 
             || [ -e "$TLS_PRIVKEYFILE" ] \
174
 
             || [ -e "$TLS_PUBKEYFILE" ]; } \
175
 
        && [ "$FORCE" -eq 0 ]; then
 
164
    if [ \( -e "$SECKEYFILE" -o -e "$PUBKEYFILE" \) \
 
165
        -a "$FORCE" -eq 0 ]; then
176
166
        echo "Refusing to overwrite old key files; use --force" >&2
177
167
        exit 1
178
168
    fi
228
218
        #Handle: <no-spaces>
229
219
        #%pubring pubring.gpg
230
220
        #%secring secring.gpg
231
 
        %no-protection
232
221
        %commit
233
222
        EOF
234
223
    
242
231
        date
243
232
    fi
244
233
    
245
 
    # Backup any old key files
246
 
    if cp --backup=numbered --force "$TLS_PRIVKEYFILE" "$TLS_PRIVKEYFILE" \
247
 
        2>/dev/null; then
248
 
        shred --remove "$TLS_PRIVKEYFILE"
249
 
    fi
250
 
    if cp --backup=numbered --force "$TLS_PUBKEYFILE" "$TLS_PUBKEYFILE" \
251
 
        2>/dev/null; then
252
 
        rm --force "$TLS_PUBKEYFILE"
253
 
    fi
254
 
 
255
 
    ## Generate TLS private key
256
 
 
257
 
    # First try certtool from GnuTLS
258
 
    if ! certtool --generate-privkey --password='' \
259
 
         --outfile "$TLS_PRIVKEYFILE" --sec-param ultra \
260
 
         --key-type="$TLS_KEYTYPE" --pkcs8 --no-text 2>/dev/null; then
261
 
        # Otherwise try OpenSSL
262
 
        if ! openssl genpkey -algorithm X25519 -out \
263
 
             /etc/keys/mandos/tls-privkey.pem; then
264
 
            rm --force /etc/keys/mandos/tls-privkey.pem
265
 
            # None of the commands succeded; give up
266
 
            return 1
267
 
        fi
268
 
    fi
269
 
 
270
 
    ## TLS public key
271
 
 
272
 
    # First try certtool from GnuTLS
273
 
    if ! certtool --password='' --load-privkey="$TLS_PRIVKEYFILE" \
274
 
         --outfile="$TLS_PUBKEYFILE" --pubkey-info --no-text \
275
 
         2>/dev/null; then
276
 
        # Otherwise try OpenSSL
277
 
        if ! openssl pkey -in "$TLS_PRIVKEYFILE" \
278
 
             -out "$TLS_PUBKEYFILE" -pubout; then
279
 
            rm --force "$TLS_PUBKEYFILE"
280
 
            # None of the commands succeded; give up
281
 
            return 1
282
 
        fi
283
 
    fi
284
 
    
285
234
    # Make sure trustdb.gpg exists;
286
235
    # this is a workaround for Debian bug #737128
287
236
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
336
285
    esac
337
286
    
338
287
    if [ $SSH -eq 1 ]; then
339
 
        for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
 
288
        for ssh_keytype in ed25519 rsa; do
340
289
            set +e
341
290
            ssh_fingerprint="`ssh-keyscan -t $ssh_keytype localhost 2>/dev/null`"
342
 
            err=$?
343
291
            set -e
344
 
            if [ $err -ne 0 ]; then
 
292
            if [ $? -ne 0 ]; then
345
293
                ssh_fingerprint=""
346
294
                continue
347
295
            fi
369
317
    
370
318
    test -n "$FINGERPRINT"
371
319
    
372
 
    KEY_ID="$(certtool --key-id --hash=sha256 \
373
 
                       --infile="$TLS_PUBKEYFILE" 2>/dev/null || :)"
374
 
 
375
 
    if [ -z "$KEY_ID" ]; then
376
 
        KEY_ID=$(openssl pkey -pubin -in /tmp/tls-pubkey.pem \
377
 
                         -outform der \
378
 
                     | openssl sha256 \
379
 
                     | sed --expression='s/^.*[^[:xdigit:]]//')
380
 
    fi
381
 
    test -n "$KEY_ID"
382
 
    
383
320
    FILECOMMENT="Encrypted password for a Mandos client"
384
321
    
385
322
    while [ ! -s "$SECFILE" ]; do
387
324
            cat "$PASSFILE"
388
325
        else
389
326
            tty --quiet && stty -echo
390
 
            echo -n "Enter passphrase: " >/dev/tty
391
 
            read -r first
 
327
            echo -n "Enter passphrase: " >&2
 
328
            read first
392
329
            tty --quiet && echo >&2
393
 
            echo -n "Repeat passphrase: " >/dev/tty
394
 
            read -r second
 
330
            echo -n "Repeat passphrase: " >&2
 
331
            read second
395
332
            if tty --quiet; then
396
333
                echo >&2
397
334
                stty echo
419
356
    cat <<-EOF
420
357
        [$KEYNAME]
421
358
        host = $KEYNAME
422
 
        key_id = $KEY_ID
423
359
        fingerprint = $FINGERPRINT
424
360
        secret =
425
361
        EOF