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