January 7, 2004

cgiwrap, OS X, and AppleEvents

Filed under: ResearchAndDevelopment — Ryan Wilcox @ 1:16 am

Sometimes you want a CGI script to run as a different user than what the web server process is running as. This could be for added security, or to allow a certain script to have capabilities you’d never let the web server user have.

Cut back to OS X. In OS 9 and earlier, CGIs were controlled (mostly) by Apple Events. Apple Events were the (primary) Interapplication Communication method on OS 9, and, as a lesser extent, on OS X.

On OS 9, if a web user accessed a CGI script, Apple Events would be dispatched from the webserver to the appropriate CGI, and the CGI would do something. Now, if this was an Applescript CGI, it would (usually) talk to other applications via Apple Events.

In the brave new world of OS X, we have other ways of talking to processes, but some applications (ie: GUI applications) can only talk to external programs via Apple Events.

This poses a problem. Most routines in the Apple Event Manager require a window manager session – except, if you’ve been good, security-savvy admins, the currently logged in user is not the owner of the web server (usually Apache).

There is however a solution…

Apache comes suexec, an application that will run certain CGI scripts as a different user. The disadvantage to suexec is that it has to be compiled when you compile Apache. This requirement assumes you have a forward thinking administrator that thinks about enabling suexec while they’re updating to the latest Apache.

Because of (well founded) security concerns, suexec is compiled off by default (even in the Apache install on OS X).

Seemingly at a dead-end, found cgiwrap. This wonderful piece of software plugs right into an existing Apache installation, correctly executes specified CGI scripts as another user, and is a very useful debugging aid for when your scripts go wrong.

The setup process was fairly easy – the hard part, like so many open-source projects, was deciphering/changing-instructions-for-my-setup/ignoring-parts-that-I-know-won’t-work-on-OSX the documentation. After I had everything set up, I was able to run my Apple Event CGI script as the logged in user – and it worked!

Here then, is how I did it:

Compiling And Setting Up cgiwrap

Download

Download the cgiwrap package, untar it, then go into the newly created directory.

curl http://telia.dl.sourceforge.net/sourceforge/cgiwrap/cgiwrap-3.8.tar.gz > cgiwrap-3.8.tar.gz

tar -xzvf cgiwrap-3.8.tar.gz

cd cgiwrap-3.8

Configure, the first

Now we need to configure the software. However, cgiwrap doesn’t know about OS X, so we have to copy config.guess and config.sub from packages that do understand about OS X. You can go find copies of these files yourself, or download both files here.

After you’ve download and extracted these files, copy them into the cgiwrap-3.8 folder, replacing existing.

Configure, the second

Now, we configure the software:

./configure --with-vhost-override --with-cgi-dir=/Library/WebServer/CGI-Executables/ --with-httpd-user=www --with-install-dir=/Library/WebServer/CGI-Executables

This command sets up cgiwrap to work in the default environment provided by OS X: Apache runs as the ‘www’ user, and the files should be installed in /Library/WebServer/CGI-Executables.

Notice the with-cgi-dir parameter. Currently this value means that cgiwrap will look for CGIs to execute in the the Library/WebServer/CGI-Executables folder of the specified user. This could, of course, be changed, but this seems like a safe place for these scripts (and away from the Sites folder).

Make

Making the software is just like any other piece of unix software. Nothing special to see here.

make
sudo make install

The second make command may give you the following error:

chgrp root /Library/WebServer/CGI-Executables/cgiwrap
chgrp: root: Invalid argument
make: *** [install] Error 1

If so, do the following commands, finishing the install steps manually:

cd /Library/WebServer/CGI-Executables/
chown root cgiwrap
chmod 4755 cgiwrap
ln -s cgiwrap cgiwrapd
ln -s cgiwrap nph-cgiwrap
ln -s cgiwrap nph-cgiwrapd

Configure Apache

Now, we configure Apache to use cgiwrap. Open up /etc/httpd/httpd.conf in your favorite text editor and enter the following lines (and inserting the name the user you want to execute scripts as in the indicated place):

AddHandler cgi-wrapper .cgi
AddHandler cgi-wrapper .py
Action cgi-wrapper /cgi-bin/cgiwrapd

<Directory "/Users/[USER TO EXEC SCRIPTS AS]/Library/WebServer/CGI-Executables/">
Options All
AllowOverride All
</Directory>

You also need to find the following chunk of code in httpd.conf:

<Directory "/Library/WebServer/CGI-Executables">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>

and change the Options line to:

Options FollowSymLinks

Restart Apache

After the editing you’ll have to restart apache. Execute the following commands:

sudo apachectl configtest
sudo apachectl graceful

Home Stretch

One last command to create the directories cgiwrap will look for our scripts in:

mkdir /Users/[USER TO EXEC SCRIPT AS]/Library/WebServer/
mkdir /Users/[USER TO EXEC SCRIPT AS]/Library/WebServer/CGI-Executables

Now We just need to copy a cgi script to /Users/[USER TO EXEC SCRIPT AS]/Library/WebServer/CGI-Executables/ to test your new cgiwrap enabled site out. Make sure this cgi has the permissions of 755.

Now, visit the following URL in your webbrowser, replacing the parts in brackets with things from your setup: http://[localhost]/cgi-bin/cgiwrap/[USER TO EXEC SCRIPT AS]/[THE CGI FILE YOU MOVED].cgi

How cgiwrap works (and what it gives you)

cgiwrap does several (good) things:

Redirects

First it will redirect requests for /cgi-bin/cgiwrap/ to a directory in [USER TO EXEC SCRIPT AS] (or UTESA)’s home directory. A bit of security through obscurity here – while cgiwrap uses the home directory of UTESA, one would think this is hard to find out for a hacker trying to break in. You can use mod_rewrite to rewrite the URL displayed to the user, so they don’t know what (if anything) is going on

Execute As User

Secondly, it executes the requested CGI as UTESA. This means it can do all the things UTESA can – so extra care must be made while writing a cgi-script. (However, only files YOU have access to can get messed up). NOTE: you don’t want to have Admin (or, in unix: wheel) users running cgiwraped scripts. This could be bad. However, if you’re on OS X and writing CGI scripts that require the window manager (scripts that use AppleEvents, as we mentioned at the beginning of this article, for example) having the logged in user execute the cgi scripts is both useful and easy (and required, since most AE calls require an active window manager)

(Securely)

Thirdly, it (seems to?) provide as much security as suexec, without making the site admin recompile Apache themselves

Easier Debugging

Lastly, testing your scripts with cgiwrapd (http://127.0.0.1/cgi-bin/cgiwrapd/[USER TO EXEC SCRIPT AS]/thefile.cgi) gives you WAY more debugging information than the standard apache error log/error message does.

Conclusion

I hope this entry is helpful to those people trying to run Apache servers on OS X – especially my fellow CGI coders that require AppleEvents for their work.

Updated 01-16-04 to include the following:

  • Commands to make the /Users/[USER To..]/Library/ directories needed
  • Added some missed options from the httpd.conf file
  • Fixed non-html encoded entities (now encoded)
  • Added additional commands to execute if make install fails

2 Comments

  1. OSX and cgiwrap

    I’ve had one heck of a time trying to make my MT installation a little more secure. As it turns out, I can’t find the…

    Trackback by This OldWorld Mac — April 29, 2004 @ 9:36 am

  2. Mac OSX 10.3, Apache2 and cgiwrap – A How To

    Having found only one good resource on the topic of setting up cgiwrap to work under Panther, this little tutorial is for those who are in the same boat as myself.

    Trackback by jim mitchell designs — August 15, 2004 @ 1:03 am

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.