1*d9f008e6SMax Reitz#!/usr/bin/env bash
2*d9f008e6SMax Reitz# group: rw
3*d9f008e6SMax Reitz#
4*d9f008e6SMax Reitz# Test FUSE exports' allow-other option
5*d9f008e6SMax Reitz#
6*d9f008e6SMax Reitz# Copyright (C) 2021 Red Hat, Inc.
7*d9f008e6SMax Reitz#
8*d9f008e6SMax Reitz# This program is free software; you can redistribute it and/or modify
9*d9f008e6SMax Reitz# it under the terms of the GNU General Public License as published by
10*d9f008e6SMax Reitz# the Free Software Foundation; either version 2 of the License, or
11*d9f008e6SMax Reitz# (at your option) any later version.
12*d9f008e6SMax Reitz#
13*d9f008e6SMax Reitz# This program is distributed in the hope that it will be useful,
14*d9f008e6SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of
15*d9f008e6SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*d9f008e6SMax Reitz# GNU General Public License for more details.
17*d9f008e6SMax Reitz#
18*d9f008e6SMax Reitz# You should have received a copy of the GNU General Public License
19*d9f008e6SMax Reitz# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*d9f008e6SMax Reitz#
21*d9f008e6SMax Reitz
22*d9f008e6SMax Reitzseq=$(basename "$0")
23*d9f008e6SMax Reitzecho "QA output created by $seq"
24*d9f008e6SMax Reitz
25*d9f008e6SMax Reitzstatus=1	# failure is the default!
26*d9f008e6SMax Reitz
27*d9f008e6SMax Reitz_cleanup()
28*d9f008e6SMax Reitz{
29*d9f008e6SMax Reitz    _cleanup_qemu
30*d9f008e6SMax Reitz    _cleanup_test_img
31*d9f008e6SMax Reitz    rm -f "$EXT_MP"
32*d9f008e6SMax Reitz}
33*d9f008e6SMax Reitztrap "_cleanup; exit \$status" 0 1 2 3 15
34*d9f008e6SMax Reitz
35*d9f008e6SMax Reitz# get standard environment, filters and checks
36*d9f008e6SMax Reitz. ../common.rc
37*d9f008e6SMax Reitz. ../common.filter
38*d9f008e6SMax Reitz. ../common.qemu
39*d9f008e6SMax Reitz
40*d9f008e6SMax Reitz_supported_fmt generic
41*d9f008e6SMax Reitz
42*d9f008e6SMax Reitz_supported_proto file # We create the FUSE export manually
43*d9f008e6SMax Reitz
44*d9f008e6SMax Reitzsudo -n -u nobody true || \
45*d9f008e6SMax Reitz    _notrun 'Password-less sudo as nobody required to test allow_other'
46*d9f008e6SMax Reitz
47*d9f008e6SMax Reitz# $1: Export ID
48*d9f008e6SMax Reitz# $2: Options (beyond the node-name and ID)
49*d9f008e6SMax Reitz# $3: Expected return value (defaults to 'return')
50*d9f008e6SMax Reitz# $4: Node to export (defaults to 'node-format')
51*d9f008e6SMax Reitzfuse_export_add()
52*d9f008e6SMax Reitz{
53*d9f008e6SMax Reitz    allow_other_not_supported='option allow_other only allowed if'
54*d9f008e6SMax Reitz
55*d9f008e6SMax Reitz    output=$(
56*d9f008e6SMax Reitz        success_or_failure=yes _send_qemu_cmd $QEMU_HANDLE \
57*d9f008e6SMax Reitz            "{'execute': 'block-export-add',
58*d9f008e6SMax Reitz              'arguments': {
59*d9f008e6SMax Reitz                  'type': 'fuse',
60*d9f008e6SMax Reitz                  'id': '$1',
61*d9f008e6SMax Reitz                  'node-name': '${4:-node-format}',
62*d9f008e6SMax Reitz                  $2
63*d9f008e6SMax Reitz              } }" \
64*d9f008e6SMax Reitz            "${3:-return}" \
65*d9f008e6SMax Reitz            "$allow_other_not_supported" \
66*d9f008e6SMax Reitz            | _filter_imgfmt
67*d9f008e6SMax Reitz    )
68*d9f008e6SMax Reitz
69*d9f008e6SMax Reitz    if echo "$output" | grep -q "$allow_other_not_supported"; then
70*d9f008e6SMax Reitz        # Shut down qemu gracefully so it can unmount the export
71*d9f008e6SMax Reitz        _send_qemu_cmd $QEMU_HANDLE \
72*d9f008e6SMax Reitz            "{'execute': 'quit'}" \
73*d9f008e6SMax Reitz            'return'
74*d9f008e6SMax Reitz
75*d9f008e6SMax Reitz        wait=yes _cleanup_qemu
76*d9f008e6SMax Reitz
77*d9f008e6SMax Reitz        _notrun "allow_other not supported"
78*d9f008e6SMax Reitz    fi
79*d9f008e6SMax Reitz
80*d9f008e6SMax Reitz    echo "$output"
81*d9f008e6SMax Reitz}
82*d9f008e6SMax Reitz
83*d9f008e6SMax ReitzEXT_MP="$TEST_DIR/fuse-export"
84*d9f008e6SMax Reitz
85*d9f008e6SMax Reitz_make_test_img 64k
86*d9f008e6SMax Reitztouch "$EXT_MP"
87*d9f008e6SMax Reitz
88*d9f008e6SMax Reitzecho
89*d9f008e6SMax Reitzecho '=== Test permissions ==='
90*d9f008e6SMax Reitz
91*d9f008e6SMax Reitz# $1: allow-other value ('on'/'off'/'auto')
92*d9f008e6SMax Reitzrun_permission_test()
93*d9f008e6SMax Reitz{
94*d9f008e6SMax Reitz    _launch_qemu \
95*d9f008e6SMax Reitz        -blockdev \
96*d9f008e6SMax Reitz        "$IMGFMT,node-name=node-format,file.driver=file,file.filename=$TEST_IMG"
97*d9f008e6SMax Reitz
98*d9f008e6SMax Reitz    _send_qemu_cmd $QEMU_HANDLE \
99*d9f008e6SMax Reitz        "{'execute': 'qmp_capabilities'}" \
100*d9f008e6SMax Reitz        'return'
101*d9f008e6SMax Reitz
102*d9f008e6SMax Reitz    fuse_export_add 'export' \
103*d9f008e6SMax Reitz        "'mountpoint': '$EXT_MP',
104*d9f008e6SMax Reitz         'allow-other': '$1'"
105*d9f008e6SMax Reitz
106*d9f008e6SMax Reitz    # Should always work
107*d9f008e6SMax Reitz    echo '(Removing all permissions)'
108*d9f008e6SMax Reitz    chmod 000 "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
109*d9f008e6SMax Reitz    stat -c 'Permissions post-chmod: %a' "$EXT_MP"
110*d9f008e6SMax Reitz
111*d9f008e6SMax Reitz    # Should always work
112*d9f008e6SMax Reitz    echo '(Granting u+r)'
113*d9f008e6SMax Reitz    chmod u+r "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
114*d9f008e6SMax Reitz    stat -c 'Permissions post-chmod: %a' "$EXT_MP"
115*d9f008e6SMax Reitz
116*d9f008e6SMax Reitz    # Should only work with allow-other: Otherwise, no permissions can be
117*d9f008e6SMax Reitz    # granted to the group or others
118*d9f008e6SMax Reitz    echo '(Granting read permissions for everyone)'
119*d9f008e6SMax Reitz    chmod 444 "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
120*d9f008e6SMax Reitz    stat -c 'Permissions post-chmod: %a' "$EXT_MP"
121*d9f008e6SMax Reitz
122*d9f008e6SMax Reitz    echo 'Doing operations as nobody:'
123*d9f008e6SMax Reitz    # Change to TEST_DIR, so nobody will not have to attempt a lookup
124*d9f008e6SMax Reitz    pushd "$TEST_DIR" >/dev/null
125*d9f008e6SMax Reitz
126*d9f008e6SMax Reitz    # This is already prevented by the permissions (without allow-other, FUSE
127*d9f008e6SMax Reitz    # exports always have o-r), but test it anyway
128*d9f008e6SMax Reitz    sudo -n -u nobody cat fuse-export >/dev/null
129*d9f008e6SMax Reitz
130*d9f008e6SMax Reitz    # If the only problem were the lack of permissions, we should still be able
131*d9f008e6SMax Reitz    # to stat the export as nobody; it should not work without allow-other,
132*d9f008e6SMax Reitz    # though
133*d9f008e6SMax Reitz    sudo -n -u nobody \
134*d9f008e6SMax Reitz        stat -c 'Permissions seen by nobody: %a' fuse-export 2>&1 \
135*d9f008e6SMax Reitz        | _filter_imgfmt
136*d9f008e6SMax Reitz
137*d9f008e6SMax Reitz    # To prove the point, revoke read permissions for others and try again
138*d9f008e6SMax Reitz    chmod o-r fuse-export 2>&1 | _filter_testdir | _filter_imgfmt
139*d9f008e6SMax Reitz
140*d9f008e6SMax Reitz    # Should fail
141*d9f008e6SMax Reitz    sudo -n -u nobody cat fuse-export >/dev/null
142*d9f008e6SMax Reitz    # Should work with allow_other
143*d9f008e6SMax Reitz    sudo -n -u nobody \
144*d9f008e6SMax Reitz        stat -c 'Permissions seen by nobody: %a' fuse-export 2>&1 \
145*d9f008e6SMax Reitz        | _filter_imgfmt
146*d9f008e6SMax Reitz
147*d9f008e6SMax Reitz    popd >/dev/null
148*d9f008e6SMax Reitz
149*d9f008e6SMax Reitz    _send_qemu_cmd $QEMU_HANDLE \
150*d9f008e6SMax Reitz        "{'execute': 'quit'}" \
151*d9f008e6SMax Reitz        'return'
152*d9f008e6SMax Reitz
153*d9f008e6SMax Reitz    wait=yes _cleanup_qemu
154*d9f008e6SMax Reitz}
155*d9f008e6SMax Reitz
156*d9f008e6SMax Reitz# 'auto' should behave exactly like 'on', because 'on' tests that
157*d9f008e6SMax Reitz# allow_other works (otherwise, this test is skipped)
158*d9f008e6SMax Reitzfor ao in off on auto; do
159*d9f008e6SMax Reitz    echo
160*d9f008e6SMax Reitz    echo "--- allow-other=$ao ---"
161*d9f008e6SMax Reitz
162*d9f008e6SMax Reitz    run_permission_test "$ao"
163*d9f008e6SMax Reitzdone
164*d9f008e6SMax Reitz
165*d9f008e6SMax Reitz# success, all done
166*d9f008e6SMax Reitzecho "*** done"
167*d9f008e6SMax Reitzrm -f $seq.full
168*d9f008e6SMax Reitzstatus=0
169