A truck load of updates/fixes/tweaks
[pkgusr] / usr / sbin / add_package_user
1 #!/bin/bash
2 # Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
3 # You may do everything with this code except misrepresent its origin.
4 # PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND!
5
6 #Package user home directories will be located under this directory
7 homebase=/usr/src
8
9 #Contents of following directory are copied into home directory when creating 
10 #a new package user (existing files will not be overwritten)
11 skel=/etc/pkgusr/skel-package
12
13 if [ $# -lt 7 ]; then
14     echo 1>&2 'USAGE: '
15     echo 1>&2 'add_package_user <description> <name> <minuid> <maxuid>'
16     echo 1>&2 '                              <group> <mingid> <maxgid> [-d <home>]'
17     echo 1>&2
18     echo 1>&2 'If a user account called <name> exists, a message will be printed and'
19     echo 1>&2 'everything will be left as-is. If a user account called <name> does not'
20     echo 1>&2 'exist, one will be created.'
21     echo 1>&2 'The account'"'"'s primary group will be <group> and the /etc/passwd'
22     echo 1>&2 'description field will be set to <description>. If a group called <group>'
23     echo 1>&2 'does not already exist, one will be created.'
24     echo 1>&2 'The new account will get the "install" group as a supplementary group. If'
25     echo 1>&2 'a group named "install" does not exist, one will be created.'
26     echo 1>&2
27     echo 1>&2 '<description> needs to be a valid string for the /etc/passwd description'
28     echo 1>&2 '  field. This means, among other things, that it must not contain ":".'
29     echo 1>&2 '  Don'"'"'t forget to properly quote <description> if it contains spaces or'
30     echo 1>&2 '  other characters interpreted by the shell!'
31     echo 1>&2
32     echo 1>&2 '<minuid>(incl.) and <maxuid>(excl.) determine the numeric range from which'
33     echo 1>&2 '  the new account'"'"'s UID will be picked in the following way:'
34     echo 1>&2
35     echo 1>&2 '  1. If the range contains no unused UID => Exit with error.'
36     echo 1>&2 '  2. If <maxuid>-1 is still unused, find the greatest UID from the range'
37     echo 1>&2 '     that is used and pick the number after that.'
38     echo 1>&2 '  3. If <maxuid>-1 is in use, pick the first unused number from the range.'
39     echo 1>&2
40     echo 1>&2 '<mingid>(incl.) and <maxgid>(excl.) determine the numeric range from which'
41     echo 1>&2 '  to pick the GID for group <group> and/or group "install", if it needs to be'
42     echo 1>&2 '  created. The process for picking the GID is the same as that for the UID.'
43     echo 1>&2 ''
44     echo 1>&2 '<home> specifies the new user'"'"'s home directory. If it is not provided,'
45     echo 1>&2 '  it will default to '"$homebase/<name> ."
46     echo 1>&2 '  If the home directory does not exist yet it will be created, otherwise'
47     echo 1>&2 '  the existing directory will be recursively chown'"'"'ed to the new user.'
48     echo 1>&2 '  The home directory will be populated with a copy of the contents of'
49     echo 1>&2 "  $skel, but pre-existing files in the home directory"
50     echo 1>&2 '  will not be overwritten. Note that symlinks will be copied as symlinks!'
51     echo 1>&2 ''
52     exit 1
53 fi
54
55 grpfile=/etc/group
56 passwd=/etc/passwd
57
58
59
60 description=$1
61 name=$2
62 minuid=$3
63 maxuid=$4
64 gname=$5
65 mingid=$6
66 maxgid=$7
67 home=$homebase/$name
68
69 set -- "$@" _eNd_OF_lisT_
70 while [ "$1" != "_eNd_OF_lisT_" ]; do
71     case "$1" in
72         -d)
73             shift 1
74             if [ "$1" = "_eNd_OF_lisT_" ]; then
75                 echo 1>&2 "-d directory name missing!"
76                 exit 1
77             fi
78             home="$1"
79             shift 1
80             ;;
81         *)
82             temp="$1" 
83             shift 1
84             set -- "$@" "$temp"
85             ;;
86     esac     
87 done
88 shift 1 #throw away _eNd_OF_lisT_
89
90 if [ $UID -ne 0 ]; then
91     echo Please run this script as root.
92     exit 1
93 fi
94
95 #test if user already exists
96 grep "^$name:.*" $passwd
97 if [ $? -eq 0 ]; then 
98     echo 'Package user does already exist! Do su '$name' to do maintenance work.'
99     exit 1
100 fi 
101
102 #test if minuid, maxuid, mingid and maxgid are integers, otherwise error
103 error=0
104 expr ${minuid} + 1 2>/dev/null 1>&2 || error=1
105 expr ${maxuid} + 1 2>/dev/null 1>&2 || error=1
106 expr ${mingid} + 1 2>/dev/null 1>&2 || error=1
107 expr ${maxgid} + 1 2>/dev/null 1>&2 || error=1
108
109 if [ $error -eq 1 ]; then
110     echo Error: Illegal numeric value!
111     exit 1
112 fi
113
114 if [ $minuid -ge $maxuid ]; then
115     echo 'Error: minuid must be less than maxuid !' 
116     exit 1
117 fi
118
119 if [ $mingid -ge $maxgid ]; then
120     echo 'Error: mingid must be less than maxgid !' 
121     exit 1
122 fi
123
124
125 uidlist=`cut -d : -f 3 $passwd | sort -n`
126
127 #find last used UID within range
128 u=0
129 for i in $uidlist
130 do
131     if [ $i -ge $maxuid ]; then break; fi
132     if [ $i -ge $minuid ]; then u=$i; fi 
133 done
134
135 #if no UID from the range is used, pick the first, otherwise pick the one
136 #immediately following the last UID in use.
137 if [ $u -eq 0 ]; then
138     u=$minuid
139 else
140     u=`expr $u + 1`
141 fi
142
143 #if the UID determined above is >= maxuid (i.e. illegal)
144 #then we look for the first unused uid in the range.
145 if [ $u -ge $maxuid ]; then
146     u=$minuid
147     for i in $uidlist
148     do
149         if [ $u -eq $i ]; then
150             u=`expr $u + 1`
151         fi
152         if [ $i -ge $maxuid ]; then
153             break
154         fi
155     done  
156
157     if [ $u -ge $maxuid ]; then
158         echo Error: UID range is full!
159         exit 1
160     fi
161 fi
162
163 echo Will create user $name with uid: $u
164
165 unset uidlist
166
167 #############################################################################
168 #                                 group
169 #############################################################################
170
171 #execute the following for gname and "install" to get gids for those 2 groups
172
173 g=0
174 creategroup=0
175 for group in install $gname
176 do
177     oldg=$g #save gid from previous run
178     createinstall=$creategroup
179     creategroup=0
180  
181     #test if group already exists and extract gid if so
182     g=`grep ^${group}:.\* $grpfile | cut -d : -f 3 -`
183
184     #if group does not exist, then check range for a free gid
185     if [ z$g = z ]; then 
186         creategroup=1
187     
188         gidlist=`cut -d : -f 3 $grpfile | sort -n`
189
190         #find last used GID within range
191         g=0
192         for i in $gidlist; do
193             if [ $i -ge $maxgid ]; then break; fi
194             if [ $i -ge $mingid ]; then g=$i; fi
195         done
196
197         #if no GID from the range is used, pick the first, otherwise pick the one
198         #immediately following the last GID in use.
199         if [ $g -eq 0 ]; then
200             g=$mingid
201         else
202             g=`expr $g + 1`
203         fi
204     
205         #don't reuse gid from previous run 
206         if [ $g -eq $oldg ]; then
207             g=`expr $g + 1`
208         fi
209
210         #if the GID determined above is >= maxgid (i.e. illegal)
211         #then we look for the first unused gid in the range.
212         if [ $g -ge $maxgid ]; then
213             g=$mingid
214             for i in $gidlist; do
215                 if [ $g -eq $i ]; then g=`expr $g + 1` ; fi
216                 if [ $g -eq $oldg ]; then g=`expr $g + 1` ; fi
217                 if [ $i -ge $maxgid ]; then break; fi
218             done  
219
220             if [ $g -ge $maxgid ]; then
221                 echo Error: GID range is full!
222                 exit 1
223             fi
224         fi
225     fi
226 done
227
228 unset gidlist
229
230 if [ $createinstall -eq 1 ]; then
231     echo Creating group install with gid $oldg
232     groupadd -g $oldg install || exit 1
233 else
234     echo Group install has gid $oldg
235 fi
236 if [ $creategroup -eq 1 ]; then
237     echo Creating group $gname with gid $g
238     groupadd -g $g $gname || exit 1
239 else 
240     echo Group $gname has gid $g
241 fi
242
243
244 ## Bastard Note:
245 #  Once you have the shadow package installed, uncomment this section
246 #  and comment out the section below it.
247 ##
248 #useradd -c "${description}" -d ${home} -g ${gname} -G install \
249 #    -m -k /etc/pkgusr/skel-package \
250 #    -s /bin/bash -u ${u} ${name}
251
252 ## Bastard Note:
253 #  Once the shadow package is installed, comment this section out and
254 #  use the above section.
255 ##
256 useradd -c "${description}" -d ${home} -g ${gname} -G install \
257         -s /bin/bash -u ${u} ${name}  || exit 1
258
259 mkdir -p $home || exit 1
260
261 yes n|cp -ai -R ${skel}/{[^.],.[^.],..?}* ${home} 2>/dev/null >/dev/null
262
263 cd ${home}
264 chown --recursive ${u}:${g} .
265
266
267
268 exit 0