Typo
[linux_from_scratch_hints.git] / OLD / more_control_and_pkg_man.txt
blob402d800bc99a2a1840e62568522faa21b69380d0
1 TITLE:          More control and package management using package users (v0.8)
2 LFS VERSION:    3.1 (should work with later versions with minor changes)
3 AUTHOR:         Matthias S. Benkmann <m.s.b@gmx.net>
5 SYNOPSIS:
6         -You want to know which packages your files belong to ?
7         -You want to deinstall software that doesn't have make uninstall ?
8         -You are bothered by programs installed setuid root behind your back ?
9         -You don't want packages to overwrite files from other packages ?
10         -You don't like package managers like RPM ?
11         -YOU WANT TOTAL CONTROL USING ONLY UNIX BUILTINS ?
13 HINT:
15 LEGALESE: The author does not take responsibility for any damage of any kind
16 caused directly or indirectly by applying the methods described below. 
17 There is no warranty of any kind, not even the implied warranty of fitness for
18 the purposes mentioned in the text, on any of the programs/scripts/commands 
19 listed below and the author may not be held liable for any damage of any kind 
20 caused by the execution of said programs/scripts/commands.
21 Proceed at your own risk!
23 ########################################################################### 
24  Changelog
25 ###########################################################################
27 2002-01-30  -added Changelog
28             -moved "chown 0.10000 `cat /tmp/installdirs`" command up (before
29              glibc package user is created)
30             -add_package_user: create home directory with "mkdir -p"
31                                use $grpfile everywhere instead of /etc/group
32             -improved mammoth sentence in Introduction
33             -added note about possibility to have user name==group name
34             -source bashrc_basic in bashrc_package
35             -minor textual changes
37 2002-02-18
38             -added section "Security issues with NFS"
39             -submitted v0.7
40             
41 2002-03-16  -added note, that on Linux make doesn't need to be setgid kmem
43 2002-04-20
44             -changed LFS VERSION header to be more conservative
45             -added <br> tags to the synopsis for the sake of the hints 
46              index
47             -added group mmedia to the list of suggested groups 
48             -submitted v0.8
49             
52 ########################################################################### 
53  Introduction
54 ###########################################################################
56 Let's say I have written a program that you would like to use. To make it
57 easier for you I come over to install it for you. Would you give me the root
58 account and then leave the room ? No ? Then why do you give it to complete
59 strangers who you have never seen in your life, to install software packages
60 pulled from some Internet server, that come with no warranty and don't even 
61 list their contents in the README, although they will happily spread them all 
62 over your system ?
63 It is a mystery why Unix admins who wouldn't even trust their employer with
64 more than a normal user account carelessly execute complex and incomprehensible
65 installation scripts with full root rights.
67 Users and groups are the basic security principle in a Unix system. They have
68 been used successfully for a long time to control who has created a file and 
69 who is allowed to delete or change this file. But this control has only been
70 imposed on the files of ordinary users. What a waste! I suggest to extend
71 this control to all system files.
74 #############################################################################
75  Package users
76 #############################################################################
78 The basic idea of this scheme is easily explained. Every package belongs to a 
79 certain "package user". This is a special user account whose HOME directory
80 is /usr/src/<package> (or wherever you keep the tarballs for the package).
81 Usually this account has no password so that only root can su to a package 
82 user, which ensures that package users do not open an additional way into the 
83 system and undermine security.
84 Of course you *may* set passwords anyway to allow a co-admin who you want to
85 be able to install and maintain certain software packages to do so without 
86 having access to the actual root account. This co-admin could for instance
87 install, delete, change additional libraries which might be necessary for his
88 workgroup. He would be unable, though, to remove or modify libraries which 
89 don't belong to him/her, such as libc.
91 Every package user has a primary group that reflects the purpose of the
92 package, such as "system" for essential packages, "devel" for packages
93 related to software development and so on. There are other useful
94 organizational schemes, of course. You might want to have the group reflect
95 the workgroup of the above-mentioned co-admin who installed the file for 
96 instance. Another possibility is to create a new group for every package
97 user with the same name as the user name. That way, even if a file needs to
98 be setuid root (and consequently has to be owned by root), the group of the
99 file tells you about the package where it originates. 
101 In addition to the primary group, there is the secondary group which is the
102 same for all package users. This is the "install" group. All directories
103 that packages are allowed to install stuff in belong to the install group.
104 This includes directories such as /bin and /usr/bin but excludes directories
105 like /root or /. The directories owned by the install group are always
106 group-writeable. Without further preparation this does not give added security
107 or control because every package could replace the files from a different
108 package (the change would be visible in the output from ls -la, though).
109 For this reason we make all install directories sticky. The sticky attribute
110 allows users to create new files and delete or modify their own files in
111 the directory while preventing them from writing or deleting files from other
112 users.
115 ############################################################################
116  How to install software
117 ############################################################################
119 Isn't this all very tedious ? Not if you use this script:
121 -------------------- begin $LFS/sbin/install_package ------------------------
122 #!/bin/sh
123 if [ $# -ne 3 ]; then
124 echo USAGE: install_package description name group
125 echo "!!Don't forget to put description in quotes if it contains spaces.!!"
126 echo "This will create a new package user name in group. This will set up"
127 echo "a home directory for this package user. After that, this script will"
128 echo "automatically su to the new user so that you can begin with the"
129 echo "installation right away. "
130 exit 1
133 if [ $UID -ne 0 ]; then echo Please run this script as root. ; exit 1; fi
134 add_package_user "${1}" $2 10000 20000 $3 10000 20000 || exit 1
135 su $2
136 ------------------- end $LFS/sbin/install_package ----------------------------
138 The above script is a shortcut for the following script, which does the
139 actual adding of the package user in a certain range of UIDs and GIDs:
141 -------------------- begin $LFS/sbin/add_package_user -----------------------
142 #!/bin/sh
144 if [ $# -lt 7 ]; then
145 echo 'Copyright (c) 2000 Matthias Benkmann'
146 echo 'USAGE: '
147 echo 'add_package_user description name minuid maxuid group mingid maxgid [-d home]'
148 echo 
149 echo Don\'t forget to put description in quotes. 
150 echo description must be valid for a /etc/passwd entry, that means especially
151 echo that it must not contain \":\".
152 echo If group doesn\'t exist, it will be added. 
153 echo group will be the user\'s main group. 
154 echo 'The user will also belong to group "install" (created if necessary).'
155 echo 'A home directory /usr/src/name (or home if -d home specified) 
156 echo will be created if it doesn\'t exist
157 echo 'and the files from /etc/skel-package will be copied into it (existing'
158 echo 'target files will *not* be overwritten)'
159 echo 'minuid (incl.) and maxuid (excl.)  determine'
160 echo 'the range of UIDs used by this script. The script will pick the first'
161 echo 'UID greater than all UIDs from this range already in use.' 
162 echo 'If that UID is out of range (i.e. equal to maxuid), the'
163 echo 'script will pick the first available UID in this range. If the range is'
164 echo 'full, the script will give up. This process ensures that UIDs for packages'
165 echo that have been removed, don\'t get reassigned unless really necessary.
166 echo 'This avoids trouble if some files were overlooked when removing the package.'
167 echo 'Otherwise these files might be assigned to the wrong package.'
168 echo 'mingid (incl.) and maxgid (excl.) define'
169 echo 'the permissible range for the GID of group if it has to be added (and '
170 echo 'the install group if it must be added).'
171 exit 1
174 grpfile=/etc/group
175 passwd=/etc/passwd
176 homebase=/usr/src
177 skel=/etc/skel-package
178 description=$1
179 name=$2
180 minuid=$3
181 maxuid=$4
182 gname=$5
183 mingid=$6
184 maxgid=$7
185 home=$homebase/$name
187 set -- "$@" _eNd_OF_lisT_
188 while [ "$1" != "_eNd_OF_lisT_" ]; do
189   case "$1" in
190     -d) shift 1
191         if [ "$1" = "_eNd_OF_lisT_" ]; then
192           echo 1>&2 "-d directory name missing!"
193           exit 1
194         fi
195         home="$1"
196         shift 1
197         ;;
198     *) temp="$1" 
199        shift 1
200        set -- "$@" "$temp"
201        ;;
202   esac     
203 done
204 shift 1 #throw away _eNd_OF_lisT_
206 if [ $UID -ne 0 ]; then echo Please run this script as root. ; exit 1; fi
208 #test if user already exists
209 grep "^$name:.*" $passwd
210 if [ $? -eq 0 ]; then 
211   echo 'Package user does already exist! Do su '$name' to do maintenance work.'
212   exit 1
213 fi 
215 #test if minuid, maxuid, mingid and maxgid are integers, otherwise set
216 #to defaults.
217 error=0
218 expr ${minuid} + 1 2>/dev/null 1>&2 || error=1
219 expr ${maxuid} + 1 2>/dev/null 1>&2 || error=1
220 expr ${mingid} + 1 2>/dev/null 1>&2 || error=1
221 expr ${maxgid} + 1 2>/dev/null 1>&2 || error=1
223 if [ $error -eq 1 ]; then
224   echo Error: Illegal numeric value!
225   exit 1
228 if [ $minuid -ge $maxuid ]; then
229   echo 'Error: minuid must be less than maxuid !' 
230   exit 1
233 if [ $mingid -ge $maxgid ]; then
234   echo 'Error: mingid must be less than maxgid !' 
235   exit 1
239 uidlist=`cut -d : -f 3 $passwd | sort -n`
241 #find last used UID within range
243 for i in $uidlist
245   if [ $i -ge $maxuid ]; then break; fi
246   if [ $i -ge $minuid ]; then u=$i; fi 
247 done
249 #if no UID from the range is used, pick the first, otherwise pick the one
250 #immediately following the last UID in use.
251 if [ $u -eq 0 ]; then u=$minuid; else u=`expr $u + 1`; fi
253 #if the last UID used from the range is maxuid-1, i.e. we may 
254 #not use its successor as UID, then we look for the first unused uid
255 #in the range.
256 if [ $u -ge $maxuid ]; then
257   u=$minuid
258   for i in $uidlist
259   do
260     if [ $u -eq $i ]; then u=`expr $u + 1` ; fi
261     if [ $i -ge $maxuid ]; then break; fi
262   done  
264   if [ $u -ge $maxuid ]; then
265     echo Error: UID range is full!
266     exit 1
267   fi
270 echo Will create user $name with uid: $u
272 unset uidlist
274 #############################################################################
275 #                                 group
276 #############################################################################
278 #execute the following for gname and "install" to get gids for those 2 groups
281 creategroup=0
282 for group in install $gname
284   oldg=$g #save gid from previous run
285   createinstall=$creategroup
286   creategroup=0
288   #test if group already exists and extract gid if so
289   g=`grep ^${group}:.\* $grpfile | cut -d : -f 3 -`
291   #if group does not exist, then check range for a free gid
292   if [ z$g = z ]; then 
293     creategroup=1
294     
295     gidlist=`cut -d : -f 3 $grpfile | sort -n`
297     #find last used GID within range
298     g=0
299     for i in $gidlist
300     do
301       if [ $i -ge $maxgid ]; then break; fi
302       if [ $i -ge $mingid ]; then g=$i; fi
303     done
305     #if no GID from the range is used, pick the first, otherwise pick the one
306     #immediately following the last GID in use.
307     if [ $g -eq 0 ]; then g=$mingid; else g=`expr $g + 1`; fi
308     
309     #don't reuse gid from previous run 
310     if [ $g -eq $oldg ]; then g=`expr $g + 1`; fi
312     #if the last GID used from the range is maxgid-1, i.e. we may 
313     #not use its successor as GID, then we look for the first unused gid
314     #in the range.
315     if [ $g -ge $maxgid ]; then
316       g=$mingid
317       for i in $gidlist
318       do
319         if [ $g -eq $i ]; then g=`expr $g + 1` ; fi
320         if [ $g -eq $oldg ]; then g=`expr $g + 1` ; fi
321         if [ $i -ge $maxgid ]; then break; fi
322       done  
324       if [ $g -ge $maxgid ]; then
325         echo Error: GID range is full!
326         exit 1
327       fi
328     fi
329   fi
330 done
332 unset gidlist
334 if [ $createinstall -eq 1 ]; then
335   echo Creating group install with gid $oldg
336   groupadd -g $oldg install || exit 1
337 else
338   echo Group install has gid $oldg
340 if [ $creategroup -eq 1 ]; then
341   echo Creating group $gname with gid $g
342   groupadd -g $g $gname || exit 1
343 else 
344   echo Group $gname has gid $g
349 useradd -c "${description}" -d ${home} -g ${gname} -G install \
350         -s /bin/bash -u ${u} ${name}  || exit 1
352 mkdir -p $home || exit 1
354 yes n|cp -ai -R ${skel}/{[^.],.[^.],..?}* ${home} 2>/dev/null >/dev/null
356 cd ${home}
357 chown --recursive ${u}.${g} .
360 exit 0
361 -------------------- end $LFS/sbin/add_package_user ------------------------
364 If you use these scripts, you can install a new package like this
366 install_package 'Foo description' foo foogroup
368 and the package user foo will be created and you will automatically be su'd to 
369 it and put into the package user's home directory. Now just copy the tarball
370 from your download directory, untar and install. It's no more work than
371 doing it as root.
374 ############################################################################
375  Pitfalls and Solutions
376 ############################################################################
378 There are some pitfalls when you use this system. The following situations are
379 common:
381 1. A package install script is poorly written and insists on changing
382    ownership/permissions of system directories or its own files.
383    
384 2. A package install script has a legitimate reason to change 
385    ownership/permissions of files it installs.
386    
387 3. Package A contains a program that is also part of package B. Package B
388    was installed first.
389    
390 4. A package tests if the user installing it is root and does not install
391    certain programs otherwise.
392    
393 5. A package creates a directory that other packages need to write to.
395 1-3 usually result in an "Operation not permitted" error during make install.
396 Note that this is not actually a flaw of the package user scheme, it's a
397 feature. It's the reason why we made the install directories sticky and use
398 package users in the first place. We don't want stuff like this to happen
399 without our (divine :-) intervention. Fixing these issues is usually easy:
401 1. Look at the output from "make install". It will contain the offending
402    command such as "install --owner root foo /bin" right before the
403    "Operation not permitted" error. grep through the Makefiles of the package
404    and remove the offending switch (in this case "--owner foo"). 
405    Sometimes you may not want to remove it altogether but may need to change 
406    it to something harmless. For instance "install -m 4755 ..." which tries to 
407    set the setuid bit should be changed to "install -m 755 ...".
408    You can automate these changes with a sed script or use a wrapper script
409    around install (see below) to avoid having to manually change Makefiles.
410    Note that you either have to perform these changes *after* the configure
411    step or you have to modify the source Makefiles (usually Makefile.in or
412    Makefile.am).
414 2. This is basically like 1 but in this case the package actually has a reason
415    (that you accept) for doing what it does. This is seldom but happens for
416    some packages that install setuid root programs that you want to have
417    setuid root, such as ping. In this case, act like in case 1 and execute
418    the appropriate changes manually as root afterwards,
419    such as chown root.root /bin/ping && chmod 4755 /bin/ping.
420    
421 3. In this case you have to decide which package you actually want to provide
422    the program in question. If you want to replace package B's program with
423    that of package A, simply delete the program manually as root.
424    If you don't want package A to overwrite the program with its own,
425    grep through the Makefiles for the name of the program in question (and
426    its manpages). Usually you will find a list like
427    PROGRAMS=foo bar fubar barfu
428    and it is sufficient to remove the program from this list. In very rare
429    cases you may need to remove some "install <programname> <destination>"
430    lines from the Makefile.
431    
432 4. This case is usually documented in the INSTALL file of the package and a 
433    make target to install the programs left out, such as "install-root", is 
434    provided. So this is not normally an issue.
436 5. This case is easy to fix by assigning the directory in question to the 
437    install group and making it group-writeable and sticky. This does not even
438    have to be done as root. The package user who created the directory has the
439    permissions to do it. So you can insert an appropriate line into the 
440    Makefile.
442 Manually changing Makefiles is annoying, even if it happens only occasionally.
443 Sed scripts do help but they have to be custom fitted to every package that
444 needs them. There is a better solution, though. While building LFS with the
445 package user scheme, I have noticed that although there are a lot of possible
446 things a Makefile could contain which would trigger an 
447 "Operation not permitted" error, only few of them are actually used.
448 So far I have only encountered these problems in connection with mkdir, chgrp,
449 chown and install. 
450 I have written the following scripts to handle them automatically. If you make
451 sure the directory where these scripts are located (in my case /usr/src/lfs)
452 is the first in the PATH for every package user, you should be able to install
453 most LFS packages without having to fix any Makefiles manually. 
455 ATTENTION! These wrapper scripts allow "make install" to complete without
456 aborting due to "Operation not permitted" errors. However, some of the
457 operations that are suppressed this way are legitimate (see 2. above).
458 For that reason, the wrapper scripts output lines beginning with "***"
459 to stderr that contain the original command that the installation wanted to
460 execute. 
461 You *must* check these lines and if it was a legitimate operation you have to
462 take appropriate action manually or the programs in question will not
463 work properly. The following is a list of things you should look for and
464 what you have to do:
466 1. "*** install -m 4xxx -o root" : This wants to make a binary setuid root.
467    The important thing here is "-m 4x". Many install scripts try to use
468    "install -m 755 -o root" or something similar. This can be ignored. The
469    owner (specified with "-o owner") is only important for binaries with mode
470    4xxx (specified with "-m 4xxx").  If you decide that the binary really 
471    should be setuid root (for the LFS base packages this is usually okay)
472    you have to do
473        chown root.root <binaryname>
474        chmod u+s <binaryname>
476 2. "*** chgrp xxx" : This wants to change the group of a binary. This is
477    usually only done if a binary is made setgid. You will see that in the
478    output of "ls -l" like this
479    rwxr-sr-x   1 util-lin tty          8348 Dec  3  2000 write
480    The "s" in the group field tells you this is a setgid binary.
481    Right now the chgrp wrapper below only intercepts chgrp for xxx=tty
482    because that is the only thing needed for installing LFS. 
483    If such a call has been intercepted and you want the binary to be setgid,
484    you have to do the following:
485         chgrp xxx <binaryname>
486         chmod g+s <binaryname>
488 TIP:
489     It is important that you check the error log religiously when installing
490     a package as a package user, especially if you use the scripts below.
491     
492     To make this easier, install like this
493     
494       make install 3>&1 1>&2 2>&3 | tee install.err
495       
496     This will give you the normal make output (i.e. errors and normal messages)
497     to the screen but in addition to that it will put a copy of all error 
498     messages into install.err. You can "cat install.err" after the installation
499     to examine error messages.
500     Note that "make install | tee install.err" does *not* work. This would
501     copy all normal messages *without* the errors.
502     
503     If you want to redirect screen output (i.e. the complete install log,
504     including errors and non-errors) to a file, do it like this
506       { make install 3>&1 1>&2 2>&3 | tee install.err ;} &>install.log
508     You should probably create a shell function for this to save you typing.
511 Here are the wrapper scripts:
513 ------------- begin $LFS/usr/src/lfs/wrappers/mkdir --------------------------
514 #!/bin/sh
516 DAISY_CHAIN=""
518 for p in $(type -ap mkdir) ; do
519   if [ ! $p -ef $0 ]; then DAISY_CHAIN=$p ; break ; fi
520 done
522 if [ ! -n "$DAISY_CHAIN" ]; then
523   echo Cannot find real ${0##*/} command 
524   exit 1
527 if [ $UID == 0 ]; then
528   exec $DAISY_CHAIN "$@"
531 watchdir=/usr/share/locale
533 cmdline="$@"
535 dirs=""
536 for((i=$#; $i>0;))
538   a="$1"
539   shift 1; i=$(($i-1))
540   case "$a" in
541     $watchdir/*) dirs="$dirs ""`expr $a : "$watchdir/\(.*\)"`" 
542                  set -- "$@" "$a" 
543                  ;;
544     *) set -- "$@" "$a" ;;
545   esac
546 done
548 $DAISY_CHAIN "$@" || exit $?
550 test z"$dirs" != z &&
551 echo 1>&2 '***' mkdir "$cmdline"
552 for dir in $dirs ; do
553   cumuldir=""
554   for d in `echo $dirs | sed 's#/# #g' -` ; do
555     cumuldir=$cumuldir$d/
556     chgrp install $watchdir/$cumuldir
557     chmod g+w,o+t $watchdir/$cumuldir
558   done  
559 done
560 exit 0
561 ------------ end $LFS/usr/src/lfs/wrappers/mkdir --------------------------
563 ------------ begin $LFS/usr/src/lfs/wrappers/chgrp ------------------------
564 #!/bin/sh
566 DAISY_CHAIN=""
568 for p in $(type -ap chgrp) ; do
569   if [ ! $p -ef $0 ]; then DAISY_CHAIN=$p ; break ; fi
570 done
572 if [ ! -n "$DAISY_CHAIN" ]; then
573   echo Cannot find real ${0##*/} command 
574   exit 1
577 if [ $UID == 0 ]; then
578   exec $DAISY_CHAIN "$@"
581 if [ "$1" == "tty" ]; then
582   echo 1>&2 '***' chgrp "$@"  
583 else
584   $DAISY_CHAIN "$@" || exit $?
587 exit 0
588 ------------ end $LFS/usr/src/lfs/wrappers/chgrp --------------------------
590 ------------ begin $LFS/usr/src/lfs/wrappers/chown ------------------------
591 #!/bin/sh
593 DAISY_CHAIN=""
595 for p in $(type -ap chown) ; do
596   if [ ! $p -ef $0 ]; then DAISY_CHAIN=$p ; break ; fi
597 done
599 if [ ! -n "$DAISY_CHAIN" ]; then
600   echo Cannot find real ${0##*/} command 
601   exit 1
604 if [ $UID == 0 ]; then
605   exec $DAISY_CHAIN "$@"
608 if [ "$1" == "root.root" ]; then
609   echo 1>&2 '***' chown "$@"  
610 else
611   $DAISY_CHAIN "$@" || exit $?
614 exit 0
615 -------------- end $LFS/usr/src/lfs/wrappers/chown ------------------------
617 ------------ begin $LFS/usr/src/lfs/wrappers/install ----------------------
618 #!/bin/sh
620 localedir=/usr/share/locale
621 cmdline="$@"
622 manpagesowner=man-pages
624 DAISY_CHAIN=""
626 for p in $(type -ap install) ; do
627   if [ ! $p -ef $0 ]; then DAISY_CHAIN=$p ; break ; fi
628 done
630 if [ ! -n "$DAISY_CHAIN" ]; then
631   echo Cannot find real ${0##*/} command 
632   exit 1
635 if [ $UID == 0 ]; then
636   exec $DAISY_CHAIN "$@"
640         #********** test if we create directories ********************
641 if [ \( z"$1" = z"-d" \) -o \( z"$1" = z"-m" -a z"$3" = z"-d" \) ]; then  
642   locdirs=""
643   notify=0
644   havedir=0
645   for((i=$#; $i>0; ))
646   do
647     a="$1"
648     shift 1; i=$(($i-1))
649     case "$a" in
650       -o|-g|--owner|--group) notify=1 
651                         shift 1; i=$(($i-1))
652                         set -- "$@" 
653           ;;
654       $localedir/*) if [ ! -d "$a" ]; then
655                       locdirs="$locdirs ""`expr $a : "$localedir/\(.*\)"`" 
656                       set -- "$@" "$a"
657                       havedir=1
658                     else
659                       notify=1
660                       set -- "$@"
661                     fi  
662                    ;;
663       */*|/sbin) if [ ! -d "$a" ]; then 
664              set -- "$@" "$a" 
665              havedir=1
666            else
667              notify=1
668              set -- "$@"
669            fi             
670            ;;
671       *) set -- "$@" "$a" ;;
672     esac
673   done
674   
675   test $notify -eq 1 -o z"$locdirs" != z && \
676                                         echo 1>&2 '***' install "$cmdline"
678   test $havedir -eq 0 && exit 0
680   $DAISY_CHAIN "$@" || exit $?
681   
682   test z"$locdirs" != z &&
683   for dir in $locdirs ; do
684     cumuldir=""
685     for d in `echo $locdirs | sed 's#/# #g' -` ; do
686       cumuldir=$cumuldir$d/
687       if [ -d $localedir/$cumuldir ]; then
688         chgrp install $localedir/$cumuldir
689         chmod g+w,o+t $localedir/$cumuldir
690       fi  
691     done  
692   done
694 else  #if "$1" != "-d"  ,i.e. we do not create directories *****************
695   notify=0
696   for((i=$# ; $i>0; ))
697   do
698     a="$1"
699     shift 1; i=$(($i-1))
700     case "$a" in
701      -m)      set -- "$@" "$a" 
702               a="$1"
703               shift 1; i=$(($i-1))
704               case "$a" in
705                 4755) notify=1 ; set -- "$@" "755" ;;
706                 *) set -- "$@" "$a"  ;;
707               esac
708           ;;
709       -m4755) notify=1 ; set -- "$@" "-m755" ;;
710       -o|-g|--owner|--group)    notify=1 
711                 shift 1; i=$(($i-1))
712                 set -- "$@" 
713           ;;
714       */man/man?/*) 
715                 if [ -e "$a" -a ! -O "$a" ]; then
716                   if [ `find "$a" -printf \%u` = $manpagesowner ]; then
717                     notify=1
718                     set -- "$@" not_installed
719                   else
720                     set -- "$@" "$a"
721                   fi  
722                 else
723                   set -- "$@" "$a"
724                 fi
725           ;;    
726       *) set -- "$@" "$a" ;;
727     esac
728   done
730   test $notify -eq 1 && echo 1>&2 '***' install "$cmdline"
732   $DAISY_CHAIN "$@" || exit $?
735 exit 0
736 ----------- end $LFS/usr/src/lfs/wrappers/install --------------------------
738 If you improve any of these scripts, I would be grateful if you could mail
739 me your changes together with a note saying which package prompted the
740 change. Note that these scripts are supposed to have minimal intrusiveness.
741 So writing a common case "-m*)" instead of the case "-m4755" is undesirable.
742 The scripts should only deal with the problems that have actually been
743 encountered, not all possible problems.
745 #############################################################################
746  LFS specifics
747 #############################################################################
749 For the user name of the package users I always use the name of the package
750 without the version number, including dashes and possibly exceeding 8
751 characters in length, e.g. "util-linux". 
752 Aside from ls -l which chops off the last characters
753 of the user name I have not noticed any problems with this. The other programs
754 I have tested seem to deal with these user names just fine. 
755 If you encounter problems, please report them to me.
757 Now how do we apply the above to the building of an LFS system ?
759 ##########################################################################
760 Pre-chroot phase 
761 ##########################################################################
763 We don't use package users in the pre-chroot phase. This does not mean we
764 install as root. I suggest building the pre-chroot system as a normal user.
765 That way, you can later distinguish files created inside chroot (these
766 have uid 0 or the uid of a package user) and remaining files created during 
767 the pre-chroot phase (these carry the uid of your normal user account on
768 your host system). Building as an ordinary user also protects you against 
769 typos that might otherwise cause a package to overwrite files on your host
770 system.
772 The actual commands of the pre-chroot phase don't need be changed but you
773 have to do some additional things.
774 The first problem is that we need find right after installing glibc inside
775 chroot. The best thing to do is to build a static version during the 
776 pre-chroot phase like this:
778 ./configure --prefix=$LFS/usr --disable-nls &&
779 make LDFLAGS=-static CPPFLAGS=-Dre_max_failures=re_max_f2 &&
780 make libexecdir=$LFS/usr/bin install
782 Another problem is that some programs such as chown can not resolve usernames
783 before glibc is installed. Fortunately most programs accept a numeric UID
784 or GID. There is one nasty exception, though: su. The most fundamental
785 program when using package users doesn't swallow numeric ids :-|
787 Now how do we become a package user before glibc is installed ? 
788 If you guessed that I have a written a script to replace it, you guessed ...
789 ... wrong :-) I have written a C program to replace it. 
791 It just happens that sh-utils
792 contains an su program which is not used in LFS. It gets installed 
793 statically linked during the pre-chroot phase, is never used there (assuming
794 a standard LFS build), gets replaced with a dynamically linked version when 
795 sh-utils is reinstalled and then is finally replaced by the su from shadow 
796 which is the version we will use when the LFS system is finished. So all
797 you need to do is to replace the file src/su.c in the sh-utils source tree
798 with the following file before compiling your chapter 5 sh-utils.
799 Note that if you compile chapter 5 as non-root, you need to issue the command
800 `make install-root' after `make install' or sh-utils won't install su.
802 -------- begin $LFS/usr/src/sh-utils/sh-utils-<version>/src/su.c ------------
803 #include <stdio.h>
804 #include <sys/types.h>
805 #include <unistd.h>
806 #include <stdlib.h>
807 #include <errno.h>
808 #include <string.h>
809 #include <ctype.h>
810 #include <grp.h>
812 #define NUMGIDS 1024
814 int main(int argc,char* argv[])
816   char* Res;
817   char Buffy[4096];
818   uid_t tuid=-1,uid;
819   gid_t gid;
820   int i;
821   FILE* File;
822   char* command=NULL;
823   char* shell;
824   char* HOME;
825   gid_t gid_list[NUMGIDS];
826   ssize_t NumGids=0;
828   if (argc>1) 
829   {
830     if (strcmp(argv[1],"--help")==0) 
831       { fprintf(stdout,"There is no help!\n"); exit(0);}
832     if (strcmp(argv[1],"--version")==0) {fprintf(stdout,"0.6\n"); exit(0); }
833   }
835   if ((argc==4) && (strcmp(argv[2],"-c")==0)) command=argv[3]; else
836   if (argc!=2)
837   {
838     fprintf(stdout,"USAGE: su username|uid [-c command]\n");
839     return 1;
840   };
842   i=0;
843   while(isdigit(argv[1][i])) ++i;
844   if (argv[1][i]==0) tuid=atol(argv[1]);
846   File=fopen("/etc/passwd","rb");
847   if (File==NULL) {perror("/etc/passwd"); return 1;};
848   
849   while(1)
850   {
851     errno=0;
852     Res=fgets(Buffy,1024,File);
853     if (Res==NULL) {
854       if (errno!=0) perror("/etc/passwd"); 
855         else fprintf(stderr,"su: User not found!\n");
856       return 1;
857     };
858     
859     Res=strtok(Buffy,":");
860     if (Res==NULL) continue;
861     strtok(NULL,":");
862     uid=atol(strtok(NULL,":"));
863     gid=atol(strtok(NULL,":"));
864     strtok(NULL,":");
865     HOME=strtok(NULL,":");
866     shell=strtok(NULL,":");
867     if (tuid==uid) {argv[1]=strdup(Buffy); break;}
868     if (strcmp(argv[1],Buffy)==0) break;
869   };
870   HOME=strdup(HOME);
871   shell=strdup(shell);
872   
873   File=fopen("/etc/group","rb");
874   if (File==NULL) {perror("/etc/group"); return 1;};
875   
876   while(1)
877   {
878 ContinueReadingEtcGroup:
879     errno=0;
880     Res=fgets(Buffy,1024,File);
881     if (Res==NULL) {
882       if (errno!=0) {perror("/etc/group"); return 1;} else break;
883     };
884     
885     Res=strtok(Buffy,":,\n");
886     if (Res==NULL) continue;
887     strtok(NULL,":,\n");
888     gid_list[NumGids]=atol(strtok(NULL,":,\n"));
889     Res=strtok(NULL,":,\n");
891     while(Res!=NULL)
892     {
893       if (strcmp(Res,argv[1])==0) 
894       {
895         ++NumGids;
896         if (NumGids>=NUMGIDS) goto SetNewIdentity; 
897                          else goto ContinueReadingEtcGroup;
898       };
899       Res=strtok(NULL,":,\n");
900     };
901   };
903 SetNewIdentity:
904   if (command==NULL) command=shell;
905   setenv("HOME",HOME,1);
906   setgroups(NumGids,gid_list);
907   setgid(gid);
908   setuid(uid);
909   errno=0;
910   i=system(command);
911   if (((i<0) || (i==127)) && (errno!=0)) {perror("/bin/sh"); return 1;};
912   return i;
914 -------- end $LFS/usr/src/sh-utils/sh-utils-<version>/src/su.c ------------
916 This su program accepts user names as well as numeric UIDs. It does its own
917 name resolution using /etc/passwd so it works even without glibc being
918 installed. 
919 Note that sh-utils installs the su program with the setuid bit set. 
920 If you install the pre-chroot system as an ordinary user (which you should 
921 for safety reasons), this will result in a su that doesn't work even when 
922 executed by root. Simply remove the setuid bit like this
924 chmod u-s $LFS/bin/su
926 and su will work fine once we have entered the chroot environment (where
927 we work as root). Note that this allows you to su from root to a package
928 user but not the other way around. If you want to be able to su from a package
929 user to root you will have to make su setuid root 
930 (i.e. chown root.root $LFS/bin/su && chmod u+s $LFS/bin/su). Make sure that
931 you don't keep such an su lying around on a system that others have access to.
932 The above su does not check for a password, so if you make it setuid root,
933 everyone can use it to become root without a password!
936 ##########################################################################  
937  Chroot phase - preparing the LFS system: 
938 ##########################################################################
940 This is the tricky part. Once we
941 have entered chroot, we have to assign install directories to the
942 install group and make them group-writeable. However, since glibc is not
943 yet installed, we can't use user names, yet. Furthermore, groupadd and useradd
944 which are part of the shadow package are not installed, yet.
945 This means that we can't create any package users, at least not without
946 editing /etc/group and /etc/passwd manually. 
947 But don't despair. The following
948 scripts make nice replacements for useradd and groupadd as long as shadow
949 isn't there. Note that they only accept the exact syntax with which the
950 useradd and groupadd commands are used in the add_package_user script.
951 I assume you will be using the install_package/add_package_user scripts to
952 add package users to the system. Here are the scripts:
954 --------------------- begin $LFS/usr/sbin/useradd ----------------------------  
955 #!/bin/sh
956 if [ $# -ne 13 -o z$1 != z-c -o z$3 != z-d -o z$5 != z-g -o z$7 != z-G -o z$9 != z-s -o z${11} != z-u ]; then
957 echo 1>&2 USAGE: useradd -c description -d home -g maingroup -G addgroup -s shell -u uid login 
958 exit 1
961 #test if user already exists
962 grep "^${13}:.*" /etc/passwd 
963 if [ $? -eq 0 ]; then
964   echo 1>&2 $0: User does already exist
965   exit 1
966 fi       
968 g=`grep ^${6}:.\* /etc/group | cut -d : -f 3 -`
969 if [ z${g} = z ]; then
970   echo 1>&2 $0: Group ${6} does not exist!
971   exit 1
974 grep ^${8}:.\* /etc/group >/dev/null || \
976   echo 1>&2 $0: Group ${8} does not exist!
977   exit 1
981 cp /etc/passwd /tmp/passwd123456
982 echo "${13}:x:${12}:$g:$2:$4:/bin/bash" \
983 | sort -t : -k3,3n -m /tmp/passwd123456 - > /etc/passwd
986 cp /etc/group /tmp/group123456
987 sed  -e 's/^\('"${8}"':[^:]*:[0-9]*:..*\)$/\1,'"${13}"'/' \
988      -e 's/^\('"${8}"':[^:]*:[0-9]*\):$/\1:'"${13}"'/' \
989                                                 /tmp/group123456 >/etc/group
990 ---------------------- end $LFS/usr/sbin/useradd ----------------------------  
992 --------------------- begin $LFS/usr/sbin/groupadd --------------------------
993 #!/bin/sh
994 if [ $# -ne 3 -o z$1 != z-g ]; then
995 echo 1>&2 USAGE: groupadd -g gid groupname
996 exit 1
999 #test if group already exists
1000 grep "^${3}:.*" /etc/group 
1001 if [ $? -eq 0 ]; then
1002   echo 1>&2 $0: Group does already exist
1003   exit 1
1004 fi       
1006 cp /etc/group /tmp/group123456
1007 echo ${3}:x:${2}: | sort -t : -k3,3n -m /tmp/group123456 - > /etc/group
1008 --------------------- end $LFS/usr/sbin/groupadd ----------------------------
1010 These scripts overcome the problem of the missing shadow utilities. 
1012 With the above scripts and su program we now have everything we need to
1013 begin our chroot phase. 
1015 ###########################################################################
1016  Tips before you chroot
1017 ###########################################################################
1019 Whenever add_package_user creates a new package user it copies the files
1020 from /etc/skel-package (if you create this directory) to the new package
1021 user's home directory. Symlinks are copied as symlinks.
1022 A useful symlink to place in /etc/skel-package is one like
1024 .bashrc -> /etc/bashrc_package 
1026 with something like the following:
1028 ------------------ begin $LFS/etc/bashrc_package --------------------------
1029 #first load basic configuration to make system work normal
1030 source /etc/bashrc_basic
1032 export PATH=/usr/src/lfs/wrappers:$PATH
1034 #make prompt reflect that we are a package user. Do it via USER_PROMPT_COMMAND
1035 #rather than PROMPT_COMMAND because we want to keep root's prompt if we su to root
1036 export USER_PROMPT_COMMAND='PS1="package \u:"`pwd`"> "'
1038 alias mafobu='make -f /usr/src/lfs/mafobu'
1040 #The following command will put us in the home directory. 
1042 ------------------ end $LFS/etc/bashrc_package ----------------------------
1044 ------------------ begin $LFS/etc/bashrc_basic ----------------------------
1045 #This file should be sourced by all users' .bashrc files
1047 if [ $UID -eq 0 ]; then
1048   export PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin
1049 else
1050   export PATH=/usr/local/bin:/bin:/usr/bin
1053   #set a red prompt when user is root. If a user wants to override this
1054   #s/he should use USER_PROMPT_COMMAND instead of PROMPT_COMMAND in order to 
1055   #keep 
1056   #root's prompt when su'ed to root. If a user wants to change PS1 directly
1057   #s/he should do "unset USER_PROMPT_COMMAND".
1058 export PROMPT_COMMAND='if [ $UID -eq 0 ]; then \
1059   PS1="\[\033[0;31m\]root@\h:"`pwd -P`"# \[\033[0m\]" ; \
1060     else eval $USER_PROMPT_COMMAND ; fi'
1061   #make PROMPT_COMMAND read-only to protect against careless users
1062 declare -r PROMPT_COMMAND
1063   #set a reasonable default USER_PROMPT_COMMAND
1064 export USER_PROMPT_COMMAND='PS1="\u@\h:"`pwd`"> "'
1066   #make keys (del, bs, home, end,...) work normal
1067 export INPUTRC=/etc/inputrc
1068 bind -f $INPUTRC
1069 ------------------ end $LFS/etc/bashrc_basic ------------------------------
1073 Another useful file to place in /etc/skel-package is a .project file like
1074 this:
1076 ------------------ begin $LFS/etc/skel-package/.project ------------------
1077 DESCRIPTION:
1078   bogus package
1079 CONTENTS:
1080   foo,bar,fubar
1081 LAST UPDATED:
1082   30 Feb 2042
1083 DOWNLOAD LOCATION:
1084   ftp://ftp.gnu.org/gnu/foo/
1085 WEB SITE:
1086   <none>
1087 INSTALL NOTES:
1088 GENERAL NOTES:
1089 ----------------- end $LFS/etc/skel-package/.project ------------------
1091 Update this file whenever you re/install a package. It is called .project
1092 so that it is automatically displayed when you issue the command 
1093 "finger <package>" or "pinky -l <package>".
1096 ###########################################################################
1097  Inside the chroot environment
1098 ###########################################################################
1100 After you have chroot'ed do
1102 groupadd -g 10000 install
1104 which will create the install group. Now use 
1106 chown 0.10000 `cat /tmp/installdirs`
1107 chmod ug=rwx,o=rx `cat /tmp/installdirs`
1109 to assign directories to the install group. Note that we do not make the
1110 directories sticky, yet. This is because they still contain files belonging
1111 to root or some unknown user (if you installed pre-chroot as non-root). These
1112 files must be overwriteable. The file /tmp/installdirs is the following list:
1114 ----------------- begin $LFS/tmp/installdirs ------------------------------
1115 /usr/bin
1116 /usr/etc
1117 /usr/sbin
1118 /usr/include
1119 /usr/lib
1120 /usr/man/man?
1121 /usr/doc
1122 /usr/info
1123 /usr/local/man/man?
1124 /usr/local/doc
1125 /usr/share
1126 /usr/share/dict
1127 /usr/share/doc
1128 /usr/share/info
1129 /usr/share/locale
1130 /usr/share/man/man1
1131 /usr/share/man/man2
1132 /usr/share/man/man3
1133 /usr/share/man/man4
1134 /usr/share/man/man5
1135 /usr/share/man/man6
1136 /usr/share/man/man7
1137 /usr/share/man/man8
1138 /usr/share/nls
1139 /usr/share/misc
1140 /usr/share/terminfo
1141 /usr/share/zoneinfo
1142 /usr/share/i18n
1143 /usr/share/aclocal
1144 /usr/local/bin
1145 /usr/local/etc
1146 /usr/local/include
1147 /usr/local/lib
1148 /usr/local/sbin
1149 /usr/local/share
1150 /usr/local/share/dict
1151 /usr/local/share/doc
1152 /usr/local/share/info
1153 /usr/local/share/locale
1154 /usr/local/share/man/man1
1155 /usr/local/share/man/man2
1156 /usr/local/share/man/man3
1157 /usr/local/share/man/man4
1158 /usr/local/share/man/man5
1159 /usr/local/share/man/man6
1160 /usr/local/share/man/man7
1161 /usr/local/share/man/man8
1162 /usr/local/share/nls
1163 /usr/local/share/misc
1164 /usr/local/share/terminfo
1165 /usr/local/share/zoneinfo
1166 /etc
1167 /sbin
1168 /bin
1169 /lib
1170 ----------------- end $LFS/tmp/installdirs --------------------------------
1172 Now do
1174 chown 0.10000 /usr/share/info/dir
1175 chmod ug=rw,o=r /usr/share/info/dir
1177 which makes sure packages can install their info pages. 
1181 #########################################################################
1182  Chroot phase -installing the packages 
1183 #########################################################################
1185 Now we can finally install glibc. Create /dev/null as root by doing
1187 mknod -m 0666 /dev/null c 1 3
1189 then do
1191 install_package "GNU C library" glibc system
1193 which will create the system group and a user glibc and will also su to the new
1194 glibc package user. Note that the mkdir and install wrapper
1195 don't work properly during the installation of glibc because they use
1196 the name "install" rather than the gid. This means we have to do the
1197 following *after* installing glibc:
1199 find /usr/share/locale/* -type d -user glibc -exec chmod ug=rwx,o=rxt \{\} \;\
1200                                          -exec chgrp install \{\} \;
1203 Now do
1205 exit
1207 to become root and begin installing the rest of the packages. Use the command
1209 install_package <description> <packagename> <group>
1211 to create and become the package user. Then unpack in that user's home 
1212 directory and use the guidelines below and the book's directions to 
1213 install each package.
1215 ############################################################################
1216  Group guidelines
1217 ############################################################################
1219 I recommend the following groups for use with package users:
1221 devel: development related stuff, e.g. compilers. This is not restricted to
1222        software development. TeX for instance would belong in this group.
1223        
1224 utils: Most software fits into this category, even somewhat essential software 
1225        like grep or text editors.
1226       
1227 net: network related stuff such as an ftp daemon or a web browser. This
1228      group overlaps with other groups to a large extent. It should be used
1229      in preference of the other groups whenever a package is clearly focused
1230      towards Internet, LAN, WWW,... A utility like wget for instance would
1231      go in net rather than utils. Exceptions from this rule are the groups
1232      docs, addons, games and mmedia. If a package fits into one of those 
1233      groups, use the respective group instead of net.
1234      
1235 docs: Documentation related packages, such as a tarball with Linux howtos.
1236       Note that software to create documentation such as XML processors should
1237       probably go in devel and software to view or post-process documentation
1238       such as man or groff should probably go in utils.
1239       
1240 system: important system software, such as bash. This group should be used
1241         only for really essential packages. Most packages you would put in 
1242         this group are better put into "utils". Vi for instance belongs in 
1243         utils. 
1244         It is unlikely that any package not part of basic LFS belongs in the
1245         system group.
1246         
1247 libs: What utils is for executables, libs is for libraries. Libraries that are
1248       not strongly related to any of the other categories should go here, such
1249       as zlib or libpng.
1250       Essential system libraries such as glibc, ncurses or gettext should
1251       go in system instead.
1252       The libs group is also used for run-time environments such as the
1253       Java Virtual Machine, dosemu and wine. Other emulators like MAME for
1254       instance should probably go into games instead. 
1255      
1256 games: what do you expect ;-)
1258 mmedia: This is the group for audio and video editors, mp3 players etc.
1260 apps: Applications such as spreadsheets and word processors (not text editors)
1261       but also CAD software and graphics software such as Gimp.
1262       The apps group is a bit like utils, but apps are usually more user 
1263       friendly and more streamlined and focused than utils. 
1264       Apps feel less geekish and nerdish than
1265       utils. Emacs for instance belongs in utils, not in apps.
1266       
1267 addons: plugins, filters and similar that are meant to be used in conjunction
1268        with another package.
1269        
1270 x: software that relates to the X Window System in general and does not fit
1271    into any of the other categories, such as the X server itself or window 
1272    managers.
1273    Most X software should be put into other more specific groups.
1274    A game like xmines would go in games for instance and a text editor for
1275    X would go in utils.
1276    
1277 kde: Software that relates to KDE and does not fit into
1278      any other category. This group should be used with care. 
1279      Do *not* use it for all KDE software. K Office for instance belongs in
1280      apps. Konqueror belongs in net.
1281      
1282 gnome: Software that relates to GNOME and does not fit into
1283        any other category. This group should be used with care. 
1284        Do *not* use it for all GNOME software. Gimp for instance belongs 
1285        in apps. A GNOME-aware window manager that works with plain X should
1286        go in the x group.
1288 The following is a list of the LFS packages with the user.group assignments
1289 I think are appropriate. The user name in general should be the name of
1290 the main tarball without extensions and version. The groups try to follow
1291 the guidelines above but sometimes it is hard to find the "correct" group.
1292 The list also contains some notes I made when I installed them. 
1293 If you use the mkdir, chgrp and install wrappers, you should
1294 not have any trouble.
1296 glibc.system:
1297   see above.
1299 MAKEDEV: not installed as a package user
1301 man-pages.docs
1302 findutils.utils
1303 mawk.devel:
1304         rm /usr/bin/mawk /usr/share/man/man1/mawk.1 
1305         as root before `make install'
1306 ncurses.system
1307 vim.utils
1308 ed.utils
1309 gcc.devel:
1310         Before `make install' assign the /usr/lib/gcc-lib and /usr/include/g++
1311         to the gcc package user by doing (as root)
1312           chown -R gcc. /usr/lib/gcc-lib /usr/include/g++
1313 bison.devel
1314 less.utils
1315 groff.utils
1316 man.utils
1317 perl.utils
1318 m4.devel
1319 texinfo.utils
1320 autoconf.devel
1321 automake.devel:
1322         Creates the directory /usr/share/aclocal. This directory is written to
1323         by other packages, so chgrp install and chmod g+w,o+t it.
1325 bash.system:
1326         When ./configure is done as a package user (more precisely when done 
1327         in a su environment), it will fail to detect /dev/stdin. This will 
1328         cause bash to compile an emulation of /dev/std* and /dev/fd/*. 
1329         I actually prefer this emulation because it matches the description 
1330         in the manpage while the normal behaviour (i.e. to open the 
1331         respective device) does not always.  If a normal bash is desired, 
1332         use sed to change configure and replace 
1333         "test -r /dev/stdin" with "test -e /dev/stdin" (same for /dev/fd). 
1334         [ This information is for bash 2.05, I reported the issue so it may
1335         be fixed in future versions. ]
1336 flex.devel
1337 file.utils
1338 libtool.devel
1339 bin86.devel
1340 binutils.devel
1341 bzip2.utils
1342 gettext.system
1343 kbd.system
1344 diffutils.utils
1345 e2fsprogs.utils
1346 fileutils.system
1347 grep.utils
1348 gzip.utils
1349 lilo.system
1350 make.devel:
1351         make wants to be setgid kmem in order for the -l option to work.
1352         If you are not a developer who knows what this option does, you
1353         don't need it and should not give make special privileges.
1354         [UPDATE] On Linux the -l option seems to work even if make is not
1355         setgid kmem.
1357 linux kernel: not installed as package user
1358 modutils.system:
1359         The modutils check if modules are owned by root before using them.
1360         This is the reason why the linux kernel should be compiled and
1361         installed as root, rather than as a package user.
1363 netkit-base.net
1364 patch.utils
1365 procinfo.utils
1366 procps.utils
1367 psmisc.utils
1368 sed.utils
1369 sh-utils.system
1370 net-tools.net
1371 shadow.system:
1372         This package installs quite a few setuid root progs. If you're not
1373         religious about package users you might want to install this one
1374         as root.root to make life easier for yourself.
1375         If you do install as package user don't forget to make the
1376         binaries in question setuid root manually afterwards.
1377         After installing shadow make sure that the useradd and groupadd
1378         scripts have been properly replaced. Execute
1379           find / -maxdepth 3 -name groupadd
1380         to make sure that you don't have 2 copies (e.g. one in /sbin and
1381         one in /usr/sbin)  
1382         
1384 sysklogd.system
1385         This package has /usr/bin/install hardwired, so install with
1386           make INSTALL=install install
1387         to make it use the wrapper.
1389 sysvinit.system:
1390         This one is a bit tricky. You have to create /dev/initctl manually
1391         as root *before* doing "make install" because a package user does
1392         not have permission to write to /dev. So do (as root!!)
1393           rm -f /dev/initctl
1394           mknod -m 600 /dev/initctl p
1396 tar.utils
1397 textutils.utils
1398 util-linux.system:
1399         Don't forget to make mount and umount setuid root manually after
1400         installing this package. And the write program wants to be
1401         setgid tty.
1403 ###########################################################################
1404  Final steps
1405 ###########################################################################
1407 After installing everything, make the install directories sticky:
1409 chmod ug=rwx,o=rxt `cat /tmp/installdirs`
1411 If you installed pre-chroot as a normal user there are now some directories
1412 owned by that user even though they should be owned by a package user. This
1413 happens because the package users in question did not/could not recreate
1414 these directories. The following script will fix that. It works by looking
1415 for directories not owned by a registered user (-nouser option). The list
1416 of these directories is processed in a for loop. For each directory find is
1417 then used to look for all files owned by a registered user and to list those
1418 users. With "sort -u" (unique) we get a list of registered users that have
1419 files in the directory in question and wc tells us how many of these users
1420 there are. If there is only one such user (i.e. all files in the directory
1421 belong either to an unregistered user or the one registered user we 
1422 identified) then we assign the directory to this user.
1424 ----------------- begin $LFS/usr/src/lfs/fixowner -------------------------
1425 #!/bin/sh   
1426 #find all directories owned by an unknown user (i.e. the normal user
1427 #account you installed pre-chroot with, if you installed as a normal
1428 #user) and assign those that have an unambiguous intended owner (i.e.
1429 #only files belonging to a single owner aside from the unknown one
1430 #are found in the directory) to that owner.
1431 get_dir_owners() 
1433   owners=`find $1 -not -nouser -printf "%u\n" | sort -u `
1434   num=`echo $owners | wc -w | tr -d " "`
1437 for dir in `find / -path "/proc" -prune -or -type d -nouser -print` 
1438 do 
1439   get_dir_owners $dir 
1440   if [ $num == 1 ]; then 
1441     chown `echo $owners | tr -d " "`. $dir 
1442     chmod u=rwx,go=rx $dir 
1443     echo "Assigning $dir to $owners"
1444   fi  
1445 done
1446 ----------------- end $LFS/usr/src/lfs/fixowner ---------------------------
1448 Finally you should
1449 use find to find files that still belong to the user you
1450 installed pre-chroot with. You can also use find to identify any directories
1451 that are group-writeable and not sticky. You should also check for setuid
1452 and setgid programs that don't belong to root. Apply your common sense to
1453 deal with these files (or send me a mail so I can mention the issue here).
1455 find / -path "/proc/*" -prune -or -perm +u+s -printf "%p: suid %u\n"
1456 find / -path "/proc/*" -prune -or -perm +g+s -printf "%p: sgid %g\n"
1457 find / -path "/proc/*" -prune -or \
1458        -type d -perm +o+w -not -perm +o+t -printf "%p: world-writeable\n"
1459 find / -path "/proc/*" -prune -or -type d -perm +g+w -not -perm +o+w \
1460                              -not -perm +o+t -printf "%p: group-writeable\n"
1461 find / -path "/proc/*" -prune -or \
1462        -not -type d -not -type l -perm +o+w -printf "%p: world-writeable\n"
1463 find / -path "/proc/*" -prune -or -path "/dev/*" -prune -or \
1464        -not -type d -not -type l -perm +g+w -not -perm +o+w \
1465                                            -printf "%p: group-writeable\n"
1466 find / -path "/proc/*" -prune -or -nouser -printf "%p: unknown user: %u\n"
1467 find / -path "/proc/*" -prune -or -nogroup -printf "%p: unknown group: %g\n"
1471 ###########################################################################
1472  Security issues with NFS
1473 ###########################################################################
1475 If you use the network filesystem NFS, there are some things you need to
1476 look out for when using the package user system described in this hint.
1477 A fundamental security problem with NFS is that it blindly trusts the uid and 
1478 gid of the client. If an attacker can get access to the root account on a
1479 system in your network that is allowed to mount NFS shares from your server,
1480 or if the attacker can attach his own computer to your network, then this
1481 attacker can pretend to be anyone. NFS will happily allow the attacker to
1482 work in the NFS exported directory as any user he wants to be.
1483 The only exception is the root account. By default NFS exports directories 
1484 with the root_squash option that maps all incoming requests from uid 0 to 
1485 anonuid (65534 unless set in /etc/exports) and gid 0 to anongid
1486 (65534 unless set in /etc/exports). This protects files owned by 
1487 root.root. On a normal system this includes most files in /bin, /etc, /lib
1488 and most other directories except /home. If you use the package user scheme,
1489 however, most of these files are owned by package users. These files are
1490 not protected by the root_squash option. 
1491 In order to make NFS exports secure, you have to add the option "all_squash"
1492 to every entry in /etc/exports that exports a directory that contains 
1493 files owned by package users. Note that all_squash is always a good idea
1494 because even systems that don't use package users usually have some programs 
1495 owned by other users such as daemon or bin and other groups such as tty, 
1496 because they need to be setuid or setgid.