rpm  4.10.0
rpmsign.c
Go to the documentation of this file.
00001 #include "system.h"
00002 #include <errno.h>
00003 #include <sys/wait.h>
00004 
00005 #include <popt.h>
00006 #include <rpm/rpmcli.h>
00007 #include <rpm/rpmsign.h>
00008 #include "cliutils.h"
00009 #include "debug.h"
00010 
00011 #if !defined(__GLIBC__) && !defined(__APPLE__)
00012 char ** environ = NULL;
00013 #endif
00014 
00015 enum modes {
00016     MODE_ADDSIGN = (1 << 0),
00017     MODE_RESIGN  = (1 << 1),
00018     MODE_DELSIGN = (1 << 2),
00019 };
00020 
00021 static int mode = 0;
00022 
00023 static struct poptOption signOptsTable[] = {
00024     { "addsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_ADDSIGN,
00025         N_("sign package(s)"), NULL },
00026     { "resign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_RESIGN,
00027         N_("sign package(s) (identical to --addsign)"), NULL },
00028     { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
00029         N_("delete package signatures"), NULL },
00030     POPT_TABLEEND
00031 };
00032 
00033 static struct poptOption optionsTable[] = {
00034     { NULL, '\0', POPT_ARG_INCLUDE_TABLE, signOptsTable, 0,
00035         N_("Signature options:"), NULL },
00036     { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
00037         N_("Common options for all rpm modes and executables:"), NULL },
00038 
00039     POPT_AUTOALIAS
00040     POPT_AUTOHELP
00041     POPT_TABLEEND
00042 };
00043 
00044 static int checkPassPhrase(const char * passPhrase)
00045 {
00046     int passPhrasePipe[2];
00047     int pid, status;
00048     int rc;
00049     int xx;
00050 
00051     if (passPhrase == NULL)
00052         return -1;
00053 
00054     passPhrasePipe[0] = passPhrasePipe[1] = 0;
00055     xx = pipe(passPhrasePipe);
00056     if (!(pid = fork())) {
00057         char * cmd, * gpg_path;
00058         char *const *av;
00059         int fdno;
00060 
00061         xx = close(STDIN_FILENO);
00062         xx = close(STDOUT_FILENO);
00063         xx = close(passPhrasePipe[1]);
00064         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00065             xx = dup2(fdno, STDIN_FILENO);
00066             xx = close(fdno);
00067         }
00068         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00069             xx = dup2(fdno, STDOUT_FILENO);
00070             xx = close(fdno);
00071         }
00072         xx = dup2(passPhrasePipe[0], 3);
00073 
00074         unsetenv("MALLOC_CHECK_");
00075         gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00076 
00077         if (!rstreq(gpg_path, ""))
00078             setenv("GNUPGHOME", gpg_path, 1);
00079         
00080         cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00081         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00082         if (!rc)
00083             rc = execve(av[0], av+1, environ);
00084 
00085         fprintf(stderr, _("Could not exec %s: %s\n"), "gpg",
00086                     strerror(errno));
00087         _exit(EXIT_FAILURE);
00088     }
00089 
00090     xx = close(passPhrasePipe[0]);
00091     xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
00092     xx = write(passPhrasePipe[1], "\n", 1);
00093     xx = close(passPhrasePipe[1]);
00094 
00095     (void) waitpid(pid, &status, 0);
00096 
00097     return ((WIFEXITED(status) && WEXITSTATUS(status) == 0)) ? 0 : 1;
00098 }
00099 
00100 /* TODO: permit overriding macro setup on the command line */
00101 static int doSign(poptContext optCon)
00102 {
00103     int rc = EXIT_FAILURE;
00104     char * passPhrase = NULL;
00105     char * name = rpmExpand("%{?_gpg_name}", NULL);
00106 
00107     if (rstreq(name, "")) {
00108         fprintf(stderr, _("You must set \"%%_gpg_name\" in your macro file\n"));
00109         goto exit;
00110     }
00111 
00112     /* XXX FIXME: eliminate obsolete getpass() usage */
00113     passPhrase = getpass(_("Enter pass phrase: "));
00114     passPhrase = (passPhrase != NULL) ? rstrdup(passPhrase) : NULL;
00115     if (checkPassPhrase(passPhrase) == 0) {
00116         const char *arg;
00117         fprintf(stderr, _("Pass phrase is good.\n"));
00118         rc = 0;
00119         while ((arg = poptGetArg(optCon)) != NULL) {
00120             rc += rpmPkgSign(arg, NULL, passPhrase);
00121         }
00122     } else {
00123         fprintf(stderr, _("Pass phrase check failed or gpg key expired\n"));
00124     }
00125 
00126 exit:
00127     free(passPhrase);
00128     free(name);
00129     return rc;
00130 }
00131 
00132 int main(int argc, char *argv[])
00133 {
00134     int ec = EXIT_FAILURE;
00135     poptContext optCon = rpmcliInit(argc, argv, optionsTable);
00136     const char *arg;
00137     
00138     if (argc <= 1) {
00139         printUsage(optCon, stderr, 0);
00140         goto exit;
00141     }
00142 
00143     if (poptPeekArg(optCon) == NULL) {
00144         argerror(_("no arguments given"));
00145     }
00146 
00147     switch (mode) {
00148     case MODE_ADDSIGN:
00149     case MODE_RESIGN:
00150         ec = doSign(optCon);
00151         break;
00152     case MODE_DELSIGN:
00153         ec = 0;
00154         while ((arg = poptGetArg(optCon)) != NULL) {
00155             ec += rpmPkgDelSign(arg);
00156         }
00157         break;
00158     default:
00159         argerror(_("only one major mode may be specified"));
00160         break;
00161     }
00162 
00163 exit:
00164     rpmcliFini(optCon);
00165     return ec;
00166 }