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