1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
# Copyright (c) 2017 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Johnny C. Lam.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# NAME
# usergroup_exists.subr -- check for the existence of users and groups
#
# SYNOPSIS
# task_group_exists <group> [<groupid>]
# task_user_exists <user> [<userid>]
#
# DESCRIPTION
# The task_group_exists function checks that a group exists on the
# system, and also matches the group ID if it is given.
#
# The task_user_exists function checks that a user exists on the
# system, and also matches the user ID if it is given.
#
# NOTES
# These functions test for the presence of groups and users in a
# portable manner by using chgrp(1) and chown(1) to change the
# ownership of a temporary file and checking the return values.
#
# RETURN VALUES
# The task_group_exists function has the following return values:
#
# 0 if <group> exists, and has gid <groupid> if given
# 1 if neither <group> nor <groupid> exist
# 2 if <group> or <groupid> exist but don't match
# 3 if an error occurs
#
# The task_user_exists function has the following return values:
#
# 0 if <user> exists, and has uid <userid> if given
# 1 if neither <user> nor <userid> exist
# 2 if <user> or <userid> exist but don't match
# 3 if an error occurs
#
# ENVIRONMENT
# The following variables are used if they are set:
#
# CHOWN The name or path to the chown(8) utility.
#
# LS The name or path to the ls(1) utility.
#
# RM The name or path to the rm(1) utility.
#
__task_usergroup_exists__="yes"
__task_usergroup_exists_init__="_usergroup_exists_init"
task_load cleanup
task_load createfile
task_load echo
task_load maketemp
task_group_exists()
{
: ${CHOWN:=chown}
: ${LS:=ls}
local group="$1"; shift
local groupid="$1"; [ $# -eq 0 ] || shift
[ -n "$group" ] || return 3
# Check using chown(1) to work properly in an NSS/NIS environment.
__group_tmpdir__=$( task_maketemp -dq -t "pkgtasks.group_exists" ) || return 3
local testpath="$__group_tmpdir__/group_exists"
task_createfile "$testpath"
local result=0
#
# Redirect standarrd error below because failing to chgrp(2) is
# part of the test and not actually an error.
#
if ${CHOWN} ":$group" "$testpath" >/dev/null 2>&1; then
# group exists
if [ -n "$groupid" ]; then
${LS} -dln "$testpath" 2>/dev/null |
( read __ __ __ gid __; [ "$groupid" = "$gid" ] )
if [ $? -gt 0 ]; then
# group exists but doesn't match groupid
result=2
else
# group exists and groupid exists and match
result=0
fi
else
# group exists and groupid is not set
result=0
fi
elif [ -z "$groupid" ]; then
# group doesn't exist and groupid is not set
result=1
elif ${CHOWN} ":$groupid" "$testpath" >/dev/null 2>&1; then
# group doesn't exist
${LS} -dl "$testpath" 2>/dev/null |
( read __ __ __ name __
#
# If the ls(1) output shows a group name instead of the
# raw GID, then the GID must exist and map to a valid
# group name on the system.
#
[ "$groupid" != "$name" ] )
if [ $? -gt 0 ]; then
# group doesn't exist, groupid doesn't exist
result=1
else
# group doesn't exist, groupid exists
result=2
fi
else
# group doesn't exist and groupid doesn't exist
result=1
fi
_task_group_exists_cleanup
return $result
}
task_user_exists()
{
: ${CHOWN:=chown}
: ${LS:=ls}
local user="$1"; shift
local userid="$1"; [ $# -eq 0 ] || shift
[ -n "$user" ] || return 3
# Check using chown(1) to work properly in an NSS/NIS environment.
__user_tmpdir__=$( task_maketemp -dq -t "pkgtasks.user_exists" ) || return 3
local testpath="$__user_tmpdir__/user_exists"
task_createfile "$testpath"
local result=0
#
# Redirect standarrd error below because failing to chown(2) is
# part of the test and not actually an error.
#
if ${CHOWN} "$user" "$testpath" >/dev/null 2>&1; then
# user exists
if [ -n "$userid" ]; then
${LS} -dln "$testpath" 2>/dev/null |
( read __ __ uid __; [ "$userid" = "$uid" ] )
if [ $? -gt 0 ]; then
# user exists but doesn't match userid
result=2
else
# user exists and userid exists and match
result=0
fi
else
# user exists and userid is not set
result=0
fi
elif [ -z "$userid" ]; then
# user doesn't exist and userid is not set
result=1
elif ${CHOWN} "$userid" "$testpath" >/dev/null 2>&1; then
# user doesn't exist
${LS} -dl "$testpath" 2>/dev/null |
( read __ __ name __
#
# If the ls(1) output shows a username instead of the
# raw UID, then the UID must exist and map to a valid
# username on the system.
#
[ "$userid" != "$name" ] )
if [ $? -gt 0 ]; then
# user doesn't exist, userid doesn't exist
result=1
else
# user doesn't exist, userid exists
result=2
fi
else
# user doesn't exist and userid doesn't exist
result=1
fi
_task_user_exists_cleanup
return $result
}
_task_group_exists_cleanup()
{
: ${RM:=rm}
# Sanity check before blowing away $__group_tmpdir__.
case $__group_tmpdir__ in
/tmp/*) ${RM} -fr "$__group_tmpdir__" ;;
"") : "skip empty tmpdir" ;;
*) task_echo "!!! WARNING: usergroup_exists: Remove directory $__group_tmpdir__" ;;
esac
__group_tmpdir__=
}
_task_user_exists_cleanup()
{
: ${RM:=rm}
# Sanity check before blowing away $__user_tmpdir__.
case $__user_tmpdir__ in
/tmp/*) ${RM} -fr "$__user_tmpdir__" ;;
"") : "skip empty tmpdir" ;;
*) task_echo "!!! WARNING: usergroup_exists: Remove directory $__user_tmpdir__" ;;
esac
__user_tmpdir__=
}
_usergroup_exists_init()
{
task_cleanup_add_hook \
_task_group_exists_cleanup \
_task_user_exists_cleanup
}
# Static variables for temporary directories that should be removed if an
# error occurs.
#
__group_tmpdir__=
__user_tmpdir__=
|