1#- 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2021, 2023 The FreeBSD Foundation 5# 6# This software was developed by Mark Johnston under sponsorship from 7# the FreeBSD Foundation. 8# 9# This software was developed by Jake Freeland under sponsorship from 10# the FreeBSD Foundation. 11# 12 13# Tests to-do: 14# actions: hostname, users 15 16readonly SYSLOGD_UDP_PORT="5140" 17readonly SYSLOGD_CONFIG="${PWD}/syslog.conf" 18readonly SYSLOGD_LOCAL_SOCKET="${PWD}/log.sock" 19readonly SYSLOGD_PIDFILE="${PWD}/syslogd.pid" 20readonly SYSLOGD_LOCAL_PRIVSOCKET="${PWD}/logpriv.sock" 21 22# Start a private syslogd instance. 23syslogd_start() 24{ 25 local jail 26 27 if [ "$1" = "-j" ]; then 28 jail="jexec $2" 29 shift 2 30 fi 31 $jail syslogd \ 32 -b ":${SYSLOGD_UDP_PORT}" \ 33 -C \ 34 -d \ 35 -f "${SYSLOGD_CONFIG}" \ 36 -H \ 37 -p "${SYSLOGD_LOCAL_SOCKET}" \ 38 -P "${SYSLOGD_PIDFILE}" \ 39 -S "${SYSLOGD_LOCAL_PRIVSOCKET}" \ 40 $@ \ 41 & 42 43 # Give syslogd a bit of time to spin up. 44 while [ "$((i+=1))" -le 20 ]; do 45 [ -S "${SYSLOGD_LOCAL_SOCKET}" ] && return 46 sleep 0.1 47 done 48 atf_fail "timed out waiting for syslogd to start" 49} 50 51# Simple logger(1) wrapper. 52syslogd_log() 53{ 54 atf_check -s exit:0 -o empty -e empty logger $* 55} 56 57# Make syslogd reload its configuration file. 58syslogd_reload() 59{ 60 pkill -HUP -F "${SYSLOGD_PIDFILE}" 61} 62 63# Stop a private syslogd instance. 64syslogd_stop() 65{ 66 pid=$(cat "${SYSLOGD_PIDFILE}") 67 if pkill -F "${SYSLOGD_PIDFILE}"; then 68 wait "${pid}" 69 rm -f "${SYSLOGD_PIDFILE}" "${SYSLOGD_LOCAL_SOCKET}" \ 70 "${SYSLOGD_LOCAL_PRIVSOCKET}" 71 fi 72} 73 74atf_test_case "basic" "cleanup" 75basic_head() 76{ 77 atf_set descr "Messages are logged via supported transports" 78} 79basic_body() 80{ 81 logfile="${PWD}/basic.log" 82 printf "user.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 83 syslogd_start 84 85 syslogd_log -p user.debug -t basic -h "${SYSLOGD_LOCAL_SOCKET}" \ 86 "hello, world (unix)" 87 atf_check -s exit:0 -o match:"basic: hello, world \(unix\)" \ 88 tail -n 1 "${logfile}" 89 90 # Grab kernel configuration file. 91 sysctl kern.conftxt > conf.txt 92 93 # We have INET transport; make sure we can use it. 94 if grep -qw "INET" conf.txt; then 95 syslogd_log -4 -p user.debug -t basic -h 127.0.0.1 -P "${SYSLOGD_UDP_PORT}" \ 96 "hello, world (v4)" 97 atf_check -s exit:0 -o match:"basic: hello, world \(v4\)" \ 98 tail -n 1 "${logfile}" 99 fi 100 # We have INET6 transport; make sure we can use it. 101 if grep -qw "INET6" conf.txt; then 102 syslogd_log -6 -p user.debug -t basic -h ::1 -P "${SYSLOGD_UDP_PORT}" \ 103 "hello, world (v6)" 104 atf_check -s exit:0 -o match:"basic: hello, world \(v6\)" \ 105 tail -n 1 "${logfile}" 106 fi 107} 108basic_cleanup() 109{ 110 syslogd_stop 111} 112 113atf_test_case "reload" "cleanup" 114reload_head() 115{ 116 atf_set descr "SIGHUP correctly refreshes configuration" 117} 118reload_body() 119{ 120 logfile="${PWD}/reload.log" 121 printf "user.debug\t/${logfile}\n" > "${SYSLOGD_CONFIG}" 122 syslogd_start 123 124 syslogd_log -p user.debug -t reload -h "${SYSLOGD_LOCAL_SOCKET}" \ 125 "pre-reload" 126 atf_check -s exit:0 -o match:"reload: pre-reload" tail -n 1 "${logfile}" 127 128 # Override the old rule. 129 truncate -s 0 "${logfile}" 130 printf "news.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 131 syslogd_reload 132 133 syslogd_log -p user.debug -t reload -h "${SYSLOGD_LOCAL_SOCKET}" \ 134 "post-reload user" 135 syslogd_log -p news.debug -t reload -h "${SYSLOGD_LOCAL_SOCKET}" \ 136 "post-reload news" 137 atf_check -s exit:0 -o not-match:"reload: post-reload user" cat ${logfile} 138 atf_check -s exit:0 -o match:"reload: post-reload news" cat ${logfile} 139} 140reload_cleanup() 141{ 142 syslogd_stop 143} 144 145atf_test_case "prog_filter" "cleanup" 146prog_filter_head() 147{ 148 atf_set descr "Messages are only received from programs in the filter" 149} 150prog_filter_body() 151{ 152 logfile="${PWD}/prog_filter.log" 153 printf "!prog1,prog2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 154 syslogd_start 155 156 for i in 1 2 3; do 157 syslogd_log -p user.debug -t "prog${i}" -h "${SYSLOGD_LOCAL_SOCKET}" \ 158 "hello this is prog${i}" 159 done 160 atf_check -s exit:0 -o match:"prog1: hello this is prog1" cat "${logfile}" 161 atf_check -s exit:0 -o match:"prog2: hello this is prog2" cat "${logfile}" 162 atf_check -s exit:0 -o not-match:"prog3: hello this is prog3" cat "${logfile}" 163 164 # Override the old rule. 165 truncate -s 0 ${logfile} 166 printf "!-prog1,prog2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 167 syslogd_reload 168 169 for i in 1 2 3; do 170 syslogd_log -p user.debug -t "prog${i}" -h "${SYSLOGD_LOCAL_SOCKET}" \ 171 "hello this is prog${i}" 172 done 173 atf_check -s exit:0 -o not-match:"prog1: hello this is prog1" cat "${logfile}" 174 atf_check -s exit:0 -o not-match:"prog2: hello this is prog2" cat "${logfile}" 175 atf_check -s exit:0 -o match:"prog3: hello this is prog3" cat "${logfile}" 176} 177prog_filter_cleanup() 178{ 179 syslogd_stop 180} 181 182atf_test_case "host_filter" "cleanup" 183host_filter_head() 184{ 185 atf_set descr "Messages are only received from hostnames in the filter" 186} 187host_filter_body() 188{ 189 logfile="${PWD}/host_filter.log" 190 printf "+host1,host2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 191 syslogd_start 192 193 for i in 1 2 3; do 194 syslogd_log -p user.debug -t "host${i}" -H "host${i}" \ 195 -h "${SYSLOGD_LOCAL_SOCKET}" "hello this is host${i}" 196 done 197 atf_check -s exit:0 -o match:"host1: hello this is host1" cat "${logfile}" 198 atf_check -s exit:0 -o match:"host2: hello this is host2" cat "${logfile}" 199 atf_check -s exit:0 -o not-match:"host3: hello this is host3" cat "${logfile}" 200 201 # Override the old rule. 202 truncate -s 0 ${logfile} 203 printf "\-host1,host2\nuser.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 204 syslogd_reload 205 206 for i in 1 2 3; do 207 syslogd_log -p user.debug -t "host${i}" -H "host${i}" \ 208 -h "${SYSLOGD_LOCAL_SOCKET}" "hello this is host${i}" 209 done 210 atf_check -s exit:0 -o not-match:"host1: hello this is host1" cat "${logfile}" 211 atf_check -s exit:0 -o not-match:"host2: hello this is host2" cat "${logfile}" 212 atf_check -s exit:0 -o match:"host3: hello this is host3" cat "${logfile}" 213} 214host_filter_cleanup() 215{ 216 syslogd_stop 217} 218 219atf_test_case "prop_filter" "cleanup" 220prop_filter_head() 221{ 222 atf_set descr "Messages are received based on conditions in the propery based filter" 223} 224prop_filter_body() 225{ 226 logfile="${PWD}/prop_filter.log" 227 printf ":msg,contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \ 228 > "${SYSLOGD_CONFIG}" 229 syslogd_start 230 231 syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD" 232 syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd" 233 atf_check -s exit:0 -o match:"prop1: FreeBSD" cat "${logfile}" 234 atf_check -s exit:0 -o not-match:"prop2: freebsd" cat "${logfile}" 235 236 truncate -s 0 ${logfile} 237 printf ":msg,!contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \ 238 > "${SYSLOGD_CONFIG}" 239 syslogd_reload 240 241 syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD" 242 syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd" 243 atf_check -s exit:0 -o not-match:"prop1: FreeBSD" cat "${logfile}" 244 atf_check -s exit:0 -o match:"prop2: freebsd" cat "${logfile}" 245 246 truncate -s 0 ${logfile} 247 printf ":msg,icase_contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \ 248 > "${SYSLOGD_CONFIG}" 249 syslogd_reload 250 251 syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD" 252 syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd" 253 atf_check -s exit:0 -o match:"prop1: FreeBSD" cat "${logfile}" 254 atf_check -s exit:0 -o match:"prop2: freebsd" cat "${logfile}" 255 256 truncate -s 0 ${logfile} 257 printf ":msg,!icase_contains,\"FreeBSD\"\nuser.debug\t${logfile}\n" \ 258 > "${SYSLOGD_CONFIG}" 259 syslogd_reload 260 261 syslogd_log -p user.debug -t "prop1" -h "${SYSLOGD_LOCAL_SOCKET}" "FreeBSD" 262 syslogd_log -p user.debug -t "prop2" -h "${SYSLOGD_LOCAL_SOCKET}" "freebsd" 263 syslogd_log -p user.debug -t "prop3" -h "${SYSLOGD_LOCAL_SOCKET}" "Solaris" 264 atf_check -s exit:0 -o not-match:"prop1: FreeBSD" cat "${logfile}" 265 atf_check -s exit:0 -o not-match:"prop2: freebsd" cat "${logfile}" 266 atf_check -s exit:0 -o match:"prop3: Solaris" cat "${logfile}" 267} 268prop_filter_cleanup() 269{ 270 syslogd_stop 271} 272 273atf_test_case "pipe_action" "cleanup" 274pipe_action_head() 275{ 276 atf_set descr "The pipe action evaluates provided command in sh(1)" 277} 278pipe_action_body() 279{ 280 logfile="${PWD}/pipe_action.log" 281 printf "\"While I'm digging in the tunnel, the elves will often come to me \ 282 with solutions to my problem.\"\n-Saymore Crey" > ${logfile} 283 284 printf "!pipe\nuser.debug\t| sed -i '' -e 's/Saymore Crey/Seymour Cray/g' \ 285 ${logfile}\n" > "${SYSLOGD_CONFIG}" 286 syslogd_start 287 288 syslogd_log -p user.debug -t "pipe" -h "${SYSLOGD_LOCAL_SOCKET}" \ 289 "fix spelling error" 290 atf_check -s exit:0 -o match:"Seymour Cray" cat "${logfile}" 291} 292pipe_action_cleanup() 293{ 294 syslogd_stop 295} 296 297atf_test_case "jail_noinet" "cleanup" 298jail_noinet_head() 299{ 300 atf_set descr "syslogd -ss can be run in a jail without INET support" 301 atf_set require.user root 302} 303jail_noinet_body() 304{ 305 local logfile 306 307 atf_check jail -c name=syslogd_noinet persist 308 309 logfile="${PWD}/jail_noinet.log" 310 printf "user.debug\t${logfile}\n" > "${SYSLOGD_CONFIG}" 311 syslogd_start -j syslogd_noinet -ss 312 313 syslogd_log -p user.debug -t "test" -h "${SYSLOGD_LOCAL_SOCKET}" \ 314 "hello, world" 315 atf_check -s exit:0 -o match:"test: hello, world" cat "${logfile}" 316} 317jail_noinet_cleanup() 318{ 319 jail -r syslogd_noinet 320} 321 322atf_init_test_cases() 323{ 324 atf_add_test_case "basic" 325 atf_add_test_case "reload" 326 atf_add_test_case "prog_filter" 327 atf_add_test_case "host_filter" 328 atf_add_test_case "prop_filter" 329 atf_add_test_case "pipe_action" 330 atf_add_test_case "jail_noinet" 331} 332