|Maximum RPM: Taking the Red Hat Package Manager to the Limit|
|Prev||Chapter 16. Making a Package That Can Build Anywhere||Next|
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>
The <mode> is represented in traditional numeric fashion.
The <user> is specified by the login name of the user. Numeric UIDs are not used, for reasons we'll explore in a moment.
The <group> is specified by the group's name, as entered in /etc/group. Numeric GIDs are not used, either. Yes, we'll be discussing that, too!
<file> represents the file. Shell-style globbing is supported.
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.
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 line — in 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 rot 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, it looks like /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* #
RPM did just what it was supposed to — It gave the files the attributes specified by the %attr macros.
At the start of this section, we mentioned that the %attr macro wouldn't accept numeric uids or gids, and we promised to explain why. The reason is simply that, even if a package requires a certain user or group to own the package's files, the user may not have the same uid/gid from system to system. There — wasn't that simple?
In the next chapter, we'll discuss how to make your packaged software safe against modification by unscrupulous people. The name of the game is Pretty Good Privacy, and you'll see how signing packages with PGP is easier than you think!