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