/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 dracut-module/module-setup.sh

  • Committer: teddy at recompile
  • Date: 2020-04-05 21:30:59 UTC
  • Revision ID: teddy@recompile.se-20200405213059-fb2a61ckqynrmatk
Fix file descriptor leak in mandos-client

When the local network has Mandos servers announcing themselves using
real, globally reachable, IPv6 addresses (i.e. not link-local
addresses), but there is no router on the local network providing IPv6
RA (Router Advertisement) packets, the client cannot reach the server
by normal means, since the client only has a link-local IPv6 address,
and has no usable route to reach the server's global IPv6 address.
(This is not a common situation, and usually only happens when the
router itself reboots and runs a Mandos client, since it cannot then
give RA packets to itself.)  The client code has a solution for
this, which consists of adding a temporary local route to reach the
address of the server during communication, and removing this
temporary route afterwards.

This solution with a temporary route works, but has a file descriptor
leak; it leaks one file descriptor for each addition and for each
removal of a route.  If one server requiring an added route is present
on the network, but no servers gives a password, making the client
retry after the default ten seconds, and we furthermore assume a
default 1024 open files limit, the client runs out of file descriptors
after about 90 minutes, after which time the client process will be
useless and fail to retrieve any passwords, necessitating manual
password entry via the keyboard.

Fix this by eliminating the file descriptor leak in the client.

* plugins.d/mandos-client.c (add_delete_local_route): Do
  close(devnull) also in parent process, also if fork() fails, and on
  any failure in child process.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/bin/sh
 
2
#
 
3
# This file should be present in the root file system directory
 
4
# /usr/lib/dracut/modules.d/90mandos.  When dracut creates the
 
5
# initramfs image, dracut will source this file and run the shell
 
6
# functions defined in this file: "install", "check", "depends",
 
7
# "cmdline", and "installkernel".
 
8
 
9
# Despite the above #!/bin/sh line and the executable flag, this file
 
10
# is not executed; this file is sourced by dracut when creating the
 
11
# initramfs image file.
 
12
 
 
13
mandos_libdir(){
 
14
    for dir in /usr/lib \
 
15
        "/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`" \
 
16
        "`rpm --eval='%{_libdir}' 2>/dev/null`" /usr/local/lib; do
 
17
        if [ -d "$dir"/mandos ]; then
 
18
            echo "$dir"/mandos
 
19
            return
 
20
        fi
 
21
    done
 
22
    # Mandos not found
 
23
    return 1
 
24
}
 
25
 
 
26
mandos_keydir(){
 
27
    for dir in /etc/keys/mandos /etc/mandos/keys; do
 
28
        if [ -d "$dir" ]; then
 
29
            echo "$dir"
 
30
            return
 
31
        fi
 
32
    done
 
33
    # Mandos key directory not found
 
34
    return 1
 
35
}
 
36
 
 
37
check(){
 
38
    if [ "${hostonly:-no}" = "no" ]; then
 
39
        dwarning "Mandos: Dracut not in hostonly mode"
 
40
        return 1
 
41
    fi
 
42
 
 
43
    local libdir=`mandos_libdir`
 
44
    if [ -z "$libdir" ]; then
 
45
        dwarning "Mandos lib directory not found"
 
46
        return 1
 
47
    fi
 
48
 
 
49
    local keydir=`mandos_keydir`
 
50
    if [ -z "$keydir" ]; then
 
51
        dwarning "Mandos key directory not found"
 
52
        return 1
 
53
    fi
 
54
}
 
55
 
 
56
install(){
 
57
    chmod go+w,+t "$initdir"/tmp
 
58
    local libdir=`mandos_libdir`
 
59
    local keydir=`mandos_keydir`
 
60
    set `{ getent passwd _mandos \
 
61
        || getent passwd nobody \
 
62
        || echo ::65534:65534:::; } \
 
63
        | cut --delimiter=: --fields=3,4 --only-delimited \
 
64
        --output-delimiter=" "`
 
65
    local mandos_user="$1"
 
66
    local mandos_group="$2"
 
67
    inst "${libdir}" /lib/mandos
 
68
    if dracut_module_included "systemd"; then
 
69
        plugindir=/lib/mandos
 
70
        inst "${libdir}/plugins.d/mandos-client" \
 
71
             "${plugindir}/mandos-client"
 
72
        chmod u-s "${initdir}/${plugindir}/mandos-client"
 
73
        inst "${moddir}/ask-password-mandos.service" \
 
74
             "${systemdsystemunitdir}/ask-password-mandos.service"
 
75
        if [ -d /etc/systemd/system/ask-password-mandos.service.d ]; then
 
76
            inst /etc/systemd/system/ask-password-mandos.service.d
 
77
            inst_multiple -o /etc/systemd/system/ask-password-mandos.service.d/*.conf
 
78
        fi
 
79
        if [ ${mandos_user} != 65534 ]; then
 
80
            sed --in-place \
 
81
                --expression="s,^ExecStart=/lib/mandos/password-agent ,&--user=${mandos_user} ," \
 
82
                "${initdir}/${systemdsystemunitdir}/ask-password-mandos.service"
 
83
        fi
 
84
        if [ ${mandos_group} != 65534 ]; then
 
85
            sed --in-place \
 
86
                --expression="s,^ExecStart=/lib/mandos/password-agent ,&--group=${mandos_group} ," \
 
87
                "${initdir}/${systemdsystemunitdir}/ask-password-mandos.service"
 
88
        fi
 
89
    else
 
90
        inst_hook cmdline 20 "$moddir"/cmdline-mandos.sh
 
91
        plugindir=/lib/mandos/plugins.d
 
92
        inst "${libdir}/plugin-runner" /lib/mandos/plugin-runner
 
93
        inst /etc/mandos/plugin-runner.conf
 
94
        sed --in-place \
 
95
            --expression='1i--options-for=mandos-client:--pubkey=/etc/mandos/keys/pubkey.txt,--seckey=/etc/mandos/keys/seckey.txt,--tls-pubkey=/etc/mandos/keys/tls-pubkey.pem,--tls-privkey=/etc/mandos/keys/tls-privkey.pem' \
 
96
            "${initdir}/etc/mandos/plugin-runner.conf"
 
97
        if [ ${mandos_user} != 65534 ]; then
 
98
            sed --in-place --expression="1i--userid=${mandos_user}" \
 
99
                "${initdir}/etc/mandos/plugin-runner.conf"
 
100
        fi
 
101
        if [ ${mandos_group} != 65534 ]; then
 
102
            sed --in-place \
 
103
                --expression="1i--groupid=${mandos_group}" \
 
104
                "${initdir}/etc/mandos/plugin-runner.conf"
 
105
        fi
 
106
        inst "${libdir}/plugins.d" "$plugindir"
 
107
        chown ${mandos_user}:${mandos_group} "${initdir}/${plugindir}"
 
108
        # Copy the packaged plugins
 
109
        for file in "$libdir"/plugins.d/*; do
 
110
            base="`basename \"$file\"`"
 
111
            # Is this plugin overridden?
 
112
            if [ -e "/etc/mandos/plugins.d/$base" ]; then
 
113
                continue
 
114
            fi
 
115
            case "$base" in
 
116
                *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
 
117
                    : ;;
 
118
                "*") dwarning "Mandos client plugin directory is empty." >&2 ;;
 
119
                askpass-fifo) : ;; # Ignore packaged for dracut
 
120
                *) inst "${file}" "${plugindir}/${base}" ;;
 
121
            esac
 
122
        done
 
123
        # Copy any user-supplied plugins
 
124
        for file in /etc/mandos/plugins.d/*; do
 
125
            base="`basename \"$file\"`"
 
126
            case "$base" in
 
127
                *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
 
128
                    : ;;
 
129
                "*") : ;;
 
130
                *) inst "$file" "${plugindir}/${base}" ;;
 
131
            esac
 
132
        done
 
133
        # Copy any user-supplied plugin helpers
 
134
        for file in /etc/mandos/plugin-helpers/*; do
 
135
            base="`basename \"$file\"`"
 
136
            case "$base" in
 
137
                *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
 
138
                    : ;;
 
139
                "*") : ;;
 
140
                *) inst "$file" "/lib/mandos/plugin-helpers/$base";;
 
141
            esac
 
142
        done
 
143
    fi
 
144
    # Copy network hooks
 
145
    for hook in /etc/mandos/network-hooks.d/*; do
 
146
        basename=`basename "$hook"`
 
147
        case "$basename" in
 
148
            "*") continue ;;
 
149
            *[!A-Za-z0-9_.-]*) continue ;;
 
150
            *) test -d "$hook" || inst "$hook" "/lib/mandos/network-hooks.d/$basename" ;;
 
151
        esac
 
152
        if [ -x "$hook" ]; then
 
153
            # Copy any files needed by the network hook
 
154
            MANDOSNETHOOKDIR=/etc/mandos/network-hooks.d MODE=files \
 
155
                VERBOSITY=0 "$hook" files | while read file target; do
 
156
                if [ ! -e "${file}" ]; then
 
157
                    dwarning "WARNING: file ${file} not found, requested by Mandos network hook '${basename}'" >&2
 
158
                fi
 
159
                if [ -z "${target}" ]; then
 
160
                    inst "$file"
 
161
                else
 
162
                    inst "$file" "$target"
 
163
                fi
 
164
            done
 
165
        fi
 
166
    done
 
167
    # Copy the packaged plugin helpers
 
168
    for file in "$libdir"/plugin-helpers/*; do
 
169
        base="`basename \"$file\"`"
 
170
        # Is this plugin overridden?
 
171
        if [ -e "/etc/mandos/plugin-helpers/$base" ]; then
 
172
            continue
 
173
        fi
 
174
        case "$base" in
 
175
            *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
 
176
                : ;;
 
177
            "*") : ;;
 
178
            *) inst "$file" "/lib/mandos/plugin-helpers/$base";;
 
179
        esac
 
180
    done
 
181
    local gpg=/usr/bin/gpg
 
182
    if [ -e /usr/bin/gpgconf ]; then
 
183
        inst /usr/bin/gpgconf
 
184
        gpg="`/usr/bin/gpgconf|sed --quiet --expression='s/^gpg:[^:]*://p'`"
 
185
        gpgagent="`/usr/bin/gpgconf|sed --quiet --expression='s/^gpg-agent:[^:]*://p'`"
 
186
        # Newer versions of GnuPG 2 requires the gpg-agent binary
 
187
        if [ -e "$gpgagent" ]; then
 
188
            inst "$gpgagent"
 
189
        fi
 
190
    fi
 
191
    inst "$gpg"
 
192
    if dracut_module_included "systemd"; then
 
193
        inst "${moddir}/password-agent" /lib/mandos/password-agent
 
194
        inst "${moddir}/ask-password-mandos.path" \
 
195
             "${systemdsystemunitdir}/ask-password-mandos.path"
 
196
        ln_r "${systemdsystemunitdir}/ask-password-mandos.path" \
 
197
             "${systemdsystemunitdir}/sysinit.target.wants/ask-password-mandos.path"
 
198
    fi
 
199
    # Key files
 
200
    for file in "$keydir"/*; do
 
201
        if [ -d "$file" ]; then
 
202
            continue
 
203
        fi
 
204
        case "$file" in
 
205
            *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
 
206
                : ;;
 
207
            "*") : ;;
 
208
            *)
 
209
                inst "$file" "/etc/mandos/keys/`basename \"$file\"`"
 
210
                chown ${mandos_user}:${mandos_group} \
 
211
                      "${initdir}/etc/mandos/keys/`basename \"$file\"`"
 
212
                if [ `basename "$file"` = dhparams.pem ]; then
 
213
                    # Use Diffie-Hellman parameters file
 
214
                    if dracut_module_included "systemd"; then
 
215
                        sed --in-place \
 
216
                            --expression='/^ExecStart/s/ \$MANDOS_CLIENT_OPTIONS/ --dh-params=\/etc\/mandos\/keys\/dhparams.pem&/' \
 
217
                            "${initdir}/${systemdsystemunitdir}/ask-password-mandos.service"
 
218
                    else
 
219
                        sed --in-place \
 
220
                            --expression="1i--options-for=mandos-client:--dh-params=/etc/mandos/keys/dhparams.pem" \
 
221
                            "${initdir}/etc/mandos/plugin-runner.conf"
 
222
                    fi
 
223
                fi
 
224
                ;;
 
225
        esac
 
226
    done
 
227
}
 
228
 
 
229
installkernel(){
 
230
    instmods =drivers/net
 
231
    hostonly='' instmods ipv6
 
232
    # Copy any kernel modules needed by network hooks
 
233
    for hook in /etc/mandos/network-hooks.d/*; do
 
234
        basename=`basename "$hook"`
 
235
        case "$basename" in
 
236
            "*") continue ;;
 
237
            *[!A-Za-z0-9_.-]*) continue ;;
 
238
        esac
 
239
        if [ -x "$hook" ]; then
 
240
            # Copy and load any modules needed by the network hook
 
241
            MANDOSNETHOOKDIR=/etc/mandos/network-hooks.d MODE=modules \
 
242
                VERBOSITY=0 "$hook" modules | while read module; do
 
243
                if [ -z "${target}" ]; then
 
244
                    instmods "$module"
 
245
                fi
 
246
            done
 
247
        fi
 
248
    done
 
249
}
 
250
 
 
251
depends(){
 
252
    echo crypt
 
253
}
 
254
 
 
255
cmdline(){
 
256
    :
 
257
}