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