static rpmRC includeFileSignatures(FD_t fd, const char *rpm, Header *sigp, Header *hdrp, off_t sigStart, off_t headerStart) { FD_t ofd = NULL; char *trpm = NULL; char *key; char *keypass; char *SHA1 = NULL; uint8_t *MD5 = NULL; size_t sha1len; size_t md5len; off_t sigTargetSize; rpmRC rc = RPMRC_OK; struct rpmtd_s osigtd; char *o_sha1 = NULL; uint8_t o_md5[16]; #ifndef WITH_IMAEVM rpmlog(RPMLOG_ERR, _("missing libimaevm\n")); return RPMRC_FAIL; #endif unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE); key = rpmExpand("%{?_file_signing_key}", NULL); keypass = rpmExpand("%{_file_signing_key_password}", NULL); if (rstreq(keypass, "")) { free(keypass); keypass = NULL; } rc = rpmSignFiles(*hdrp, key, keypass); if (rc != RPMRC_OK) { goto exit; } *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE); if (*hdrp == NULL) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("headerReload failed\n")); goto exit; } ofd = rpmMkTempFile(NULL, &trpm); if (ofd == NULL || Ferror(ofd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n")); goto exit; } /* Copy archive to temp file */ if (copyFile(&fd, rpm, &ofd, trpm)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("copyFile failed\n")); goto exit; } if (Fseek(fd, headerStart, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } /* Start MD5 calculation */ fdInitDigest(fd, PGPHASHALGO_MD5, 0); /* Write header to rpm and recalculate SHA1 */ fdInitDigest(fd, PGPHASHALGO_SHA1, 0); rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("headerWrite failed\n")); goto exit; } fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, &sha1len, 1); /* Copy archive from temp file */ if (Fseek(ofd, 0, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } if (copyFile(&ofd, trpm, &fd, rpm)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("copyFile failed\n")); goto exit; } unlink(trpm); sigTargetSize = Ftell(fd) - headerStart; fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&MD5, &md5len, 0); if (headerGet(*sigp, RPMSIGTAG_MD5, &osigtd, HEADERGET_DEFAULT)) { memcpy(o_md5, osigtd.data, 16); rpmtdFreeData(&osigtd); } if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) { o_sha1 = xstrdup(osigtd.data); rpmtdFreeData(&osigtd); } if (memcmp(MD5, o_md5, md5len) == 0 && strcmp(SHA1, o_sha1) == 0) rpmlog(RPMLOG_WARNING, _("%s already contains identical file signatures\n"), rpm); else replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA1, MD5); exit: free(trpm); free(MD5); free(SHA1); free(o_sha1); free(keypass); free(key); if (ofd) (void) closeFile(&ofd); return rc; }
cr_Package * cr_package_from_header(Header hdr, int changelog_limit, cr_HeaderReadingFlags hdrrflags, G_GNUC_UNUSED GError **err) { cr_Package *pkg; assert(hdr); assert(!err || *err == NULL); // Create new package structure pkg = cr_package_new(); pkg->loadingflags |= CR_PACKAGE_FROM_HEADER; pkg->loadingflags |= CR_PACKAGE_LOADED_PRI; pkg->loadingflags |= CR_PACKAGE_LOADED_FIL; pkg->loadingflags |= CR_PACKAGE_LOADED_OTH; // Create rpm tag data container rpmtd td = rpmtdNew(); headerGetFlags flags = HEADERGET_MINMEM | HEADERGET_EXT; // Fill package structure pkg->name = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_NAME)); gint64 is_src = headerGetNumber(hdr, RPMTAG_SOURCEPACKAGE); if (is_src) { pkg->arch = cr_safe_string_chunk_insert(pkg->chunk, "src"); } else { pkg->arch = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_ARCH)); } pkg->version = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_VERSION)); #define MAX_STR_INT_LEN 24 char tmp_epoch[MAX_STR_INT_LEN]; if (snprintf(tmp_epoch, MAX_STR_INT_LEN, "%llu", (long long unsigned int) headerGetNumber(hdr, RPMTAG_EPOCH)) <= 0) { tmp_epoch[0] = '\0'; } pkg->epoch = g_string_chunk_insert_len(pkg->chunk, tmp_epoch, MAX_STR_INT_LEN); pkg->release = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_RELEASE)); pkg->summary = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_SUMMARY)); pkg->description = cr_safe_string_chunk_insert_null(pkg->chunk, headerGetString(hdr, RPMTAG_DESCRIPTION)); pkg->url = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_URL)); if (headerGet(hdr, RPMTAG_BUILDTIME, td, flags)) { pkg->time_build = rpmtdGetNumber(td); } pkg->rpm_license = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_LICENSE)); pkg->rpm_vendor = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_VENDOR)); pkg->rpm_group = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_GROUP)); pkg->rpm_buildhost = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_BUILDHOST)); pkg->rpm_sourcerpm = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_SOURCERPM)); pkg->rpm_packager = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_PACKAGER)); if (headerGet(hdr, RPMTAG_SIZE, td, flags)) { pkg->size_installed = rpmtdGetNumber(td); } if (headerGet(hdr, RPMTAG_ARCHIVESIZE, td, flags)) { pkg->size_archive = rpmtdGetNumber(td); } rpmtdFreeData(td); rpmtdFree(td); // // Fill files // rpmtd full_filenames = rpmtdNew(); // Only for filenames_hashtable rpmtd indexes = rpmtdNew(); rpmtd filenames = rpmtdNew(); rpmtd fileflags = rpmtdNew(); rpmtd filemodes = rpmtdNew(); GHashTable *filenames_hashtable = g_hash_table_new(g_str_hash, g_str_equal); rpmtd dirnames = rpmtdNew(); // Create list of pointer to directory names int dir_count; char **dir_list = NULL; if (headerGet(hdr, RPMTAG_DIRNAMES, dirnames, flags) && (dir_count = rpmtdCount(dirnames))) { int x = 0; dir_list = malloc(sizeof(char *) * dir_count); while (rpmtdNext(dirnames) != -1) { dir_list[x] = cr_safe_string_chunk_insert(pkg->chunk, rpmtdGetString(dirnames)); x++; } assert(x == dir_count); } if (headerGet(hdr, RPMTAG_FILENAMES, full_filenames, flags) && headerGet(hdr, RPMTAG_DIRINDEXES, indexes, flags) && headerGet(hdr, RPMTAG_BASENAMES, filenames, flags) && headerGet(hdr, RPMTAG_FILEFLAGS, fileflags, flags) && headerGet(hdr, RPMTAG_FILEMODES, filemodes, flags)) { rpmtdInit(full_filenames); rpmtdInit(indexes); rpmtdInit(filenames); rpmtdInit(fileflags); rpmtdInit(filemodes); while ((rpmtdNext(full_filenames) != -1) && (rpmtdNext(indexes) != -1) && (rpmtdNext(filenames) != -1) && (rpmtdNext(fileflags) != -1) && (rpmtdNext(filemodes) != -1)) { cr_PackageFile *packagefile = cr_package_file_new(); packagefile->name = cr_safe_string_chunk_insert(pkg->chunk, rpmtdGetString(filenames)); packagefile->path = (dir_list) ? dir_list[(int) rpmtdGetNumber(indexes)] : ""; if (S_ISDIR(rpmtdGetNumber(filemodes))) { // Directory packagefile->type = cr_safe_string_chunk_insert(pkg->chunk, "dir"); } else if (rpmtdGetNumber(fileflags) & RPMFILE_GHOST) { // Ghost packagefile->type = cr_safe_string_chunk_insert(pkg->chunk, "ghost"); } else { // Regular file packagefile->type = cr_safe_string_chunk_insert(pkg->chunk, ""); } g_hash_table_replace(filenames_hashtable, (gpointer) rpmtdGetString(full_filenames), (gpointer) rpmtdGetString(full_filenames)); pkg->files = g_slist_prepend(pkg->files, packagefile); } pkg->files = g_slist_reverse (pkg->files); rpmtdFreeData(dirnames); rpmtdFreeData(indexes); rpmtdFreeData(filenames); rpmtdFreeData(fileflags); rpmtdFreeData(filemodes); } rpmtdFree(dirnames); rpmtdFree(indexes); rpmtdFree(filemodes); if (dir_list) { free((void *) dir_list); } // // PCOR (provides, conflicts, obsoletes, requires) // rpmtd fileversions = rpmtdNew(); // Struct used as value in ap_hashtable struct ap_value_struct { const char *flags; const char *version; int pre; }; // Hastable with filenames from provided GHashTable *provided_hashtable = g_hash_table_new(g_str_hash, g_str_equal); // Hashtable with already processed files from requires GHashTable *ap_hashtable = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free); for (int deptype=0; dep_items[deptype].type != DEP_SENTINEL; deptype++) { if (headerGet(hdr, dep_items[deptype].nametag, filenames, flags) && headerGet(hdr, dep_items[deptype].flagstag, fileflags, flags) && headerGet(hdr, dep_items[deptype].versiontag, fileversions, flags)) { // Because we have to select only libc.so with highest version // e.g. libc.so.6(GLIBC_2.4) cr_Dependency *libc_require_highest = NULL; rpmtdInit(filenames); rpmtdInit(fileflags); rpmtdInit(fileversions); while ((rpmtdNext(filenames) != -1) && (rpmtdNext(fileflags) != -1) && (rpmtdNext(fileversions) != -1)) { int pre = 0; const char *filename = rpmtdGetString(filenames); guint64 num_flags = rpmtdGetNumber(fileflags); const char *flags = cr_flag_to_str(num_flags); const char *full_version = rpmtdGetString(fileversions); // Requires specific stuff if (deptype == DEP_REQUIRES) { // Skip requires which start with "rpmlib(" if (!strncmp("rpmlib(", filename, 7)) { continue; } // Skip package primary files if (g_hash_table_lookup_extended(filenames_hashtable, filename, NULL, NULL)) { if (cr_is_primary(filename)) { continue; } } // Skip files which are provided if (g_hash_table_lookup_extended(provided_hashtable, filename, NULL, NULL)) { continue; } // Calculate pre value if (num_flags & (RPMSENSE_PREREQ | RPMSENSE_SCRIPT_PRE | RPMSENSE_SCRIPT_POST)) { pre = 1; } // Skip duplicate files gpointer value; if (g_hash_table_lookup_extended(ap_hashtable, filename, NULL, &value)) { struct ap_value_struct *ap_value = value; if (!g_strcmp0(ap_value->flags, flags) && !strcmp(ap_value->version, full_version) && (ap_value->pre == pre)) { continue; } } } // Parse dep string cr_EVR *evr = cr_str_to_evr(full_version, pkg->chunk); if ((full_version && *full_version) && !evr->epoch) { // NULL in epoch mean that the epoch was bad (non-numerical) _cleanup_free_ gchar *pkg_nevra = cr_package_nevra(pkg); g_warning("Bad epoch in version string \"%s\" for dependency \"%s\" in package \"%s\"", full_version, filename, pkg_nevra); g_warning("Skipping this dependency"); g_free(evr); continue; } // Create dynamic dependency object cr_Dependency *dependency = cr_dependency_new(); dependency->name = cr_safe_string_chunk_insert(pkg->chunk, filename); dependency->flags = cr_safe_string_chunk_insert(pkg->chunk, flags); dependency->epoch = evr->epoch; dependency->version = evr->version; dependency->release = evr->release; g_free(evr); switch (deptype) { case DEP_PROVIDES: g_hash_table_replace(provided_hashtable, dependency->name, dependency->name); pkg->provides = g_slist_prepend(pkg->provides, dependency); break; case DEP_CONFLICTS: pkg->conflicts = g_slist_prepend(pkg->conflicts, dependency); break; case DEP_OBSOLETES: pkg->obsoletes = g_slist_prepend(pkg->obsoletes, dependency); break; case DEP_REQUIRES: dependency->pre = pre; // XXX: libc.so filtering //////////////////////////// if (g_str_has_prefix(dependency->name, "libc.so.6")) { if (!libc_require_highest) libc_require_highest = dependency; else { if (cr_compare_dependency(libc_require_highest->name, dependency->name) == 2) { g_free(libc_require_highest); libc_require_highest = dependency; } else g_free(dependency); } break; } // XXX: libc.so filtering - END /////////////////////// pkg->requires = g_slist_prepend(pkg->requires, dependency); // Add file into ap_hashtable struct ap_value_struct *value = malloc(sizeof(struct ap_value_struct)); value->flags = flags; value->version = full_version; value->pre = dependency->pre; g_hash_table_replace(ap_hashtable, dependency->name, value); break; //case REQUIRES end case DEP_SUGGESTS: pkg->suggests = g_slist_prepend(pkg->suggests, dependency); break; case DEP_ENHANCES: pkg->enhances = g_slist_prepend(pkg->enhances, dependency); break; case DEP_RECOMMENDS: pkg->recommends = g_slist_prepend(pkg->recommends, dependency); break; case DEP_SUPPLEMENTS: pkg->supplements = g_slist_prepend(pkg->supplements, dependency); break; #ifdef ENABLE_LEGACY_WEAKDEPS case DEP_OLDSUGGESTS: if ( num_flags & RPMSENSE_STRONG ) { pkg->recommends = g_slist_prepend(pkg->recommends, dependency); } else { pkg->suggests = g_slist_prepend(pkg->suggests, dependency); } break; case DEP_OLDENHANCES: if ( num_flags & RPMSENSE_STRONG ) { pkg->supplements = g_slist_prepend(pkg->supplements, dependency); } else { pkg->enhances = g_slist_prepend(pkg->enhances, dependency); } break; #endif } // Switch end } // While end // XXX: libc.so filtering //////////////////////////////// if (deptype == DEP_REQUIRES && libc_require_highest) pkg->requires = g_slist_prepend(pkg->requires, libc_require_highest); // XXX: libc.so filtering - END //////////////////////////////// } rpmtdFreeData(filenames); rpmtdFreeData(fileflags); rpmtdFreeData(fileversions); } pkg->provides = g_slist_reverse (pkg->provides); pkg->conflicts = g_slist_reverse (pkg->conflicts); pkg->obsoletes = g_slist_reverse (pkg->obsoletes); pkg->requires = g_slist_reverse (pkg->requires); pkg->suggests = g_slist_reverse (pkg->suggests); pkg->enhances = g_slist_reverse (pkg->enhances); pkg->recommends = g_slist_reverse (pkg->recommends); pkg->supplements = g_slist_reverse (pkg->supplements); g_hash_table_remove_all(filenames_hashtable); g_hash_table_remove_all(provided_hashtable); g_hash_table_remove_all(ap_hashtable); g_hash_table_unref(filenames_hashtable); g_hash_table_unref(provided_hashtable); g_hash_table_unref(ap_hashtable); rpmtdFree(filenames); rpmtdFree(fileflags); rpmtdFree(fileversions); rpmtdFreeData(full_filenames); rpmtdFree(full_filenames); // // Changelogs // rpmtd changelogtimes = rpmtdNew(); rpmtd changelognames = rpmtdNew(); rpmtd changelogtexts = rpmtdNew(); if (headerGet(hdr, RPMTAG_CHANGELOGTIME, changelogtimes, flags) && headerGet(hdr, RPMTAG_CHANGELOGNAME, changelognames, flags) && headerGet(hdr, RPMTAG_CHANGELOGTEXT, changelogtexts, flags)) { gint64 last_time = G_GINT64_CONSTANT(0); rpmtdInit(changelogtimes); rpmtdInit(changelognames); rpmtdInit(changelogtexts); while ((rpmtdNext(changelogtimes) != -1) && (rpmtdNext(changelognames) != -1) && (rpmtdNext(changelogtexts) != -1) && (changelog_limit > 0 || changelog_limit == -1)) { gint64 time = rpmtdGetNumber(changelogtimes); cr_ChangelogEntry *changelog = cr_changelog_entry_new(); changelog->author = cr_safe_string_chunk_insert(pkg->chunk, rpmtdGetString(changelognames)); changelog->date = time; changelog->changelog = cr_safe_string_chunk_insert(pkg->chunk, rpmtdGetString(changelogtexts)); // Remove space from end of author name if (changelog->author) { size_t len, x; len = strlen(changelog->author); for (x=(len-1); x > 0; x--) { if (changelog->author[x] == ' ') { changelog->author[x] = '\0'; } else { break; } } } pkg->changelogs = g_slist_prepend(pkg->changelogs, changelog); if (changelog_limit != -1) changelog_limit--; // If a previous entry has the same time, increment time of the previous // entry by one. Ugly but works! if (last_time == time) { int tmp_time = time; GSList *previous = pkg->changelogs; while ((previous = g_slist_next(previous)) != NULL && ((cr_ChangelogEntry *) (previous->data))->date == tmp_time) { ((cr_ChangelogEntry *) (previous->data))->date++; tmp_time++; } } else { last_time = time; } } //pkg->changelogs = g_slist_reverse (pkg->changelogs); } rpmtdFreeData(changelogtimes); rpmtdFreeData(changelognames); rpmtdFreeData(changelogtexts); rpmtdFree(changelogtimes); rpmtdFree(changelognames); rpmtdFree(changelogtexts); // // Keys and hdrid (data used for caching when the --cachedir is specified) // if (hdrrflags & CR_HDRR_LOADHDRID) pkg->hdrid = cr_safe_string_chunk_insert(pkg->chunk, headerGetString(hdr, RPMTAG_HDRID)); if (hdrrflags & CR_HDRR_LOADSIGNATURES) { rpmtd gpgtd = rpmtdNew(); rpmtd pgptd = rpmtdNew(); if (headerGet(hdr, RPMTAG_SIGGPG, gpgtd, hdrrflags) && gpgtd->count > 0) { pkg->siggpg = cr_binary_data_new(); pkg->siggpg->size = gpgtd->count; pkg->siggpg->data = g_string_chunk_insert_len(pkg->chunk, gpgtd->data, gpgtd->count); } if (headerGet(hdr, RPMTAG_SIGPGP, pgptd, hdrrflags) && pgptd->count > 0) { pkg->sigpgp = cr_binary_data_new(); pkg->sigpgp->size = pgptd->count; pkg->sigpgp->data = g_string_chunk_insert_len(pkg->chunk, pgptd->data, pgptd->count); } rpmtdFree(gpgtd); rpmtdFree(pgptd); } return pkg; }
/** * Adjust file states in database for files shared with this package: * currently either "replaced" or "wrong color". * @param psm package state machine data * @return 0 always */ static rpmRC markReplacedFiles(const rpmpsm psm) { const rpmts ts = psm->ts; rpmfs fs = rpmteGetFileStates(psm->te); sharedFileInfo replaced = rpmfsGetReplaced(fs); sharedFileInfo sfi; rpmdbMatchIterator mi; Header h; unsigned int * offsets; unsigned int prev; unsigned int num; if (!replaced) return RPMRC_OK; num = prev = 0; for (sfi = replaced; sfi; sfi=rpmfsNextReplaced(fs, sfi)) { if (prev && prev == sfi->otherPkg) continue; prev = sfi->otherPkg; num++; } if (num == 0) return RPMRC_OK; offsets = xmalloc(num * sizeof(*offsets)); offsets[0] = 0; num = prev = 0; for (sfi = replaced; sfi; sfi=rpmfsNextReplaced(fs, sfi)) { if (prev && prev == sfi->otherPkg) continue; prev = sfi->otherPkg; offsets[num++] = sfi->otherPkg; } mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0); rpmdbAppendIterator(mi, offsets, num); rpmdbSetIteratorRewrite(mi, 1); sfi = replaced; while ((h = rpmdbNextIterator(mi)) != NULL) { int modified; struct rpmtd_s secStates; modified = 0; if (!headerGet(h, RPMTAG_FILESTATES, &secStates, HEADERGET_MINMEM)) continue; prev = rpmdbGetIteratorOffset(mi); num = 0; while (sfi && sfi->otherPkg == prev) { int ix = rpmtdSetIndex(&secStates, sfi->otherFileNum); assert(ix != -1); char *state = rpmtdGetChar(&secStates); if (state && *state != sfi->rstate) { *state = sfi->rstate; if (modified == 0) { /* Modified header will be rewritten. */ modified = 1; rpmdbSetIteratorModified(mi, modified); } num++; } sfi=rpmfsNextReplaced(fs, sfi); } rpmtdFreeData(&secStates); } rpmdbFreeIterator(mi); free(offsets); return RPMRC_OK; }
static void compressFilelist(Header h) { struct rpmtd_s fileNames; char ** dirNames; const char ** baseNames; uint32_t * dirIndexes; rpm_count_t count; int i; int dirIndex = -1; /* * This assumes the file list is already sorted, and begins with a * single '/'. That assumption isn't critical, but it makes things go * a bit faster. */ if (headerIsEntry(h, RPMTAG_DIRNAMES)) { headerDel(h, RPMTAG_OLDFILENAMES); return; /* Already converted. */ } if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM)) return; count = rpmtdCount(&fileNames); if (count < 1) return; dirNames = xmalloc(sizeof(*dirNames) * count); /* worst case */ baseNames = xmalloc(sizeof(*dirNames) * count); dirIndexes = xmalloc(sizeof(*dirIndexes) * count); /* HACK. Source RPM, so just do things differently */ { const char *fn = rpmtdGetString(&fileNames); if (fn && *fn != '/') { dirIndex = 0; dirNames[dirIndex] = xstrdup(""); while ((i = rpmtdNext(&fileNames)) >= 0) { dirIndexes[i] = dirIndex; baseNames[i] = rpmtdGetString(&fileNames); } goto exit; } } /* * XXX EVIL HACK, FIXME: * This modifies (and then restores) a const string from rpmtd * through basename retrieved from strrchr() which silently * casts away const on return. */ while ((i = rpmtdNext(&fileNames)) >= 0) { char ** needle; char savechar; char * baseName; size_t len; char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */ if (filename == NULL) /* XXX can't happen */ continue; baseName = strrchr(filename, '/') + 1; len = baseName - filename; needle = dirNames; savechar = *baseName; *baseName = '\0'; if (dirIndex < 0 || (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) { char *s = xmalloc(len + 1); rstrlcpy(s, filename, len + 1); dirIndexes[i] = ++dirIndex; dirNames[dirIndex] = s; } else dirIndexes[i] = needle - dirNames; *baseName = savechar; baseNames[i] = baseName; } exit: if (count > 0) { headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, count); headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, count); headerPutStringArray(h, RPMTAG_DIRNAMES, (const char **) dirNames, dirIndex + 1); } rpmtdFreeData(&fileNames); for (i = 0; i <= dirIndex; i++) { free(dirNames[i]); } free(dirNames); free(baseNames); free(dirIndexes); headerDel(h, RPMTAG_OLDFILENAMES); }
rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense, rpmscriptTriggerModes tm, int priorityClass) { int nerrors = 0, i; rpmdbIndexIterator ii; const void *key; char *pfx; size_t keylen; Header trigH; int (*matchFunc)(rpmts, rpmte, const char*, rpmsenseFlags sense); rpmTagVal priorityTag; rpmtriggers triggers = rpmtriggersCreate(10); /* Decide if we match triggers against files in te or in whole ts */ if (tm == RPMSCRIPT_FILETRIGGER) { matchFunc = matchFilesInPkg; priorityTag = RPMTAG_FILETRIGGERPRIORITIES; } else { matchFunc = matchFilesInTran; priorityTag = RPMTAG_TRANSFILETRIGGERPRIORITIES; } ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), triggerDsTag(tm)); /* Loop over all file triggers in rpmdb */ while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0) { pfx = xmalloc(keylen + 1); memcpy(pfx, key, keylen); pfx[keylen] = '\0'; /* Check if file trigger is fired by any file in ts/te */ if (matchFunc(ts, te, pfx, sense)) { for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++) { struct rpmtd_s priorities; unsigned int priority; unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i); unsigned int tix = rpmdbIndexIteratorTagNum(ii, i); /* * Don't handle transaction triggers installed in current * transaction to avoid executing the same script two times. * These triggers are handled in runImmedFileTriggers(). */ if (tm == RPMSCRIPT_TRANSFILETRIGGER && (packageHashHasEntry(ts->members->removedPackages, offset) || packageHashHasEntry(ts->members->installedPackages, offset))) continue; /* Get priority of trigger from header */ trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offset); headerGet(trigH, priorityTag, &priorities, HEADERGET_MINMEM); rpmtdSetIndex(&priorities, tix); priority = *rpmtdGetUint32(&priorities); headerFree(trigH); /* Store file trigger in array */ rpmtriggersAdd(triggers, offset, tix, priority); } } free(pfx); } rpmdbIndexIteratorFree(ii); /* Sort triggers by priority, offset, trigger index */ rpmtriggersSortAndUniq(triggers); if (rpmChrootIn() != 0) { rpmtriggersFree(triggers); return RPMRC_FAIL; } /* Handle stored triggers */ for (i = 0; i < triggers->count; i++) { if (priorityClass == 1) { if (triggers->triggerInfo[i].priority < TRIGGER_PRIORITY_BOUND) continue; } else if (priorityClass == 2) { if (triggers->triggerInfo[i].priority >= TRIGGER_PRIORITY_BOUND) continue; } trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), triggers->triggerInfo[i].hdrNum); if (tm == RPMSCRIPT_FILETRIGGER) nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 0, triggers->triggerInfo[i].tix); else nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 1, triggers->triggerInfo[i].tix); headerFree(trigH); } rpmtriggersFree(triggers); /* XXX an error here would require a full abort */ (void) rpmChrootOut(); return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL; }
/** * Retrieve trigger info. * @param h header * @retval td tag data container * @return 1 on success */ static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags) { uint32_t * indices; int i, j; char ** conds; struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd; int hgeflags = HEADERGET_MINMEM; if (!headerGet(h, RPMTAG_TRIGGERNAME, &nametd, hgeflags)) { return 0; } headerGet(h, RPMTAG_TRIGGERINDEX, &indextd, hgeflags); headerGet(h, RPMTAG_TRIGGERFLAGS, &flagtd, hgeflags); headerGet(h, RPMTAG_TRIGGERVERSION, &versiontd, hgeflags); headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripttd, hgeflags); td->type = RPM_STRING_ARRAY_TYPE; td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED; td->data = conds = xmalloc(sizeof(*conds) * rpmtdCount(&scripttd)); td->count = rpmtdCount(&scripttd); indices = indextd.data; while ((i = rpmtdNext(&scripttd)) >= 0) { rpm_flag_t *flag; char *flagStr, *item; ARGV_t items = NULL; rpmtdInit(&nametd); rpmtdInit(&flagtd); rpmtdInit(&versiontd); while ((j = rpmtdNext(&nametd)) >= 0) { /* flag and version arrays match name array size always */ rpmtdNext(&flagtd); rpmtdNext(&versiontd); if (indices[j] != i) continue; flag = rpmtdGetUint32(&flagtd); if (flag && *flag & RPMSENSE_SENSEMASK) { flagStr = rpmtdFormat(&flagtd, RPMTD_FORMAT_DEPFLAGS, NULL); rasprintf(&item, "%s %s %s", rpmtdGetString(&nametd), flagStr, rpmtdGetString(&versiontd)); free(flagStr); } else { item = xstrdup(rpmtdGetString(&nametd)); } argvAdd(&items, item); free(item); } conds[i] = argvJoin(items, ", "); argvFree(items); } rpmtdFreeData(&nametd); rpmtdFreeData(&versiontd); rpmtdFreeData(&flagtd); rpmtdFreeData(&indextd); rpmtdFreeData(&scripttd); return 1; }
/* Check files in the transactions against the rpmdb * Lookup all files with the same basename in the rpmdb * and then check for matching finger prints * @param ts transaction set * @param fpc global finger print cache */ static void checkInstalledFiles(rpmts ts, fingerPrintCache fpc) { rpmps ps; rpmte p; rpmfi fi; rpmfs fs; rpmfi otherFi=NULL; int j; int xx; unsigned int fileNum; const char * oldDir; rpmdbMatchIterator mi; Header h, newheader; int beingRemoved; rpmlog(RPMLOG_DEBUG, "computing file dispositions\n"); mi = rpmFindBaseNamesInDB(ts); /* For all installed headers with matching basename's ... */ if (mi == NULL) return; if (rpmdbGetIteratorCount(mi) == 0) { mi = rpmdbFreeIterator(mi); return; } ps = rpmtsProblems(ts); /* Loop over all packages from the rpmdb */ h = newheader = rpmdbNextIterator(mi); while (h != NULL) { headerGetFlags hgflags = HEADERGET_MINMEM; struct rpmtd_s bnames, dnames, dindexes, ostates; fingerPrint fp; unsigned int installedPkg; /* Is this package being removed? */ installedPkg = rpmdbGetIteratorOffset(mi); beingRemoved = 0; if (ts->removedPackages != NULL) for (j = 0; j < ts->numRemovedPackages; j++) { if (ts->removedPackages[j] != installedPkg) continue; beingRemoved = 1; break; } h = headerLink(h); headerGet(h, RPMTAG_BASENAMES, &bnames, hgflags); headerGet(h, RPMTAG_DIRNAMES, &dnames, hgflags); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, hgflags); headerGet(h, RPMTAG_FILESTATES, &ostates, hgflags); oldDir = NULL; /* loop over all interesting files in that package */ do { int gotRecs; struct rpmffi_s * recs; int numRecs; const char * dirName; const char * baseName; fileNum = rpmdbGetIteratorFileNum(mi); rpmtdSetIndex(&bnames, fileNum); rpmtdSetIndex(&dindexes, fileNum); rpmtdSetIndex(&dnames, *rpmtdGetUint32(&dindexes)); rpmtdSetIndex(&ostates, fileNum); dirName = rpmtdGetString(&dnames); baseName = rpmtdGetString(&bnames); /* lookup finger print for this file */ if ( dirName == oldDir) { /* directory is the same as last round */ fp.baseName = baseName; } else { fp = fpLookup(fpc, dirName, baseName, 1); oldDir = dirName; } /* search for files in the transaction with same finger print */ gotRecs = rpmFpHashGetEntry(ts->ht, &fp, &recs, &numRecs, NULL); for (j=0; (j<numRecs)&&gotRecs; j++) { p = recs[j].p; fi = rpmteFI(p); fs = rpmteGetFileStates(p); /* Determine the fate of each file. */ switch (rpmteType(p)) { case TR_ADDED: if (!otherFi) { otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); } rpmfiSetFX(fi, recs[j].fileno); rpmfiSetFX(otherFi, fileNum); xx = handleInstInstalledFile(ts, p, fi, h, otherFi, beingRemoved); break; case TR_REMOVED: if (!beingRemoved) { rpmfiSetFX(fi, recs[j].fileno); if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL) rpmfsSetAction(fs, recs[j].fileno, FA_SKIP); } break; } } newheader = rpmdbNextIterator(mi); } while (newheader==h); otherFi = rpmfiFree(otherFi); rpmtdFreeData(&ostates); rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); headerFree(h); h = newheader; } mi = rpmdbFreeIterator(mi); }
rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg) { char *buf = NULL; int32_t block[4]; int32_t il; int32_t dl; int32_t * ei = NULL; entryInfo pe; unsigned int nb, uc; struct indexEntry_s entry; unsigned char * dataStart; Header sigh = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int xx; int i; if (sighp) *sighp = NULL; if (sig_type != RPMSIGTYPE_HEADERSIG) goto exit; memset(block, 0, sizeof(block)); if ((xx = Freadall(fd, block, sizeof(block))) != sizeof(block)) { rasprintf(&buf, _("sigh size(%d): BAD, read returned %d"), (int)sizeof(block), xx); goto exit; } if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) { rasprintf(&buf, _("sigh magic: BAD")); goto exit; } il = ntohl(block[2]); if (il < 0 || il > 32) { rasprintf(&buf, _("sigh tags: BAD, no. of tags(%d) out of range"), il); goto exit; } dl = ntohl(block[3]); if (dl < 0 || dl > 8192) { rasprintf(&buf, _("sigh data: BAD, no. of bytes(%d) out of range"), dl); goto exit; } memset(&entry, 0, sizeof(entry)); nb = (il * sizeof(struct entryInfo_s)) + dl; uc = sizeof(il) + sizeof(dl) + nb; ei = xmalloc(uc); ei[0] = block[2]; ei[1] = block[3]; pe = (entryInfo) &ei[2]; dataStart = (unsigned char *) (pe + il); if ((xx = Freadall(fd, pe, nb)) != nb) { rasprintf(&buf, _("sigh blob(%d): BAD, read returned %d"), (int)nb, xx); goto exit; } /* Verify header immutable region if there is one */ xx = headerVerifyRegion(RPMTAG_HEADERSIGNATURES, &entry, il, dl, pe, dataStart, NULL, NULL, &buf); /* Not found means a legacy V3 package with no immutable region */ if (xx != RPMRC_OK && xx != RPMRC_NOTFOUND) goto exit; /* Sanity check signature tags */ for (i = 1; i < il; i++) { xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d"), i, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } } /* OK, blob looks sane, load the header. */ sigh = headerImport(ei, uc, 0); if (sigh == NULL) { rasprintf(&buf, _("sigh load: BAD")); goto exit; } ei = NULL; /* XXX will be freed with header */ { size_t sigSize = headerSizeof(sigh, HEADER_MAGIC_YES); size_t pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */ ssize_t trc; struct rpmtd_s sizetag; rpm_loff_t archSize = 0; /* Position at beginning of header. */ if (pad && (trc = Freadall(fd, block, pad)) != pad) { rasprintf(&buf, _("sigh pad(%zd): BAD, read %zd bytes"), pad, trc); goto exit; } /* Print package component sizes. */ if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) { rpm_loff_t *tsize = rpmtdGetUint64(&sizetag); archSize = (tsize) ? *tsize : 0; } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) { rpm_off_t *tsize = rpmtdGetUint32(&sizetag); archSize = (tsize) ? *tsize : 0; } rpmtdFreeData(&sizetag); rc = printSize(fd, sigSize, pad, archSize); if (rc != RPMRC_OK) { rasprintf(&buf, _("sigh sigSize(%zd): BAD, fstat(2) failed"), sigSize); goto exit; } } exit: if (sighp && sigh && rc == RPMRC_OK) *sighp = headerLink(sigh); headerFree(sigh); free(ei); if (msg != NULL) { *msg = buf; } else { free(buf); } return rc; }
/** * dnf_keyring_check_untrusted_file: */ gboolean dnf_keyring_check_untrusted_file(rpmKeyring keyring, const gchar *filename, GError **error) { FD_t fd = NULL; gboolean ret = FALSE; Header hdr = NULL; pgpDig dig = NULL; rpmRC rc; rpmtd td = NULL; rpmts ts = NULL; /* open the file for reading */ fd = Fopen(filename, "r.fdio"); if (fd == NULL) { g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID, "failed to open %s", filename); goto out; } if (Ferror(fd)) { g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID, "failed to open %s: %s", filename, Fstrerror(fd)); goto out; } /* we don't want to abort on missing keys */ ts = rpmtsCreate(); rpmtsSetVSFlags(ts, _RPMVSF_NOSIGNATURES); /* read in the file */ rc = rpmReadPackageFile(ts, fd, filename, &hdr); if (rc != RPMRC_OK) { /* we only return SHA1 and MD5 failures, as we're not * checking signatures at this stage */ g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID, "%s could not be verified", filename); goto out; } /* convert and upscale */ headerConvert(hdr, HEADERCONV_RETROFIT_V3); /* get RSA key */ td = rpmtdNew(); rc = headerGet(hdr, RPMTAG_RSAHEADER, td, HEADERGET_MINMEM); if (rc != 1) { /* try to read DSA key as a fallback */ rc = headerGet(hdr, RPMTAG_DSAHEADER, td, HEADERGET_MINMEM); } /* the package has no signing key */ if (rc != 1) { g_autofree char *package_filename = g_path_get_basename(filename); ret = FALSE; g_set_error(error, DNF_ERROR, DNF_ERROR_GPG_SIGNATURE_INVALID, "package not signed: %s", package_filename); goto out; } /* make it into a digest */ dig = pgpNewDig(); rc = pgpPrtPkts(td->data, td->count, dig, 0); if (rc != 0) { g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID, "failed to parse digest header for %s", filename); goto out; } /* does the key exist in the keyring */ rc = rpmKeyringLookup(keyring, dig); if (rc != RPMRC_OK) { g_set_error(error, DNF_ERROR, DNF_ERROR_GPG_SIGNATURE_INVALID, "failed to lookup digest in keyring for %s", filename); goto out; } /* the package is signed by a key we trust */ g_debug("%s has been verified as trusted", filename); ret = TRUE; out: if (dig != NULL) pgpFreeDig(dig); if (td != NULL) { rpmtdFreeData(td); rpmtdFree(td); } if (ts != NULL) rpmtsFree(ts); if (hdr != NULL) headerFree(hdr); if (fd != NULL) Fclose(fd); return ret; }
static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName, CSA_t csa, char **cookie) { FD_t fd = NULL; FD_t ifd = NULL; char * sigtarget = NULL;; char * rpmio_flags = NULL; char * SHA1 = NULL; const char *s; Header h; Header sig = NULL; int xx; rpmRC rc = RPMRC_OK; struct rpmtd_s td; rpmTagVal sizetag; rpmTagVal payloadtag; /* Transfer header reference form *hdrp to h. */ h = headerLink(*hdrp); *hdrp = headerFree(*hdrp); if (pkgidp) *pkgidp = NULL; /* Save payload information */ if (headerIsSource(h)) rpmio_flags = rpmExpand("%{?_source_payload}", NULL); else rpmio_flags = rpmExpand("%{?_binary_payload}", NULL); /* If not configured or bogus, fall back to gz */ if (rpmio_flags[0] != 'w') { free(rpmio_flags); rpmio_flags = xstrdup("w9.gzdio"); } s = strchr(rpmio_flags, '.'); if (s) { char *buf = NULL; const char *compr = NULL; headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio"); if (rstreq(s+1, "ufdio")) { compr = NULL; } else if (rstreq(s+1, "gzdio")) { compr = "gzip"; #if HAVE_BZLIB_H } else if (rstreq(s+1, "bzdio")) { compr = "bzip2"; /* Add prereq on rpm version that understands bzip2 payloads */ (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1"); #endif #if HAVE_LZMA_H } else if (rstreq(s+1, "xzdio")) { compr = "xz"; (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1"); } else if (rstreq(s+1, "lzdio")) { compr = "lzma"; (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1"); #endif } else { rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"), rpmio_flags); rc = RPMRC_FAIL; goto exit; } if (compr) headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr); buf = xstrdup(rpmio_flags); buf[s - rpmio_flags] = '\0'; headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1); free(buf); } /* check if the package has a dependency with a '~' */ if (haveTildeDep(h)) (void) rpmlibNeedsFeature(h, "TildeInVersions", "4.10.0-1"); /* Create and add the cookie */ if (cookie) { rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime())); headerPutString(h, RPMTAG_COOKIE, *cookie); } /* Reallocate the header into one contiguous region. */ h = headerReload(h, RPMTAG_HEADERIMMUTABLE); if (h == NULL) { /* XXX can't happen */ rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n")); goto exit; } /* Re-reference reallocated header. */ *hdrp = headerLink(h); /* * Write the header+archive into a temp file so that the size of * archive (after compression) can be added to the header. */ fd = rpmMkTempFile(NULL, &sigtarget); if (fd == NULL || Ferror(fd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n")); goto exit; } fdInitDigest(fd, PGPHASHALGO_SHA1, 0); if (headerWrite(fd, h, HEADER_MAGIC_YES)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write temp header\n")); } else { /* Write the archive and get the size */ (void) Fflush(fd); fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1); if (csa->cpioList != NULL) { rc = cpio_doio(fd, h, csa, rpmio_flags); } else { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Bad CSA data\n")); } } if (rc != RPMRC_OK) goto exit; (void) Fclose(fd); fd = NULL; (void) unlink(fileName); /* Generate the signature */ (void) fflush(stdout); sig = rpmNewSignature(); /* * There should be rpmlib() dependency on this, but that doesn't * really do much good as these are signature tags that get read * way before dependency checking has a chance to figure out anything. * On the positive side, not inserting the 32bit tag at all means * older rpm will just bail out with error message on attempt to read * such a package. */ if (csa->cpioArchiveSize < UINT32_MAX) { sizetag = RPMSIGTAG_SIZE; payloadtag = RPMSIGTAG_PAYLOADSIZE; } else { sizetag = RPMSIGTAG_LONGSIZE; payloadtag = RPMSIGTAG_LONGARCHIVESIZE; } (void) rpmGenDigest(sig, sigtarget, sizetag); (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5); if (SHA1) { /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */ rpmtdReset(&td); td.tag = RPMSIGTAG_SHA1; td.type = RPM_STRING_TYPE; td.data = SHA1; td.count = 1; headerPut(sig, &td, HEADERPUT_DEFAULT); SHA1 = _free(SHA1); } { /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */ rpmtdReset(&td); td.tag = payloadtag; td.count = 1; if (payloadtag == RPMSIGTAG_PAYLOADSIZE) { rpm_off_t asize = csa->cpioArchiveSize; td.type = RPM_INT32_TYPE; td.data = &asize; headerPut(sig, &td, HEADERPUT_DEFAULT); } else { rpm_loff_t asize = csa->cpioArchiveSize; td.type = RPM_INT64_TYPE; td.data = &asize; headerPut(sig, &td, HEADERPUT_DEFAULT); } } /* Reallocate the signature into one contiguous region. */ sig = headerReload(sig, RPMTAG_HEADERSIGNATURES); if (sig == NULL) { /* XXX can't happen */ rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n")); goto exit; } /* Open the output file */ fd = Fopen(fileName, "w.ufdio"); if (fd == NULL || Ferror(fd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } /* Write the lead section into the package. */ { rpmlead lead = rpmLeadFromHeader(h); rc = rpmLeadWrite(fd, lead); rpmLeadFree(lead); if (rc != RPMRC_OK) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd)); goto exit; } } /* Write the signature section into the package. */ if (rpmWriteSignature(fd, sig)) { rc = RPMRC_FAIL; goto exit; } /* Append the header and archive */ ifd = Fopen(sigtarget, "r.ufdio"); if (ifd == NULL || Ferror(ifd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } /* Add signatures to header, and write header into the package. */ /* XXX header+payload digests/signatures might be checked again here. */ { Header nh = headerRead(ifd, HEADER_MAGIC_YES); if (nh == NULL) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } xx = headerWrite(fd, nh, HEADER_MAGIC_YES); headerFree(nh); if (xx) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } } /* Write the payload into the package. */ rc = copyPayload(ifd, fileName, fd, sigtarget); exit: free(rpmio_flags); free(SHA1); headerFree(h); /* XXX Fish the pkgid out of the signature header. */ if (sig != NULL && pkgidp != NULL) { struct rpmtd_s md5tag; headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT); if (rpmtdType(&md5tag) == RPM_BIN_TYPE && md5tag.count == 16 && md5tag.data != NULL) { *pkgidp = md5tag.data; } } rpmFreeSignature(sig); Fclose(ifd); Fclose(fd); if (sigtarget) { (void) unlink(sigtarget); free(sigtarget); } if (rc == RPMRC_OK) rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName); else (void) unlink(fileName); return rc; }
/* * Create a spec file object from a spec file * @param [String] filename Spec file path * @return [Spec] */ static VALUE spec_s_open(VALUE klass, VALUE filename) { #if RPM_VERSION_CODE < RPM_VERSION(4,1,0) Spec rspec; #else rpmts ts = NULL; #endif if (TYPE(filename) != T_STRING) { rb_raise(rb_eTypeError, "illegal argument type"); } #if RPM_VERSION_CODE < RPM_VERSION(4,1,0) switch (parseSpec(&rspec, RSTRING_PTR(filename), "/", NULL, 0, "", NULL, 1, 1)) { case 0: if (rspec != NULL) { break; } default: rb_raise(rb_eRuntimeError, "specfile `%s' parsing failed", RSTRING_PTR(filename)); } return Data_Wrap_Struct(klass, NULL, spec_free, rspec); #else ts = rpmtsCreate(); #if RPM_VERSION_CODE < RPM_VERSION(4,4,8) switch (parseSpec(ts, RSTRING_PTR(filename), "/", NULL, 0, "", NULL, 1, 1)) { #elif RPM_VERSION_CODE < RPM_VERSION(4,5,90) switch (parseSpec(ts, RSTRING_PTR(filename), "/", 0, "", NULL, 1, 1, 0)) { #elif RPM_VERSION_CODE < RPM_VERSION(5,0,0) switch (parseSpec(ts, RSTRING_PTR(filename), "/", NULL, 0, "", NULL, 1, 1)) { #else switch (parseSpec(ts, RSTRING_PTR(filename), "/", 0, "", NULL, 1, 1, 0)) { #endif case 0: if (ts != NULL) { break; } default: rb_raise(rb_eRuntimeError, "specfile `%s' parsing failed", RSTRING_PTR(filename)); } return Data_Wrap_Struct(klass, NULL, ts_free, ts); #endif } /* * * Alias for Spec#open */ VALUE rpm_spec_open(const char* filename) { return spec_s_open(rpm_cSpec, rb_str_new2(filename)); } /* * @return [String] Return Build root defined in the spec file */ VALUE rpm_spec_get_buildroot(VALUE spec) { #if RPM_VERSION_CODE < RPM_VERSION(4,5,90) if (RPM_SPEC(spec)->buildRootURL) { return rb_str_new2(RPM_SPEC(spec)->buildRootURL); } #elif RPM_VERSION_CODE < RPM_VERSION(4,5,90) if (RPM_SPEC(spec)->rootURL) { return rb_str_new2(RPM_SPEC(spec)->rootURL); } #elif RPM_VERSION_CODE < RPM_VERSION(5,0,0) if (RPM_SPEC(spec)->buildRoot) { return rb_str_new2(RPM_SPEC(spec)->buildRoot); } #else const char *buildRootURL = rpmGenPath(RPM_SPEC(spec)->rootURL, "%{?buildroot}", NULL); VALUE result = rb_str_new2(buildRootURL); buildRootURL = _free(buildRootURL); return result; #endif return Qnil; } /* * @return [String] Return Build subdirectory defined in the spec file */ VALUE rpm_spec_get_buildsubdir(VALUE spec) { if (RPM_SPEC(spec)->buildSubdir) { return rb_str_new2(RPM_SPEC(spec)->buildSubdir); } return Qnil; } /* * @return [Array<String>] Return Build architectures defined in the spec file */ VALUE rpm_spec_get_buildarchs(VALUE spec) { VALUE ba = rb_ivar_get(spec, id_ba); if (NIL_P(ba)) { register int i; ba = rb_ary_new(); for (i = 0; i < RPM_SPEC(spec)->BACount; i++) { rb_ary_push(ba, rb_str_new2(RPM_SPEC(spec)->BANames[i])); } rb_ivar_set(spec, id_ba, ba); } return ba; } /* * @return [Array<RPM::Require>] Return Build requires defined in the spec file */ VALUE rpm_spec_get_buildrequires(VALUE spec) { VALUE br = rb_ivar_get(spec, id_br); #if RPM_VERSION_CODE < RPM_VERSION(4,6,0) || RPM_VERSION_CODE >= RPM_VERSION(5,0,0) if (NIL_P(br)) { const char** names; const char** vers; int_32* flags; int_32 count; rpmTagType nt, vt, type; register int i; br = rb_ary_new(); if (!headerGetEntryMinMemory(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIRENAME, (hTYP_t)&nt, (hPTR_t*)&names, (hCNT_t)&count)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREVERSION, &vt, (void*)&vers); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREFLAGS, &type, (void*)&flags); for (i = 0; i < count; i++) { rb_ary_push(br, rpm_require_new(names[i], rpm_version_new(vers[i]), flags[i], spec)); } release_entry(nt, names); release_entry(vt, vers); rb_ivar_set(spec, id_br, br); } leave: return br; #else rpmtd nametd = rpmtdNew(); rpmtd versiontd = rpmtdNew(); rpmtd flagtd = rpmtdNew(); if (NIL_P(br)) { br = rb_ary_new(); if (!headerGet(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIRENAME, nametd, HEADERGET_MINMEM)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREVERSION, versiontd); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_REQUIREFLAGS, flagtd); rpmtdInit(nametd); while ( rpmtdNext(nametd) != -1 ) { rb_ary_push(br, rpm_require_new(rpmtdGetString(nametd), rpm_version_new(rpmtdNextString(versiontd)), *rpmtdNextUint32(flagtd), spec)); } rb_ivar_set(spec, id_br, br); } leave: rpmtdFree(nametd); rpmtdFree(versiontd); rpmtdFree(flagtd); return br; #endif } /* * @return [Array<RPM::Conflict>] Return Build conflicts defined in the spec file */ VALUE rpm_spec_get_buildconflicts(VALUE spec) { VALUE bc = rb_ivar_get(spec, id_bc); #if RPM_VERSION_CODE < RPM_VERSION(4,6,0) || RPM_VERSION_CODE >= RPM_VERSION(5,0,0) if (NIL_P(bc)) { const char** names; const char** vers; int_32* flags; int_32 count; rpmTagType nt, vt, type; register int i; bc = rb_ary_new(); if (!headerGetEntryMinMemory(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTNAME, (hTYP_t)&nt, (hPTR_t*)&names, (hCNT_t)&count)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTVERSION, &vt, (void*)&vers); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTFLAGS, &type, (void*)&flags); for (i = 0; i < count; i++) { rb_ary_push(bc, rpm_conflict_new(names[i], rpm_version_new(vers[i]), flags[i], spec)); } release_entry(nt, names); release_entry(vt, vers); rb_ivar_set(spec, id_bc, bc); } leave: return bc; #else rpmtd nametd = rpmtdNew(); rpmtd versiontd = rpmtdNew(); rpmtd flagtd = rpmtdNew(); if (NIL_P(bc)) { bc = rb_ary_new(); if (!headerGet(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTNAME, nametd, HEADERGET_MINMEM)) { goto leave; } get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTVERSION, versiontd); get_entry(RPM_SPEC(spec)->buildRestrictions, RPMTAG_CONFLICTFLAGS, flagtd); rpmtdInit(nametd); while ( rpmtdNext(nametd) != -1) { rb_ary_push(bc, rpm_conflict_new(rpmtdGetString(nametd), rpm_version_new(rpmtdNextString(versiontd)), *rpmtdNextUint32(flagtd), spec)); } rb_ivar_set(spec, id_bc, bc); } leave: rpmtdFree(nametd); rpmtdFree(versiontd); rpmtdFree(flagtd); return bc; #endif }
int parseDescription(Spec spec) /*@globals name, lang @*/ /*@modifies name, lang @*/ { rpmParseState nextPart = (rpmParseState) RPMRC_FAIL; /* assume error */ rpmiob iob = NULL; int flag = PART_SUBNAME; Package pkg; int rc, argc; int arg; const char **argv = NULL; poptContext optCon = NULL; spectag t = NULL; { char * se = strchr(spec->line, '#'); if (se) { *se = '\0'; while (--se >= spec->line && strchr(" \t\n\r", *se) != NULL) *se = '\0'; } } if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%description: %s\n"), spec->lineNum, poptStrerror(rc)); goto exit; } name = NULL; lang = RPMBUILD_DEFAULT_LANG; optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); while ((arg = poptGetNextOpt(optCon)) > 0) {;} if (name != NULL) flag = PART_NAME; if (arg < -1) { rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"), spec->lineNum, poptBadOption(optCon, POPT_BADOPTION_NOALIAS), spec->line); goto exit; } if (poptPeekArg(optCon)) { if (name == NULL) name = poptGetArg(optCon); if (poptPeekArg(optCon)) { rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"), spec->lineNum, spec->line); goto exit; } } if (lookupPackage(spec, name, flag, &pkg) != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"), spec->lineNum, spec->line); goto exit; } /* Lose the inheirited %description (if present). */ if (spec->packages->header != pkg->header) { HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); int xx; he->tag = RPMTAG_DESCRIPTION; xx = headerGet(pkg->header, he, 0); he->p.ptr = _free(he->p.ptr); if (xx && he->t == RPM_STRING_TYPE) xx = headerDel(pkg->header, he, 0); } t = stashSt(spec, pkg->header, RPMTAG_DESCRIPTION, lang); iob = rpmiobNew(0); if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; goto exit; } if (rc < 0) { nextPart = (rpmParseState) RPMRC_FAIL; goto exit; } while ((nextPart = isPart(spec)) == PART_NONE) { iob = rpmiobAppend(iob, spec->line, 1); if (t) t->t_nlines++; if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; break; } if (rc) { nextPart = (rpmParseState) RPMRC_FAIL; goto exit; } } iob = rpmiobRTrim(iob); if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) { const char * s = rpmiobStr(iob); (void) headerAddI18NString(pkg->header, RPMTAG_DESCRIPTION, s, lang); } exit: iob = rpmiobFree(iob); argv = _free(argv); optCon = poptFreeContext(optCon); return nextPart; }
/*@-mods@*/ rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp) { HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); HE_t she = (HE_t) memset(alloca(sizeof(*she)), 0, sizeof(*she)); pgpDig dig = rpmtsDig(ts); char buf[8*BUFSIZ]; ssize_t count; Header sigh = NULL; rpmtsOpX opx; rpmop op = NULL; size_t nb; unsigned ix; Header h = NULL; const char * msg = NULL; rpmVSFlags vsflags; rpmRC rc = RPMRC_FAIL; /* assume failure */ rpmop opsave = (rpmop) memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave)); int xx; pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); if (hdrp) *hdrp = NULL; assert(dig != NULL); (void) fdSetDig(fd, dig); /* Snapshot current I/O counters (cached persistent I/O reuses counters) */ (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ)); { const char item[] = "Lead"; msg = NULL; rc = rpmpkgRead(item, fd, NULL, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); /*@fallthrough@*/ case RPMRC_NOTFOUND: msg = _free(msg); goto exit; /*@notreached@*/ break; case RPMRC_OK: break; } msg = _free(msg); } { const char item[] = "Signature"; msg = NULL; rc = rpmpkgRead(item, fd, &sigh, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item, (msg && *msg ? msg : _("read failed\n"))); msg = _free(msg); goto exit; /*@notreached@*/ break; case RPMRC_OK: if (sigh == NULL) { rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); rc = RPMRC_FAIL; goto exit; } break; } msg = _free(msg); } #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask))) /* * Figger the most effective available signature. * Prefer signatures over digests, then header-only over header+payload. * DSA will be preferred over RSA if both exist because tested first. * Note that NEEDPAYLOAD prevents header+payload signatures and digests. */ she->tag = (rpmTag)0; opx = (rpmtsOpX)0; vsflags = pgpDigVSFlags; if (_chk(RPMVSF_NOECDSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_ECDSA)) { she->tag = (rpmTag)RPMSIGTAG_ECDSA; } else if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) { she->tag = (rpmTag)RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) { she->tag = (rpmTag)RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) { she->tag = (rpmTag)RPMSIGTAG_SHA1; } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5)) { she->tag = (rpmTag)RPMSIGTAG_MD5; fdInitDigest(fd, PGPHASHALGO_MD5, 0); opx = RPMTS_OP_DIGEST; } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; msg = NULL; /* XXX stats will include header i/o and setup overhead. */ /* XXX repackaged packages have appended tags, legacy dig/sig check fails */ if (opx > 0) { op = (rpmop) pgpStatsAccumulator(dig, opx); (void) rpmswEnter(op, 0); } /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */ nb = fd->stats->ops[FDSTAT_READ].bytes; { const char item[] = "Header"; msg = NULL; rc = rpmpkgRead(item, fd, &h, &msg); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); msg = _free(msg); goto exit; } msg = _free(msg); } nb = fd->stats->ops[FDSTAT_READ].bytes - nb; /*@=type@*/ if (opx > 0 && op != NULL) { (void) rpmswExit(op, nb); op = NULL; } /* Any digests or signatures to check? */ if (she->tag == 0) { rc = RPMRC_OK; goto exit; } dig->nbytes = 0; /* Fish out the autosign pubkey (if present). */ he->tag = RPMTAG_PUBKEYS; xx = headerGet(h, he, 0); if (xx && he->p.argv != NULL && he->c > 0) switch (he->t) { default: break; case RPM_STRING_ARRAY_TYPE: ix = he->c - 1; /* XXX FIXME: assumes last pubkey */ dig->pub = _free(dig->pub); dig->publen = 0; { rpmiob iob = rpmiobNew(0); iob = rpmiobAppend(iob, he->p.argv[ix], 0); xx = pgpArmorUnwrap(iob, (rpmuint8_t **)&dig->pub, &dig->publen); iob = rpmiobFree(iob); } if (xx != PGPARMOR_PUBKEY) { dig->pub = _free(dig->pub); dig->publen = 0; } break; } he->p.ptr = _free(he->p.ptr); /* Retrieve the tag parameters from the signature header. */ xx = headerGet(sigh, she, 0); if (she->p.ptr == NULL) { rc = RPMRC_FAIL; goto exit; } /*@-ownedtrans -noeffect@*/ xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); /*@=ownedtrans =noeffect@*/ switch ((rpmSigTag)she->tag) { default: /* XXX keep gcc quiet. */ assert(0); /*@notreached@*/ break; case RPMSIGTAG_RSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hrsa); break; case RPMSIGTAG_DSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hdsa); break; case RPMSIGTAG_ECDSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hecdsa); break; case RPMSIGTAG_SHA1: /* XXX dig->hsha? */ xx = hBlobDigest(h, dig, PGPHASHALGO_SHA1, &dig->hdsa); break; case RPMSIGTAG_MD5: /* Legacy signatures need the compressed payload in the digest too. */ op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ (void) rpmswEnter(op, 0); while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) dig->nbytes += count; (void) rpmswExit(op, dig->nbytes); op->count--; /* XXX one too many */ dig->nbytes += nb; /* XXX include size of header blob. */ if (count < 0) { rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); rc = RPMRC_FAIL; goto exit; } /* XXX Steal the digest-in-progress from the file handle. */ fdStealDigest(fd, dig); break; } /** @todo Implement disable/enable/warn/error/anal policy. */ buf[0] = '\0'; rc = rpmVerifySignature(dig, buf); switch (rc) { case RPMRC_OK: /* Signature is OK. */ rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf); break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_NOKEY: /* Public key is unavailable. */ #ifndef DYING /* XXX Print NOKEY/NOTTRUSTED warning only once. */ { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); rpmlog(lvl, "%s: %s\n", fn, buf); } break; case RPMRC_NOTFOUND: /* Signature is unknown type. */ rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf); break; #else case RPMRC_NOTFOUND: /* Signature is unknown type. */ case RPMRC_NOSIG: /* Signature is unavailable. */ #endif default: case RPMRC_FAIL: /* Signature does not verify. */ rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf); break; } exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); } (void)headerFree(h); h = NULL; /* Accumulate time reading package header. */ (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR), fdstat_op(fd, FDSTAT_READ)); (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR), opsave); #ifdef NOTYET /* Return RPMRC_NOSIG for MANDATORY signature verification. */ { rpmSigTag sigtag = pgpGetSigtag(dig); switch (sigtag) { default: rc = RPMRC_NOSIG; /*@fallthrough@*/ case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: case RPMSIGTAG_ECDSA: break; } } #endif rpmtsCleanDig(ts); (void)headerFree(sigh); sigh = NULL; return rc; }
/** \ingroup rpmcli * Create/modify elements in signature header. * @param rpm path to package * @param deleting adding or deleting signature? * @param signfiles sign files if non-zero * @return 0 on success, -1 on error */ static int rpmSign(const char *rpm, int deleting, int signfiles) { FD_t fd = NULL; FD_t ofd = NULL; rpmlead lead = NULL; char *trpm = NULL; Header sigh = NULL; Header h = NULL; char *msg = NULL; int res = -1; /* assume failure */ rpmRC rc; struct rpmtd_s utd; off_t headerStart; off_t sigStart; struct sigTarget_s sigt1; struct sigTarget_s sigt2; unsigned int origSigSize; int insSig = 0; fprintf(stdout, "%s:\n", rpm); if (manageFile(&fd, rpm, O_RDWR)) goto exit; if ((rc = rpmLeadRead(fd, &lead, NULL, &msg)) != RPMRC_OK) { rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg); goto exit; } sigStart = Ftell(fd); rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm, (msg && *msg ? msg : "\n")); goto exit; } headerStart = Ftell(fd); if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), rpm, msg); goto exit; } if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n")); goto exit; } if (signfiles) { includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart); } unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES); origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES); if (deleting) { /* Nuke all the signature tags. */ deleteSigs(sigh); } else { /* Signature target containing header + payload */ sigt1.fd = fd; sigt1.start = headerStart; sigt1.fileName = rpm; sigt1.size = fdSize(fd) - headerStart; /* Signature target containing only header */ sigt2 = sigt1; sigt2.size = headerSizeof(h, HEADER_MAGIC_YES); res = replaceSignature(sigh, &sigt1, &sigt2); if (res != 0) { if (res == 1) { rpmlog(RPMLOG_WARNING, _("%s already contains identical signature, skipping\n"), rpm); /* Identical signature is not an error */ res = 0; } goto exit; } res = -1; } /* Try to make new signature smaller to have size of original signature */ rpmtdReset(&utd); if (headerGet(sigh, RPMSIGTAG_RESERVEDSPACE, &utd, HEADERGET_MINMEM)) { int diff; int count; char *reservedSpace = NULL; count = utd.count; diff = headerSizeof(sigh, HEADER_MAGIC_YES) - origSigSize; if (diff < count) { reservedSpace = xcalloc(count - diff, sizeof(char)); headerDel(sigh, RPMSIGTAG_RESERVEDSPACE); rpmtdReset(&utd); utd.tag = RPMSIGTAG_RESERVEDSPACE; utd.count = count - diff; utd.type = RPM_BIN_TYPE; utd.data = reservedSpace; headerPut(sigh, &utd, HEADERPUT_DEFAULT); free(reservedSpace); insSig = 1; } } /* Reallocate the signature into one contiguous region. */ sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES); if (sigh == NULL) /* XXX can't happen */ goto exit; if (insSig) { /* Insert new signature into original rpm */ if (Fseek(fd, sigStart, SEEK_SET) < 0) { rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } if (rpmWriteSignature(fd, sigh)) { rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), rpm, Fstrerror(fd)); goto exit; } res = 0; } else { /* Replace orignal rpm with new rpm containing new signature */ rasprintf(&trpm, "%s.XXXXXX", rpm); ofd = rpmMkTemp(trpm); if (ofd == NULL || Ferror(ofd)) { rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n")); goto exit; } /* Write the lead/signature of the output rpm */ rc = rpmLeadWrite(ofd, lead); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm, Fstrerror(ofd)); goto exit; } if (rpmWriteSignature(ofd, sigh)) { rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm, Fstrerror(ofd)); goto exit; } if (Fseek(fd, headerStart, SEEK_SET) < 0) { rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } /* Append the header and archive from the temp file */ if (copyFile(&fd, rpm, &ofd, trpm) == 0) { struct stat st; /* Move final target into place, restore file permissions. */ if (stat(rpm, &st) == 0 && unlink(rpm) == 0 && rename(trpm, rpm) == 0 && chmod(rpm, st.st_mode) == 0) { res = 0; } else { rpmlog(RPMLOG_ERR, _("replacing %s failed: %s\n"), rpm, strerror(errno)); } } } exit: if (fd) (void) closeFile(&fd); if (ofd) (void) closeFile(&ofd); rpmFreeSignature(sigh); headerFree(h); rpmLeadFree(lead); free(msg); /* Clean up intermediate target */ if (trpm) { (void) unlink(trpm); free(trpm); } return res; }
static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage) { const rpmts ts = psm->ts; rpmfi fi = psm->fi; rpmRC rc = RPMRC_OK; switch (stage) { case PSM_UNKNOWN: break; case PSM_INIT: rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n", psm->goalName, rpmteNEVR(psm->te), rpmfiFC(fi)); /* * When we run scripts, we pass an argument which is the number of * versions of this package that will be installed when we are * finished. */ psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te)); if (psm->npkgs_installed < 0) { rc = RPMRC_FAIL; break; } if (psm->goal == PKG_INSTALL) { Header h = rpmteHeader(psm->te); psm->scriptArg = psm->npkgs_installed + 1; psm->amount = 0; psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE); /* fake up something for packages with no files */ if (psm->total == 0) psm->total = 100; /* HACK: reinstall abuses te instance to remove old header */ if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG) markReplacedInstance(ts, psm->te); if (rpmfiFC(fi) > 0) { struct rpmtd_s filenames; rpmTag ftag = RPMTAG_FILENAMES; if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) { ftag = RPMTAG_ORIGFILENAMES; } headerGet(h, ftag, &filenames, HEADERGET_EXT); fi->apath = filenames.data; /* Ick.. */ } headerFree(h); } if (psm->goal == PKG_ERASE) { psm->scriptArg = psm->npkgs_installed - 1; psm->amount = 0; psm->total = rpmfiFC(fi) ? rpmfiFC(fi) : 100; } break; case PSM_PRE: if (psm->goal == PKG_INSTALL) { psm->scriptTag = RPMTAG_PREIN; psm->sense = RPMSENSE_TRIGGERPREIN; psm->countCorrection = 0; /* XXX is this correct?!? */ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) { /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; /* Run triggers in this package other package(s) set off. */ rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) { rc = rpmpsmNext(psm, PSM_SCRIPT); if (rc) break; } } if (psm->goal == PKG_ERASE) { psm->scriptTag = RPMTAG_PREUN; psm->sense = RPMSENSE_TRIGGERUN; psm->countCorrection = -1; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) { /* Run triggers in this package other package(s) set off. */ rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS); if (rc) break; /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN)) rc = rpmpsmNext(psm, PSM_SCRIPT); } break; case PSM_PROCESS: if (psm->goal == PKG_INSTALL) { int fsmrc = 0; rpmpsmNotify(psm, RPMCALLBACK_INST_START, 0); /* make sure first progress call gets made */ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, 0); if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) { FD_t payload = rpmtePayload(psm->te); if (payload == NULL) { rc = RPMRC_FAIL; break; } fsmrc = rpmPackageFilesInstall(psm->ts, psm->te, psm->fi, payload, psm, &psm->failedFile); rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); Fclose(payload); } /* XXX make sure progress reaches 100% */ rpmpsmNotify(psm, 0, psm->total); rpmpsmNotify(psm, RPMCALLBACK_INST_STOP, psm->total); if (fsmrc) { char *emsg = rpmcpioStrerror(fsmrc); rpmlog(RPMLOG_ERR, _("unpacking of archive failed%s%s: %s\n"), (psm->failedFile != NULL ? _(" on file ") : ""), (psm->failedFile != NULL ? psm->failedFile : ""), emsg); free(emsg); rc = RPMRC_FAIL; /* XXX notify callback on error. */ rpmtsNotify(ts, psm->te, RPMCALLBACK_UNPACK_ERROR, 0, 0); break; } } if (psm->goal == PKG_ERASE) { if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break; rpmpsmNotify(psm, RPMCALLBACK_UNINST_START, 0); /* make sure first progress call gets made */ rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, 0); /* XXX should't we log errors from here? */ if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) { rc = rpmPackageFilesRemove(psm->ts, psm->te, psm->fi, psm, &psm->failedFile); } /* XXX make sure progress reaches 100% */ rpmpsmNotify(psm, 0, psm->total); rpmpsmNotify(psm, RPMCALLBACK_UNINST_STOP, psm->total); } break; case PSM_POST: if (psm->goal == PKG_INSTALL) { rpm_time_t installTime = (rpm_time_t) time(NULL); rpmfs fs = rpmteGetFileStates(psm->te); rpm_count_t fc = rpmfsFC(fs); rpm_fstate_t * fileStates = rpmfsGetStates(fs); Header h = rpmteHeader(psm->te); rpm_color_t tscolor = rpmtsColor(ts); if (fileStates != NULL && fc > 0) { headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc); } headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1); headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1); headerFree(h); /* * If this package has already been installed, remove it from * the database before adding the new one. */ if (rpmteDBInstance(psm->te)) { rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE); if (rc) break; } rc = rpmpsmNext(psm, PSM_RPMDB_ADD); if (rc) break; psm->scriptTag = RPMTAG_POSTIN; psm->sense = RPMSENSE_TRIGGERIN; psm->countCorrection = 0; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) { rc = rpmpsmNext(psm, PSM_SCRIPT); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) { /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; /* Run triggers in this package other package(s) set off. */ rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS); if (rc) break; } rc = markReplacedFiles(psm); } if (psm->goal == PKG_ERASE) { psm->scriptTag = RPMTAG_POSTUN; psm->sense = RPMSENSE_TRIGGERPOSTUN; psm->countCorrection = -1; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) { rc = rpmpsmNext(psm, PSM_SCRIPT); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) { /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; } rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE); } break; case PSM_UNDO: break; case PSM_FINI: if (rc) { char *emsg = rpmcpioStrerror(rc); if (psm->failedFile) rpmlog(RPMLOG_ERR, _("%s failed on file %s: %s\n"), psm->goalName, psm->failedFile, emsg); else rpmlog(RPMLOG_ERR, _("%s failed: %s\n"), psm->goalName, emsg); free(emsg); /* XXX notify callback on error. */ rpmtsNotify(ts, psm->te, RPMCALLBACK_CPIO_ERROR, 0, 0); } psm->failedFile = _free(psm->failedFile); fi->apath = _free(fi->apath); break; case PSM_CREATE: break; case PSM_DESTROY: break; case PSM_SCRIPT: /* Run current package scriptlets. */ rc = runInstScript(psm); break; case PSM_TRIGGERS: /* Run triggers in other package(s) this package sets off. */ rc = runTriggers(psm); break; case PSM_IMMED_TRIGGERS: /* Run triggers in this package other package(s) set off. */ rc = runImmedTriggers(psm); break; case PSM_RPMDB_ADD: { Header h = rpmteHeader(psm->te); if (!headerIsEntry(h, RPMTAG_INSTALLTID)) { rpm_tid_t tid = rpmtsGetTid(ts); if (tid != 0 && tid != (rpm_tid_t)-1) headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1); } (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0); rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL; (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0); if (rc == RPMRC_OK) rpmteSetDBInstance(psm->te, headerGetInstance(h)); headerFree(h); } break; case PSM_RPMDB_REMOVE: (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0); rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(psm->te)) == 0) ? RPMRC_OK : RPMRC_FAIL; (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0); if (rc == RPMRC_OK) rpmteSetDBInstance(psm->te, 0); break; default: break; } return rc; }
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, const char * fn, Header * hdrp) { pgpDig dig = NULL; char buf[8*BUFSIZ]; ssize_t count; rpmlead l = NULL; Header sigh = NULL; rpmSigTag sigtag; struct rpmtd_s sigtd; Header h = NULL; char * msg; rpmRC rc = RPMRC_FAIL; /* assume failure */ int leadtype = -1; headerGetFlags hgeflags = HEADERGET_DEFAULT; DIGEST_CTX ctx = NULL; if (hdrp) *hdrp = NULL; rpmtdReset(&sigtd); l = rpmLeadNew(); if ((rc = rpmLeadRead(fd, l)) == RPMRC_OK) { const char * err = NULL; if ((rc = rpmLeadCheck(l, &err)) == RPMRC_FAIL) { rpmlog(RPMLOG_ERR, "%s: %s\n", fn, err); } leadtype = rpmLeadType(l); } l = rpmLeadFree(l); if (rc != RPMRC_OK) goto exit; /* Read the signature header. */ msg = NULL; rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn, (msg && *msg ? msg : "\n")); msg = _free(msg); goto exit; break; case RPMRC_OK: if (sigh == NULL) { rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); rc = RPMRC_FAIL; goto exit; } break; } msg = _free(msg); #define _chk(_mask, _tag) \ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag))) /* * Figger the most effective available signature. * Prefer signatures over digests, then header-only over header+payload. * DSA will be preferred over RSA if both exist because tested first. * Note that NEEDPAYLOAD prevents header+payload signatures and digests. */ sigtag = 0; if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) { sigtag = RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) { sigtag = RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_GPG)) { sigtag = RPMSIGTAG_GPG; fdInitDigest(fd, PGPHASHALGO_SHA1, 0); } else if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_PGP)) { sigtag = RPMSIGTAG_PGP; fdInitDigest(fd, PGPHASHALGO_MD5, 0); } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) { sigtag = RPMSIGTAG_SHA1; } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_MD5)) { sigtag = RPMSIGTAG_MD5; fdInitDigest(fd, PGPHASHALGO_MD5, 0); } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; msg = NULL; rc = rpmpkgReadHeader(keyring, vsflags, fd, &h, &msg); if (rc != RPMRC_OK || h == NULL) { rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s"), fn, (msg && *msg ? msg : "\n")); msg = _free(msg); goto exit; } msg = _free(msg); /* Any digests or signatures to check? */ if (sigtag == 0) { rc = RPMRC_OK; goto exit; } dig = pgpNewDig(); if (dig == NULL) { rc = RPMRC_FAIL; goto exit; } /* Retrieve the tag parameters from the signature header. */ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) { rc = RPMRC_FAIL; goto exit; } switch (sigtag) { case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) { goto exit; } /* fallthrough */ case RPMSIGTAG_SHA1: { struct rpmtd_s utd; pgpHashAlgo hashalgo = (sigtag == RPMSIGTAG_SHA1) ? PGPHASHALGO_SHA1 : dig->signature.hash_algo; if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) break; ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE); (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); (void) rpmDigestUpdate(ctx, utd.data, utd.count); rpmtdFreeData(&utd); } break; case RPMSIGTAG_GPG: case RPMSIGTAG_PGP5: /* XXX legacy */ case RPMSIGTAG_PGP: if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) { goto exit; } /* fallthrough */ case RPMSIGTAG_MD5: /* Legacy signatures need the compressed payload in the digest too. */ while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {} if (count < 0) { rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); rc = RPMRC_FAIL; goto exit; } ctx = rpmDigestBundleDupCtx(fdGetBundle(fd), (sigtag == RPMSIGTAG_MD5) ? PGPHASHALGO_MD5 : dig->signature.hash_algo); break; default: break; } /** @todo Implement disable/enable/warn/error/anal policy. */ rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &msg); switch (rc) { case RPMRC_OK: /* Signature is OK. */ rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg); break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_NOKEY: /* Public key is unavailable. */ /* XXX Print NOKEY/NOTTRUSTED warning only once. */ { int lvl = (stashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); rpmlog(lvl, "%s: %s", fn, msg); } break; case RPMRC_NOTFOUND: /* Signature is unknown type. */ rpmlog(RPMLOG_WARNING, "%s: %s", fn, msg); break; default: case RPMRC_FAIL: /* Signature does not verify. */ rpmlog(RPMLOG_ERR, "%s: %s", fn, msg); break; } free(msg); exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) { if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } } /* * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) { headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } /* * Convert legacy headers on the fly. Not having "new" style compressed * filenames is close enough estimate for legacy indication... */ if (!headerIsEntry(h, RPMTAG_DIRNAMES)) { headerConvert(h, HEADERCONV_RETROFIT_V3); } /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); } rpmtdFreeData(&sigtd); rpmDigestFinal(ctx, NULL, NULL, 0); h = headerFree(h); pgpFreeDig(dig); sigh = rpmFreeSignature(sigh); return rc; }
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, FD_t fd, Header * hdrp, unsigned int *keyidp, char **msg) { pgpDigParams sig = NULL; Header sigh = NULL; rpmTagVal sigtag; struct rpmtd_s sigtd; struct sigtInfo_s sinfo; Header h = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int leadtype = -1; headerGetFlags hgeflags = HEADERGET_DEFAULT; if (hdrp) *hdrp = NULL; rpmtdReset(&sigtd); if ((rc = rpmLeadRead(fd, &leadtype, msg)) != RPMRC_OK) { /* Avoid message spew on manifests */ if (rc == RPMRC_NOTFOUND) { *msg = _free(*msg); } goto exit; } /* Read the signature header. */ rc = rpmReadSignature(fd, &sigh, msg); if (rc != RPMRC_OK) { goto exit; } #define _chk(_mask, _tag) \ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag))) /* * Figger the most effective means of verification available, prefer * signatures over digests. Legacy header+payload entries are not used. * DSA will be preferred over RSA if both exist because tested first. */ sigtag = 0; if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) { sigtag = RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) { sigtag = RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) { sigtag = RPMSIGTAG_SHA1; } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; rc = rpmpkgReadHeader(fd, &h, msg); if (rc != RPMRC_OK || h == NULL) { goto exit; } /* Any digests or signatures to check? */ if (sigtag == 0) { rc = RPMRC_OK; goto exit; } /* Free up any previous "ok" message before signature/digest check */ *msg = _free(*msg); /* Retrieve the tag parameters from the signature header. */ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) { rc = RPMRC_FAIL; goto exit; } if (rpmSigInfoParse(&sigtd, "package", &sinfo, &sig, msg) == RPMRC_OK) { struct rpmtd_s utd; DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE); if (headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) { rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, utd.data, utd.count); rpmtdFreeData(&utd); } /** @todo Implement disable/enable/warn/error/anal policy. */ rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, msg); rpmDigestFinal(ctx, NULL, NULL, 0); } else { rc = RPMRC_FAIL; } exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) { if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } } /* * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) { headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } /* * Convert legacy headers on the fly. Not having immutable region * equals a truly ancient package, do full retrofit. OTOH newer * packages might have been built with --nodirtokens, test and handle * the non-compressed filelist case separately. */ if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) headerConvert(h, HEADERCONV_RETROFIT_V3); else if (headerIsEntry(h, RPMTAG_OLDFILENAMES)) headerConvert(h, HEADERCONV_COMPRESSFILELIST); /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); if (keyidp) *keyidp = getKeyid(sig); } rpmtdFreeData(&sigtd); h = headerFree(h); pgpDigParamsFree(sig); sigh = headerFree(sigh); return rc; }
/** @todo Generalize --freshen policies. */ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv) { struct rpmEIU * eiu = xcalloc(1, sizeof(*eiu)); rpmRelocation * relocations; char * fileURL = NULL; rpmVSFlags vsflags, ovsflags; int rc; int i; vsflags = setvsFlags(ia); ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD)); if (fileArgv == NULL) goto exit; (void) rpmtsSetFlags(ts, ia->transFlags); relocations = ia->relocations; setNotifyFlag(ia, ts); if ((eiu->relocations = relocations) != NULL) { while (eiu->relocations->oldPath) eiu->relocations++; if (eiu->relocations->newPath == NULL) eiu->relocations = NULL; } /* Build fully globbed list of arguments in argv[argc]. */ for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) { ARGV_t av = NULL; int ac = 0; if (giFlags & RPMGI_NOGLOB) { rc = rpmNoGlob(*eiu->fnp, &ac, &av); } else { char * fn = rpmEscapeSpaces(*eiu->fnp); rc = rpmGlob(fn, &ac, &av); fn = _free(fn); } if (rc || ac == 0) { if (giFlags & RPMGI_NOGLOB) { rpmlog(RPMLOG_ERR, _("File not found: %s\n"), *eiu->fnp); } else { rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp); } eiu->numFailed++; continue; } argvAppend(&(eiu->argv), av); argvFree(av); eiu->argc += ac; } restart: /* Allocate sufficient storage for next set of args. */ if (eiu->pkgx >= eiu->numPkgs) { eiu->numPkgs = eiu->pkgx + eiu->argc; eiu->pkgURL = xrealloc(eiu->pkgURL, (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL)); memset(eiu->pkgURL + eiu->pkgx, 0, ((eiu->argc + 1) * sizeof(*eiu->pkgURL))); eiu->pkgState = xrealloc(eiu->pkgState, (eiu->numPkgs + 1) * sizeof(*eiu->pkgState)); memset(eiu->pkgState + eiu->pkgx, 0, ((eiu->argc + 1) * sizeof(*eiu->pkgState))); } /* Retrieve next set of args, cache on local storage. */ for (i = 0; i < eiu->argc; i++) { fileURL = _free(fileURL); fileURL = eiu->argv[i]; eiu->argv[i] = NULL; switch (urlIsURL(fileURL)) { case URL_IS_HTTPS: case URL_IS_HTTP: case URL_IS_FTP: { char *tfn = NULL; FD_t tfd; if (rpmIsVerbose()) fprintf(stdout, _("Retrieving %s\n"), fileURL); tfd = rpmMkTempFile(rpmtsRootDir(ts), &tfn); if (tfd && tfn) { Fclose(tfd); rc = urlGetFile(fileURL, tfn); } else { rc = -1; } if (rc != 0) { rpmlog(RPMLOG_ERR, _("skipping %s - transfer failed\n"), fileURL); eiu->numFailed++; eiu->pkgURL[eiu->pkgx] = NULL; tfn = _free(tfn); break; } eiu->pkgState[eiu->pkgx] = 1; eiu->pkgURL[eiu->pkgx] = tfn; eiu->pkgx++; } break; case URL_IS_PATH: case URL_IS_DASH: /* WRONG WRONG WRONG */ case URL_IS_HKP: /* WRONG WRONG WRONG */ default: eiu->pkgURL[eiu->pkgx] = fileURL; fileURL = NULL; eiu->pkgx++; break; } } fileURL = _free(fileURL); if (eiu->numFailed) goto exit; /* Continue processing file arguments, building transaction set. */ for (eiu->fnp = eiu->pkgURL+eiu->prevx; *eiu->fnp != NULL; eiu->fnp++, eiu->prevx++) { Header h = NULL; const char * fileName; rpmlog(RPMLOG_DEBUG, "============== %s\n", *eiu->fnp); (void) urlPath(*eiu->fnp, &fileName); if (tryReadHeader(ts, eiu, &h) == RPMRC_FAIL) continue; if (eiu->rpmrc == RPMRC_NOTFOUND) { rc = tryReadManifest(eiu); if (rc == RPMRC_OK) { eiu->prevx++; goto restart; } } if (headerIsSource(h)) { if (ia->installInterfaceFlags & INSTALL_FRESHEN) { headerFree(h); continue; } rpmlog(RPMLOG_DEBUG, "\tadded source package [%d]\n", eiu->numSRPMS); eiu->sourceURL = xrealloc(eiu->sourceURL, (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL)); eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp; *eiu->fnp = NULL; eiu->numSRPMS++; eiu->sourceURL[eiu->numSRPMS] = NULL; continue; } if (eiu->relocations) { struct rpmtd_s prefixes; headerGet(h, RPMTAG_PREFIXES, &prefixes, HEADERGET_DEFAULT); if (rpmtdCount(&prefixes) == 1) { eiu->relocations->oldPath = xstrdup(rpmtdGetString(&prefixes)); rpmtdFreeData(&prefixes); } else { rpmlog(RPMLOG_ERR, _("package %s is not relocatable\n"), headerGetString(h, RPMTAG_NAME)); eiu->numFailed++; goto exit; } } if (ia->installInterfaceFlags & INSTALL_FRESHEN) if (checkFreshenStatus(ts, h) != 1) { headerFree(h); continue; } if (ia->installInterfaceFlags & INSTALL_REINSTALL) rc = rpmtsAddReinstallElement(ts, h, (fnpyKey)fileName); else rc = rpmtsAddInstallElement(ts, h, (fnpyKey)fileName, (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0, relocations); headerFree(h); if (eiu->relocations) eiu->relocations->oldPath = _free(eiu->relocations->oldPath); switch (rc) { case 0: rpmlog(RPMLOG_DEBUG, "\tadded binary package [%d]\n", eiu->numRPMS); break; case 1: rpmlog(RPMLOG_ERR, _("error reading from file %s\n"), *eiu->fnp); eiu->numFailed++; goto exit; break; default: eiu->numFailed++; goto exit; break; } eiu->numRPMS++; } rpmlog(RPMLOG_DEBUG, "found %d source and %d binary packages\n", eiu->numSRPMS, eiu->numRPMS); if (eiu->numFailed) goto exit; if (eiu->numRPMS) { int rc = rpmcliTransaction(ts, ia, eiu->numPkgs); if (rc < 0) eiu->numFailed += eiu->numRPMS; else if (rc > 0) eiu->numFailed += rc; } if (eiu->numSRPMS && (eiu->sourceURL != NULL)) { rpmcliProgressState = 0; rpmcliProgressTotal = 0; rpmcliProgressCurrent = 0; for (i = 0; i < eiu->numSRPMS; i++) { rpmsqPoll(); if (eiu->sourceURL[i] != NULL) { rc = RPMRC_OK; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) rc = rpmInstallSource(ts, eiu->sourceURL[i], NULL, NULL); if (rc != 0) eiu->numFailed++; } } } exit: if (eiu->pkgURL != NULL) { for (i = 0; i < eiu->numPkgs; i++) { if (eiu->pkgURL[i] == NULL) continue; if (eiu->pkgState[i] == 1) (void) unlink(eiu->pkgURL[i]); eiu->pkgURL[i] = _free(eiu->pkgURL[i]); } } eiu->pkgState = _free(eiu->pkgState); eiu->pkgURL = _free(eiu->pkgURL); eiu->argv = _free(eiu->argv); rc = eiu->numFailed; free(eiu); rpmtsEmpty(ts); rpmtsSetVSFlags(ts, ovsflags); return rc; }
/** \ingroup rpmfi * Retrieve file names from header. * * The representation of file names in package headers changed in rpm-4.0. * Originally, file names were stored as an array of absolute paths. * In rpm-4.0, file names are stored as separate arrays of dirname's and * basename's, * with a dirname index to associate the correct dirname * with each basname. * * This function is used to retrieve file names independent of how the * file names are represented in the package header. * * @param h header * @param tagN RPMTAG_BASENAMES | PMTAG_ORIGBASENAMES * @param withstate take file state into account? * @retval td tag data container * @return 1 on success */ static int fnTag(Header h, rpmTag tagN, int withstate, rpmtd td) { const char **baseNames, **dirNames; const char *fileStates = NULL; uint32_t *dirIndexes; rpm_count_t count, retcount, dncount; size_t size = 0; rpmTag dirNameTag = RPMTAG_DIRNAMES; rpmTag dirIndexesTag = RPMTAG_DIRINDEXES; int i, j; int rc = 0; /* assume failure */ struct rpmtd_s bnames, dnames, dixs, fstates; if (tagN == RPMTAG_ORIGBASENAMES) { dirNameTag = RPMTAG_ORIGDIRNAMES; dirIndexesTag = RPMTAG_ORIGDIRINDEXES; } if (!headerGet(h, tagN, &bnames, HEADERGET_MINMEM)) { return 0; /* no file list */ } (void) headerGet(h, dirNameTag, &dnames, HEADERGET_MINMEM); (void) headerGet(h, dirIndexesTag, &dixs, HEADERGET_MINMEM); retcount = count = rpmtdCount(&bnames); dncount = rpmtdCount(&dnames); /* Basic sanity checking for our interrelated tags */ if (rpmtdCount(&dixs) != count || dncount < 1 || dncount > count) td->flags |= RPMTD_INVALID; if (withstate) { /* no recorded states means no installed files */ if (!headerGet(h, RPMTAG_FILESTATES, &fstates, HEADERGET_MINMEM)) goto exit; if (rpmtdCount(&fstates) != count) td->flags |= RPMTD_INVALID; fileStates = fstates.data; } if (td->flags & RPMTD_INVALID) goto exit; baseNames = bnames.data; dirNames = dnames.data; dirIndexes = dixs.data; /* * fsm, psm and rpmfi assume the data is stored in a single allocation * block, until those assumptions are removed we need to jump through * a few hoops here and precalculate sizes etc */ for (i = 0; i < count; i++) { if (fileStates && !RPMFILE_IS_INSTALLED(fileStates[i])) { retcount--; continue; } /* Sanity check directory indexes are within bounds */ if (dirIndexes[i] >= dncount) { td->flags |= RPMTD_INVALID; break; } size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1; } if (!(td->flags & RPMTD_INVALID)) { char **fileNames = xmalloc(size + (sizeof(*fileNames) * retcount)); char *t = ((char *) fileNames) + (sizeof(*fileNames) * retcount); for (i = 0, j = 0; i < count; i++) { if (fileStates && !RPMFILE_IS_INSTALLED(fileStates[i])) continue; fileNames[j++] = t; t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]); *t++ = '\0'; } td->data = fileNames; td->count = retcount; td->type = RPM_STRING_ARRAY_TYPE; td->flags |= RPMTD_ALLOCED; rc = 1; } exit: rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dixs); /* only safe if the headerGet() on file states was actually called */ if (fileStates) rpmtdFreeData(&fstates); return rc; }
void rpmhdrs_diff_prnt_block (gboolean changelogs, struct RpmHeadersDiff *diff) { int num = 0; g_assert (diff->hs_mod_old->len == diff->hs_mod_new->len); if (diff->hs_mod_old->len) { gboolean done = FALSE; for (num = 0; num < diff->hs_mod_new->len; ++num) { Header ho = diff->hs_mod_old->pdata[num]; Header hn = diff->hs_mod_new->pdata[num]; struct rpmtd_s ochanges_date_s; _cleanup_rpmtddata_ rpmtd ochanges_date = NULL; struct rpmtd_s ochanges_name_s; _cleanup_rpmtddata_ rpmtd ochanges_name = NULL; struct rpmtd_s ochanges_text_s; _cleanup_rpmtddata_ rpmtd ochanges_text = NULL; struct rpmtd_s nchanges_date_s; _cleanup_rpmtddata_ rpmtd nchanges_date = NULL; struct rpmtd_s nchanges_name_s; _cleanup_rpmtddata_ rpmtd nchanges_name = NULL; struct rpmtd_s nchanges_text_s; _cleanup_rpmtddata_ rpmtd nchanges_text = NULL; int ocnum = 0; int ncnum = 0; uint64_t ochange_date = 0; const char *ochange_name = NULL; const char *ochange_text = NULL; uint64_t nchange_date = 0; const char *nchange_name = NULL; const char *nchange_text = NULL; g_assert (!header_name_cmp (ho, hn)); if (rpmVersionCompare (ho, hn) > 0) continue; if (!done) { done = TRUE; g_print ("Upgraded:\n"); } printf (" "); pkg_print (hn); if (!changelogs) continue; /* Load the old %changelog entries */ ochanges_date = &ochanges_date_s; headerGet (ho, RPMTAG_CHANGELOGTIME, ochanges_date, HEADERGET_MINMEM); ochanges_name = &ochanges_name_s; headerGet (ho, RPMTAG_CHANGELOGNAME, ochanges_name, HEADERGET_MINMEM); ochanges_text = &ochanges_text_s; headerGet (ho, RPMTAG_CHANGELOGTEXT, ochanges_text, HEADERGET_MINMEM); ocnum = rpmtdCount (ochanges_date); if (!ocnum) continue; /* Load the new %changelog entries */ nchanges_date = &nchanges_date_s; headerGet (hn, RPMTAG_CHANGELOGTIME, nchanges_date, HEADERGET_MINMEM); nchanges_name = &nchanges_name_s; headerGet (hn, RPMTAG_CHANGELOGNAME, nchanges_name, HEADERGET_MINMEM); nchanges_text = &nchanges_text_s; headerGet (hn, RPMTAG_CHANGELOGTEXT, nchanges_text, HEADERGET_MINMEM); ncnum = rpmtdCount (nchanges_date); if (!ncnum) continue; /* Load the latest old %changelog entry. */ ochange_date = rpmtdGetNumber (ochanges_date); ochange_name = rpmtdGetString (ochanges_name); ochange_text = rpmtdGetString (ochanges_text); while (ncnum > 0) { GDateTime *dt = NULL; g_autofree char *date_time_str = NULL; /* Load next new %changelog entry, starting at the newest. */ rpmtdNext (nchanges_date); rpmtdNext (nchanges_name); rpmtdNext (nchanges_text); nchange_date = rpmtdGetNumber (nchanges_date); nchange_name = rpmtdGetString (nchanges_name); nchange_text = rpmtdGetString (nchanges_text); /* If we are now older than, or match, the latest old %changelog * then we are done. */ if (ochange_date > nchange_date) break; if ((ochange_date == nchange_date) && g_str_equal (ochange_name, nchange_name) && g_str_equal (ochange_text, nchange_text)) break; /* Otherwise, print. */ dt = g_date_time_new_from_unix_utc (nchange_date); date_time_str = g_date_time_format (dt, "%a %b %d %Y"); g_date_time_unref (dt); printf ("* %s %s\n%s\n\n", date_time_str, nchange_name, nchange_text); --ncnum; } } done = FALSE; for (num = 0; num < diff->hs_mod_new->len; ++num) { Header ho = diff->hs_mod_old->pdata[num]; Header hn = diff->hs_mod_new->pdata[num]; g_assert (!header_name_cmp (ho, hn)); if (rpmVersionCompare (ho, hn) < 0) continue; if (!done) { done = TRUE; g_print ("Downgraded:\n"); } printf (" "); pkg_print (hn); } } if (diff->hs_del->len) { g_print ("Removed:\n"); for (num = 0; num < diff->hs_del->len; ++num) { Header hd = diff->hs_del->pdata[num]; printf (" "); pkg_print (hd); } } if (diff->hs_add->len) { g_print ("Added:\n"); for (num = 0; num < diff->hs_add->len; ++num) { Header ha = diff->hs_add->pdata[num]; printf (" "); pkg_print (ha); } } rpmhdrs_diff_free (diff); }
/* * explode source RPM into the current directory * use filters to skip packages and files we do not need */ int explodeRPM(const char *source, filterfunc filter, dependencyfunc provides, dependencyfunc deps, void* userptr) { char buffer[BUFFERSIZE+1]; /* make space for trailing \0 */ FD_t fdi; Header h; char * rpmio_flags = NULL; rpmRC rc; FD_t gzdi; struct archive *cpio; struct archive_entry *cpio_entry; struct cpio_mydata cpio_mydata; rpmts ts; rpmVSFlags vsflags; const char *compr; if (strcmp(source, "-") == 0) fdi = fdDup(STDIN_FILENO); else fdi = Fopen(source, "r.ufdio"); if (Ferror(fdi)) { const char *srcname = (strcmp(source, "-") == 0) ? "<stdin>" : source; logMessage(ERROR, "%s: %s\n", srcname, Fstrerror(fdi)); return EXIT_FAILURE; } rpmReadConfigFiles(NULL, NULL); /* Initialize RPM transaction */ ts = rpmtsCreate(); vsflags = 0; /* Do not check digests, signatures or headers */ vsflags |= _RPMVSF_NODIGESTS; vsflags |= _RPMVSF_NOSIGNATURES; vsflags |= RPMVSF_NOHDRCHK; (void) rpmtsSetVSFlags(ts, vsflags); rc = rpmReadPackageFile(ts, fdi, "rpm2dir", &h); ts = rpmtsFree(ts); switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: logMessage(ERROR, "%s is not an RPM package", source); return EXIT_FAILURE; break; case RPMRC_FAIL: default: logMessage(ERROR, "error reading header from %s package\n", source); return EXIT_FAILURE; break; } /* Retrieve all dependencies and run them through deps function */ while (deps) { struct rpmtd_s td; const char *depname; if (!headerGet(h, RPMTAG_REQUIRENAME, &td, HEADERGET_MINMEM)) break; /* iterator */ while ((depname = rpmtdNextString(&td))) { if (deps(depname, userptr)) { Fclose(fdi); return EXIT_BADDEPS; } } rpmtdFreeData(&td); break; } /* Retrieve all provides and run them through provides function */ while (provides) { struct rpmtd_s td; const char *depname; int found = 0; if (!headerGet(h, RPMTAG_PROVIDES, &td, HEADERGET_MINMEM)) break; /* iterator */ while ((depname = rpmtdNextString(&td))) { if (!provides(depname, userptr)) { found++; } } rpmtdFreeData(&td); if (found<=0) return EXIT_BADDEPS; break; } /* Retrieve type of payload compression. */ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); if (compr && strcmp(compr, "gzip")) { checked_asprintf(&rpmio_flags, "r.%sdio", compr); } else { checked_asprintf(&rpmio_flags, "r.gzdio"); } /* Open uncompressed cpio stream */ gzdi = Fdopen(fdi, rpmio_flags); free(rpmio_flags); if (gzdi == NULL) { logMessage(ERROR, "cannot re-open payload: %s\n", Fstrerror(gzdi)); return EXIT_FAILURE; } /* initialize cpio decompressor */ cpio = archive_read_new(); if (cpio==NULL) { Fclose(gzdi); return -1; } cpio_mydata.gzdi = gzdi; cpio_mydata.buffer = buffer; archive_read_support_compression_all(cpio); archive_read_support_format_all(cpio); rc = archive_read_open(cpio, &cpio_mydata, NULL, rpm_myread, rpm_myclose); /* check the status of archive_open */ if (rc != ARCHIVE_OK){ Fclose(gzdi); return -1; } /* read all files in cpio archive */ while ((rc = archive_read_next_header(cpio, &cpio_entry)) == ARCHIVE_OK){ const struct stat *fstat; int64_t fsize; const char* filename; int needskip = 1; /* do we need to read the data to get to the next header? */ int offset = 0; int towrite = 0; filename = archive_entry_pathname(cpio_entry); fstat = archive_entry_stat(cpio_entry); fsize = archive_entry_size(cpio_entry); /* Strip leading slashes */ while (filename[offset] == '/') offset+=1; /* Strip leading ./ */ while (filename[offset] == '.' && filename[offset+1] == '/') offset+=2; /* Other file type - we do not care except special cases */ if (!S_ISREG(fstat->st_mode)) towrite = 1; else towrite = 2; if (filter && filter(filename+offset, fstat, userptr)) { /* filter this file */ towrite = 0; } /* Create directories */ char* dirname = strdup(filename+offset); /* If the dup fails, let's hope the dirs already exist */ if (dirname){ char* dirptr = dirname; while (dirptr && *dirptr) { dirptr = strchr(dirptr, '/'); if (dirptr) { *dirptr = 0; mkdir(dirname, 0700); *dirptr = '/'; dirptr++; } } free(dirname); } /* Regular file */ if (towrite>=2) { FILE *fdout = fopen(filename+offset, "w"); if (fdout==NULL){ rc = 33; break; } rc = archive_read_data_into_fd(cpio, fileno(fdout)); if (rc!=ARCHIVE_OK) { /* XXX We didn't get the file.. well.. */ needskip = 0; } else { needskip = 0; fclose(fdout); } } /* symlink, we assume that the path contained in symlink * is shorter than BUFFERSIZE */ while (towrite && S_ISLNK(fstat->st_mode)) { char symlinkbuffer[BUFFERSIZE-1]; needskip = 0; if ((rc = archive_read_data(cpio, symlinkbuffer, fsize))!=ARCHIVE_OK) { /* XXX We didn't get the file.. well.. */ break; } if (symlink(buffer, filename+offset)) { logMessage(ERROR, "Failed to create symlink %s -> %s", filename+offset, buffer); } break; } if(needskip) archive_read_data_skip(cpio); } archive_read_finish(cpio); return rc != ARCHIVE_OK; }
rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg) { char *buf = NULL; int32_t block[4]; int32_t il; int32_t dl; int32_t * ei = NULL; entryInfo pe; unsigned int nb, uc; int32_t ril = 0; struct indexEntry_s entry; struct entryInfo_s info; unsigned char * dataStart; unsigned char * dataEnd = NULL; Header sigh = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ int xx; int i; if (sighp) *sighp = NULL; if (sig_type != RPMSIGTYPE_HEADERSIG) goto exit; memset(block, 0, sizeof(block)); if ((xx = Freadall(fd, block, sizeof(block))) != sizeof(block)) { rasprintf(&buf, _("sigh size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx); goto exit; } if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) { rasprintf(&buf, _("sigh magic: BAD\n")); goto exit; } il = ntohl(block[2]); if (il < 0 || il > 32) { rasprintf(&buf, _("sigh tags: BAD, no. of tags(%d) out of range\n"), il); goto exit; } dl = ntohl(block[3]); if (dl < 0 || dl > 8192) { rasprintf(&buf, _("sigh data: BAD, no. of bytes(%d) out of range\n"), dl); goto exit; } memset(&entry, 0, sizeof(entry)); memset(&info, 0, sizeof(info)); nb = (il * sizeof(struct entryInfo_s)) + dl; uc = sizeof(il) + sizeof(dl) + nb; ei = xmalloc(uc); ei[0] = block[2]; ei[1] = block[3]; pe = (entryInfo) &ei[2]; dataStart = (unsigned char *) (pe + il); if ((xx = Freadall(fd, pe, nb)) != nb) { rasprintf(&buf, _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx); goto exit; } /* Check (and convert) the 1st tag element. */ xx = headerVerifyInfo(1, dl, pe, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), 0, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is there an immutable header region tag? */ if (entry.info.tag == RPMTAG_HEADERSIGNATURES) { /* Is the region tag sane? */ if (!(entry.info.type == REGION_TAG_TYPE && entry.info.count == REGION_TAG_COUNT)) { rasprintf(&buf, _("region tag: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is the trailer within the data area? */ if (entry.info.offset + REGION_TAG_COUNT > dl) { rasprintf(&buf, _("region offset: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is there an immutable header region tag trailer? */ dataEnd = dataStart + entry.info.offset; (void) memcpy(&info, dataEnd, REGION_TAG_COUNT); /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */ if (info.tag == htonl(RPMTAG_HEADERIMAGE)) { rpmTagVal stag = htonl(RPMTAG_HEADERSIGNATURES); info.tag = stag; memcpy(dataEnd, &stag, sizeof(stag)); } dataEnd += REGION_TAG_COUNT; xx = headerVerifyInfo(1, il * sizeof(*pe), &info, &entry.info, 1); if (xx != -1 || !((entry.info.tag == RPMTAG_HEADERSIGNATURES || entry.info.tag == RPMTAG_HEADERIMAGE) && entry.info.type == REGION_TAG_TYPE && entry.info.count == REGION_TAG_COUNT)) { rasprintf(&buf, _("region trailer: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } memset(&info, 0, sizeof(info)); /* Is the no. of tags in the region less than the total no. of tags? */ ril = entry.info.offset/sizeof(*pe); if ((entry.info.offset % sizeof(*pe)) || ril > il) { rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il); goto exit; } } /* Sanity check signature tags */ memset(&info, 0, sizeof(info)); for (i = 1; i < il; i++) { xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"), i, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } } /* OK, blob looks sane, load the header. */ sigh = headerImport(ei, uc, 0); if (sigh == NULL) { rasprintf(&buf, _("sigh load: BAD\n")); goto exit; } { size_t sigSize = headerSizeof(sigh, HEADER_MAGIC_YES); size_t pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */ ssize_t trc; struct rpmtd_s sizetag; rpm_loff_t archSize = 0; /* Position at beginning of header. */ if (pad && (trc = Freadall(fd, block, pad)) != pad) { rasprintf(&buf, _("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc); goto exit; } /* Print package component sizes. */ if (headerGet(sigh, RPMSIGTAG_LONGSIZE, &sizetag, HEADERGET_DEFAULT)) { rpm_loff_t *tsize = rpmtdGetUint64(&sizetag); archSize = (tsize) ? *tsize : 0; } else if (headerGet(sigh, RPMSIGTAG_SIZE, &sizetag, HEADERGET_DEFAULT)) { rpm_off_t *tsize = rpmtdGetUint32(&sizetag); archSize = (tsize) ? *tsize : 0; } rpmtdFreeData(&sizetag); rc = printSize(fd, sigSize, pad, archSize); if (rc != RPMRC_OK) { rasprintf(&buf, _("sigh sigSize(%zd): BAD, fstat(2) failed\n"), sigSize); goto exit; } } ei = NULL; /* XXX will be freed with header */ exit: if (sighp && sigh && rc == RPMRC_OK) *sighp = headerLink(sigh); headerFree(sigh); free(ei); if (msg != NULL) { *msg = buf; } else { free(buf); } return rc; }
/* * Run all file triggers in header h * @param searchMode 0 match trigger prefixes against files in te * 1 match trigger prefixes against files in whole ts * 2 match trigger prefixes against files in whole * rpmdb */ static int runHandleTriggersInPkg(rpmts ts, rpmte te, Header h, rpmsenseFlags sense, rpmscriptTriggerModes tm, int searchMode, int ti) { int nerrors = 0; rpmds rpmdsTriggers, rpmdsTrigger; rpmfiles files = NULL; matchFilesIter mfi = NULL; rpmScript script; struct rpmtd_s installPrefixes; char *(*inputFunc)(void *); rpmdsTriggers = rpmdsNew(h, triggerDsTag(tm), 0); rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, ti); /* * Now rpmdsTrigger contains all dependencies belonging to one trigger * with trigger index tix. Have a look at the first one to check flags. */ if ((rpmdsNext(rpmdsTrigger) >= 0) && (rpmdsFlags(rpmdsTrigger) & sense)) { switch (searchMode) { case 0: /* Create iterator over files in te that this trigger matches */ files = rpmteFiles(te); mfi = matchFilesIterator(rpmdsTrigger, files); break; case 1: /* Create iterator over files in ts that this trigger matches */ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 1); break; case 2: /* Create iterator over files in whole rpmd that this trigger matches */ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 0); break; } /* If this trigger matches any file then run trigger script */ if (!matchFilesEmpty(mfi)) { script = rpmScriptFromTriggerTag(h, triggertag(sense), tm, ti); headerGet(h, RPMTAG_INSTPREFIXES, &installPrefixes, HEADERGET_ALLOC|HEADERGET_ARGV); /* * As input function set function to get next file from * matching file iterator. As parameter for this function * set matching file iterator. Input function will be called * during execution of trigger script in order to get data * that will be passed as stdin to trigger script. To get * these data from lua script function rpm.input() can be used. */ inputFunc = (char *(*)(void *)) matchFilesNext; rpmScriptSetNextFileFunc(script, inputFunc, mfi); nerrors += runScript(ts, te, installPrefixes.data, script, 0, 0); rpmtdFreeData(&installPrefixes); rpmScriptFree(script); } rpmfilesFree(files); matchFilesIteratorFree(mfi); } rpmdsFree(rpmdsTrigger); rpmdsFree(rpmdsTriggers); return nerrors; }
int printDepList(rpmts *ts, int tscount) { int rc = 0; if( tscount > 1 ) fprintf(stderr, ">1 database specified with dependency list, using first only\n"); /* Get list of names */ rpmdb db = rpmtsGetRdb(ts[0]); ARGV_t names = NULL; rc = rpmdbMireApply(db, RPMTAG_NAME, RPMMIRE_STRCMP, NULL, &names); int nnames = argvCount(names); /* Get list of NVRAs */ ARGV_t keys = NULL; rc = rpmdbMireApply(db, RPMTAG_NVRA, RPMMIRE_STRCMP, NULL, &keys); if (keys) { int i, j; HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); int nkeys = argvCount(keys); for(i=0; i<nkeys; i++) { rpmmi mi = rpmmiInit(db, RPMTAG_NVRA, keys[i], 0); Header h; if ((h = rpmmiNext(mi)) != NULL) { /* Get name of package */ he->tag = RPMTAG_NAME; rc = (headerGet(h, he, 0) != 1); char *name = strdup((char *)he->p.ptr); /* Get its requires */ he->tag = RPMTAG_REQUIRENAME; if (rc = (headerGet(h, he, 0) != 1)) { if (debugmode) { printf("DEBUG: %s requires null\n", name); } rc = 0; free(name); (void)rpmmiFree(mi); continue; } ARGV_t reqs = (ARGV_t)he->p.ptr; /* Get its requireflags */ he->tag = RPMTAG_REQUIREFLAGS; rc = (headerGet(h, he, 0) != 1); rpmuint32_t *reqflags = (rpmuint32_t *)he->p.ui32p; for(j=0; j<he->c; j++) { int k; char *prov = NULL; for(k=0; k<nnames; k++) { if(strcmp(names[k], reqs[j]) == 0) { prov = names[k]; break; } } if(prov) { if((int)reqflags[j] & 0x80000) fprintf(outf, "%s|%s [REC]\n", name, prov); else fprintf(outf, "%s|%s\n", name, prov); } else { rc = lookupProvider(ts[0], reqs[j], &prov); if(rc==0 && prov) { if((int)reqflags[j] & 0x80000) fprintf(outf, "%s|%s [REC]\n", name, prov); else fprintf(outf, "%s|%s\n", name, prov); free(prov); } } } free(name); } (void)rpmmiFree(mi); } } return rc; }
/* Check files in the transactions against the rpmdb * Lookup all files with the same basename in the rpmdb * and then check for matching finger prints * @param ts transaction set * @param fpc global finger print cache */ static void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) { tsMembers tsmem = rpmtsMembers(ts); rpmte p; rpmfiles fi; rpmfs fs; int j; unsigned int fileNum; rpmdbMatchIterator mi; Header h, newheader; rpmlog(RPMLOG_DEBUG, "computing file dispositions\n"); mi = rpmFindBaseNamesInDB(ts, fileCount); /* For all installed headers with matching basename's ... */ if (mi == NULL) return; if (rpmdbGetIteratorCount(mi) == 0) { mi = rpmdbFreeIterator(mi); return; } /* Loop over all packages from the rpmdb */ h = newheader = rpmdbNextIterator(mi); while (h != NULL) { headerGetFlags hgflags = HEADERGET_MINMEM; struct rpmtd_s bnames, dnames, dindexes, ostates; fingerPrint *fpp = NULL; unsigned int installedPkg; int beingRemoved = 0; rpmfiles otherFi = NULL; rpmte *removedPkg = NULL; /* Is this package being removed? */ installedPkg = rpmdbGetIteratorOffset(mi); if (packageHashGetEntry(tsmem->removedPackages, installedPkg, &removedPkg, NULL, NULL)) { beingRemoved = 1; otherFi = rpmteFiles(removedPkg[0]); } h = headerLink(h); /* For packages being removed we can use its rpmfi to avoid all this */ if (!beingRemoved) { headerGet(h, RPMTAG_BASENAMES, &bnames, hgflags); headerGet(h, RPMTAG_DIRNAMES, &dnames, hgflags); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, hgflags); headerGet(h, RPMTAG_FILESTATES, &ostates, hgflags); } /* loop over all interesting files in that package */ do { int fpIx; struct rpmffi_s * recs; int numRecs; const char * dirName; const char * baseName; /* lookup finger print for this file */ fileNum = rpmdbGetIteratorFileNum(mi); if (!beingRemoved) { rpmtdSetIndex(&bnames, fileNum); rpmtdSetIndex(&dindexes, fileNum); rpmtdSetIndex(&dnames, *rpmtdGetUint32(&dindexes)); rpmtdSetIndex(&ostates, fileNum); dirName = rpmtdGetString(&dnames); baseName = rpmtdGetString(&bnames); fpLookup(fpc, dirName, baseName, &fpp); fpIx = 0; } else { fpp = rpmfilesFps(otherFi); fpIx = fileNum; } /* search for files in the transaction with same finger print */ fpCacheGetByFp(fpc, fpp, fpIx, &recs, &numRecs); for (j = 0; j < numRecs; j++) { p = recs[j].p; fi = rpmteFiles(p); fs = rpmteGetFileStates(p); /* Determine the fate of each file. */ switch (rpmteType(p)) { case TR_ADDED: if (!otherFi) { /* XXX What to do if this fails? */ otherFi = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); } handleInstInstalledFile(ts, p, fi, recs[j].fileno, h, otherFi, fileNum, beingRemoved); break; case TR_REMOVED: if (!beingRemoved) { if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL) rpmfsSetAction(fs, recs[j].fileno, FA_SKIP); } break; } rpmfilesFree(fi); } newheader = rpmdbNextIterator(mi); } while (newheader==h); otherFi = rpmfilesFree(otherFi); if (!beingRemoved) { rpmtdFreeData(&ostates); rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); free(fpp); } headerFree(h); h = newheader; } rpmdbFreeIterator(mi); }
static sepol *sepolNew(rpmte te) { sepol *head = NULL; sepol *ret = NULL; sepolAction action; Header h; struct rpmtd_s policies, names, types, typesidx, flags; int i, j; int count; rpmtdReset(&policies); rpmtdReset(&names); rpmtdReset(&types); rpmtdReset(&typesidx); rpmtdReset(&flags); h = rpmteHeader(te); if (!h) { goto exit; } if (!headerIsEntry(h, RPMTAG_POLICIES)) { goto exit; } if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) { goto exit; } count = rpmtdCount(&policies); if (count <= 0) { goto exit; } if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM) || rpmtdCount(&names) != count) { goto exit; } if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM) || rpmtdCount(&flags) != count) { goto exit; } if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) { goto exit; } if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM) || rpmtdCount(&types) != rpmtdCount(&typesidx)) { goto exit; } action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE; for (i = 0; i < count; i++) { sepol *pol = xcalloc(1, sizeof(*pol)); pol->next = head; head = pol; pol->data = xstrdup(rpmtdNextString(&policies)); pol->name = xstrdup(rpmtdNextString(&names)); pol->flags = *rpmtdNextUint32(&flags); pol->action = action; for (j = 0; j < rpmtdCount(&types); j++) { uint32_t index = ((uint32_t *) typesidx.data)[j]; if (index < 0 || index >= count) { goto exit; } if (index != i) { continue; } argvAdd(&pol->types, rpmtdNextString(&types)); } argvSort(pol->types, NULL); } ret = head; exit: headerFree(h); rpmtdFreeData(&policies); rpmtdFreeData(&names); rpmtdFreeData(&types); rpmtdFreeData(&typesidx); rpmtdFreeData(&flags); if (!ret) { sepolFree(head); } return ret; }
/** * Execute triggers. * @todo Trigger on any provides, not just package NVR. * @param ts transaction set * @param te transaction element * @param sense trigger type * @param sourceH header of trigger source * @param trigH header of triggered package * @param arg2 * @param triggersAlreadyRun * @return */ static rpmRC handleOneTrigger(rpmts ts, rpmte te, rpmsenseFlags sense, Header sourceH, Header trigH, int countCorrection, int arg2, unsigned char * triggersAlreadyRun) { rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0)); struct rpmtd_s pfx; const char * sourceName = headerGetString(sourceH, RPMTAG_NAME); const char * triggerName = headerGetString(trigH, RPMTAG_NAME); rpmRC rc = RPMRC_OK; int i; if (trigger == NULL) return rc; headerGet(trigH, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV); (void) rpmdsSetNoPromote(trigger, 1); while ((i = rpmdsNext(trigger)) >= 0) { uint32_t tix; if (!(rpmdsFlags(trigger) & sense)) continue; if (!rstreq(rpmdsN(trigger), sourceName)) continue; /* XXX Trigger on any provided dependency, not just the package NEVR */ if (!rpmdsAnyMatchesDep(sourceH, trigger, 1)) continue; tix = rpmdsTi(trigger); if (triggersAlreadyRun == NULL || triggersAlreadyRun[tix] == 0) { int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName); if (arg1 < 0) { /* XXX W2DO? fails as "execution of script failed" */ rc = RPMRC_FAIL; } else { rpmScript script = rpmScriptFromTriggerTag(trigH, triggertag(sense), tix); arg1 += countCorrection; rc = runScript(ts, te, pfx.data, script, arg1, arg2); if (triggersAlreadyRun != NULL) triggersAlreadyRun[tix] = 1; rpmScriptFree(script); } } /* * Each target/source header pair can only result in a single * script being run. */ break; } rpmtdFreeData(&pfx); rpmdsFree(trigger); return rc; }
rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd, char ** specFilePtr, char ** cookie) { rpmfi fi = NULL; char * specFile = NULL; const char *rootdir = rpmtsRootDir(ts); Header h = NULL; rpmpsm psm = NULL; rpmte te = NULL; rpmRC rpmrc; int specix = -1; struct rpmtd_s filenames; rpmtdReset(&filenames); rpmrc = rpmReadPackageFile(ts, fd, NULL, &h); switch (rpmrc) { case RPMRC_NOTTRUSTED: case RPMRC_NOKEY: case RPMRC_OK: break; default: goto exit; break; } if (h == NULL) goto exit; rpmrc = RPMRC_FAIL; /* assume failure */ if (!headerIsSource(h)) { rpmlog(RPMLOG_ERR, _("source package expected, binary found\n")); goto exit; } /* src.rpm install can require specific rpmlib features, check them */ if (!rpmlibDeps(h)) goto exit; if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_ALLOC)) { struct rpmtd_s td; const char *str; const char *_cookie = headerGetString(h, RPMTAG_COOKIE); if (cookie && _cookie) *cookie = xstrdup(_cookie); /* Try to find spec by file flags */ if (_cookie && headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) { rpmfileAttrs *flags; while (specix < 0 && (flags = rpmtdNextUint32(&td))) { if (*flags & RPMFILE_SPECFILE) specix = rpmtdGetIndex(&td); } } /* Still no spec? Look by filename. */ while (specix < 0 && (str = rpmtdNextString(&filenames))) { if (rpmFileHasSuffix(str, ".spec")) specix = rpmtdGetIndex(&filenames); } } if (rootdir && rstreq(rootdir, "/")) rootdir = NULL; /* Macros need to be added before trying to create directories */ rpmInstallLoadMacros(h); if (specix >= 0) { const char *bn; headerDel(h, RPMTAG_BASENAMES); headerDel(h, RPMTAG_DIRNAMES); headerDel(h, RPMTAG_DIRINDEXES); rpmtdInit(&filenames); for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) { int spec = (i == specix); char *fn = rpmGenPath(rpmtsRootDir(ts), spec ? "%{_specdir}" : "%{_sourcedir}", bn); headerPutString(h, RPMTAG_OLDFILENAMES, fn); if (spec) specFile = xstrdup(fn); free(fn); } headerConvert(h, HEADERCONV_COMPRESSFILELIST); } else { rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n")); goto exit; }; if (rpmtsAddInstallElement(ts, h, NULL, 0, NULL)) { goto exit; } te = rpmtsElement(ts, 0); if (te == NULL) { /* XXX can't happen */ goto exit; } rpmteSetFd(te, fd); rpmteSetHeader(te, h); fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); h = headerFree(h); if (fi == NULL) { goto exit; } fi->apath = filenames.data; /* Ick */ rpmteSetFI(te, fi); fi = rpmfiFree(fi); if (rpmMkdirs(rpmtsRootDir(ts), "%{_topdir}:%{_sourcedir}:%{_specdir}")) { goto exit; } { /* set all files to be installed */ rpmfs fs = rpmteGetFileStates(te); int i; unsigned int fc = rpmfiFC(fi); for (i=0; i<fc; i++) rpmfsSetAction(fs, i, FA_CREATE); } psm = rpmpsmNew(ts, te); psm->goal = PKG_INSTALL; /* FIX: psm->fi->dnl should be owned. */ if (rpmpsmStage(psm, PSM_PROCESS) == RPMRC_OK) rpmrc = RPMRC_OK; (void) rpmpsmStage(psm, PSM_FINI); rpmpsmFree(psm); exit: if (specFilePtr && specFile && rpmrc == RPMRC_OK) *specFilePtr = specFile; else free(specFile); headerFree(h); rpmfiFree(fi); /* XXX nuke the added package(s). */ rpmtsClean(ts); return rpmrc; }
/** @todo Generalize --freshen policies. */ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv) { struct rpmEIU * eiu = xcalloc(1, sizeof(*eiu)); rpmps ps; rpmprobFilterFlags probFilter; rpmRelocation * relocations; char * fileURL = NULL; int stopInstall = 0; rpmVSFlags vsflags, ovsflags, tvsflags; int rc; int xx; int i; if (fileArgv == NULL) goto exit; rpmcliPackagesTotal = 0; (void) rpmtsSetFlags(ts, ia->transFlags); probFilter = ia->probFilter; relocations = ia->relocations; if (ia->installInterfaceFlags & INSTALL_UPGRADE) vsflags = rpmExpandNumeric("%{?_vsflags_erase}"); else vsflags = rpmExpandNumeric("%{?_vsflags_install}"); if (ia->qva_flags & VERIFY_DIGEST) vsflags |= _RPMVSF_NODIGESTS; if (ia->qva_flags & VERIFY_SIGNATURE) vsflags |= _RPMVSF_NOSIGNATURES; if (ia->qva_flags & VERIFY_HDRCHK) vsflags |= RPMVSF_NOHDRCHK; ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD)); { int notifyFlags; notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 ); xx = rpmtsSetNotifyCallback(ts, rpmShowProgress, (void *) ((long)notifyFlags)); } if ((eiu->relocations = relocations) != NULL) { while (eiu->relocations->oldPath) eiu->relocations++; if (eiu->relocations->newPath == NULL) eiu->relocations = NULL; } /* Build fully globbed list of arguments in argv[argc]. */ for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) { ARGV_t av = NULL; int ac = 0; char * fn; fn = rpmEscapeSpaces(*eiu->fnp); rc = rpmGlob(fn, &ac, &av); fn = _free(fn); if (rc || ac == 0) { rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp); eiu->numFailed++; continue; } argvAppend(&(eiu->argv), av); argvFree(av); eiu->argc += ac; } restart: /* Allocate sufficient storage for next set of args. */ if (eiu->pkgx >= eiu->numPkgs) { eiu->numPkgs = eiu->pkgx + eiu->argc; eiu->pkgURL = xrealloc(eiu->pkgURL, (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL)); memset(eiu->pkgURL + eiu->pkgx, 0, ((eiu->argc + 1) * sizeof(*eiu->pkgURL))); eiu->pkgState = xrealloc(eiu->pkgState, (eiu->numPkgs + 1) * sizeof(*eiu->pkgState)); memset(eiu->pkgState + eiu->pkgx, 0, ((eiu->argc + 1) * sizeof(*eiu->pkgState))); } /* Retrieve next set of args, cache on local storage. */ for (i = 0; i < eiu->argc; i++) { fileURL = _free(fileURL); fileURL = eiu->argv[i]; eiu->argv[i] = NULL; switch (urlIsURL(fileURL)) { case URL_IS_HTTPS: case URL_IS_HTTP: case URL_IS_FTP: { char *tfn; FD_t tfd; if (rpmIsVerbose()) fprintf(stdout, _("Retrieving %s\n"), fileURL); tfd = rpmMkTempFile(rpmtsRootDir(ts), &tfn); if (tfd && tfn) { Fclose(tfd); rc = urlGetFile(fileURL, tfn); } else { rc = -1; } if (rc != 0) { rpmlog(RPMLOG_ERR, _("skipping %s - transfer failed\n"), fileURL); eiu->numFailed++; eiu->pkgURL[eiu->pkgx] = NULL; tfn = _free(tfn); break; } eiu->pkgState[eiu->pkgx] = 1; eiu->pkgURL[eiu->pkgx] = tfn; eiu->pkgx++; } break; case URL_IS_PATH: case URL_IS_DASH: /* WRONG WRONG WRONG */ case URL_IS_HKP: /* WRONG WRONG WRONG */ default: eiu->pkgURL[eiu->pkgx] = fileURL; fileURL = NULL; eiu->pkgx++; break; } } fileURL = _free(fileURL); if (eiu->numFailed) goto exit; /* Continue processing file arguments, building transaction set. */ for (eiu->fnp = eiu->pkgURL+eiu->prevx; *eiu->fnp != NULL; eiu->fnp++, eiu->prevx++) { const char * fileName; rpmlog(RPMLOG_DEBUG, "============== %s\n", *eiu->fnp); (void) urlPath(*eiu->fnp, &fileName); /* Try to read the header from a package file. */ eiu->fd = Fopen(*eiu->fnp, "r.ufdio"); if (eiu->fd == NULL || Ferror(eiu->fd)) { rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp, Fstrerror(eiu->fd)); if (eiu->fd != NULL) { xx = Fclose(eiu->fd); eiu->fd = NULL; } eiu->numFailed++; *eiu->fnp = NULL; continue; } /* Read the header, verifying signatures (if present). */ tvsflags = rpmtsSetVSFlags(ts, vsflags); eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h); tvsflags = rpmtsSetVSFlags(ts, tvsflags); xx = Fclose(eiu->fd); eiu->fd = NULL; switch (eiu->rpmrc) { case RPMRC_FAIL: rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), *eiu->fnp); eiu->numFailed++; *eiu->fnp = NULL; continue; break; case RPMRC_NOTFOUND: goto maybe_manifest; break; case RPMRC_NOTTRUSTED: case RPMRC_NOKEY: case RPMRC_OK: default: break; } eiu->isSource = headerIsSource(eiu->h); if (eiu->isSource) { rpmlog(RPMLOG_DEBUG, "\tadded source package [%d]\n", eiu->numSRPMS); eiu->sourceURL = xrealloc(eiu->sourceURL, (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL)); eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp; *eiu->fnp = NULL; eiu->numSRPMS++; eiu->sourceURL[eiu->numSRPMS] = NULL; continue; } if (eiu->relocations) { struct rpmtd_s prefixes; headerGet(eiu->h, RPMTAG_PREFIXES, &prefixes, HEADERGET_DEFAULT); if (rpmtdCount(&prefixes) == 1) { eiu->relocations->oldPath = xstrdup(rpmtdGetString(&prefixes)); rpmtdFreeData(&prefixes); } else { const char * name; xx = headerNVR(eiu->h, &name, NULL, NULL); rpmlog(RPMLOG_ERR, _("package %s is not relocatable\n"), name); eiu->numFailed++; goto exit; } } /* On --freshen, verify package is installed and newer */ if (ia->installInterfaceFlags & INSTALL_FRESHEN) { rpmdbMatchIterator mi; const char * name; Header oldH; int count; xx = headerNVR(eiu->h, &name, NULL, NULL); mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0); count = rpmdbGetIteratorCount(mi); while ((oldH = rpmdbNextIterator(mi)) != NULL) { if (rpmVersionCompare(oldH, eiu->h) < 0) continue; /* same or newer package already installed */ count = 0; break; } mi = rpmdbFreeIterator(mi); if (count == 0) { eiu->h = headerFree(eiu->h); continue; } /* Package is newer than those currently installed. */ } rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName, (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0, relocations); /* XXX reference held by transaction set */ eiu->h = headerFree(eiu->h); if (eiu->relocations) eiu->relocations->oldPath = _free(eiu->relocations->oldPath); switch(rc) { case 0: rpmlog(RPMLOG_DEBUG, "\tadded binary package [%d]\n", eiu->numRPMS); break; case 1: rpmlog(RPMLOG_ERR, _("error reading from file %s\n"), *eiu->fnp); eiu->numFailed++; goto exit; break; case 2: rpmlog(RPMLOG_ERR, _("file %s requires a newer version of RPM\n"), *eiu->fnp); eiu->numFailed++; goto exit; break; default: eiu->numFailed++; goto exit; break; } eiu->numRPMS++; continue; maybe_manifest: /* Try to read a package manifest. */ eiu->fd = Fopen(*eiu->fnp, "r.fpio"); if (eiu->fd == NULL || Ferror(eiu->fd)) { rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp, Fstrerror(eiu->fd)); if (eiu->fd != NULL) { xx = Fclose(eiu->fd); eiu->fd = NULL; } eiu->numFailed++; *eiu->fnp = NULL; break; } /* Read list of packages from manifest. */ /* FIX: *eiu->argv can be NULL */ rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv); if (rc != RPMRC_OK) rpmlog(RPMLOG_ERR, _("%s: not an rpm package (or package manifest): %s\n"), *eiu->fnp, Fstrerror(eiu->fd)); xx = Fclose(eiu->fd); eiu->fd = NULL; /* If successful, restart the query loop. */ if (rc == RPMRC_OK) { eiu->prevx++; goto restart; } eiu->numFailed++; *eiu->fnp = NULL; break; } rpmlog(RPMLOG_DEBUG, "found %d source and %d binary packages\n", eiu->numSRPMS, eiu->numRPMS); if (eiu->numFailed) goto exit; if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) { if (rpmtsCheck(ts)) { eiu->numFailed = eiu->numPkgs; stopInstall = 1; } ps = rpmtsProblems(ts); if (!stopInstall && rpmpsNumProblems(ps) > 0) { rpmlog(RPMLOG_ERR, _("Failed dependencies:\n")); rpmpsPrint(NULL, ps); eiu->numFailed = eiu->numPkgs; stopInstall = 1; } ps = rpmpsFree(ps); } if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) { if (rpmtsOrder(ts)) { eiu->numFailed = eiu->numPkgs; stopInstall = 1; } } if (eiu->numRPMS && !stopInstall) { rpmcliPackagesTotal += eiu->numSRPMS; rpmlog(RPMLOG_DEBUG, "installing binary packages\n"); /* Drop added/available package indices and dependency sets. */ rpmtsClean(ts); rc = rpmtsRun(ts, NULL, probFilter); ps = rpmtsProblems(ts); if (rc < 0) { eiu->numFailed += eiu->numRPMS; } else if (rc > 0) { eiu->numFailed += rc; if (rpmpsNumProblems(ps) > 0) rpmpsPrint(stderr, ps); } ps = rpmpsFree(ps); } if (eiu->numSRPMS && !stopInstall) { if (eiu->sourceURL != NULL) for (i = 0; i < eiu->numSRPMS; i++) { rpmdbCheckSignals(); if (eiu->sourceURL[i] == NULL) continue; eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio"); if (eiu->fd == NULL || Ferror(eiu->fd)) { rpmlog(RPMLOG_ERR, _("cannot open file %s: %s\n"), eiu->sourceURL[i], Fstrerror(eiu->fd)); if (eiu->fd != NULL) { xx = Fclose(eiu->fd); eiu->fd = NULL; } continue; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) { eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL); if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++; } xx = Fclose(eiu->fd); eiu->fd = NULL; } } exit: if (eiu->pkgURL != NULL) for (i = 0; i < eiu->numPkgs; i++) { if (eiu->pkgURL[i] == NULL) continue; if (eiu->pkgState[i] == 1) (void) unlink(eiu->pkgURL[i]); eiu->pkgURL[i] = _free(eiu->pkgURL[i]); } eiu->pkgState = _free(eiu->pkgState); eiu->pkgURL = _free(eiu->pkgURL); eiu->argv = _free(eiu->argv); rc = eiu->numFailed; free(eiu); rpmtsEmpty(ts); return rc; }
int addReqProv(/*@unused@*/ Spec spec, Header h, /*@unused@*/ rpmTag tagN, const char * N, const char * EVR, rpmsenseFlags Flags, rpmuint32_t index) { HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); const char ** names; rpmTag nametag = 0; rpmTag versiontag = 0; rpmTag flagtag = 0; rpmTag indextag = 0; int len; rpmsenseFlags extra = RPMSENSE_ANY; int xx; if (Flags & RPMSENSE_PROVIDES) { nametag = RPMTAG_PROVIDENAME; versiontag = RPMTAG_PROVIDEVERSION; flagtag = RPMTAG_PROVIDEFLAGS; extra = Flags & RPMSENSE_FIND_PROVIDES; } else if (Flags & RPMSENSE_OBSOLETES) { nametag = RPMTAG_OBSOLETENAME; versiontag = RPMTAG_OBSOLETEVERSION; flagtag = RPMTAG_OBSOLETEFLAGS; } else if (Flags & RPMSENSE_CONFLICTS) { nametag = RPMTAG_CONFLICTNAME; versiontag = RPMTAG_CONFLICTVERSION; flagtag = RPMTAG_CONFLICTFLAGS; } else if (Flags & RPMSENSE_TRIGGER) { nametag = RPMTAG_TRIGGERNAME; versiontag = RPMTAG_TRIGGERVERSION; flagtag = RPMTAG_TRIGGERFLAGS; indextag = RPMTAG_TRIGGERINDEX; extra = Flags & RPMSENSE_TRIGGER; } else { nametag = RPMTAG_REQUIRENAME; versiontag = RPMTAG_REQUIREVERSION; flagtag = RPMTAG_REQUIREFLAGS; extra = Flags & _ALL_REQUIRES_MASK; } Flags = (Flags & RPMSENSE_SENSEMASK) | extra; if (EVR == NULL) EVR = ""; #if defined(RPM_VENDOR_MANDRIVA) /* Check that provide isn't duplicate of package */ else if (nametag == RPMTAG_PROVIDENAME) { const char *NEVR; size_t len; int duplicate; len = strlen(N); NEVR = headerSprintf(h, "%{NAME}-%|EPOCH?{%{EPOCH}:}|%{VERSION}-%{RELEASE}", NULL, NULL, NULL); duplicate = !strncmp(NEVR, N, len) && !strcmp(NEVR+len+1, EVR); _free(NEVR); if (duplicate) return 0; } #endif /* Check for duplicate dependencies. */ he->tag = nametag; xx = headerGet(h, he, 0); names = he->p.argv; len = he->c; if (xx) { const char ** versions = NULL; rpmuint32_t * flags = NULL; rpmuint32_t * indexes = NULL; int duplicate = 0; if (flagtag) { he->tag = versiontag; xx = headerGet(h, he, 0); versions = he->p.argv; he->tag = flagtag; xx = headerGet(h, he, 0); flags = he->p.ui32p; } if (indextag) { he->tag = indextag; xx = headerGet(h, he, 0); indexes = he->p.ui32p; } while (len > 0) { len--; if (strcmp(names[len], N)) continue; #if defined(RPM_VENDOR_MANDRIVA) /* filter-overlapping-dependencies */ /* XXX: Potential drawbacks? Need to study & discuess this one a * bit further, leaving under #ifdef for now... * TODO: auto-generated deps too */ if (flagtag && versions != NULL) { int overlap; if(*EVR && !*versions[len]) { overlap = 1; flags[len] = Flags; he->tag = flagtag; he->t = RPM_UINT32_TYPE; he->p.argv = (void *) &Flags; xx = headerMod(h, he, 0); } else { EVR_t lEVR = rpmEVRnew(RPMSENSE_ANY, 0), rEVR = rpmEVRnew(RPMSENSE_ANY, 0); rpmEVRparse(EVR, lEVR); rpmEVRparse(versions[len], rEVR); lEVR->Flags = Flags | RPMSENSE_EQUAL; rEVR->Flags = flags[len] | RPMSENSE_EQUAL; overlap = rpmEVRoverlap(lEVR, rEVR); if (!overlap) if (rpmEVRoverlap(rEVR, lEVR)) duplicate = 1; lEVR = rpmEVRfree(lEVR); rEVR = rpmEVRfree(rEVR); } if (overlap) { versions[len] = EVR; he->tag = versiontag; he->t = RPM_STRING_ARRAY_TYPE; he->p.argv = versions; xx = headerMod(h, he, 0); } else continue; } #else if (flagtag && versions != NULL && (strcmp(versions[len], EVR) || (rpmsenseFlags)flags[len] != Flags)) continue; #endif if (indextag && indexes != NULL && indexes[len] != index) continue; /* This is a duplicate dependency. */ duplicate = 1; break; } /*@-usereleased@*/ names = _free(names); versions = _free(versions); flags = _free(flags); indexes = _free(indexes); /*@=usereleased@*/ if (duplicate) return 0; } /* Add this dependency. */ he->tag = nametag; he->t = RPM_STRING_ARRAY_TYPE; he->p.argv = &N; he->c = 1; he->append = 1; xx = headerPut(h, he, 0); he->append = 0; if (flagtag) { he->tag = versiontag; he->t = RPM_STRING_ARRAY_TYPE; he->p.argv = &EVR; he->c = 1; he->append = 1; xx = headerPut(h, he, 0); he->append = 0; he->tag = flagtag; he->t = RPM_UINT32_TYPE; he->p.ui32p = (void *) &Flags; he->c = 1; he->append = 1; xx = headerPut(h, he, 0); he->append = 0; } if (indextag) { he->tag = indextag; he->t = RPM_UINT32_TYPE; he->p.ui32p = &index; he->c = 1; he->append = 1; xx = headerPut(h, he, 0); he->append = 0; } return 0; }