-->
Page 232
+ umask 022 Executing: %prep + cd /home/ed/mybuild/BUILD + cd /home/ed/mybuild/BUILD + rm -rf cdplayer-1.0 + gzip -dc /home/ed/mybuild/SOURCES/cdplayer-1.0.tgz + tar -xvvf - drwxrwxr-x root/users 0 Aug 20 20:58 1996 cdplayer-1.0/ -rw-r--r-- root/users 17982 Nov 10 01:10 1995 cdplayer-1.0/COPYING ... + cd /home/ed/mybuild/BUILD/cdplayer-1.0 + chmod -R a+rX,g-w,o-w . + exit 0 Executing: %build + cd /home/ed/mybuild/BUILD + cd cdplayer-1.0 + make gcc -Wall -O2 -c -I/usr/include/ncurses cdp.c ... Executing: %install + cd /home/ed/mybuild/BUILD + make ROOT=/home/ed/mybuildroot/cdplayer install install -m 755 -o 0 -g 0 -d /home/ed/mybuildroot/cdplayer/usr/local/bin/ install: /home/ed/mybuildroot/cdplayer: Operation not permitted install: /home/ed/mybuildroot/cdplayer/usr: Operation not permitted install: /home/ed/mybuildroot/cdplayer/usr/local: Operation not permitted install: /home/ed/mybuildroot/cdplayer/usr/local/bin: Operation not permitted install: /home/ed/mybuildroot/cdplayer/usr/local/bin/: Operation not permitted make: *** [install] Error 1 Bad exit status %
Things started out pretty well. The %prep section of the spec file unpacked the sources into the new build area, as did the %build section. The build was proceeding normally in the user-specified build area, and root access was not required. In the %install section, however, things started to fall apart. What happened?
Take a look at that install command. The two options, -o 0 and -g 0, dictate that the directories to be created in the build root are to be owned by the root account. Since the user performing this build did not have root access, the install failed, and rightly so.
Okay, let's remove the offending options and see where that gets us. Here's the install section of the makefile after our modifications:
install: cdp cdp.1.Z install -m 755 -d $(ROOT)/usr/local/bin/ install -m 755 cdp $(ROOT)/usr/local/bin/cdp rm -f $(ROOT)/usr/local/bin/cdplay ln -s ./cdp $(ROOT)/usr/local/bin/cdplay install -m 755 -d $(ROOT)/usr/local/man/man1/ install -m 755 cdp.1 $(ROOT)/usr/local/man/man1/cdp.1
We'll spare you having to read through another build, but this time it completed successfully. Now, let's put our sysadmin hat on and install the newly built package:
Page 233
# rpm -ivh cdplayer-1.0-1.i386.rpm cdplayer ################################################## #
Well, that was easy enough. Let's take a look at some of the files and make sure everything looks okay. We know there are some files installed in /usr/local/bin, so let's check those:
# ls -al /usr/local/bin -rwxr-xr-x 1 ed ed 40739 Sep 13 20:16 cdp* lrwxrwxrwx 1 ed ed 47 Sep 13 20:34 cdplay -> ./cdp* #
Looks pretty good. Wait a minute! What's up with the owner and group? The answer is simple: User ed ran the build, which executed the makefile, which ran install, which created the files. Since ed created the files, they are owned by him.
This brings up an interesting point. Software must be installed with very specific file ownership and permissions. But a nonroot user can't create files that are owned by anyone other than himself or herself. What is a nonroot user to do?
In cases where the package builder cannot create the files to be packaged with the proper ownership and permissions, the %attr macro can be used to make things right.
The %attr macro has the following format:
%attr(<mode>, <user>, <group>) <file>
There are a couple other wrinkles to using the %attr macro. If a particular file attribute doesn't need to be specified, that attribute can be replaced with a dash (-), and %attr will not change it. Say, for instance, that a package's files are installed with the permissions correctly set, as they almost always are. Instead of having to go to the trouble of entering the permissions for each and every file, each file can have the same %attr:
%attr(-, root, root)
This works for user and group specifications, as well.
Page 234
The other wrinkle is that although we've been showing the three file attributes separated by commas, in reality they could be separated by spaces as well. Whichever delimiter you choose, it pays to be consistent throughout a spec file.
Let's fix up cdplayer with a liberal sprinkling of %attrs. Here's what the %files list looks like after we've had our way with it:
%files %attr(-, root, root) %doc README %attr(4755, root, root) /usr/local/bin/cdp %attr(-, root, root) /usr/local/bin/cdplay %attr(-, root, rot) /usr/local/man/man1/cdp.1
A couple points are worth noting here. The line for README shows that multiple macros can be used on a linein this case, one to set file attributes and one to mark the file as being documentation. The %attr for /usr/local/bin/cdp declares the file to be setuid root. If it sends a shiver down your spine to know that anybody can create a package that will run setuid root when installed on your system, good! Just because RPM makes it easy to install software doesn't mean that you should blindly install every package you find.
A single RPM command can quickly point out areas of potential problems and should be issued on any package file whose creators you don't trust:
% rpm -qlvp ../RPMS/i386/cdplayer-1.0-1.i386.rpm drwxr-xr-x- root root 1024 Sep 13 20:16 /usr/doc/cdplayer-1.0-1 -rw-r--r-- root root 1085 Nov 10 01:10 /usr/doc/cdplayer-1.0-1/README -rwsr-xr-x- root root 40739 Sep 13 21:32 /usr/local/bin/cdp lrwxrwxrwx- root root 47 Sep 13 21:32 /usr/local/bin/cdplay -> ./cdp -rwxr-xr-x- root root 4550 Sep 13 21:32 /usr/local/man/man1/cdp.1 %
Sure enough. There's that setuid root file. In this case we trust the package builder, so let's install it:
# rpm -ivh cdplayer-1.0-1.i386.rpm cdplayer ################################################## group rot does not exist - using root #
What's this about group rot? Looking back at the rpm -qlvp output, you can see that /usr/local/man/man1/cdp.1 has a bogus group. Looking back even further, it's there in the %attr for that file. Must have been a typo. We could pretend that RPM used advanced artificial intelligence technology to come to the same conclusion as we did and made the appropriate change, but, in reality, RPM simply used the only group identifier it could count on: root. RPM will do the same thing if it can't resolve a user specification.
Let's look at some of the files the package installed, including that worrisome setuid root file:
# ls /usr/local/bin total 558 -rwsr-xr-x 1 root root 40739 Sep 13 21:32 cdp* lrwxrwxrwx 1 root root 47 Sep 13 21:36 cdplay -> ./cdp* #