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"
00022
00023 #define _RPMPS_INTERNAL
00024 #define _RPMTS_INTERNAL
00025 #include <rpmcli.h>
00026
00027 #include "debug.h"
00028
00029
00030
00031
00032 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00033
00034
00035 extern int _rpmds_unspecified_epoch_noise;
00036
00046 static int rpmVerifyFile(const rpmts ts, const rpmfi fi,
00047 rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
00048
00049
00050
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
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
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 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
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
00127
00128 if (fileAttrs & RPMFILE_GHOST)
00129 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00130 RPMVERIFY_LINKTO);
00131
00132
00133
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
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
00184
00185
00186 filemode = (unsigned short)sb.st_mode;
00187
00188
00189
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( QVA_t qva, rpmts ts,
00245 rpmfi fi, FD_t scriptFd)
00246
00247
00248
00249 {
00250 rpmpsm psm = rpmpsmNew(ts, NULL, fi);
00251 int rc = 0;
00252
00253 if (psm == NULL)
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
00286
00287 {
00288 rpmVerifyAttrs verifyResult = 0;
00289
00290 rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00291
00292 int ec = 0;
00293 char * t, * te;
00294 char buf[BUFSIZ];
00295 int i;
00296
00297 te = t = buf;
00298 *te = '\0';
00299
00300
00301 fi = rpmfiLink(fi, "verifyHeader");
00302
00303 fi = rpmfiInit(fi, 0);
00304 if (fi != NULL)
00305 while ((i = rpmfiNext(fi)) >= 0) {
00306 rpmfileAttrs fflags;
00307 int rc;
00308
00309 fflags = rpmfiFFlags(fi);
00310
00311
00312 if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
00313 continue;
00314
00315
00316 if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
00317 continue;
00318
00319
00320
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')
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 static const char *const aok = ".";
00347 static const char *const unknown = "?";
00348
00349 if (!ec)
00350 ec = (verifyResult != 0);
00351
00352 if (qva->qva_mode != 'v') {
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')
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( QVA_t qva, rpmts ts,
00410 Header h)
00411
00412
00413 {
00414 #ifdef NOTYET
00415 int instance = headerGetInstance(h);
00416 #endif
00417 rpmps ps;
00418 int rc = 0;
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
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
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
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 }