00001
00006 #include "system.h"
00007
00008 #include <rpmcli.h>
00009
00010 #include "psm.h"
00011 #include "rpmfi.h"
00012 #include "rpmts.h"
00013
00014 #include "legacy.h"
00015 #include "ugid.h"
00016 #include "debug.h"
00017
00018
00019
00020
00021
00022 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00023
00024
00025 extern int _rpmds_unspecified_epoch_noise;
00026 extern int _cacheDependsRC;
00027
00028 int rpmVerifyFile(const rpmts ts, const rpmfi fi,
00029 rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
00030 {
00031 unsigned short fmode = rpmfiFMode(fi);
00032 rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
00033 rpmVerifyAttrs flags = rpmfiVFlags(fi);
00034 const char * fn = rpmfiFN(fi);
00035 int selinuxEnabled = rpmtsSELinuxEnabled(ts);
00036 struct stat sb;
00037 int rc;
00038
00039 *res = RPMVERIFY_NONE;
00040
00041
00042
00043
00044 switch (rpmfiFState(fi)) {
00045 case RPMFILE_STATE_NETSHARED:
00046 case RPMFILE_STATE_REPLACED:
00047 case RPMFILE_STATE_NOTINSTALLED:
00048 case RPMFILE_STATE_WRONGCOLOR:
00049 return 0;
00050 break;
00051 case RPMFILE_STATE_NORMAL:
00052 break;
00053 }
00054
00055 if (fn == NULL || Lstat(fn, &sb) != 0) {
00056 *res |= RPMVERIFY_LSTATFAIL;
00057 return 1;
00058 }
00059
00060
00061
00062
00063 if (S_ISDIR(sb.st_mode))
00064 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00065 RPMVERIFY_LINKTO);
00066 else if (S_ISLNK(sb.st_mode)) {
00067 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00068 RPMVERIFY_MODE);
00069 #if CHOWN_FOLLOWS_SYMLINK
00070 flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00071 #endif
00072 }
00073 else if (S_ISFIFO(sb.st_mode))
00074 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00075 RPMVERIFY_LINKTO);
00076 else if (S_ISCHR(sb.st_mode))
00077 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00078 RPMVERIFY_LINKTO);
00079 else if (S_ISBLK(sb.st_mode))
00080 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00081 RPMVERIFY_LINKTO);
00082 else
00083 flags &= ~(RPMVERIFY_LINKTO);
00084
00085
00086
00087
00088 if (fileAttrs & RPMFILE_GHOST)
00089 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00090 RPMVERIFY_LINKTO);
00091
00092
00093
00094
00095 flags &= ~(omitMask | RPMVERIFY_FAILURES);
00096
00097
00098
00099 if (flags & RPMVERIFY_MD5) {
00100 unsigned char md5sum[16];
00101 size_t fsize;
00102
00103
00104 rc = domd5(fn, md5sum, 0, &fsize);
00105 sb.st_size = fsize;
00106 if (rc)
00107 *res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00108 else {
00109 const unsigned char * MD5 = rpmfiMD5(fi);
00110 if (MD5 == NULL || memcmp(md5sum, MD5, sizeof(md5sum)))
00111 *res |= RPMVERIFY_MD5;
00112 }
00113 }
00114
00115 if (flags & RPMVERIFY_LINKTO) {
00116 char linkto[1024+1];
00117 int size = 0;
00118
00119 if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
00120 *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00121 else {
00122 const char * flink = rpmfiFLink(fi);
00123 linkto[size] = '\0';
00124 if (flink == NULL || strcmp(linkto, flink))
00125 *res |= RPMVERIFY_LINKTO;
00126 }
00127 }
00128
00129 if (flags & RPMVERIFY_FILESIZE) {
00130 if (sb.st_size != rpmfiFSize(fi))
00131 *res |= RPMVERIFY_FILESIZE;
00132 }
00133
00134 if (flags & RPMVERIFY_MODE) {
00135 unsigned short metamode = fmode;
00136 unsigned short filemode;
00137
00138
00139
00140
00141
00142 filemode = (unsigned short)sb.st_mode;
00143
00144
00145
00146
00147 if (fileAttrs & RPMFILE_GHOST) {
00148 metamode &= ~0xf000;
00149 filemode &= ~0xf000;
00150 }
00151
00152 if (metamode != filemode)
00153 *res |= RPMVERIFY_MODE;
00154 }
00155
00156 if (flags & RPMVERIFY_RDEV) {
00157 if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
00158 || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
00159 {
00160 *res |= RPMVERIFY_RDEV;
00161 } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
00162 uint_16 st_rdev = (sb.st_rdev & 0xffff);
00163 uint_16 frdev = (rpmfiFRdev(fi) & 0xffff);
00164 if (st_rdev != frdev)
00165 *res |= RPMVERIFY_RDEV;
00166 }
00167 }
00168
00169 if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) {
00170
00171 rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
00172 if (rpmdbGetIteratorCount(mi) < 2)
00173 *res |= RPMVERIFY_MTIME;
00174 rpmdbFreeIterator(mi);
00175 }
00176
00177 if (flags & RPMVERIFY_USER) {
00178 const char * name = uidToUname(sb.st_uid);
00179 const char * fuser = rpmfiFUser(fi);
00180 if (name == NULL || fuser == NULL || strcmp(name, fuser))
00181 *res |= RPMVERIFY_USER;
00182 }
00183
00184 if (flags & RPMVERIFY_GROUP) {
00185 const char * name = gidToGname(sb.st_gid);
00186 const char * fgroup = rpmfiFGroup(fi);
00187 if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
00188 *res |= RPMVERIFY_GROUP;
00189 }
00190
00191 return 0;
00192 }
00193
00203 static int rpmVerifyScript( QVA_t qva, rpmts ts,
00204 rpmfi fi, FD_t scriptFd)
00205
00206
00207
00208 {
00209 rpmpsm psm = rpmpsmNew(ts, NULL, fi);
00210 int rc = 0;
00211
00212 if (psm == NULL)
00213 return rc;
00214
00215 if (scriptFd != NULL)
00216 rpmtsSetScriptFd(psm->ts, scriptFd);
00217
00218 psm->stepName = "verify";
00219 psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00220 psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00221 rc = rpmpsmStage(psm, PSM_SCRIPT);
00222
00223 if (scriptFd != NULL)
00224 rpmtsSetScriptFd(psm->ts, NULL);
00225
00226 psm = rpmpsmFree(psm);
00227
00228 return rc;
00229 }
00230
00238 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
00239
00240
00241 {
00242 int selinuxEnabled = rpmtsSELinuxEnabled(ts);
00243 rpmVerifyAttrs verifyResult = 0;
00244
00245 rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00246
00247 int ec = 0;
00248 char * t, * te;
00249 char buf[BUFSIZ];
00250 int i;
00251
00252 te = t = buf;
00253 *te = '\0';
00254
00255 fi = rpmfiLink(fi, "verifyHeader");
00256 fi = rpmfiInit(fi, 0);
00257 if (fi != NULL)
00258 while ((i = rpmfiNext(fi)) >= 0) {
00259 rpmfileAttrs fileAttrs;
00260 int rc;
00261
00262 fileAttrs = rpmfiFFlags(fi);
00263
00264
00265 if (!(qva->qva_fflags & RPMFILE_GHOST)
00266 && (fileAttrs & RPMFILE_GHOST))
00267 continue;
00268
00269
00270 rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
00271
00272 if (rc) {
00273 if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
00274 sprintf(te, _("missing %c %s"),
00275 ((fileAttrs & RPMFILE_CONFIG) ? 'c' :
00276 (fileAttrs & RPMFILE_DOC) ? 'd' :
00277 (fileAttrs & RPMFILE_GHOST) ? 'g' :
00278 (fileAttrs & RPMFILE_LICENSE) ? 'l' :
00279 (fileAttrs & RPMFILE_PUBKEY) ? 'P' :
00280 (fileAttrs & RPMFILE_README) ? 'r' : ' '),
00281 rpmfiFN(fi));
00282 te += strlen(te);
00283 if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 &&
00284 errno != ENOENT) {
00285 sprintf(te, " (%s)", strerror(errno));
00286 te += strlen(te);
00287 }
00288 ec = rc;
00289 }
00290 } else if (verifyResult || rpmIsVerbose()) {
00291 const char * size, * MD5, * link, * mtime, * mode;
00292 const char * group, * user, * rdev;
00293 static const char *const aok = ".";
00294 static const char *const unknown = "?";
00295
00296 ec = 1;
00297
00298 #define _verify(_RPMVERIFY_F, _C) \
00299 ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00300 #define _verifylink(_RPMVERIFY_F, _C) \
00301 ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00302 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00303 #define _verifyfile(_RPMVERIFY_F, _C) \
00304 ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00305 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00306
00307 MD5 = _verifyfile(RPMVERIFY_MD5, "5");
00308 size = _verify(RPMVERIFY_FILESIZE, "S");
00309 link = _verifylink(RPMVERIFY_LINKTO, "L");
00310 mtime = _verify(RPMVERIFY_MTIME, "T");
00311 rdev = _verify(RPMVERIFY_RDEV, "D");
00312 user = _verify(RPMVERIFY_USER, "U");
00313 group = _verify(RPMVERIFY_GROUP, "G");
00314 mode = _verify(RPMVERIFY_MODE, "M");
00315
00316 #undef _verifyfile
00317 #undef _verifylink
00318 #undef _verify
00319
00320 sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
00321 size, mode, MD5, rdev, link, user, group, mtime,
00322 ((fileAttrs & RPMFILE_CONFIG) ? 'c' :
00323 (fileAttrs & RPMFILE_DOC) ? 'd' :
00324 (fileAttrs & RPMFILE_GHOST) ? 'g' :
00325 (fileAttrs & RPMFILE_LICENSE) ? 'l' :
00326 (fileAttrs & RPMFILE_PUBKEY) ? 'P' :
00327 (fileAttrs & RPMFILE_README) ? 'r' : ' '),
00328 rpmfiFN(fi));
00329 te += strlen(te);
00330 }
00331
00332
00333 if (te > t) {
00334 *te++ = '\n';
00335 *te = '\0';
00336 rpmMessage(RPMMESS_NORMAL, "%s", t);
00337 te = t = buf;
00338 *t = '\0';
00339 }
00340
00341 }
00342 fi = rpmfiUnlink(fi, "verifyHeader");
00343
00344 return ec;
00345 }
00346
00354 static int verifyDependencies( QVA_t qva, rpmts ts,
00355 Header h)
00356
00357
00358 {
00359 rpmps ps;
00360 int numProblems;
00361 int rc = 0;
00362 int xx;
00363 int i;
00364
00365 rpmtsEmpty(ts);
00366 (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00367
00368 xx = rpmtsCheck(ts);
00369 ps = rpmtsProblems(ts);
00370
00371 numProblems = rpmpsNumProblems(ps);
00372
00373 if (ps != NULL && numProblems > 0) {
00374 const char * pkgNEVR, * altNEVR;
00375 rpmProblem p;
00376 char * t, * te;
00377 int nb = 512;
00378
00379 for (i = 0; i < numProblems; i++) {
00380 p = ps->probs + i;
00381 altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00382 nb += strlen(altNEVR+2) + sizeof(", ") - 1;
00383 }
00384 te = t = alloca(nb);
00385
00386 *te = '\0';
00387 pkgNEVR = (ps->probs->pkgNEVR ? ps->probs->pkgNEVR : "?pkgNEVR?");
00388 sprintf(te, _("Unsatisfied dependencies for %s: "), pkgNEVR);
00389 te += strlen(te);
00390 for (i = 0; i < numProblems; i++) {
00391 p = ps->probs + i;
00392 altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00393 if (i) te = stpcpy(te, ", ");
00394
00395 te = stpcpy(te, altNEVR+2);
00396 }
00397
00398 if (te > t) {
00399 *te++ = '\n';
00400 *te = '\0';
00401 rpmMessage(RPMMESS_NORMAL, "%s", t);
00402 te = t;
00403 *t = '\0';
00404 }
00405
00406 rc = 1;
00407 }
00408
00409
00410 ps = rpmpsFree(ps);
00411
00412 rpmtsEmpty(ts);
00413
00414 return rc;
00415 }
00416
00417 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
00418 {
00419 int scareMem = 1;
00420 rpmfi fi;
00421 int ec = 0;
00422 int rc;
00423
00424 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00425 if (fi != NULL) {
00426
00427 if (qva->qva_flags & VERIFY_DEPS) {
00428 int save_noise = _rpmds_unspecified_epoch_noise;
00429
00430 if (rpmIsVerbose())
00431 _rpmds_unspecified_epoch_noise = 1;
00432 if ((rc = verifyDependencies(qva, ts, h)) != 0)
00433 ec = rc;
00434 _rpmds_unspecified_epoch_noise = save_noise;
00435
00436 }
00437 if (qva->qva_flags & VERIFY_FILES) {
00438 if ((rc = verifyHeader(qva, ts, fi)) != 0)
00439 ec = rc;
00440 }
00441 if ((qva->qva_flags & VERIFY_SCRIPT)
00442 && headerIsEntry(h, RPMTAG_VERIFYSCRIPT))
00443 {
00444 FD_t fdo = fdDup(STDOUT_FILENO);
00445 if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
00446 ec = rc;
00447 if (fdo != NULL)
00448 rc = Fclose(fdo);
00449 }
00450
00451 fi = rpmfiFree(fi);
00452 }
00453
00454 return ec;
00455 }
00456
00457 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv)
00458 {
00459 const char * arg;
00460 rpmVSFlags vsflags, ovsflags;
00461 int ec = 0, xx;
00462 const char * rootDir = rpmtsRootDir(ts);
00463 int cachingDeps = _cacheDependsRC;
00464
00465
00466
00467
00468
00469 rpmtsOpenDB(ts, O_RDONLY);
00470 rpmdbOpenAll(rpmtsGetRdb(ts));
00471 if (rootDir && strcmp(rootDir, "/") != 0) {
00472 if (chroot(rootDir) == -1) {
00473 rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
00474 ec = 1;
00475 goto exit;
00476 } else {
00477 rpmtsSetChrootDone(ts, 1);
00478
00479 _cacheDependsRC = 0;
00480 }
00481 }
00482
00483 if (qva->qva_showPackage == NULL)
00484 qva->qva_showPackage = showVerifyPackage;
00485
00486
00487 vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
00488 if (!(qva->qva_flags & VERIFY_DIGEST))
00489 vsflags |= _RPMVSF_NODIGESTS;
00490 if (!(qva->qva_flags & VERIFY_SIGNATURE))
00491 vsflags |= _RPMVSF_NOSIGNATURES;
00492 if (!(qva->qva_flags & VERIFY_HDRCHK))
00493 vsflags |= RPMVSF_NOHDRCHK;
00494 vsflags &= ~RPMVSF_NEEDPAYLOAD;
00495
00496 ovsflags = rpmtsSetVSFlags(ts, vsflags);
00497 ec = rpmcliArgIter(ts, qva, argv);
00498 vsflags = rpmtsSetVSFlags(ts, ovsflags);
00499
00500 if (qva->qva_showPackage == showVerifyPackage)
00501 qva->qva_showPackage = NULL;
00502
00503 rpmtsEmpty(ts);
00504
00505 if (rpmtsChrootDone(ts)) {
00506
00507 xx = chroot(".");
00508 rpmtsSetChrootDone(ts, 0);
00509 }
00510 exit:
00511 _cacheDependsRC = cachingDeps;
00512
00513 return ec;
00514 }