Fixing rpmsign with evil magic

At my office we are developing a deployment mechanism for RPM packages. The general workflow looks like this:

  • You build a source rpm on your own machine.
  • You sign the rpm with your GPG key.
  • You submit the source RPM to our buildserver.
  • The buildserver validates your signature and then builds the package.
  • The buildserver signs the package using a master signing key.

The last step in that sequence represents a problem, because the rpmsign command will always, always prompt for a password and read the response from /dev/tty. This means that (a) you can’t easily provide the password on stdin, and (b) you can’t fix the problem using a passwordless key.

Other people have solved this problem using expect, but I’ve opted for another solution which in some ways seems cleaner and in others seems like a terrible idea: function interposition using LD_PRELOAD.

The rpmsign command prompts for (and reads) a password using the getpass() function call. If you look at the getpass(3) man page, you’ll see that the function is defined like this:

#include <unistd.h>
char *getpass( const char *prompt); 

So we start with the following short block of C code:

#include <stdio.h>
#include <unistd.h>

char *getpass( const char *prompt) {
 return "";

This – when properly loaded – will replace the standard C library getpass() function with our own version, which simply returns an empty string. This of course means we’ll be using a passwordless key, but you could obviously have our replacement function return an actual password instead of an empty string. I would argue that by doing so you would not substantially increase the security of your solution.

Next we create a shared library:

$ cc -fPIC -g   -c -o getpass.o getpass.c
$ ld -shared -o getpass.o

And now we perform our magic:

$ LD_PRELOAD=$(pwd)/ rpmsign --addsign some.src.rpm
Pass phrase is good.

And voila! A solution for operating rpmsign in batch mode.