rpm 5.2.1
|
00001 00006 #include "system.h" 00007 00008 #include <rpmio.h> 00009 #include <rpmiotypes.h> 00010 #include <rpmcb.h> 00011 #include "ugid.h" 00012 00013 #include <rpmtypes.h> 00014 #include <rpmtag.h> 00015 00016 #include <rpmfi.h> 00017 00018 #define _RPMSQ_INTERNAL 00019 #include "psm.h" 00020 00021 #include "legacy.h" /* XXX dodigest(), uidToUname(), gnameToGid */ 00022 00023 #define _RPMPS_INTERNAL /* XXX rpmps needs iterator. */ 00024 #define _RPMTS_INTERNAL /* XXX expose rpmtsSetScriptFd */ 00025 #include <rpmcli.h> 00026 00027 #include "debug.h" 00028 00029 /*@access rpmts @*/ /* XXX cast */ 00030 /*@access rpmpsm @*/ /* XXX for %verifyscript through rpmpsmStage() */ 00031 00032 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m))) 00033 00034 /*@unchecked@*/ 00035 extern int _rpmds_unspecified_epoch_noise; 00036 00046 static int rpmVerifyFile(const rpmts ts, const rpmfi fi, 00047 /*@out@*/ rpmVerifyAttrs * res, rpmVerifyAttrs omitMask) 00048 /*@globals h_errno, fileSystem, internalState @*/ 00049 /*@modifies fi, *res, fileSystem, internalState @*/ 00050 /*@requires maxSet(res) >= 0 @*/ 00051 { 00052 unsigned short fmode = rpmfiFMode(fi); 00053 rpmfileAttrs fileAttrs = rpmfiFFlags(fi); 00054 rpmVerifyAttrs flags = rpmfiVFlags(fi); 00055 const char * fn = rpmfiFN(fi); 00056 const char * rootDir = rpmtsRootDir(ts); 00057 struct stat sb; 00058 int rc; 00059 00060 /* Prepend the path to root (if specified). */ 00061 if (rootDir && *rootDir != '\0' 00062 && !(rootDir[0] == '/' && rootDir[1] == '\0')) 00063 { 00064 int nb = strlen(fn) + strlen(rootDir) + 1; 00065 char * tb = alloca(nb); 00066 char * t; 00067 00068 t = tb; 00069 *t = '\0'; 00070 t = stpcpy(t, rootDir); 00071 while (t > tb && t[-1] == '/') { 00072 --t; 00073 *t = '\0'; 00074 } 00075 t = stpcpy(t, fn); 00076 fn = tb; 00077 } 00078 00079 *res = RPMVERIFY_NONE; 00080 00081 /* 00082 * Check to see if the file was installed - if not pretend all is OK. 00083 */ 00084 switch (rpmfiFState(fi)) { 00085 case RPMFILE_STATE_NETSHARED: 00086 case RPMFILE_STATE_REPLACED: 00087 case RPMFILE_STATE_NOTINSTALLED: 00088 case RPMFILE_STATE_WRONGCOLOR: 00089 return 0; 00090 /*@notreached@*/ break; 00091 case RPMFILE_STATE_NORMAL: 00092 break; 00093 } 00094 00095 if (fn == NULL || Lstat(fn, &sb) != 0) { 00096 *res |= RPMVERIFY_LSTATFAIL; 00097 return 1; 00098 } 00099 00100 /* 00101 * Not all attributes of non-regular files can be verified. 00102 */ 00103 if (S_ISDIR(sb.st_mode)) 00104 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 00105 RPMVERIFY_LINKTO); 00106 else if (S_ISLNK(sb.st_mode)) { 00107 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 00108 RPMVERIFY_MODE); 00109 #if CHOWN_FOLLOWS_SYMLINK 00110 flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP); 00111 #endif 00112 } 00113 else if (S_ISFIFO(sb.st_mode)) 00114 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 00115 RPMVERIFY_LINKTO); 00116 else if (S_ISCHR(sb.st_mode)) 00117 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 00118 RPMVERIFY_LINKTO); 00119 else if (S_ISBLK(sb.st_mode)) 00120 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 00121 RPMVERIFY_LINKTO); 00122 else 00123 flags &= ~(RPMVERIFY_LINKTO); 00124 00125 /* 00126 * Content checks of %ghost files are meaningless. 00127 */ 00128 if (fileAttrs & RPMFILE_GHOST) 00129 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 00130 RPMVERIFY_LINKTO); 00131 00132 /* 00133 * Don't verify any features in omitMask. 00134 */ 00135 flags &= ~(omitMask | RPMVERIFY_FAILURES); 00136 00137 00138 if (flags & RPMVERIFY_FDIGEST) { 00139 int dalgo = 0; 00140 size_t dlen = 0; 00141 const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen); 00142 00143 if (digest == NULL) 00144 *res |= RPMVERIFY_FDIGEST; 00145 else { 00146 /* XXX If --nofdigest, then prelinked library sizes fail to verify. */ 00147 unsigned char * fdigest = memset(alloca(dlen), 0, dlen); 00148 size_t fsize; 00149 rc = dodigest(dalgo, fn, fdigest, 0, &fsize); 00150 sb.st_size = fsize; 00151 if (rc) 00152 *res |= (RPMVERIFY_READFAIL|RPMVERIFY_FDIGEST); 00153 else 00154 if (memcmp(fdigest, digest, dlen)) 00155 *res |= RPMVERIFY_FDIGEST; 00156 } 00157 } 00158 00159 if (flags & RPMVERIFY_LINKTO) { 00160 char linkto[1024+1]; 00161 int size = 0; 00162 00163 if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1) 00164 *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); 00165 else { 00166 const char * flink = rpmfiFLink(fi); 00167 linkto[size] = '\0'; 00168 if (flink == NULL || strcmp(linkto, flink)) 00169 *res |= RPMVERIFY_LINKTO; 00170 } 00171 } 00172 00173 if (flags & RPMVERIFY_FILESIZE) { 00174 if (sb.st_size != rpmfiFSize(fi)) 00175 *res |= RPMVERIFY_FILESIZE; 00176 } 00177 00178 if (flags & RPMVERIFY_MODE) { 00179 unsigned short metamode = fmode; 00180 unsigned short filemode; 00181 00182 /* 00183 * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t) 00184 * need the (unsigned short) cast here. 00185 */ 00186 filemode = (unsigned short)sb.st_mode; 00187 00188 /* 00189 * Comparing the type of %ghost files is meaningless, but perms are OK. 00190 */ 00191 if (fileAttrs & RPMFILE_GHOST) { 00192 metamode &= ~0xf000; 00193 filemode &= ~0xf000; 00194 } 00195 00196 if (metamode != filemode) 00197 *res |= RPMVERIFY_MODE; 00198 } 00199 00200 if (flags & RPMVERIFY_RDEV) { 00201 if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode) 00202 || S_ISBLK(fmode) != S_ISBLK(sb.st_mode)) 00203 { 00204 *res |= RPMVERIFY_RDEV; 00205 } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) { 00206 rpmuint16_t st_rdev = (rpmuint16_t)(sb.st_rdev & 0xffff); 00207 rpmuint16_t frdev = (rpmuint16_t)(rpmfiFRdev(fi) & 0xffff); 00208 if (st_rdev != frdev) 00209 *res |= RPMVERIFY_RDEV; 00210 } 00211 } 00212 00213 if (flags & RPMVERIFY_MTIME) { 00214 if ((rpmuint32_t)sb.st_mtime != rpmfiFMtime(fi)) 00215 *res |= RPMVERIFY_MTIME; 00216 } 00217 00218 if (flags & RPMVERIFY_USER) { 00219 const char * name = uidToUname(sb.st_uid); 00220 const char * fuser = rpmfiFUser(fi); 00221 if (name == NULL || fuser == NULL || strcmp(name, fuser)) 00222 *res |= RPMVERIFY_USER; 00223 } 00224 00225 if (flags & RPMVERIFY_GROUP) { 00226 const char * name = gidToGname(sb.st_gid); 00227 const char * fgroup = rpmfiFGroup(fi); 00228 if (name == NULL || fgroup == NULL || strcmp(name, fgroup)) 00229 *res |= RPMVERIFY_GROUP; 00230 } 00231 00232 return 0; 00233 } 00234 00244 static int rpmVerifyScript(/*@unused@*/ QVA_t qva, rpmts ts, 00245 rpmfi fi, /*@null@*/ FD_t scriptFd) 00246 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00247 /*@modifies ts, fi, scriptFd, rpmGlobalMacroContext, 00248 fileSystem, internalState @*/ 00249 { 00250 rpmpsm psm = rpmpsmNew(ts, NULL, fi); 00251 int rc = 0; 00252 00253 if (psm == NULL) /* XXX can't happen */ 00254 return rc; 00255 00256 if (scriptFd != NULL) 00257 rpmtsSetScriptFd(psm->ts, scriptFd); 00258 00259 psm->stepName = "verify"; 00260 psm->scriptTag = RPMTAG_VERIFYSCRIPT; 00261 psm->progTag = RPMTAG_VERIFYSCRIPTPROG; 00262 rc = rpmpsmStage(psm, PSM_SCRIPT); 00263 00264 psm->stepName = "sanitycheck"; 00265 psm->scriptTag = RPMTAG_SANITYCHECK; 00266 psm->progTag = RPMTAG_SANITYCHECKPROG; 00267 rc = rpmpsmStage(psm, PSM_SCRIPT); 00268 00269 if (scriptFd != NULL) 00270 rpmtsSetScriptFd(psm->ts, NULL); 00271 00272 psm = rpmpsmFree(psm, "rpmVerifyScript"); 00273 00274 return rc; 00275 } 00276 00284 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi) 00285 /*@globals h_errno, fileSystem, internalState @*/ 00286 /*@modifies fi, fileSystem, internalState @*/ 00287 { 00288 rpmVerifyAttrs verifyResult = 0; 00289 /*@-type@*/ /* FIX: union? */ 00290 rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS); 00291 /*@=type@*/ 00292 int ec = 0; /* assume no problems */ 00293 char * t, * te; 00294 char buf[BUFSIZ]; 00295 int i; 00296 00297 te = t = buf; 00298 *te = '\0'; 00299 00300 /*@-castexpose@*/ 00301 fi = rpmfiLink(fi, "verifyHeader"); 00302 /*@=castexpose@*/ 00303 fi = rpmfiInit(fi, 0); 00304 if (fi != NULL) /* XXX lclint */ 00305 while ((i = rpmfiNext(fi)) >= 0) { 00306 rpmfileAttrs fflags; 00307 int rc; 00308 00309 fflags = rpmfiFFlags(fi); 00310 00311 /* If not querying %config, skip config files. */ 00312 if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG)) 00313 continue; 00314 00315 /* If not querying %doc, skip doc files. */ 00316 if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC)) 00317 continue; 00318 00319 /* If not verifying %ghost, skip ghost files. */ 00320 /* XXX the broken!!! logic disables %ghost queries always. */ 00321 if (!(qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST)) 00322 continue; 00323 00324 rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask); 00325 if (rc) { 00326 if (qva->qva_mode != 'v') /* XXX no output w verify(...) probe. */ 00327 if (!(fflags & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) { 00328 sprintf(te, _("missing %c %s"), 00329 ((fflags & RPMFILE_CONFIG) ? 'c' : 00330 (fflags & RPMFILE_DOC) ? 'd' : 00331 (fflags & RPMFILE_GHOST) ? 'g' : 00332 (fflags & RPMFILE_LICENSE) ? 'l' : 00333 (fflags & RPMFILE_PUBKEY) ? 'P' : 00334 (fflags & RPMFILE_README) ? 'r' : ' '), 00335 rpmfiFN(fi)); 00336 te += strlen(te); 00337 if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) { 00338 sprintf(te, " (%s)", strerror(errno)); 00339 te += strlen(te); 00340 } 00341 ec = rc; 00342 } 00343 } else if (verifyResult || rpmIsVerbose()) { 00344 const char * size, * digest, * link, * mtime, * mode; 00345 const char * group, * user, * rdev; 00346 /*@observer@*/ static const char *const aok = "."; 00347 /*@observer@*/ static const char *const unknown = "?"; 00348 00349 if (!ec) 00350 ec = (verifyResult != 0); 00351 00352 if (qva->qva_mode != 'v') { /* XXX no output w verify(...) probe. */ 00353 #define _verify(_RPMVERIFY_F, _C) \ 00354 ((verifyResult & _RPMVERIFY_F) ? _C : aok) 00355 #define _verifylink(_RPMVERIFY_F, _C) \ 00356 ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \ 00357 (verifyResult & _RPMVERIFY_F) ? _C : aok) 00358 #define _verifyfile(_RPMVERIFY_F, _C) \ 00359 ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \ 00360 (verifyResult & _RPMVERIFY_F) ? _C : aok) 00361 00362 digest = _verifyfile(RPMVERIFY_FDIGEST, "5"); 00363 size = _verify(RPMVERIFY_FILESIZE, "S"); 00364 link = _verifylink(RPMVERIFY_LINKTO, "L"); 00365 mtime = _verify(RPMVERIFY_MTIME, "T"); 00366 rdev = _verify(RPMVERIFY_RDEV, "D"); 00367 user = _verify(RPMVERIFY_USER, "U"); 00368 group = _verify(RPMVERIFY_GROUP, "G"); 00369 mode = _verify(RPMVERIFY_MODE, "M"); 00370 00371 #undef _verifyfile 00372 #undef _verifylink 00373 #undef _verify 00374 00375 sprintf(te, "%s%s%s%s%s%s%s%s %c %s", 00376 size, mode, digest, rdev, link, user, group, mtime, 00377 ((fflags & RPMFILE_CONFIG) ? 'c' : 00378 (fflags & RPMFILE_DOC) ? 'd' : 00379 (fflags & RPMFILE_GHOST) ? 'g' : 00380 (fflags & RPMFILE_LICENSE) ? 'l' : 00381 (fflags & RPMFILE_PUBKEY) ? 'P' : 00382 (fflags & RPMFILE_README) ? 'r' : ' '), 00383 rpmfiFN(fi)); 00384 te += strlen(te); 00385 } 00386 } 00387 00388 if (qva->qva_mode != 'v') /* XXX no output w verify(...) probe. */ 00389 if (te > t) { 00390 *te++ = '\n'; 00391 *te = '\0'; 00392 rpmlog(RPMLOG_NOTICE, "%s", t); 00393 te = t = buf; 00394 *t = '\0'; 00395 } 00396 } 00397 fi = rpmfiUnlink(fi, "verifyHeader"); 00398 00399 return ec; 00400 } 00401 00409 static int verifyDependencies(/*@unused@*/ QVA_t qva, rpmts ts, 00410 Header h) 00411 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00412 /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/ 00413 { 00414 #ifdef NOTYET 00415 int instance = headerGetInstance(h); 00416 #endif 00417 rpmps ps; 00418 int rc = 0; /* assume no problems */ 00419 int xx; 00420 00421 rpmtsEmpty(ts); 00422 #ifdef NOTYET 00423 if (instance > 0) 00424 (void) rpmtsAddEraseElement(ts, h, instance); 00425 else 00426 #endif 00427 (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL); 00428 00429 xx = rpmtsCheck(ts); 00430 ps = rpmtsProblems(ts); 00431 00432 if (rpmpsNumProblems(ps) > 0) { 00433 const char * altNEVR; 00434 const char * pkgNEVR = NULL; 00435 rpmpsi psi; 00436 rpmProblem prob; 00437 char * t, * te; 00438 int nb = 512; 00439 00440 psi = rpmpsInitIterator(ps); 00441 while (rpmpsNextIterator(psi) >= 0) { 00442 prob = rpmpsProblem(psi); 00443 if (pkgNEVR == NULL) 00444 pkgNEVR = rpmProblemGetPkgNEVR(prob); 00445 00446 altNEVR = rpmProblemGetAltNEVR(prob); 00447 assert(altNEVR != NULL); 00448 if (altNEVR[0] == 'R' && altNEVR[1] == ' ') 00449 nb += sizeof("\tRequires: ")-1; 00450 if (altNEVR[0] == 'C' && altNEVR[1] == ' ') 00451 nb += sizeof("\tConflicts: ")-1; 00452 nb += strlen(altNEVR+2) + sizeof("\n") - 1; 00453 00454 } 00455 psi = rpmpsFreeIterator(psi); 00456 00457 te = t = alloca(nb); 00458 *te = '\0'; 00459 sprintf(te, _("Unsatisfied dependencies for %s:\n"), pkgNEVR); 00460 te += strlen(te); 00461 00462 psi = rpmpsInitIterator(ps); 00463 while (rpmpsNextIterator(psi) >= 0) { 00464 prob = rpmpsProblem(psi); 00465 00466 if ((altNEVR = rpmProblemGetAltNEVR(prob)) == NULL) 00467 altNEVR = "? ?altNEVR?"; 00468 if (altNEVR[0] == 'R' && altNEVR[1] == ' ') 00469 te = stpcpy(te, "\tRequires: "); 00470 if (altNEVR[0] == 'C' && altNEVR[1] == ' ') 00471 te = stpcpy(te, "\tConflicts: "); 00472 te = stpcpy( stpcpy(te, altNEVR+2), "\n"); 00473 00474 rc++; 00475 } 00476 psi = rpmpsFreeIterator(psi); 00477 00478 if (te > t) { 00479 *te++ = '\n'; 00480 *te = '\0'; 00481 rpmlog(RPMLOG_NOTICE, "%s", t); 00482 te = t; 00483 *t = '\0'; 00484 } 00485 } 00486 00487 ps = rpmpsFree(ps); 00488 00489 rpmtsEmpty(ts); 00490 00491 return rc; 00492 } 00493 00494 int showVerifyPackage(QVA_t qva, rpmts ts, Header h) 00495 { 00496 int scareMem = 0; 00497 rpmfi fi = NULL; 00498 int ec = 0; 00499 int rc; 00500 00501 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem); 00502 if (fi != NULL) { 00503 if (qva->qva_flags & VERIFY_DEPS) { 00504 int save_noise = _rpmds_unspecified_epoch_noise; 00505 /*@-mods@*/ 00506 if (rpmIsVerbose()) 00507 _rpmds_unspecified_epoch_noise = 1; 00508 if ((rc = verifyDependencies(qva, ts, h)) != 0) 00509 ec = rc; 00510 _rpmds_unspecified_epoch_noise = save_noise; 00511 /*@=mods@*/ 00512 } 00513 if (qva->qva_flags & VERIFY_FILES) { 00514 if ((rc = verifyHeader(qva, ts, fi)) != 0) 00515 ec = rc; 00516 } 00517 if ((qva->qva_flags & VERIFY_SCRIPT) 00518 && (headerIsEntry(h, RPMTAG_VERIFYSCRIPT) || 00519 headerIsEntry(h, RPMTAG_SANITYCHECK))) 00520 { 00521 FD_t fdo = fdDup(STDOUT_FILENO); 00522 00523 rc = rpmfiSetHeader(fi, h); 00524 if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0) 00525 ec = rc; 00526 if (fdo != NULL) 00527 rc = Fclose(fdo); 00528 rc = rpmfiSetHeader(fi, NULL); 00529 } 00530 00531 fi = rpmfiFree(fi); 00532 } 00533 00534 return ec; 00535 } 00536 00537 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv) 00538 { 00539 rpmdepFlags depFlags = qva->depFlags, odepFlags; 00540 rpmtransFlags transFlags = qva->transFlags, otransFlags; 00541 rpmVSFlags vsflags, ovsflags; 00542 int ec = 0; 00543 00544 if (qva->qva_showPackage == NULL) 00545 qva->qva_showPackage = showVerifyPackage; 00546 00547 /* XXX verify flags are inverted from query. */ 00548 vsflags = rpmExpandNumeric("%{?_vsflags_verify}"); 00549 if (!(qva->qva_flags & VERIFY_DIGEST)) 00550 vsflags |= _RPMVSF_NODIGESTS; 00551 if (!(qva->qva_flags & VERIFY_SIGNATURE)) 00552 vsflags |= _RPMVSF_NOSIGNATURES; 00553 if (!(qva->qva_flags & VERIFY_HDRCHK)) 00554 vsflags |= RPMVSF_NOHDRCHK; 00555 vsflags &= ~RPMVSF_NEEDPAYLOAD; 00556 00557 odepFlags = rpmtsSetDFlags(ts, depFlags); 00558 otransFlags = rpmtsSetFlags(ts, transFlags); 00559 ovsflags = rpmtsSetVSFlags(ts, vsflags); 00560 ec = rpmcliArgIter(ts, qva, argv); 00561 vsflags = rpmtsSetVSFlags(ts, ovsflags); 00562 transFlags = rpmtsSetFlags(ts, otransFlags); 00563 depFlags = rpmtsSetDFlags(ts, odepFlags); 00564 00565 if (qva->qva_showPackage == showVerifyPackage) 00566 qva->qva_showPackage = NULL; 00567 00568 rpmtsEmpty(ts); 00569 00570 return ec; 00571 }