Hi,

I have code that sets uid after I start it as root. I have a user A
that owns a key, and I su - to root. Then I do:
./simple-signer <my key name> '<data to sign>'  A
In this case, gpgme does not find the key for user A.

However, if I run the following as user A:
./simple-signer <my key name> '<data to sign>'
gpgme finds the key for user A.

I am attaching my code, for reference. My question is : do I need to
do something that will enable gpgme to find the key when I run my code
as root?

Thanks,
Kaustubh

-- 
Kaustubh Gadkari
kaustubh [dot] gadkari [at] gmail [dot] com
#include <stdio.h>
#include <gpgme.h>
#include <gpg-error.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <locale.h>
#include <pwd.h>
#include <stdlib.h>
#include <pwd.h>

#include <string>

using namespace std;

void _usage()
{
  fprintf(stdout, "simpl-signer <key ID> <data to sign> [<user name to switch to>]\n");
}

gpgme_error_t bb_cb(void *p_pHook, const char *p_pUidHint, const char *p_pPassphraseInfo, int p_iPrevWasBad, int p_iFd)
{
  int iRet = GPG_ERR_CANCELED;
  const char *szP = getpass("PP> ");
  if (NULL != szP)
  {
    write(p_iFd, szP, strlen(szP));
    write(p_iFd, "\n", 1);
    iRet = 0;
  }

  return iRet;
}

int main(int argc, char *argv[])
{
  int iRet = 0;
  bool bRet = false;

  if (argc < 2)
  {
    fprintf(stderr, "Unable to run w/o a key name.\n");
    _usage();
    exit(1);
  }
  else if (argc < 3)
  {
    fprintf(stderr, "Unable to sign w/o something to sign.\n");
    _usage();
    exit(1);
  }


  string sKey = argv[1];
  string sData = argv[2];
  string sOutputSig;

  if (argc > 3)
  {
    if (getuid() != 0)
    {
      fprintf(stderr, "Can't setuid() if not root.\n");
    }
    else
    {
      struct passwd *pPass = getpwnam(argv[3]);
      if (NULL == pPass)
      {
        fprintf(stderr, "Can't find user: '%s'\n", argv[3]);
      }
      else if (setuid(pPass->pw_uid) < 0)
      {
        fprintf(stderr, "Can't setuid(): '%s'\n", strerror(errno));
      }
      else
      {
        fprintf(stdout, "UID is now: %d\n", getuid());
      }
    }
  }

  gpgme_ctx_t pGpgmeCtx;
  gpgme_engine_info_t pEngInfo = NULL;
  const char *szProto = NULL;
  gpg_error_t tErr;
  const char *szVersion = NULL;
  gpgme_key_t tKey;

  szVersion = gpgme_check_version(NULL);
  setlocale(LC_ALL, "");
  gpg_err_init();
  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
  if (GPG_ERR_NO_ERROR != (tErr = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP)))
  {
    fprintf(stderr, "GPG engine doesn't seem to support OpenPGP protocol: '%s'\n", gpg_strerror(tErr));
  }
  else if (GPG_ERR_NO_ERROR != (tErr = gpgme_new(&pGpgmeCtx)))
  {
    fprintf(stderr, "Unable to get GPG context: '%s'\n", gpg_strerror(tErr));
  }
  else if (GPG_ERR_NO_ERROR != (tErr = gpgme_set_protocol(pGpgmeCtx, GPGME_PROTOCOL_OpenPGP)))
  {
    fprintf(stderr, "Unable to set protocol to OpenPGP: '%s'\n", gpg_strerror(tErr));
  }
  else if (NULL == (szProto = gpgme_get_protocol_name(GPGME_PROTOCOL_OpenPGP)))
  {
    fprintf(stderr, "Unable to get protocol name, but protocol exists for OpenPGP?\n");
  }
  else if (GPG_ERR_NO_ERROR != (tErr = gpgme_get_engine_info(&pEngInfo)))
  {
    fprintf(stderr, "Unable to get engine info: '%s'\n", gpg_strerror(tErr));
  }
  else if (GPG_ERR_NO_ERROR != (tErr = gpgme_ctx_set_engine_info(pGpgmeCtx,
                                                         GPGME_PROTOCOL_OpenPGP,
                                                         pEngInfo->file_name,
                                                         pEngInfo->home_dir)))
  {
    fprintf(stderr, "Unable to set engine info in context: '%s'\n", gpg_strerror(tErr));
  }
  else if (0 != (tErr = gpgme_get_key(pGpgmeCtx, sKey.c_str(), &tKey, 1))
           || NULL == tKey)
  {
    fprintf(stderr, "Error while getting key with ID: '%s': [%d] %s\n", sKey.c_str(), tErr, gpgme_strerror(tErr));
  }
  else if (0 != (tErr = gpgme_signers_add(pGpgmeCtx, tKey)))
  {
    fprintf(stderr, "Error while adding signor key for ID: '%s': [%d] %s\n", sKey.c_str(), tErr, gpgme_strerror(tErr));
    gpgme_key_unref(tKey);
  }
  else
  {
    gpgme_set_armor(pGpgmeCtx, 1);
    gpgme_set_passphrase_cb(pGpgmeCtx, bb_cb, NULL);
    gpgme_key_unref(tKey);
    bRet = true;
  }

  if (bRet)
  {
    ssize_t lRet = 0;
    size_t uDataSize = sData.size();
    off_t tCurr = 0;
    gpgme_error_t tErr;
    gpgme_data_t tData;
    gpgme_data_t tSig;
    gpgme_sig_mode_t tMode = GPGME_SIG_MODE_DETACH;
    if (GPG_ERR_NO_ERROR != (tErr = gpgme_data_new(&tData)))
    {
      fprintf(stderr, "Unable to create data buffer: '%s'\n", gpgme_strerror(tErr));
      bRet = false;
    }
    else if (GPG_ERR_NO_ERROR != (tErr = gpgme_data_new(&tSig)))
    {
      fprintf(stderr, "Unable to create signature buffer: '%s'\n", gpgme_strerror(tErr));
      gpgme_data_release(tData);
      bRet = false;
    }
    else if (-1 == (lRet = gpgme_data_write(tData, sData.c_str(), uDataSize))
             || uDataSize != (size_t) lRet
             || 0 != (lRet = gpgme_data_seek(tData, 0, SEEK_SET)))
    {
      fprintf(stderr, "Unable to write data: %d: %s\n", lRet, strerror(errno));
      gpgme_data_release(tData);
      gpgme_data_release(tSig);
      bRet = false;
    }
    else if (GPG_ERR_NO_ERROR != (tErr = gpgme_op_sign(pGpgmeCtx, tData, tSig, tMode)))
    {
      fprintf(stderr, "Unable to sign: '%s'\n", gpg_strerror(tErr));
      gpgme_data_release(tData);
      gpgme_data_release(tSig);
      bRet = false;
    }
    else if ((tCurr = gpgme_data_seek(tSig, 0, SEEK_CUR)) <= 0)
    {
      fprintf(stderr, "Unable to get sig's current offset: '%s'\n", strerror(errno));
      gpgme_data_release(tData);
      gpgme_data_release(tSig);
      bRet = false;
    }
    else
    {
      char *pBuff = new char[tCurr + 1];
      memset(pBuff, 0, tCurr + 1);
      gpgme_data_seek(tSig, 0, SEEK_SET);

      int iErr = gpgme_data_read(tSig, pBuff, tCurr);
      if (iErr <= 0)
      {
        fprintf(stderr, "Unable to read new signature: '%s'\n", strerror(errno));
        bRet = false;
      }
      else
      {
        sOutputSig = pBuff;
        fprintf(stdout, "The sig for: '%s' is '%s'\n", sData.c_str(), sOutputSig.c_str());
        bRet = true;
      }

      gpgme_data_seek(tData, 0, SEEK_SET);
      gpgme_data_seek(tSig, 0, SEEK_SET);
      gpgme_data_release(tData);
      gpgme_data_release(tSig);
      delete[] pBuff;
    }
  }

  gpgme_release(pGpgmeCtx);
  return iRet;
}

_______________________________________________
Gnupg-users mailing list
Gnupg-users@gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-users

Reply via email to