In this section, we describe the reasons for writing your own wrappers. In most cases, you won't need to write your own wrappers; you'll find that the standard UNIX wrappers will suit most situations.
A typical case in which you might want to build a wrapper yourself is when there is a report of a new bug in some existing software on your system that is triggered or aggravated when an environment variable or input is uncontrolled. By writing a small wrapper, you can filter what reaches the real program, and you can reset its environment. The software can thus continue to be used until such time as your vendor releases a formal patch.
The code in Example 22-2 is an example of such a wrapper. It was originally written by Wietse Venema and released as part of CERT Advisory 11, in 1992. An unexpected interaction between Sun Microsystems' shared library implementation and various SUID and SGID programs could result in unauthorized privileges being granted to users. The temporary fix to the problem was to put a wrapper program around susceptible programs (such as the sendmail program) to filter out environment variables that referenced unauthorized shared libraries - those variables beginning with the characters "LD_".
/* Start of C program source */ /* Change the next line to reflect the full pathname of the file to be protected by the wrapper code */ #define COMMAND "/usr/lib/sendmail.dist" #define VAR_NAME "LD_" main(argc,argv,envp) int argc; char **argv; char **envp; { register char **cpp; register char **xpp; register char *cp; for (cpp = envp; cp = *cpp;) { if (strncmp(cp, VAR_NAME, strlen(VAR_NAME))==0) { for (xpp = cpp; xpp[0] = xpp[1]; xpp++){ } /* void */ ; } else { cpp++; } } execv(COMMAND, argv); perror(COMMAND); exit(1); } /* End of C program source */
To use this code, you would compile it, move the original sendmail to a safe location, and then install the wrapper in place of the real program. For the example above, for instance, you would issue the following commands as the superuser:
# make wrapper # mv /usr/lib/sendmail /usr/lib/sendmail.dist # chmod 100 /usr/lib/sendmail.dist # mv ./wrapper /usr/lib/sendmail # chown root /usr/lib/sendmail # chmod 4711 /usr/lib/sendmail
Another case in which you might want to build your own wrapper code is when you wish to do some extra logging of a program execution, or to perform additional authentication of a user. The use of a wrapper allows you to do this without modifying the underlying code.
Suppose you suspect some user of your system of misusing the system's printer. You wish to gain some additional log information to help you determine what is being done. So, you might use a wrapper such as the one in Example 22.3.
/* Start of C program source */ /* Change the next line to reflect the full pathname of the file to be protected by the wrapper code */ #define COMMAND "/usr/lib/.hidden/lpr" #include <syslog.h> main(argc,argv,envp) int argc; char **argv, **envp; { int iloop; openlog("xtra-log", LOG_PID, LOG_LPR); syslog(LOG_INFO, "lpr invoked with %d arguments", argc); for (iloop = 1; i loop < argc; iloop++){ if(strlen(argv[iloop])>1023) argv[iloop][1023]=0; syslog(LOG_INFO, "arg %d is `%s'", argv[iloop]); } syslog(LOG_INFO, "uid is %d", getuid()); closelog(); execv(COMMAND, argv); perror(COMMAND); exit(1); } /* End of C program source */
To use this code, you follow the same basic steps as in the previous example: you compile the code, make the hidden directory, move the original lpr to a safe location, and then install the wrapper in place of the real program. For this example, you might issue the following commands as the superuser:
# make wrapper # mkdir /usr/lib/.hidden # chmod 700 /usr/lib/.hidden # mv /usr/bin/lpr /usr/lib/.hidden/lpr # chmod 100 /usr/lib/.hidden/lpr # mv ./wrapper /usr/bin/lpr # chown root /usr/bin/lpr # chmod 4711 /usr/bin/lpr
Now, whenever someone executes the lpr command, you will find a copy of the arguments and other useful information in the syslog. See Chapter 10, Auditing and Logging, for more information on syslog and other logging facilities.
The above example can be modified in various ways to do other logging, change directories, or perform other checks and changes that might be necessary for what you want to do.
You can also adopt the concept we've discussed to put a wrapper around shell files you want to make SUID. As we noted in Chapter 5, The UNIX Filesystem, on most older UNIX systems, SUID shell files are a security problem. You can create a wrapper that is SUID, cleans up the environment (including resetting the PATH variable, and removing IFS), and then exec's the shell file from a protected directory. In this way, you'll get all of the benefits of a SUID shell file, and fewer (but, alas, still some) of the dangers.