Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / tests / sanity-sec.sh
1 #!/bin/bash
2 #
3 # Run select tests by setting SEC_ONLY, or as arguments to the script.
4 # Skip specific tests by setting SEC_EXCEPT.
5 #
6
7 set -e
8
9 SRCDIR=`dirname $0`
10 export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/../utils:$PATH:/sbin
11
12 SEC_ONLY=${SEC_ONLY:-"$*"}
13 [ "$SEC_EXCEPT" ] && echo "Skipping tests: `echo $SEC_EXCEPT`"
14
15 TMP=${TMP:-/tmp}
16 LFS=${LFS:-lfs}
17 LCTL=${LCTL:-lctl}
18 RUNAS=${RUNAS:-runas}
19 WTL=${WTL:-write_time_limit}
20
21 LPROC=/proc/fs/lustre
22 ENABLE_IDENTITY=/usr/sbin/l_getidentity
23 DISABLE_IDENTITY=NONE
24 LUSTRE_CONF_DIR=/etc/lustre
25 PERM_CONF=$LUSTRE_CONF_DIR/perm.conf
26 LDLM_LPROC=$LPROC/ldlm
27 LLITE_LPROC=$LPROC/llite
28 MDC_LPROC=$LPROC/mdc
29 MDT_LPROC=$LPROC/mdt
30 OST_LPROC=$LPROC/obdfilter
31
32 sec_log() {
33         echo "$*"
34         $LCTL mark "$*" 2> /dev/null || true
35 }
36
37 SANITYSECLOG=${SANITYSECLOG:-/tmp/sanity-sec.log}
38 [ "$SANITYSECLOG" ] && rm -f $SANITYSECLOG || true
39
40 sec_error() { 
41         sec_log "FAIL: $TESTNAME $@"
42         if [ "$SANITYSECLOG" ]; then
43                 echo "FAIL: $TESTNAME $@" >> $SANITYSECLOG
44         else
45                 exit 1
46         fi
47 }
48
49 sec_pass() { 
50         echo PASS $@
51 }
52
53 sec_skip () {
54         sec_log "$0: SKIP: $TESTNAME $@"
55         [ "$SANITYSECLOG" ] && echo "$0: SKIP: $TESTNAME $@" >> $SANITYSECLOG
56 }
57
58 ID1=500
59 ID2=501
60
61 USER1=`cat /etc/passwd|grep :$ID1:$ID1:|cut -d: -f1`
62 USER2=`cat /etc/passwd|grep :$ID2:$ID2:|cut -d: -f1`
63
64 if [ -z "$USER1" ]; then
65         echo "===== Please add user1 (uid=$ID1 gid=$ID1)! Skip sanity-sec ====="
66         sec_error "===== Please add user1 (uid=$ID1 gid=$ID1)! ====="
67         exit 0
68 fi
69
70 if [ -z "$USER2" ]; then
71         echo "===== Please add user2 (uid=$ID2 gid=$ID2)! Skip sanity-sec ====="
72         sec_error "===== Please add user2 (uid=$ID2 gid=$ID2)! ====="
73         exit 0
74 fi
75
76 export NAME=${NAME:-local}
77
78 LUSTRE=${LUSTRE:-`dirname $0`/..} 
79 . $LUSTRE/tests/test-framework.sh
80 init_test_env $@
81 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
82
83 mounted_lustre_filesystems() {
84         awk '($3 ~ "lustre" && $1 ~ ":") { print $2 }' /proc/mounts
85 }
86
87 MOUNTED="`mounted_lustre_filesystems`"
88 if [ -z "$MOUNTED" ]; then
89         formatall
90         setupall
91         MOUNTED="`mounted_lustre_filesystems`"
92         [ -z "$MOUNTED" ] && sec_error "NAME=$NAME not mounted"
93         S_MOUNTED=yes
94 fi
95
96 [ `echo $MOUNT | wc -w` -gt 1 ] && sec_error "NAME=$NAME mounted more than once"
97
98 DIR=${DIR:-$MOUNT}
99 [ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && \
100         sec_cleanup && exit 99
101
102 [ `ls -l $LDLM_LPROC/namespaces 2>/dev/null | grep *-mdc-* | wc -l` -gt 1 ] \
103         && echo "skip multi-MDS test" && sec_cleanup && exit 0
104
105 OST_COUNT=$(ls -l $LDLM_LPROC/namespaces 2>/dev/null | grep osc | grep -v MDT | wc -l)
106
107 # for GSS_SUP
108 GSS_REF=$(lsmod | grep ^ptlrpc_gss | awk '{print $3}')
109 if [ ! -z "$GSS_REF" -a "$GSS_REF" != "0" ]; then
110         GSS_SUP=1
111         echo "with GSS support"
112 else
113         GSS_SUP=0
114         echo "without GSS support"
115 fi
116
117 # for MDT_TYPE
118 MDT_REF=$(lsmod | grep ^mdt | awk '{print $3}')
119 if [ ! -z "$MDT_REF" -a "$MDT_REF" != "0" ]; then
120         MDT_TYPE="local"
121         echo "local mdt"
122 else
123         MDT_TYPE="remote"
124         echo "remote mdt"
125 fi
126
127 MDT="`do_facet $SINGLEMDS ls -l $MDT_LPROC/ | grep MDT | awk '{print $9}'`"
128 if [ ! -z "$MDT" ]; then
129         IDENTITY_UPCALL=$MDT_LPROC/$MDT/identity_upcall
130         IDENTITY_UPCALL_BAK="`more $IDENTITY_UPCALL`"
131         IDENTITY_FLUSH=$MDT_LPROC/$MDT/identity_flush
132         ROOTSQUASH_UID=$MDT_LPROC/$MDT/rootsquash_uid
133         ROOTSQUASH_GID=$MDT_LPROC/$MDT/rootsquash_gid
134         NOSQUASH_NIDS=$MDT_LPROC/$MDT/nosquash_nids
135         MDSCAPA=$MDT_LPROC/$MDT/capa
136         CAPA_TIMEOUT=$MDT_LPROC/$MDT/capa_timeout
137 fi
138
139 # for CLIENT_TYPE
140 if [ -z "$(grep remote $LLITE_LPROC/*/client_type 2>/dev/null)" ]; then
141         CLIENT_TYPE="local"
142         echo "local client"
143 else
144         CLIENT_TYPE="remote"
145         echo "remote client"
146 fi
147
148 SAVE_PWD=$PWD
149
150 sec_run_one() {
151         BEFORE=`date +%s`
152         sec_log "== test $1 $2= `date +%H:%M:%S` ($BEFORE)"
153         export TESTNAME=test_$1
154         test_$1 || sec_error "exit with rc=$?"
155         unset TESTNAME
156         sec_pass "($((`date +%s` - $BEFORE))s)"
157 }
158
159 build_test_filter() {
160         for O in $SEC_ONLY; do
161             eval SEC_ONLY_${O}=true
162         done
163         for E in $SEC_EXCEPT; do
164             eval SEC_EXCEPT_${E}=true
165         done
166 }
167
168 _basetest() {
169         echo $*
170 }
171
172 basetest() {
173         IFS=abcdefghijklmnopqrstuvwxyz _basetest $1
174 }
175
176 sec_run_test() {
177          base=`basetest $1`
178          if [ "$SEC_ONLY" ]; then
179                  testname=SEC_ONLY_$1
180                  if [ ${!testname}x != x ]; then
181                         sec_run_one $1 "$2"
182                         return $?
183                  fi
184                  testname=SEC_ONLY_$base
185                  if [ ${!testname}x != x ]; then
186                          sec_run_one $1 "$2"
187                          return $?
188                  fi
189                  echo -n "."
190                  return 0
191         fi
192         testname=SEC_EXCEPT_$1
193         if [ ${!testname}x != x ]; then
194                  echo "skipping excluded test $1"
195                  return 0
196         fi
197         testname=SEC_EXCEPT_$base
198         if [ ${!testname}x != x ]; then
199                  echo "skipping excluded test $1 (base $base)"
200                  return 0
201         fi
202         sec_run_one $1 "$2"
203         return $?
204 }
205
206 build_test_filter
207
208 sec_login() {
209         local user=$1
210         local group=$2
211
212         if ! $RUNAS -u $user krb5_login.sh; then
213                 echo "$user login kerberos failed."
214                 exit 1
215         fi
216
217         if ! $RUNAS -u $user -g $group ls $DIR > /dev/null; then
218                 $RUNAS -u $user lfs flushctx -k
219                 $RUNAS -u $user krb5_login.sh
220                 if ! $RUNAS -u $user -g $group ls $DIR > /dev/null; then
221                         echo "init $user $group failed."
222                         exit 2
223                 fi
224         fi
225 }
226
227 setup() {
228         if [ ! -z "$MDT" ]; then
229                 do_facet $SINGLEMDS echo $ENABLE_IDENTITY > $IDENTITY_UPCALL
230                 do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
231         fi
232
233         if ! $RUNAS -u $ID1 ls $DIR > /dev/null 2>&1; then
234                 sec_login $USER1 $USER1
235         fi
236
237         if ! $RUNAS -u $ID2 ls $DIR > /dev/null 2>&1; then
238                 sec_login $USER2 $USER2
239         fi
240 }
241 setup
242
243 # run as different user
244 test_0() {
245         rm -rf $DIR/d0
246         mkdir $DIR/d0
247
248         chown $USER1 $DIR/d0 || sec_error
249         $RUNAS -u $ID1 ls $DIR || sec_error
250         $RUNAS -u $ID1 touch $DIR/f0 && sec_error
251         $RUNAS -u $ID1 touch $DIR/d0/f1 || sec_error
252         $RUNAS -u $ID2 touch $DIR/d0/f2 && sec_error
253         touch $DIR/d0/f3 || sec_error
254         chown root $DIR/d0
255         chgrp $USER1 $DIR/d0
256         chmod 775 $DIR/d0
257         $RUNAS -u $ID1 touch $DIR/d0/f4 || sec_error
258         $RUNAS -u $ID2 touch $DIR/d0/f5 && sec_error
259         touch $DIR/d0/f6 || sec_error
260
261         rm -rf $DIR/d0
262 }
263 sec_run_test 0 "uid permission ============================="
264
265 # setuid/gid
266 test_1() {
267         [ $GSS_SUP = 0 ] && sec_skip "without GSS support." && return
268         [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
269
270         do_facet $SINGLEMDS rm -f $PERM_CONF
271         do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
272
273         rm -rf $DIR/d1
274         mkdir $DIR/d1
275
276         chown $USER1 $DIR/d1 || sec_error
277         $RUNAS -u $ID2 -v $ID1 touch $DIR/d1/f0 && sec_error
278         do_facet $SINGLEMDS echo "\* $ID2 setuid" > $PERM_CONF
279         echo "enable uid $ID2 setuid"
280         do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
281         $RUNAS -u $ID2 -v $ID1 touch $DIR/d1/f1 || sec_error
282
283         chown root $DIR/d1
284         chgrp $USER1 $DIR/d1
285         chmod 770 $DIR/d1
286         $RUNAS -u $ID2 -g $ID2 touch $DIR/d1/f2 && sec_error
287         $RUNAS -u $ID2 -g $ID2 -j $ID1 touch $DIR/d1/f3 && sec_error
288         do_facet $SINGLEMDS echo "\* $ID2 setuid,setgid" > $PERM_CONF
289         echo "enable uid $ID2 setuid,setgid"
290         do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
291         $RUNAS -u $ID2 -g $ID2 -j $ID1 touch $DIR/d1/f4 || sec_error
292         $RUNAS -u $ID2 -v $ID1 -g $ID2 -j $ID1 touch $DIR/d1/f5 || sec_error
293
294         rm -rf $DIR/d1
295
296         do_facet $SINGLEMDS rm -f $PERM_CONF
297         do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
298 }
299 sec_run_test 1 "setuid/gid ============================="
300
301 # remote_acl
302 # for remote client only
303 test_2 () {
304         [ "$CLIENT_TYPE" = "local" ] && \
305                 sec_skip "remote_acl for remote client only" && return
306         [ -z "$(grep ^acl $MDC_LPROC/*-mdc-*/connect_flags)" ] && \
307                 sec_skip "must have acl enabled" && return
308         [ -z "$(which setfacl 2>/dev/null)" ] && \
309                 sec_skip "could not find setfacl" && return
310         [ "$UID" != 0 ] && sec_skip "must run as root" && return
311
312         rm -rf $DIR/d2
313         mkdir $DIR/d2
314         chmod 755 $DIR/d2
315         echo xxx > $DIR/d2/f0
316         chmod 644 $DIR/d2/f0
317
318         $LFS getfacl $DIR/d2/f0 || sec_error
319         $RUNAS -u $ID1 cat $DIR/d2/f0 || sec_error
320         $RUNAS -u $ID1 touch $DIR/d2/f0 && sec_error
321
322         $LFS setfacl -m u:$USER1:w $DIR/d2/f0 || sec_error
323         $LFS getfacl $DIR/d2/f0 || sec_error
324         echo "set user $USER1 write permission on file $DIR/d2/f0"
325         $RUNAS -u $ID1 touch $DIR/d2/f0 || sec_error
326         $RUNAS -u $ID1 cat $DIR/d2/f0 && sec_error
327
328         rm -rf $DIR/d2
329 }
330 sec_run_test 2 "rmtacl ============================="
331
332 # rootsquash
333 # for remote mdt only
334 test_3() {
335         [ $GSS_SUP = 0 ] && sec_skip "without GSS support." && return
336         [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
337         [ "$MDT_TYPE" = "local" ] && sec_skip "rootsquash for remote mdt only" && return
338
339         do_facet $SINGLEMDS echo "-\*" > $NOSQUASH_NIDS 
340         do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID
341         do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_GID
342
343         rm -rf $DIR/d3
344         mkdir $DIR/d3
345         chown $USER1 $DIR/d3
346         chmod 700 $DIR/d3
347         do_facet $SINGLEMDS echo $ID1 > $ROOTSQUASH_UID
348         echo "set rootsquash uid = $ID1"
349         touch $DIR/f3_0 && sec_error
350         touch $DIR/d3/f3_1 || sec_error
351
352         do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID
353         echo "disable rootsquash"
354         chown root $DIR/d3
355         chgrp $USER2 $DIR/d3
356         chmod 770 $DIR/d3
357
358         do_facet $SINGLEMDS echo $ID1 > $ROOTSQUASH_UID
359         echo "set rootsquash uid = $ID1"
360         touch $DIR/d3/f3_2 && sec_error
361         do_facet $SINGLEMDS echo $ID2 > $ROOTSQUASH_GID
362         echo "set rootsquash gid = $ID2"
363         touch $DIR/d3/f3_3 || sec_error
364
365         do_facet $SINGLEMDS echo "+\*" > $NOSQUASH_NIDS
366         echo "add host in rootsquash skip list"
367         touch $DIR/f3_4 || sec_error
368
369         do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_UID
370         do_facet $SINGLEMDS echo 0 > $ROOTSQUASH_GID
371         do_facet $SINGLEMDS echo "-\*" > $NOSQUASH_NIDS
372         rm -rf $DIR/d3
373         rm -f $DIR/f3_?
374 }
375 sec_run_test 3 "rootsquash ============================="
376
377 # bug 3285 - supplementary group should always succeed.
378 # NB: the supplementary groups are set for local client only,
379 # as for remote client, the groups of the specified uid on MDT
380 # will be obtained by upcall /sbin/l_getidentity and used.
381 test_4() {
382         rm -rf $DIR/d4
383         mkdir $DIR/d4
384         chmod 771 $DIR/d4
385         chgrp $ID1 $DIR/d4
386         $RUNAS -u $ID1 ls $DIR/d4 || sec_error "setgroups(1) failed"
387         if [ "$CLIENT_TYPE" != "remote" ]; then
388                 if [ ! -z "$MDT" ]; then
389                         do_facet $SINGLEMDS echo "\* $ID2 setgrp" > $PERM_CONF
390                         do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
391                 fi
392                 $RUNAS -u $ID2 -G1,2,$ID1 ls $DIR/d4 || sec_error "setgroups(2) failed"
393                 if [ ! -z "$MDT" ]; then
394                         do_facet $SINGLEMDS rm -f $PERM_CONF
395                         do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
396                 fi
397         fi
398         $RUNAS -u $ID2 -G1,2 ls $DIR/d4 && sec_error "setgroups(3) failed"
399         rm -rf $DIR/d4
400 }
401 sec_run_test 4 "set supplementary group ==============="
402
403 mds_capability_timeout() {
404         [ $# -lt 1 ] && echo "Miss mds capability timeout value" && return 1
405
406         echo "Set mds capability timeout as $1 seconds"
407         do_facet $SINGLEMDS echo $1 > $CAPA_TIMEOUT
408         return 0
409 }
410
411 mds_capability_switch() {
412         [ $# -lt 1 ] && echo "Miss mds capability switch value" && return 1
413
414         case $1 in
415                 0) echo "Turn off mds capability";;
416                 3) echo "Turn on mds capability";;
417                 *) echo "Invalid mds capability switch value" && return 2;;
418         esac
419
420         do_facet $SINGLEMDS echo $1 > $MDSCAPA
421         return 0
422 }
423
424 oss_capability_switch() {
425         [ $# -lt 1 ] && echo "Miss oss capability switch value" && return 1
426
427         case $1 in
428                 0) echo "Turn off oss capability";;
429                 1) echo "Turn on oss capability";;
430                 *) echo "Invalid oss capability switch value" && return 2;;
431         esac
432
433         i=0;
434         while [ $i -lt $OST_COUNT ]; do
435                 j=$i;
436                 i=`expr $i + 1`
437                 OST="`do_facet ost$i ls -l $OST_LPROC/ | grep OST | awk '{print $9}' | grep $j$`"
438                 do_facet ost$i echo $1 > $OST_LPROC/$OST/capa
439         done
440         return 0
441 }
442
443 turn_capability_on() {
444         local capa_timeout=${1:-"1800"}
445
446         # To turn on fid capability for the system,
447         # there is a requirement that fid capability
448         # is turned on on all MDS/OSS servers before
449         # client mount.
450
451         umount $MOUNT || return 1
452
453         mds_capability_switch 3 || return 2
454         oss_capability_switch 1 || return 3
455         mds_capability_timeout $capa_timeout || return 4
456
457         mount_client $MOUNT || return 5
458         return 0
459 }
460
461 turn_capability_off() {
462         # to turn off fid capability, you can just do
463         # it in a live system. But, please turn off
464         # capability of all OSS servers before MDS servers.
465
466         oss_capability_switch 0 || return 1
467         mds_capability_switch 0 || return 2
468         return 0
469 }
470
471 # We demonstrate that access to the objects in the filesystem are not
472 # accessible without supplying secrets from the MDS by disabling a
473 # proc variable on the mds so that it does not supply secrets. We then
474 # try and access objects which result in failure.
475 test_5() {
476         local file=$DIR/f5
477
478         [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
479         turn_capability_off
480         rm -f $file
481
482         # Disable proc variable
483         mds_capability_switch 0 || return 1
484         oss_capability_switch 1 || return 2
485
486         # proc variable disabled -- access to the objects in the filesystem
487         # is not allowed 
488         echo "Should get Write error here : (proc variable are disabled "\
489              "-- access to the objects in the filesystem is denied."
490         $WTL $file 30
491         if [ $? == 0 ]; then
492                 echo "Write worked well even though secrets not supplied."
493                 return 3
494         fi
495
496         turn_capability_on || return 4
497         sleep 5
498
499         # proc variable enabled, secrets supplied -- write should work now
500         echo "Should not fail here : (proc variable enabled, secrets supplied "\
501              "-- write should work now)."
502         $WTL $file 30
503         if [ $? != 0 ]; then
504                 echo "Write failed even though secrets supplied."
505                 return 5
506         fi
507
508         turn_capability_off
509         rm -f $file
510 }
511 sec_run_test 5 "capa secrets ========================="
512
513 # Expiry: A test program is performing I/O on a file. It has credential
514 # with an expiry half a minute later. While the program is running the
515 # credentials expire and no automatic extensions or renewals are
516 # enabled. The program will demonstrate an I/O failure.
517 test_6() {
518         local file=$DIR/f6
519
520         [ -z "$MDT" ] && sec_skip "do not support do_facet operations." && return
521         turn_capability_off
522         rm -f $file
523
524         turn_capability_on 30 || return 1
525         # Token expiry
526         $WTL $file 60 || return 2
527
528         # Reset MDS capability timeout
529         mds_capability_timeout 30 || exit 3
530         $WTL $file 60 &
531         local PID=$!
532         sleep 5
533
534         # To disable automatic renew, only need turn capa off on MDS.
535         mds_capability_switch 0 || return 4
536
537         echo "We expect I/O failure."
538         wait $PID
539         if [ $? == 0 ]; then
540                 echo "no I/O failure got."
541                 return 5
542         fi
543
544         turn_capability_off
545         rm -f $file
546 }
547 sec_run_test 6 "capa expiry ========================="
548
549 log "cleanup: ======================================================"
550
551 unsetup() {
552         if [ ! -z "$MDT"  ]; then
553                 do_facet $SINGLEMDS echo $IDENTITY_UPCALL_BAK > $IDENTITY_UPCALL
554                 do_facet $SINGLEMDS echo -1 > $IDENTITY_FLUSH
555         fi
556
557         $RUNAS -u $ID1 ls $DIR
558         $RUNAS -u $ID2 ls $DIR
559 }
560 unsetup
561
562 sec_cleanup() {
563         if [ "$S_MOUNTED" = "yes" ]; then
564                 cleanupall -f || sec_error "cleanup failed"
565         fi
566 }
567 sec_cleanup
568
569 echo '=========================== finished ==============================='
570 [ -f "$SANITYSECLOG" ] && \
571         cat $SANITYSECLOG && grep -q FAIL $SANITYSECLOG && exit 1 || true
572 echo "$0 completed"