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 flags |= RPMVERIFY_CONTEXTS;
00082
00083
00084
00085
00086 if (S_ISDIR(sb.st_mode))
00087 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00088 RPMVERIFY_LINKTO);
00089 else if (S_ISLNK(sb.st_mode)) {
00090 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00091 RPMVERIFY_MODE);
00092 #if CHOWN_FOLLOWS_SYMLINK
00093 flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00094 #endif
00095 }
00096 else if (S_ISFIFO(sb.st_mode))
00097 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00098 RPMVERIFY_LINKTO);
00099 else if (S_ISCHR(sb.st_mode))
00100 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00101 RPMVERIFY_LINKTO);
00102 else if (S_ISBLK(sb.st_mode))
00103 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00104 RPMVERIFY_LINKTO);
00105 else
00106 flags &= ~(RPMVERIFY_LINKTO);
00107
00108
00109
00110
00111 if (fileAttrs & RPMFILE_GHOST)
00112 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00113 RPMVERIFY_LINKTO);
00114
00115
00116
00117
00118 flags &= ~(omitMask | RPMVERIFY_FAILURES);
00119
00120
00121
00122
00123
00124 if (selinuxEnabled == 1 && (flags & RPMVERIFY_CONTEXTS)) {
00125 security_context_t con;
00126
00127 rc = lgetfilecon(fn, &con);
00128 if (rc == -1)
00129 *res |= (RPMVERIFY_LGETFILECONFAIL|RPMVERIFY_CONTEXTS);
00130 else {
00131 rpmsx sx = rpmtsREContext(ts);
00132 const char * fcontext;
00133
00134 if (sx != NULL) {
00135
00136 fcontext = rpmsxFContext(sx, fn, fmode);
00137 sx = rpmsxFree(sx);
00138 } else {
00139
00140 fcontext = rpmfiFContext(fi);
00141 }
00142 if (fcontext == NULL || strcmp(fcontext, con))
00143 *res |= RPMVERIFY_CONTEXTS;
00144 freecon(con);
00145 }
00146 }
00147
00148
00149 if (flags & RPMVERIFY_MD5) {
00150 unsigned char md5sum[16];
00151 size_t fsize;
00152
00153
00154 rc = domd5(fn, md5sum, 0, &fsize);
00155 sb.st_size = fsize;
00156 if (rc)
00157 *res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00158 else {
00159 const unsigned char * MD5 = rpmfiMD5(fi);
00160 if (MD5 == NULL || memcmp(md5sum, MD5, sizeof(md5sum)))
00161 *res |= RPMVERIFY_MD5;
00162 }
00163 }
00164
00165 if (flags & RPMVERIFY_LINKTO) {
00166 char linkto[1024+1];
00167 int size = 0;
00168
00169 if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
00170 *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00171 else {
00172 const char * flink = rpmfiFLink(fi);
00173 linkto[size] = '\0';
00174 if (flink == NULL || strcmp(linkto, flink))
00175 *res |= RPMVERIFY_LINKTO;
00176 }
00177 }
00178
00179 if (flags & RPMVERIFY_FILESIZE) {
00180 if (sb.st_size != rpmfiFSize(fi))
00181 *res |= RPMVERIFY_FILESIZE;
00182 }
00183
00184 if (flags & RPMVERIFY_MODE) {
00185 unsigned short metamode = fmode;
00186 unsigned short filemode;
00187
00188
00189
00190
00191
00192 filemode = (unsigned short)sb.st_mode;
00193
00194
00195
00196
00197 if (fileAttrs & RPMFILE_GHOST) {
00198 metamode &= ~0xf000;
00199 filemode &= ~0xf000;
00200 }
00201
00202 if (metamode != filemode)
00203 *res |= RPMVERIFY_MODE;
00204 }
00205
00206 if (flags & RPMVERIFY_RDEV) {
00207 if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
00208 || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
00209 {
00210 *res |= RPMVERIFY_RDEV;
00211 } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
00212 uint_16 st_rdev = (sb.st_rdev & 0xffff);
00213 uint_16 frdev = (rpmfiFRdev(fi) & 0xffff);
00214 if (st_rdev != frdev)
00215 *res |= RPMVERIFY_RDEV;
00216 }
00217 }
00218
00219 if (flags & RPMVERIFY_MTIME) {
00220 if (sb.st_mtime != rpmfiFMtime(fi))
00221 *res |= RPMVERIFY_MTIME;
00222 }
00223
00224 if (flags & RPMVERIFY_USER) {
00225 const char * name = uidToUname(sb.st_uid);
00226 const char * fuser = rpmfiFUser(fi);
00227 if (name == NULL || fuser == NULL || strcmp(name, fuser))
00228 *res |= RPMVERIFY_USER;
00229 }
00230
00231 if (flags & RPMVERIFY_GROUP) {
00232 const char * name = gidToGname(sb.st_gid);
00233 const char * fgroup = rpmfiFGroup(fi);
00234 if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
00235 *res |= RPMVERIFY_GROUP;
00236 }
00237
00238 return 0;
00239 }
00240
00250 static int rpmVerifyScript( QVA_t qva, rpmts ts,
00251 rpmfi fi, FD_t scriptFd)
00252
00253
00254
00255 {
00256 rpmpsm psm = rpmpsmNew(ts, NULL, fi);
00257 int rc = 0;
00258
00259 if (psm == NULL)
00260 return rc;
00261
00262 if (scriptFd != NULL)
00263 rpmtsSetScriptFd(psm->ts, scriptFd);
00264
00265 psm->stepName = "verify";
00266 psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00267 psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00268 rc = rpmpsmStage(psm, PSM_SCRIPT);
00269
00270 if (scriptFd != NULL)
00271 rpmtsSetScriptFd(psm->ts, NULL);
00272
00273 psm = rpmpsmFree(psm);
00274
00275 return rc;
00276 }
00277
00285 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
00286
00287
00288 {
00289 int selinuxEnabled = rpmtsSELinuxEnabled(ts);
00290 rpmVerifyAttrs verifyResult = 0;
00291
00292 rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00293
00294 int ec = 0;
00295 char * t, * te;
00296 char buf[BUFSIZ];
00297 int i;
00298
00299 te = t = buf;
00300 *te = '\0';
00301
00302 fi = rpmfiLink(fi, "verifyHeader");
00303 fi = rpmfiInit(fi, 0);
00304 if (fi != NULL)
00305 while ((i = rpmfiNext(fi)) >= 0) {
00306 rpmfileAttrs fileAttrs;
00307 int rc;
00308
00309 fileAttrs = rpmfiFFlags(fi);
00310
00311
00312 if (!(qva->qva_fflags & RPMFILE_GHOST)
00313 && (fileAttrs & RPMFILE_GHOST))
00314 continue;
00315
00316
00317 rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
00318
00319 if (rc) {
00320 if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
00321 sprintf(te, _("missing %c %s"),
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 ec = rc;
00331 }
00332 } else if (verifyResult || rpmIsVerbose()) {
00333 const char * size, * MD5, * link, * mtime, * mode;
00334 const char * group, * user, * rdev, *ctxt;
00335 static const char *const aok = ".";
00336 static const char *const unknown = "?";
00337 static const char *const ctxt_ignore = " ";
00338
00339 ec = 1;
00340
00341 #define _verify(_RPMVERIFY_F, _C) \
00342 ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00343 #define _verifylink(_RPMVERIFY_F, _C) \
00344 ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00345 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00346 #define _verifyfile(_RPMVERIFY_F, _C) \
00347 ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00348 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00349 #define _verifyctxt(_RPMVERIFY_F, _C) \
00350 ((selinuxEnabled != 1 ? ctxt_ignore : \
00351 (verifyResult & RPMVERIFY_LGETFILECONFAIL) ? unknown : \
00352 (verifyResult & _RPMVERIFY_F) ? _C : aok))
00353
00354 MD5 = _verifyfile(RPMVERIFY_MD5, "5");
00355 size = _verify(RPMVERIFY_FILESIZE, "S");
00356 link = _verifylink(RPMVERIFY_LINKTO, "L");
00357 mtime = _verify(RPMVERIFY_MTIME, "T");
00358 rdev = _verify(RPMVERIFY_RDEV, "D");
00359 user = _verify(RPMVERIFY_USER, "U");
00360 group = _verify(RPMVERIFY_GROUP, "G");
00361 mode = _verify(RPMVERIFY_MODE, "M");
00362 ctxt = _verifyctxt(RPMVERIFY_CONTEXTS, "C");
00363
00364 #undef _verifyctxt
00365 #undef _verifyfile
00366 #undef _verifylink
00367 #undef _verify
00368
00369 sprintf(te, "%s%s%s%s%s%s%s%s%s %c %s",
00370 size, mode, MD5, rdev, link, user, group, mtime, ctxt,
00371 ((fileAttrs & RPMFILE_CONFIG) ? 'c' :
00372 (fileAttrs & RPMFILE_DOC) ? 'd' :
00373 (fileAttrs & RPMFILE_GHOST) ? 'g' :
00374 (fileAttrs & RPMFILE_LICENSE) ? 'l' :
00375 (fileAttrs & RPMFILE_PUBKEY) ? 'P' :
00376 (fileAttrs & RPMFILE_README) ? 'r' : ' '),
00377 rpmfiFN(fi));
00378 te += strlen(te);
00379 }
00380
00381
00382 if (te > t) {
00383 *te++ = '\n';
00384 *te = '\0';
00385 rpmMessage(RPMMESS_NORMAL, "%s", t);
00386 te = t = buf;
00387 *t = '\0';
00388 }
00389
00390 }
00391 fi = rpmfiUnlink(fi, "verifyHeader");
00392
00393 return ec;
00394 }
00395
00403 static int verifyDependencies( QVA_t qva, rpmts ts,
00404 Header h)
00405
00406
00407 {
00408 rpmps ps;
00409 int numProblems;
00410 int rc = 0;
00411 int xx;
00412 int i;
00413
00414 rpmtsEmpty(ts);
00415 (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00416
00417 xx = rpmtsCheck(ts);
00418 ps = rpmtsProblems(ts);
00419
00420 numProblems = rpmpsNumProblems(ps);
00421
00422 if (ps != NULL && numProblems > 0) {
00423 const char * pkgNEVR, * altNEVR;
00424 rpmProblem p;
00425 char * t, * te;
00426 int nb = 512;
00427
00428 for (i = 0; i < numProblems; i++) {
00429 p = ps->probs + i;
00430 altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00431 nb += strlen(altNEVR+2) + sizeof(", ") - 1;
00432 }
00433 te = t = alloca(nb);
00434
00435 *te = '\0';
00436 pkgNEVR = (ps->probs->pkgNEVR ? ps->probs->pkgNEVR : "?pkgNEVR?");
00437 sprintf(te, _("Unsatisfied dependencies for %s: "), pkgNEVR);
00438 te += strlen(te);
00439 for (i = 0; i < numProblems; i++) {
00440 p = ps->probs + i;
00441 altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00442 if (i) te = stpcpy(te, ", ");
00443
00444 te = stpcpy(te, altNEVR+2);
00445 }
00446
00447 if (te > t) {
00448 *te++ = '\n';
00449 *te = '\0';
00450 rpmMessage(RPMMESS_NORMAL, "%s", t);
00451 te = t;
00452 *t = '\0';
00453 }
00454
00455 rc = 1;
00456 }
00457
00458
00459 ps = rpmpsFree(ps);
00460
00461 rpmtsEmpty(ts);
00462
00463 return rc;
00464 }
00465
00466 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
00467 {
00468 int scareMem = 1;
00469 rpmfi fi;
00470 int ec = 0;
00471 int rc;
00472
00473 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00474 if (fi != NULL) {
00475
00476 if (qva->qva_flags & VERIFY_DEPS) {
00477 int save_noise = _rpmds_unspecified_epoch_noise;
00478
00479 if (rpmIsVerbose())
00480 _rpmds_unspecified_epoch_noise = 1;
00481 if ((rc = verifyDependencies(qva, ts, h)) != 0)
00482 ec = rc;
00483 _rpmds_unspecified_epoch_noise = save_noise;
00484
00485 }
00486 if (qva->qva_flags & VERIFY_FILES) {
00487 if ((rc = verifyHeader(qva, ts, fi)) != 0)
00488 ec = rc;
00489 }
00490 if ((qva->qva_flags & VERIFY_SCRIPT)
00491 && headerIsEntry(h, RPMTAG_VERIFYSCRIPT))
00492 {
00493 FD_t fdo = fdDup(STDOUT_FILENO);
00494 if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
00495 ec = rc;
00496 if (fdo != NULL)
00497 rc = Fclose(fdo);
00498 }
00499
00500 fi = rpmfiFree(fi);
00501 }
00502
00503 return ec;
00504 }
00505
00506 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv)
00507 {
00508 const char * arg;
00509 rpmVSFlags vsflags, ovsflags;
00510 int ec = 0;
00511
00512 if (qva->qva_showPackage == NULL)
00513 qva->qva_showPackage = showVerifyPackage;
00514
00515
00516 vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
00517 if (!(qva->qva_flags & VERIFY_DIGEST))
00518 vsflags |= _RPMVSF_NODIGESTS;
00519 if (!(qva->qva_flags & VERIFY_SIGNATURE))
00520 vsflags |= _RPMVSF_NOSIGNATURES;
00521 if (!(qva->qva_flags & VERIFY_HDRCHK))
00522 vsflags |= RPMVSF_NOHDRCHK;
00523 vsflags &= ~RPMVSF_NEEDPAYLOAD;
00524
00525
00526 if (qva->qva_flags & VERIFY_CONTEXTS) {
00527 rpmsx sx = rpmtsREContext(ts);
00528 if (sx == NULL) {
00529 arg = rpmGetPath("%{?_verify_file_context_path}", NULL);
00530 if (arg != NULL && *arg != '\0') {
00531 sx = rpmsxNew(arg);
00532 (void) rpmtsSetREContext(ts, sx);
00533 }
00534 arg = _free(arg);
00535 }
00536 sx = rpmsxFree(sx);
00537 }
00538
00539 ovsflags = rpmtsSetVSFlags(ts, vsflags);
00540 ec = rpmcliArgIter(ts, qva, argv);
00541 vsflags = rpmtsSetVSFlags(ts, ovsflags);
00542
00543 if (qva->qva_showPackage == showVerifyPackage)
00544 qva->qva_showPackage = NULL;
00545
00546 rpmtsEmpty(ts);
00547
00548 return ec;
00549 }