]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-busybox.in
lxc-busybox: make some OpenSSH tools optional
[mirror_lxc.git] / templates / lxc-busybox.in
1 #!/bin/bash
2
3 #
4 # lxc: linux Container library
5
6 # Authors:
7 # Daniel Lezcano <daniel.lezcano@free.fr>
8
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
13
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
18
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with this library; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23 LXC_MAPPED_UID=
24 LXC_MAPPED_GID=
25 SSH=
26
27 # Make sure the usual locations are in PATH
28 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
29
30 am_in_userns() {
31 [ -e /proc/self/uid_map ] || { echo no; return; }
32 [ "$(wc -l /proc/self/uid_map | awk '{ print $1 }')" -eq 1 ] || { echo yes; return; }
33 line=$(awk '{ print $1 " " $2 " " $3 }' /proc/self/uid_map)
34 [ "$line" = "0 0 4294967295" ] && { echo no; return; }
35 echo yes
36 }
37
38 in_userns=0
39 [ $(am_in_userns) = "yes" ] && in_userns=1
40
41 install_busybox()
42 {
43 rootfs=$1
44 name=$2
45 res=0
46 tree="\
47 $rootfs/selinux \
48 $rootfs/dev \
49 $rootfs/home \
50 $rootfs/root \
51 $rootfs/etc \
52 $rootfs/etc/init.d \
53 $rootfs/bin \
54 $rootfs/usr/bin \
55 $rootfs/sbin \
56 $rootfs/usr/sbin \
57 $rootfs/proc \
58 $rootfs/sys \
59 $rootfs/mnt \
60 $rootfs/tmp \
61 $rootfs/var/log \
62 $rootfs/usr/share/udhcpc \
63 $rootfs/dev/pts \
64 $rootfs/dev/shm \
65 $rootfs/lib \
66 $rootfs/usr/lib \
67 $rootfs/lib64 \
68 $rootfs/usr/lib64"
69
70 mkdir -p $tree || return 1
71 chmod 755 $tree || return 1
72
73 pushd $rootfs/dev > /dev/null || return 1
74
75 # minimal devices needed for busybox
76 if [ $in_userns -eq 1 ]; then
77 for dev in tty console tty0 tty1 ram0 null urandom; do
78 echo "lxc.mount.entry = /dev/$dev dev/$dev none bind,optional,create=file 0 0" >> $path/config
79 done
80 else
81 mknod -m 666 tty c 5 0 || res=1
82 mknod -m 666 console c 5 1 || res=1
83 mknod -m 666 tty0 c 4 0 || res=1
84 mknod -m 666 tty1 c 4 0 || res=1
85 mknod -m 666 tty5 c 4 0 || res=1
86 mknod -m 600 ram0 b 1 0 || res=1
87 mknod -m 666 null c 1 3 || res=1
88 mknod -m 666 zero c 1 5 || res=1
89 mknod -m 666 urandom c 1 9 || res=1
90 fi
91
92 popd > /dev/null
93
94 # root user defined
95 cat <<EOF >> $rootfs/etc/passwd
96 root:x:0:0:root:/root:/bin/sh
97 EOF
98
99 cat <<EOF >> $rootfs/etc/group
100 root:x:0:root
101 EOF
102
103 # mount everything
104 cat <<EOF >> $rootfs/etc/init.d/rcS
105 #!/bin/sh
106 /bin/syslogd
107 /bin/mount -a
108 /bin/udhcpc
109 EOF
110
111 # executable
112 chmod 744 $rootfs/etc/init.d/rcS || return 1
113
114 # launch rcS first then make a console available
115 # and propose a shell on the tty, the last one is
116 # not needed
117 cat <<EOF >> $rootfs/etc/inittab
118 ::sysinit:/etc/init.d/rcS
119 tty1::respawn:/bin/getty -L tty1 115200 vt100
120 console::askfirst:/bin/sh
121 EOF
122 # writable and readable for other
123 chmod 644 $rootfs/etc/inittab || return 1
124
125 cat <<EOF >> $rootfs/usr/share/udhcpc/default.script
126 #!/bin/sh
127 case "\$1" in
128 deconfig)
129 ip addr flush dev \$interface
130 ;;
131
132 renew|bound)
133 # flush all the routes
134 if [ -n "\$router" ]; then
135 ip route del default 2> /dev/null
136 fi
137
138 # check broadcast
139 if [ -n "\$broadcast" ]; then
140 broadcast="broadcast \$broadcast"
141 fi
142
143 # add a new ip address
144 ip addr add \$ip/\$mask \$broadcast dev \$interface
145
146 if [ -n "\$router" ]; then
147 ip route add default via \$router dev \$interface
148 fi
149
150 [ -n "\$domain" ] && echo search \$domain > /etc/resolv.conf
151 for i in \$dns ; do
152 echo nameserver \$i >> /etc/resolv.conf
153 done
154 ;;
155 esac
156 exit 0
157 EOF
158
159 chmod 744 $rootfs/usr/share/udhcpc/default.script
160
161 return $res
162 }
163
164 install_dropbear()
165 {
166 # copy dropbear binary
167 cp $(which dropbear) $rootfs/usr/sbin
168 if [ $? -ne 0 ]; then
169 echo "Failed to copy dropbear in the rootfs"
170 return 1
171 fi
172
173 # make symlinks to various ssh utilities
174 utils="\
175 $rootfs/usr/bin/dbclient \
176 $rootfs/usr/bin/scp \
177 $rootfs/usr/bin/ssh \
178 $rootfs/usr/sbin/dropbearkey \
179 $rootfs/usr/sbin/dropbearconvert \
180 "
181 echo $utils | xargs -n1 ln -s /usr/sbin/dropbear
182
183 # add necessary config files
184 mkdir $rootfs/etc/dropbear
185 dropbearkey -t rsa -f $rootfs/etc/dropbear/dropbear_rsa_host_key > /dev/null 2>&1
186 dropbearkey -t dss -f $rootfs/etc/dropbear/dropbear_dss_host_key > /dev/null 2>&1
187
188 echo "'dropbear' ssh utility installed"
189
190 return 0
191 }
192
193 install_openssh()
194 {
195 # tools to be installed
196 server_utils="sshd"
197 client_utils="\
198 ssh \
199 scp \
200 "
201 client_optional_utils="\
202 sftp \
203 ssh-add \
204 ssh-agent \
205 ssh-keygen \
206 ssh-keyscan \
207 ssh-argv0 \
208 ssh-copy-id \
209 "
210
211 # new folders used by ssh
212 ssh_tree="\
213 $rootfs/etc/ssh \
214 $rootfs/var/empty/sshd \
215 $rootfs/var/lib/empty/sshd \
216 $rootfs/var/run/sshd \
217 "
218
219 # create folder structure
220 mkdir -p $ssh_tree
221 if [ $? -ne 0 ]; then
222 return 1
223 fi
224
225 # copy binaries
226 for bin in $server_utils $client_utils; do
227 tool_path=`which $bin`
228 cp $tool_path $rootfs/$tool_path
229 if [ $? -ne 0 ]; then
230 echo "Unable to copy $tool_path in the rootfs"
231 return 1
232 fi
233 done
234
235 for bin in $client_optional_utils; do
236 tool_path=`which $bin`
237 if [ $? -eq 0 ]; then
238 cp $tool_path $rootfs/$tool_path
239 fi
240 done
241
242 # add user and group
243 cat <<EOF >> $rootfs/etc/passwd
244 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
245 EOF
246
247 cat <<EOF >> $rootfs/etc/group
248 sshd:x:74:
249 EOF
250
251 # generate container keys
252 ssh-keygen -t rsa -N "" -f $rootfs/etc/ssh/ssh_host_rsa_key >/dev/null 2>&1
253 ssh-keygen -t dsa -N "" -f $rootfs/etc/ssh/ssh_host_dsa_key >/dev/null 2>&1
254
255 # by default setup root password with no password
256 cat <<EOF > $rootfs/etc/ssh/sshd_config
257 Port 22
258 Protocol 2
259 HostKey /etc/ssh/ssh_host_rsa_key
260 HostKey /etc/ssh/ssh_host_dsa_key
261 UsePrivilegeSeparation yes
262 KeyRegenerationInterval 3600
263 ServerKeyBits 768
264 SyslogFacility AUTH
265 LogLevel INFO
266 LoginGraceTime 120
267 PermitRootLogin yes
268 StrictModes yes
269 RSAAuthentication yes
270 PubkeyAuthentication yes
271 IgnoreRhosts yes
272 RhostsRSAAuthentication no
273 HostbasedAuthentication no
274 PermitEmptyPasswords yes
275 ChallengeResponseAuthentication no
276 EOF
277
278 echo "'OpenSSH' utility installed"
279
280 return 0
281 }
282
283 configure_busybox()
284 {
285 rootfs=$1
286
287 which busybox >/dev/null 2>&1
288
289 if [ $? -ne 0 ]; then
290 echo "busybox executable is not accessible"
291 return 1
292 fi
293
294 file -L $(which busybox) | grep -q "statically linked"
295 if [ $? -ne 0 ]; then
296 echo "warning : busybox is not statically linked."
297 echo "warning : The template script may not correctly"
298 echo "warning : setup the container environment."
299 fi
300
301 # copy busybox in the rootfs
302 cp $(which busybox) $rootfs/bin
303 if [ $? -ne 0 ]; then
304 echo "failed to copy busybox in the rootfs"
305 return 1
306 fi
307
308 # symlink busybox for the commands it supports
309 # it would be nice to just use "chroot $rootfs busybox --install -s /bin"
310 # but that only works right in a chroot with busybox >= 1.19.0
311 pushd $rootfs/bin > /dev/null || return 1
312 ./busybox --help | grep 'Currently defined functions:' -A300 | \
313 grep -v 'Currently defined functions:' | tr , '\n' | \
314 xargs -n1 ln -s busybox
315 popd > /dev/null
316
317 # relink /sbin/init
318 ln $rootfs/bin/busybox $rootfs/sbin/init
319
320 # passwd exec must be setuid
321 chmod +s $rootfs/bin/passwd
322 touch $rootfs/etc/shadow
323
324 # setting passwd for root
325 CHPASSWD_FILE=$rootfs/root/chpasswd.sh
326
327 cat <<EOF >$CHPASSWD_FILE
328 echo "setting root password to \"root\""
329
330 mount -n --bind /lib $rootfs/lib
331 if [ \$? -ne 0 ]; then
332 echo "Failed bind-mounting /lib at $rootfs/lib"
333 exit 1
334 fi
335
336 chroot $rootfs chpasswd <<EOFF 2>/dev/null
337 root:root
338 EOFF
339
340
341 if [ \$? -ne 0 ]; then
342 echo "Failed to change root password"
343 exit 1
344 fi
345
346 umount $rootfs/lib
347
348 EOF
349
350 lxc-unshare -s MOUNT -- /bin/sh < $CHPASSWD_FILE
351 rm $CHPASSWD_FILE
352
353 return 0
354 }
355
356 copy_configuration()
357 {
358 path=$1
359 rootfs=$2
360 name=$3
361
362 grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
363 cat <<EOF >> $path/config
364 lxc.haltsignal = SIGUSR1
365 lxc.rebootsignal = SIGTERM
366 lxc.utsname = $name
367 lxc.tty = 1
368 lxc.pts = 1
369 lxc.cap.drop = sys_module mac_admin mac_override sys_time
370
371 # When using LXC with apparmor, uncomment the next line to run unconfined:
372 #lxc.aa_profile = unconfined
373
374 lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
375 lxc.mount.entry = shm /dev/shm tmpfs defaults 0 0
376 EOF
377
378 libdirs="\
379 lib \
380 usr/lib \
381 lib64 \
382 usr/lib64"
383
384 for dir in $libdirs; do
385 if [ -d "/$dir" ] && [ -d "$rootfs/$dir" ]; then
386 echo "lxc.mount.entry = /$dir $dir none ro,bind 0 0" >> $path/config
387 fi
388 done
389 echo "lxc.mount.entry = /sys/kernel/security sys/kernel/security none ro,bind,optional 0 0" >>$path/config
390 }
391
392 remap_userns()
393 {
394 path=$1
395
396 if [ -n "$LXC_MAPPED_UID" ] && [ "$LXC_MAPPED_UID" != "-1" ]; then
397 chown $LXC_MAPPED_UID $path/config >/dev/null 2>&1
398 chown -R root $path/rootfs >/dev/null 2>&1
399 fi
400
401 if [ -n "$LXC_MAPPED_GID" ] && [ "$LXC_MAPPED_GID" != "-1" ]; then
402 chgrp $LXC_MAPPED_GID $path/config >/dev/null 2>&1
403 chgrp -R root $path/rootfs >/dev/null 2>&1
404 fi
405 }
406
407 usage()
408 {
409 cat <<EOF
410 $1 -h|--help -p|--path=<path> -s|--ssh={dropbear,openssh}
411 EOF
412 return 0
413 }
414
415 options=$(getopt -o hp:n:s: -l help,rootfs:,path:,name:,mapped-uid:,mapped-gid:,ssh: -- "$@")
416 if [ $? -ne 0 ]; then
417 usage $(basename $0)
418 exit 1
419 fi
420 eval set -- "$options"
421
422 while true
423 do
424 case "$1" in
425 -h|--help) usage $0 && exit 0;;
426 -p|--path) path=$2; shift 2;;
427 --rootfs) rootfs=$2; shift 2;;
428 -n|--name) name=$2; shift 2;;
429 --mapped-uid) LXC_MAPPED_UID=$2; shift 2;;
430 --mapped-gid) LXC_MAPPED_GID=$2; shift 2;;
431 -s|--ssh) SSH=$2; shift 2;;
432 --) shift 1; break ;;
433 *) break ;;
434 esac
435 done
436
437 if [ "$(id -u)" != "0" ]; then
438 echo "This script should be run as 'root'"
439 exit 1
440 fi
441
442 if [ -z "$path" ]; then
443 echo "'path' parameter is required"
444 exit 1
445 fi
446
447 # detect rootfs
448 config="$path/config"
449 if [ -z "$rootfs" ]; then
450 if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
451 rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
452 else
453 rootfs=$path/rootfs
454 fi
455 fi
456
457 install_busybox $rootfs $name
458 if [ $? -ne 0 ]; then
459 echo "failed to install busybox's rootfs"
460 exit 1
461 fi
462
463 configure_busybox $rootfs
464 if [ $? -ne 0 ]; then
465 echo "failed to configure busybox template"
466 exit 1
467 fi
468
469 copy_configuration $path $rootfs $name
470 if [ $? -ne 0 ]; then
471 echo "failed to write configuration file"
472 exit 1
473 fi
474
475 remap_userns $path
476 if [ $? -ne 0 ]; then
477 echo "failed to remap files to user"
478 exit 1
479 fi
480
481 if [ -n "$SSH" ]; then
482 case "$SSH" in
483 "dropbear")
484 install_dropbear
485 if [ $? -ne 0 ]; then
486 echo "Unable to install 'dropbear' ssh utility"
487 exit 1
488 fi ;;
489 "openssh")
490 install_openssh
491 if [ $? -ne 0 ]; then
492 echo "Unable to install 'OpenSSH' utility"
493 exit 1
494 fi ;;
495 *)
496 echo "$SSH: unrecognized ssh utility"
497 exit 1
498 esac
499 else
500 which dropbear >/dev/null 2>&1
501 if [ $? -eq 0 ]; then
502 install_dropbear
503 fi
504 fi