mirror of https://github.com/vmware/tdnf.git
453 lines
11 KiB
C
453 lines
11 KiB
C
/*
|
|
* Copyright (C) 2015-2023 VMware, Inc. All Rights Reserved.
|
|
*
|
|
* Licensed under the GNU Lesser General Public License v2.1 (the "License");
|
|
* you may not use this file except in compliance with the License. The terms
|
|
* of the License are located in the COPYING file of this distribution.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
uint32_t
|
|
TDNFGPGCheck(
|
|
rpmts pTS,
|
|
const char* pszKeyFile,
|
|
const char* pszPkgFile
|
|
)
|
|
{
|
|
uint32_t dwError = 0;
|
|
rpmKeyring pKeyring = NULL;
|
|
FD_t fp = NULL;
|
|
|
|
if(!pTS || IsNullOrEmptyString(pszKeyFile) || !pszPkgFile)
|
|
{
|
|
dwError = ERROR_TDNF_INVALID_PARAMETER;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
fp = Fopen(pszPkgFile, "r.ufdio");
|
|
if (fp == NULL) {
|
|
dwError = errno;
|
|
BAIL_ON_TDNF_SYSTEM_ERROR(dwError);
|
|
}
|
|
|
|
pKeyring = rpmtsGetKeyring(pTS, 0);
|
|
if (pKeyring == NULL) {
|
|
pr_err("failed to get RPM keyring");
|
|
dwError = ERROR_TDNF_INVALID_PARAMETER;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = AddKeyFileToKeyring(pszKeyFile, pKeyring);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if (rpmVerifySignatures(
|
|
/* unused but must be != NULL, see lib/rpmchecksig.c in rpm */ (QVA_t)1,
|
|
pTS, fp, pszPkgFile) != 0)
|
|
{
|
|
dwError = ERROR_TDNF_RPM_GPG_NO_MATCH;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
cleanup:
|
|
if(fp)
|
|
{
|
|
Fclose(fp);
|
|
}
|
|
return dwError;
|
|
|
|
error:
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t
|
|
ReadGPGKeyFile(
|
|
const char* pszFile,
|
|
char** ppszKeyData,
|
|
int* pnSize
|
|
)
|
|
{
|
|
uint32_t dwError = 0;
|
|
char* pszKeyData = NULL;
|
|
int nPathIsDir = 0;
|
|
char* pszScheme = NULL;
|
|
|
|
if(IsNullOrEmptyString(pszFile) || !ppszKeyData || !pnSize)
|
|
{
|
|
dwError = ERROR_TDNF_INVALID_PARAMETER;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = TDNFIsDir(pszFile, &nPathIsDir);
|
|
if(dwError)
|
|
{
|
|
pr_err("Error: Accessing gpgkey at %s\n",
|
|
pszFile);
|
|
}
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if(nPathIsDir)
|
|
{
|
|
dwError = ERROR_TDNF_KEYURL_INVALID;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = TDNFFileReadAllText(pszFile, &pszKeyData, pnSize);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
*ppszKeyData = pszKeyData;
|
|
|
|
cleanup:
|
|
TDNF_SAFE_FREE_MEMORY(pszScheme);
|
|
return dwError;
|
|
|
|
error:
|
|
TDNF_SAFE_FREE_MEMORY(pszKeyData);
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t
|
|
AddKeyFileToKeyring(
|
|
const char* pszFile,
|
|
rpmKeyring pKeyring
|
|
)
|
|
{
|
|
uint32_t dwError = 0;
|
|
|
|
int subkeysCount, i;
|
|
rpmPubkey *subkeys = NULL;
|
|
rpmPubkey key = NULL;
|
|
|
|
if(IsNullOrEmptyString(pszFile) || !pKeyring)
|
|
{
|
|
dwError = ERROR_TDNF_INVALID_PARAMETER;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
key = rpmPubkeyRead(pszFile);
|
|
if (key == NULL) {
|
|
pr_err("reading %s failed: %s (%d)", pszFile, strerror(errno), errno);
|
|
dwError = ERROR_TDNF_INVALID_PUBKEY_FILE;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
if (rpmKeyringAddKey(pKeyring, key) == 0) {
|
|
pr_info("added key %s to keyring");
|
|
}
|
|
subkeys = rpmGetSubkeys(key, &subkeysCount);
|
|
rpmPubkeyFree(key);
|
|
for (i = 0; i < subkeysCount; i++) {
|
|
rpmPubkey subkey = subkeys[i];
|
|
|
|
if (rpmKeyringAddKey(pKeyring, subkey) == 0) {
|
|
pr_info("added subkey %d of main key %s to keyring\n", i, pszFile);
|
|
}
|
|
rpmPubkeyFree(subkey);
|
|
}
|
|
|
|
cleanup:
|
|
if (subkeys)
|
|
free(subkeys);
|
|
return dwError;
|
|
error:
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t
|
|
TDNFImportGPGKeyFile(
|
|
rpmts pTS,
|
|
const char* pszFile
|
|
)
|
|
{
|
|
uint32_t dwError = 0;
|
|
uint8_t* pPkt = NULL;
|
|
size_t nPktLen = 0;
|
|
char* pszKeyData = NULL;
|
|
int nKeyDataSize;
|
|
int nKeys = 0;
|
|
int nOffset = 0;
|
|
|
|
if(pTS == NULL || IsNullOrEmptyString(pszFile))
|
|
{
|
|
dwError = ERROR_TDNF_INVALID_PARAMETER;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = ReadGPGKeyFile(pszFile, &pszKeyData, &nKeyDataSize);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
while (nOffset < nKeyDataSize)
|
|
{
|
|
pgpArmor nArmor = pgpParsePkts(pszKeyData + nOffset, &pPkt, &nPktLen);
|
|
if(nArmor == PGPARMOR_PUBKEY)
|
|
{
|
|
dwError = rpmtsImportPubkey(pTS, pPkt, nPktLen);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
nKeys++;
|
|
}
|
|
nOffset += nPktLen;
|
|
}
|
|
|
|
if (nKeys == 0) {
|
|
dwError = ERROR_TDNF_INVALID_PUBKEY_FILE;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
cleanup:
|
|
TDNF_SAFE_FREE_MEMORY(pszKeyData);
|
|
return dwError;
|
|
error:
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t
|
|
TDNFGPGCheckPackage(
|
|
PTDNFRPMTS pTS,
|
|
PTDNF pTdnf,
|
|
PTDNF_REPO_DATA pRepo,
|
|
const char* pszFilePath,
|
|
Header *pRpmHeader
|
|
)
|
|
{
|
|
uint32_t dwError = 0;
|
|
Header rpmHeader = NULL;
|
|
int nGPGSigCheck = 0;
|
|
FD_t fp = NULL;
|
|
char** ppszUrlGPGKeys = NULL;
|
|
char* pszLocalGPGKey = NULL;
|
|
int nAnswer = 0;
|
|
int nRemote = 0;
|
|
int i;
|
|
int nMatched = 0;
|
|
|
|
dwError = TDNFGetGPGSignatureCheck(pTdnf, pRepo, &nGPGSigCheck, NULL);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
fp = Fopen (pszFilePath, "r.ufdio");
|
|
if(!fp)
|
|
{
|
|
dwError = errno;
|
|
BAIL_ON_TDNF_SYSTEM_ERROR(dwError);
|
|
}
|
|
|
|
dwError = rpmReadPackageFile(
|
|
pTS->pTS,
|
|
fp,
|
|
pszFilePath,
|
|
&rpmHeader);
|
|
|
|
Fclose(fp);
|
|
fp = NULL;
|
|
|
|
if (dwError != RPMRC_NOTTRUSTED && dwError != RPMRC_NOKEY)
|
|
{
|
|
BAIL_ON_TDNF_RPM_ERROR(dwError);
|
|
}
|
|
else if(nGPGSigCheck)
|
|
{
|
|
dwError = TDNFGetGPGSignatureCheck(pTdnf, pRepo, &nGPGSigCheck, &ppszUrlGPGKeys);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
for (i = 0; ppszUrlGPGKeys[i]; i++) {
|
|
pr_info("importing key from %s\n", ppszUrlGPGKeys[i]);
|
|
dwError = TDNFYesOrNo(pTdnf->pArgs, "Is this ok [y/N]: ", &nAnswer);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if(!nAnswer)
|
|
{
|
|
dwError = ERROR_TDNF_OPERATION_ABORTED;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = TDNFUriIsRemote(ppszUrlGPGKeys[i], &nRemote);
|
|
if (dwError == ERROR_TDNF_URL_INVALID)
|
|
{
|
|
dwError = ERROR_TDNF_KEYURL_INVALID;
|
|
}
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if (nRemote)
|
|
{
|
|
dwError = TDNFFetchRemoteGPGKey(pTdnf, pRepo, ppszUrlGPGKeys[i], &pszLocalGPGKey);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
else
|
|
{
|
|
dwError = TDNFPathFromUri(ppszUrlGPGKeys[i], &pszLocalGPGKey);
|
|
if (dwError == ERROR_TDNF_URL_INVALID)
|
|
{
|
|
dwError = ERROR_TDNF_KEYURL_INVALID;
|
|
}
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
dwError = TDNFImportGPGKeyFile(pTS->pTS, pszLocalGPGKey);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
dwError = TDNFGPGCheck(pTS->pTS, pszLocalGPGKey, pszFilePath);
|
|
if (dwError == 0)
|
|
{
|
|
nMatched++;
|
|
}
|
|
else if (dwError == ERROR_TDNF_RPM_GPG_NO_MATCH)
|
|
{
|
|
dwError = 0;
|
|
}
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if (nRemote)
|
|
{
|
|
if (unlink(pszLocalGPGKey))
|
|
{
|
|
dwError = errno;
|
|
BAIL_ON_TDNF_SYSTEM_ERROR(dwError);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nMatched == 0)
|
|
{
|
|
dwError = ERROR_TDNF_RPM_GPG_NO_MATCH;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
fp = Fopen (pszFilePath, "r.ufdio");
|
|
if(!fp)
|
|
{
|
|
dwError = errno;
|
|
BAIL_ON_TDNF_SYSTEM_ERROR(dwError);
|
|
}
|
|
|
|
dwError = rpmReadPackageFile(
|
|
pTS->pTS,
|
|
fp,
|
|
pszFilePath,
|
|
&rpmHeader);
|
|
|
|
BAIL_ON_TDNF_RPM_ERROR(dwError);
|
|
|
|
Fclose(fp);
|
|
fp = NULL;
|
|
}
|
|
else
|
|
{
|
|
dwError = 0;
|
|
}
|
|
|
|
/* optional output parameter */
|
|
if (pRpmHeader != NULL)
|
|
{
|
|
*pRpmHeader = rpmHeader;
|
|
}
|
|
else if(rpmHeader)
|
|
{
|
|
headerFree(rpmHeader);
|
|
}
|
|
|
|
cleanup:
|
|
TDNF_SAFE_FREE_STRINGARRAY(ppszUrlGPGKeys);
|
|
TDNF_SAFE_FREE_MEMORY(pszLocalGPGKey);
|
|
if(fp)
|
|
{
|
|
Fclose(fp);
|
|
}
|
|
return dwError;
|
|
|
|
error:
|
|
if(rpmHeader)
|
|
{
|
|
headerFree(rpmHeader);
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t
|
|
TDNFFetchRemoteGPGKey(
|
|
PTDNF pTdnf,
|
|
PTDNF_REPO_DATA pRepo,
|
|
const char* pszUrlGPGKey,
|
|
char** ppszKeyLocation
|
|
)
|
|
{
|
|
uint32_t dwError = 0;
|
|
char* pszFilePath = NULL;
|
|
char* pszNormalPath = NULL;
|
|
char* pszTopKeyCacheDir = NULL;
|
|
char* pszRealTopKeyCacheDir = NULL;
|
|
char* pszDownloadCacheDir = NULL;
|
|
char* pszKeyLocation = NULL;
|
|
|
|
if(!pTdnf || !pRepo || IsNullOrEmptyString(pszUrlGPGKey))
|
|
{
|
|
dwError = ERROR_TDNF_INVALID_PARAMETER;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = TDNFPathFromUri(pszUrlGPGKey, &pszKeyLocation);
|
|
if (dwError == ERROR_TDNF_URL_INVALID)
|
|
{
|
|
dwError = ERROR_TDNF_KEYURL_INVALID;
|
|
}
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
dwError = TDNFGetCachePath(pTdnf, pRepo,
|
|
"keys", NULL,
|
|
&pszTopKeyCacheDir);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
dwError = TDNFNormalizePath(pszTopKeyCacheDir,
|
|
&pszRealTopKeyCacheDir);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
dwError = TDNFJoinPath(
|
|
&pszFilePath,
|
|
pszRealTopKeyCacheDir,
|
|
pszKeyLocation,
|
|
NULL);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
dwError = TDNFNormalizePath(
|
|
pszFilePath,
|
|
&pszNormalPath);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if (strncmp(pszRealTopKeyCacheDir, pszNormalPath, strlen(pszRealTopKeyCacheDir)))
|
|
{
|
|
dwError = ERROR_TDNF_KEYURL_INVALID;
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = TDNFDirName(pszNormalPath, &pszDownloadCacheDir);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
if(access(pszDownloadCacheDir, F_OK))
|
|
{
|
|
if(errno != ENOENT)
|
|
{
|
|
dwError = errno;
|
|
}
|
|
BAIL_ON_TDNF_SYSTEM_ERROR(dwError);
|
|
|
|
dwError = TDNFUtilsMakeDirs(pszDownloadCacheDir);
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
}
|
|
|
|
dwError = TDNFDownloadFile(pTdnf, pRepo, pszUrlGPGKey, pszFilePath,
|
|
basename(pszFilePath));
|
|
BAIL_ON_TDNF_ERROR(dwError);
|
|
|
|
*ppszKeyLocation = pszNormalPath;
|
|
|
|
cleanup:
|
|
TDNF_SAFE_FREE_MEMORY(pszFilePath);
|
|
TDNF_SAFE_FREE_MEMORY(pszRealTopKeyCacheDir);
|
|
TDNF_SAFE_FREE_MEMORY(pszTopKeyCacheDir);
|
|
TDNF_SAFE_FREE_MEMORY(pszDownloadCacheDir);
|
|
TDNF_SAFE_FREE_MEMORY(pszKeyLocation);
|
|
return dwError;
|
|
|
|
error:
|
|
pr_err("Error processing key: %s\n", pszUrlGPGKey);
|
|
TDNF_SAFE_FREE_MEMORY(pszNormalPath);
|
|
*ppszKeyLocation = NULL;
|
|
goto cleanup;
|
|
}
|
|
|