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