00001
00006 #include "system.h"
00007
00008 #include "psm.h"
00009 #include <rpmcli.h>
00010
00011 #include "ugid.h"
00012 #include "misc.h"
00013 #include "debug.h"
00014
00015
00016
00017
00018
00019
00020 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00021
00022 int rpmVerifyFile(const char * root, Header h, int filenum,
00023 rpmVerifyAttrs * result, rpmVerifyAttrs omitMask)
00024 {
00025 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00026 HFD_t hfd = headerFreeData;
00027 int_32 * fileFlags;
00028 rpmfileAttrs fileAttrs = RPMFILE_NONE;
00029 int_32 * verifyFlags;
00030 rpmVerifyAttrs flags = RPMVERIFY_ALL;
00031 unsigned short * modeList;
00032 const char * fileStatesList;
00033 const char * filespec = NULL;
00034 int count;
00035 int rc;
00036 struct stat sb;
00037
00038 rc = hge(h, RPMTAG_FILEMODES, NULL, (void **) &modeList, &count);
00039 if (hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
00040 fileAttrs = fileFlags[filenum];
00041
00042 if (hge(h, RPMTAG_FILEVERIFYFLAGS, NULL, (void **) &verifyFlags, NULL))
00043 flags = verifyFlags[filenum];
00044
00045 {
00046 const char ** baseNames;
00047 const char ** dirNames;
00048 int_32 * dirIndexes;
00049 rpmTagType bnt, dnt;
00050
00051 if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL)
00052 && hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL)
00053 && hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL))
00054 {
00055 int nb = (strlen(dirNames[dirIndexes[filenum]]) +
00056 strlen(baseNames[filenum]) + strlen(root) + 5);
00057 char * t = alloca(nb);
00058 filespec = t;
00059 *t = '\0';
00060 if (root && !(root[0] == '/' && root[1] == '\0')) {
00061 t = stpcpy(t, root);
00062 while (t > filespec && t[-1] == '/') {
00063 --t;
00064 *t = '\0';
00065 }
00066 }
00067 t = stpcpy(t, dirNames[dirIndexes[filenum]]);
00068 t = stpcpy(t, baseNames[filenum]);
00069 }
00070 baseNames = hfd(baseNames, bnt);
00071 dirNames = hfd(dirNames, dnt);
00072 }
00073
00074 *result = RPMVERIFY_NONE;
00075
00076
00077
00078
00079 if (hge(h, RPMTAG_FILESTATES, NULL, (void **) &fileStatesList, NULL) &&
00080 fileStatesList != NULL)
00081 {
00082 rpmfileState fstate = fileStatesList[filenum];
00083 switch (fstate) {
00084 case RPMFILE_STATE_NETSHARED:
00085 case RPMFILE_STATE_REPLACED:
00086 case RPMFILE_STATE_NOTINSTALLED:
00087 return 0;
00088 break;
00089 case RPMFILE_STATE_NORMAL:
00090 break;
00091 }
00092 }
00093
00094 if (filespec == NULL) {
00095 *result |= RPMVERIFY_LSTATFAIL;
00096 return 1;
00097 }
00098
00099 if (Lstat(filespec, &sb) != 0) {
00100 *result |= RPMVERIFY_LSTATFAIL;
00101 return 1;
00102 }
00103
00104
00105
00106
00107 if (S_ISDIR(sb.st_mode))
00108 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00109 RPMVERIFY_LINKTO);
00110 else if (S_ISLNK(sb.st_mode)) {
00111 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00112 RPMVERIFY_MODE);
00113 #if CHOWN_FOLLOWS_SYMLINK
00114 flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00115 #endif
00116 }
00117 else if (S_ISFIFO(sb.st_mode))
00118 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00119 RPMVERIFY_LINKTO);
00120 else if (S_ISCHR(sb.st_mode))
00121 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00122 RPMVERIFY_LINKTO);
00123 else if (S_ISBLK(sb.st_mode))
00124 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00125 RPMVERIFY_LINKTO);
00126 else
00127 flags &= ~(RPMVERIFY_LINKTO);
00128
00129
00130
00131
00132 if (fileAttrs & RPMFILE_GHOST)
00133 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00134 RPMVERIFY_LINKTO);
00135
00136
00137
00138
00139 flags &= ~(omitMask | RPMVERIFY_LSTATFAIL|RPMVERIFY_READFAIL|RPMVERIFY_READLINKFAIL);
00140
00141 if (flags & RPMVERIFY_MD5) {
00142 unsigned char md5sum[40];
00143 const char ** md5List;
00144 rpmTagType mdt;
00145
00146 if (!hge(h, RPMTAG_FILEMD5S, &mdt, (void **) &md5List, NULL))
00147 *result |= RPMVERIFY_MD5;
00148 else {
00149 rc = domd5(filespec, md5sum, 1);
00150 if (rc)
00151 *result |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00152 else if (strcmp(md5sum, md5List[filenum]))
00153 *result |= RPMVERIFY_MD5;
00154 }
00155 md5List = hfd(md5List, mdt);
00156 }
00157
00158 if (flags & RPMVERIFY_LINKTO) {
00159 char linkto[1024];
00160 int size = 0;
00161 const char ** linktoList;
00162 rpmTagType ltt;
00163
00164 if (!hge(h, RPMTAG_FILELINKTOS, <t, (void **) &linktoList, NULL)
00165 || (size = Readlink(filespec, linkto, sizeof(linkto)-1)) == -1)
00166 *result |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00167 else {
00168 linkto[size] = '\0';
00169 if (strcmp(linkto, linktoList[filenum]))
00170 *result |= RPMVERIFY_LINKTO;
00171 }
00172 linktoList = hfd(linktoList, ltt);
00173 }
00174
00175 if (flags & RPMVERIFY_FILESIZE) {
00176 int_32 * sizeList;
00177
00178 if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &sizeList, NULL)
00179 || sizeList[filenum] != sb.st_size)
00180 *result |= RPMVERIFY_FILESIZE;
00181 }
00182
00183 if (flags & RPMVERIFY_MODE) {
00184 unsigned short metamode = modeList[filenum];
00185 unsigned short filemode;
00186
00187
00188
00189
00190
00191 filemode = (unsigned short)sb.st_mode;
00192
00193
00194
00195
00196 if (fileAttrs & RPMFILE_GHOST) {
00197 metamode &= ~0xf000;
00198 filemode &= ~0xf000;
00199 }
00200
00201 if (metamode != filemode)
00202 *result |= RPMVERIFY_MODE;
00203 }
00204
00205 if (flags & RPMVERIFY_RDEV) {
00206 if (S_ISCHR(modeList[filenum]) != S_ISCHR(sb.st_mode) ||
00207 S_ISBLK(modeList[filenum]) != S_ISBLK(sb.st_mode))
00208 {
00209 *result |= RPMVERIFY_RDEV;
00210 } else if (S_ISDEV(modeList[filenum]) && S_ISDEV(sb.st_mode)) {
00211 unsigned short * rdevList;
00212 if (!hge(h, RPMTAG_FILERDEVS, NULL, (void **) &rdevList, NULL)
00213 || rdevList[filenum] != sb.st_rdev)
00214 *result |= RPMVERIFY_RDEV;
00215 }
00216 }
00217
00218 if (flags & RPMVERIFY_MTIME) {
00219 int_32 * mtimeList;
00220
00221 if (!hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtimeList, NULL)
00222 || mtimeList[filenum] != sb.st_mtime)
00223 *result |= RPMVERIFY_MTIME;
00224 }
00225
00226 if (flags & RPMVERIFY_USER) {
00227 const char * name;
00228 const char ** unameList;
00229 int_32 * uidList;
00230 rpmTagType unt;
00231
00232 if (hge(h, RPMTAG_FILEUSERNAME, &unt, (void **) &unameList, NULL)) {
00233 name = uidToUname(sb.st_uid);
00234 if (!name || strcmp(unameList[filenum], name))
00235 *result |= RPMVERIFY_USER;
00236 unameList = hfd(unameList, unt);
00237 } else if (hge(h, RPMTAG_FILEUIDS, NULL, (void **) &uidList, NULL)) {
00238 if (uidList[filenum] != sb.st_uid)
00239 *result |= RPMVERIFY_GROUP;
00240 } else {
00241 rpmError(RPMERR_INTERNAL, _("package lacks both user name and id "
00242 "lists (this should never happen)\n"));
00243 *result |= RPMVERIFY_GROUP;
00244 }
00245 }
00246
00247 if (flags & RPMVERIFY_GROUP) {
00248 const char ** gnameList;
00249 int_32 * gidList;
00250 rpmTagType gnt;
00251 gid_t gid;
00252
00253 if (hge(h, RPMTAG_FILEGROUPNAME, &gnt, (void **) &gnameList, NULL)) {
00254 rc = gnameToGid(gnameList[filenum], &gid);
00255 if (rc || (gid != sb.st_gid))
00256 *result |= RPMVERIFY_GROUP;
00257 gnameList = hfd(gnameList, gnt);
00258 } else if (hge(h, RPMTAG_FILEGIDS, NULL, (void **) &gidList, NULL)) {
00259 if (gidList[filenum] != sb.st_gid)
00260 *result |= RPMVERIFY_GROUP;
00261 } else {
00262 rpmError(RPMERR_INTERNAL, _("package lacks both group name and id "
00263 "lists (this should never happen)\n"));
00264 *result |= RPMVERIFY_GROUP;
00265 }
00266 }
00267
00268 return 0;
00269 }
00270
00279 int rpmVerifyScript(const char * rootDir, Header h, FD_t scriptFd)
00280 {
00281 rpmdb rpmdb = NULL;
00282 rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
00283 TFI_t fi = xcalloc(1, sizeof(*fi));
00284 struct psm_s psmbuf;
00285 PSM_t psm = &psmbuf;
00286 int rc;
00287
00288 if (scriptFd != NULL)
00289 ts->scriptFd = fdLink(scriptFd, "rpmVerifyScript");
00290 fi->magic = TFIMAGIC;
00291 loadFi(h, fi);
00292 memset(psm, 0, sizeof(*psm));
00293 psm->ts = ts;
00294 psm->fi = fi;
00295 psm->stepName = "verify";
00296 psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00297 psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00298 rc = psmStage(psm, PSM_SCRIPT);
00299 freeFi(fi);
00300 fi = _free(fi);
00301 ts = rpmtransFree(ts);
00302 return rc;
00303 }
00304
00305 int rpmVerifyDigest(Header h)
00306 {
00307 HGE_t hge = (HGE_t)headerGetEntry;
00308 HFD_t hfd = headerFreeData;
00309 void * uh = NULL;
00310 rpmTagType uht;
00311 int_32 uhc;
00312 const char * hdigest;
00313 rpmTagType hdt;
00314 int ec = 0;
00315
00316
00317 if (!hge(h, RPMTAG_SHA1HEADER, &hdt, (void **) &hdigest, NULL)
00318 && !hge(h, RPMTAG_SHA1RHN, &hdt, (void **) &hdigest, NULL))
00319 {
00320 if (hge(h, RPMTAG_BADSHA1HEADER, &hdt, (void **) &hdigest, NULL))
00321 return 0;
00322 }
00323
00324
00325 if (!hge(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00326 return 0;
00327
00328 if (hdigest == NULL || uh == NULL)
00329 return 0;
00330
00331
00332 { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00333 const char * digest;
00334 size_t digestlen;
00335
00336 (void) rpmDigestUpdate(ctx, uh, uhc);
00337 (void) rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
00338
00339
00340 ec = (digest == NULL || strcmp(hdigest, digest)) ? 1 : 0;
00341 digest = _free(digest);
00342 }
00343
00344 uh = hfd(uh, uht);
00345 hdigest = hfd(hdigest, hdt);
00346
00347 return ec;
00348 }
00349
00355 static int verifyHeader(QVA_t qva, Header h)
00356
00357 {
00358 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00359 char buf[BUFSIZ];
00360 char * t, * te;
00361 const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
00362 const char ** fileNames = NULL;
00363 int count;
00364 int_32 * fileFlags = NULL;
00365 rpmVerifyAttrs verifyResult = 0;
00366 rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00367 int ec = 0;
00368 int i;
00369
00370 te = t = buf;
00371 *te = '\0';
00372
00373 if (!hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
00374 goto exit;
00375
00376 if (!headerIsEntry(h, RPMTAG_BASENAMES))
00377 goto exit;
00378
00379 rpmBuildFileList(h, &fileNames, &count);
00380
00381 for (i = 0; i < count; i++) {
00382 rpmfileAttrs fileAttrs;
00383 int rc;
00384
00385 fileAttrs = fileFlags[i];
00386
00387
00388 if (!(qva->qva_fflags & RPMFILE_GHOST)
00389 && (fileAttrs & RPMFILE_GHOST))
00390 continue;
00391
00392 rc = rpmVerifyFile(prefix, h, i, &verifyResult, omitMask);
00393 if (rc) {
00394
00395 if (!(fileAttrs & RPMFILE_MISSINGOK) || rpmIsVerbose()) {
00396 sprintf(te, _("missing %s"), fileNames[i]);
00397 te += strlen(te);
00398 ec = rc;
00399 }
00400
00401 } else if (verifyResult) {
00402 const char * size, * md5, * link, * mtime, * mode;
00403 const char * group, * user, * rdev;
00404 static const char *const aok = ".";
00405 static const char *const unknown = "?";
00406
00407 ec = 1;
00408
00409 #define _verify(_RPMVERIFY_F, _C) \
00410 ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00411 #define _verifylink(_RPMVERIFY_F, _C) \
00412 ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00413 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00414 #define _verifyfile(_RPMVERIFY_F, _C) \
00415 ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00416 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00417
00418 md5 = _verifyfile(RPMVERIFY_MD5, "5");
00419 size = _verify(RPMVERIFY_FILESIZE, "S");
00420 link = _verifylink(RPMVERIFY_LINKTO, "L");
00421 mtime = _verify(RPMVERIFY_MTIME, "T");
00422 rdev = _verify(RPMVERIFY_RDEV, "D");
00423 user = _verify(RPMVERIFY_USER, "U");
00424 group = _verify(RPMVERIFY_GROUP, "G");
00425 mode = _verify(RPMVERIFY_MODE, "M");
00426
00427 #undef _verify
00428 #undef _verifylink
00429 #undef _verifyfile
00430
00431 sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
00432 size, mode, md5, rdev, link, user, group, mtime,
00433 ((fileAttrs & RPMFILE_CONFIG) ? 'c' :
00434 (fileAttrs & RPMFILE_DOC) ? 'd' :
00435 (fileAttrs & RPMFILE_GHOST) ? 'g' :
00436 (fileAttrs & RPMFILE_LICENSE) ? 'l' :
00437 (fileAttrs & RPMFILE_README) ? 'r' : ' '),
00438 fileNames[i]);
00439 te += strlen(te);
00440 }
00441
00442 if (te > t) {
00443 *te++ = '\n';
00444 *te = '\0';
00445 rpmMessage(RPMMESS_NORMAL, "%s", t);
00446 te = t = buf;
00447 *t = '\0';
00448 }
00449 }
00450
00451 exit:
00452 fileNames = _free(fileNames);
00453 return ec;
00454 }
00455
00462 static int verifyDependencies(rpmdb rpmdb, Header h)
00463
00464 {
00465 rpmTransactionSet ts;
00466 rpmDependencyConflict conflicts;
00467 int numConflicts;
00468 int rc = 0;
00469 int i;
00470
00471 ts = rpmtransCreateSet(rpmdb, NULL);
00472 (void) rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
00473
00474 (void) rpmdepCheck(ts, &conflicts, &numConflicts);
00475 ts = rpmtransFree(ts);
00476
00477
00478 if (numConflicts) {
00479 const char *n, *v, *r;
00480 char * t, * te;
00481 int nb = 512;
00482 (void) headerNVR(h, &n, &v, &r);
00483
00484 for (i = 0; i < numConflicts; i++) {
00485 nb += strlen(conflicts[i].needsName) + sizeof(", ") - 1;
00486 if (conflicts[i].needsFlags)
00487 nb += strlen(conflicts[i].needsVersion) + 5;
00488 }
00489 te = t = alloca(nb);
00490 *te = '\0';
00491 sprintf(te, _("Unsatisfied dependencies for %s-%s-%s: "), n, v, r);
00492 te += strlen(te);
00493 for (i = 0; i < numConflicts; i++) {
00494 if (i) te = stpcpy(te, ", ");
00495 te = stpcpy(te, conflicts[i].needsName);
00496 if (conflicts[i].needsFlags) {
00497 int flags = conflicts[i].needsFlags;
00498 *te++ = ' ';
00499 if (flags & RPMSENSE_LESS) *te++ = '<';
00500 if (flags & RPMSENSE_GREATER) *te++ = '>';
00501 if (flags & RPMSENSE_EQUAL) *te++ = '=';
00502 *te++ = ' ';
00503 te = stpcpy(te, conflicts[i].needsVersion);
00504 }
00505 }
00506 conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
00507 if (te > t) {
00508 *te++ = '\n';
00509 *te = '\0';
00510 rpmMessage(RPMMESS_NORMAL, "%s", t);
00511 te = t;
00512 *t = '\0';
00513 }
00514 rc = 1;
00515 }
00516
00517 return rc;
00518 }
00519
00520 int showVerifyPackage(QVA_t qva, rpmdb rpmdb, Header h)
00521 {
00522 const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
00523 int ec = 0;
00524 int rc;
00525
00526 if (qva->qva_flags & VERIFY_DIGEST) {
00527 if ((rc = rpmVerifyDigest(h)) != 0) {
00528 const char *n, *v, *r;
00529 (void) headerNVR(h, &n, &v, &r);
00530 rpmMessage(RPMMESS_NORMAL,
00531 _("%s-%s-%s: immutable header region digest check failed\n"),
00532 n, v, r);
00533 ec = rc;
00534 }
00535 }
00536 if (qva->qva_flags & VERIFY_DEPS) {
00537 if ((rc = verifyDependencies(rpmdb, h)) != 0)
00538 ec = rc;
00539 }
00540 if (qva->qva_flags & VERIFY_FILES) {
00541 if ((rc = verifyHeader(qva, h)) != 0)
00542 ec = rc;
00543 }
00544 if (qva->qva_flags & VERIFY_SCRIPT) {
00545 FD_t fdo = fdDup(STDOUT_FILENO);
00546 if ((rc = rpmVerifyScript(prefix, h, fdo)) != 0)
00547 ec = rc;
00548 if (fdo)
00549 rc = Fclose(fdo);
00550 }
00551 return ec;
00552 }
00553
00554 int rpmVerify(QVA_t qva, rpmQVSources source, const char * arg)
00555 {
00556 rpmdb rpmdb = NULL;
00557 int rc;
00558
00559 switch (source) {
00560 case RPMQV_RPM:
00561 if (!(qva->qva_flags & VERIFY_DEPS))
00562 break;
00563
00564 default:
00565 if ((rc = rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644)) != 0)
00566 return 1;
00567 break;
00568 }
00569
00570 rc = rpmQueryVerify(qva, source, arg, rpmdb, showVerifyPackage);
00571
00572 if (rpmdb != NULL)
00573 (void) rpmdbClose(rpmdb);
00574
00575 return rc;
00576 }