00001
00005 #include "system.h"
00006
00007 #include <rpmlib.h>
00008 #include <rpmbuild.h>
00009 #include <rpmurl.h>
00010
00011 #include "depends.h"
00012 #include "install.h"
00013 #include "md5.h"
00014 #include "misc.h"
00015 #include "debug.h"
00016
00017 static int _ie = 0x44332211;
00018 static union _vendian { int i; char b[4]; } *_endian = (union _vendian *)&_ie;
00019 #define IS_BIG_ENDIAN() (_endian->b[0] == '\x44')
00020 #define IS_LITTLE_ENDIAN() (_endian->b[0] == '\x11')
00021
00022 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00023
00024 #define POPT_NODEPS 1000
00025 #define POPT_NOFILES 1001
00026 #define POPT_NOMD5 1002
00027 #define POPT_NOSCRIPTS 1003
00028
00029
00030 static void verifyArgCallback(poptContext con,
00031 enum poptCallbackReason reason,
00032 const struct poptOption * opt, const char * arg,
00033 const void * data)
00034 {
00035 QVA_t *qva = &rpmQVArgs;
00036 switch (opt->val) {
00037 case POPT_NODEPS: qva->qva_flags |= VERIFY_DEPS; break;
00038 case POPT_NOFILES: qva->qva_flags |= VERIFY_FILES; break;
00039 case POPT_NOMD5: qva->qva_flags |= VERIFY_MD5; break;
00040 case POPT_NOSCRIPTS: qva->qva_flags |= VERIFY_SCRIPT; break;
00041 }
00042 }
00043
00044 static int noDeps = 0;
00045 static int noFiles = 0;
00046 static int noMd5 = 0;
00047 static int noScripts = 0;
00048
00050 struct poptOption rpmVerifyPoptTable[] = {
00051 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
00052 verifyArgCallback, 0, NULL, NULL },
00053 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQVSourcePoptTable, 0,
00054 NULL, NULL },
00055 { "nodeps", '\0', 0, &noDeps, POPT_NODEPS,
00056 N_("do not verify package dependencies"),
00057 NULL },
00058 { "nofiles", '\0', 0, &noFiles, POPT_NOFILES,
00059 N_("don't verify files in package"),
00060 NULL},
00061 { "nomd5", '\0', 0, &noMd5, POPT_NOMD5,
00062 N_("do not verify file md5 checksums"),
00063 NULL },
00064 { "noscripts", '\0', 0, &noScripts, POPT_NOSCRIPTS,
00065 N_("do not execute %verifyscript (if any)"),
00066 NULL },
00067 POPT_TABLEEND
00068 };
00069
00070
00071 int rpmVerifyFile(const char * prefix, Header h, int filenum,
00072 int * result, int omitMask)
00073 {
00074 char ** baseNames, ** md5List, ** linktoList, ** dirNames;
00075 int_32 * verifyFlags;
00076 rpmVerifyAttrs flags;
00077 int_32 * sizeList, * mtimeList, * dirIndexes;
00078 unsigned short * modeList, * rdevList;
00079 char * fileStatesList;
00080 char * filespec;
00081 char * name;
00082 gid_t gid;
00083 int type, count, rc;
00084 struct stat sb;
00085 unsigned char md5sum[40];
00086 int_32 * uidList, * gidList;
00087 char linkto[1024];
00088 int size;
00089 char ** unameList, ** gnameList;
00090 int_32 useBrokenMd5;
00091
00092 if (IS_BIG_ENDIAN()) {
00093 int_32 * brokenPtr;
00094 if (!headerGetEntry(h, RPMTAG_BROKENMD5, NULL, (void **) &brokenPtr, NULL)) {
00095 char * rpmVersion;
00096
00097 if (headerGetEntry(h, RPMTAG_RPMVERSION, NULL, (void **) &rpmVersion,
00098 NULL)) {
00099 useBrokenMd5 = ((rpmvercmp(rpmVersion, "2.3.3") >= 0) &&
00100 (rpmvercmp(rpmVersion, "2.3.8") <= 0));
00101 } else {
00102 useBrokenMd5 = 1;
00103 }
00104 headerAddEntry(h, RPMTAG_BROKENMD5, RPM_INT32_TYPE, &useBrokenMd5, 1);
00105 } else {
00106 useBrokenMd5 = *brokenPtr;
00107 }
00108 } else {
00109 useBrokenMd5 = 0;
00110 }
00111
00112 headerGetEntry(h, RPMTAG_FILEMODES, &type, (void **) &modeList, &count);
00113
00114 if (headerGetEntry(h, RPMTAG_FILEVERIFYFLAGS, &type, (void **) &verifyFlags,
00115 &count)) {
00116 flags = verifyFlags[filenum];
00117 } else {
00118 flags = RPMVERIFY_ALL;
00119 }
00120
00121 headerGetEntry(h, RPMTAG_BASENAMES, &type, (void **) &baseNames,
00122 &count);
00123 headerGetEntry(h, RPMTAG_DIRINDEXES, &type, (void **) &dirIndexes,
00124 NULL);
00125 headerGetEntry(h, RPMTAG_DIRNAMES, &type, (void **) &dirNames, NULL);
00126
00127 filespec = alloca(strlen(dirNames[dirIndexes[filenum]]) +
00128 strlen(baseNames[filenum]) + strlen(prefix) + 5);
00129 sprintf(filespec, "%s/%s%s", prefix, dirNames[dirIndexes[filenum]],
00130 baseNames[filenum]);
00131 free(baseNames);
00132 free(dirNames);
00133
00134 *result = 0;
00135
00136
00137 if (headerGetEntry(h, RPMTAG_FILESTATES, &type,
00138 (void **) &fileStatesList, &count) && fileStatesList) {
00139 if (fileStatesList[filenum] == RPMFILE_STATE_NOTINSTALLED)
00140 return 0;
00141 }
00142
00143 if (lstat(filespec, &sb)) {
00144 *result |= RPMVERIFY_LSTATFAIL;
00145 return 1;
00146 }
00147
00148 if (S_ISDIR(sb.st_mode))
00149 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00150 RPMVERIFY_LINKTO);
00151 else if (S_ISLNK(sb.st_mode)) {
00152 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00153 RPMVERIFY_MODE);
00154 # if CHOWN_FOLLOWS_SYMLINK
00155 flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00156 # endif
00157 }
00158 else if (S_ISFIFO(sb.st_mode))
00159 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00160 RPMVERIFY_LINKTO);
00161 else if (S_ISCHR(sb.st_mode))
00162 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00163 RPMVERIFY_LINKTO);
00164 else if (S_ISBLK(sb.st_mode))
00165 flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00166 RPMVERIFY_LINKTO);
00167 else
00168 flags &= ~(RPMVERIFY_LINKTO);
00169
00170
00171 flags &= ~(omitMask | RPMVERIFY_LSTATFAIL|RPMVERIFY_READFAIL|RPMVERIFY_READLINKFAIL);
00172
00173 if (flags & RPMVERIFY_MD5) {
00174 headerGetEntry(h, RPMTAG_FILEMD5S, &type, (void **) &md5List, &count);
00175 if (useBrokenMd5) {
00176 rc = mdfileBroken(filespec, md5sum);
00177 } else {
00178 rc = mdfile(filespec, md5sum);
00179 }
00180
00181 if (rc)
00182 *result |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00183 else if (strcmp(md5sum, md5List[filenum]))
00184 *result |= RPMVERIFY_MD5;
00185 free(md5List);
00186 }
00187 if (flags & RPMVERIFY_LINKTO) {
00188 headerGetEntry(h, RPMTAG_FILELINKTOS, &type, (void **) &linktoList, &count);
00189 size = readlink(filespec, linkto, sizeof(linkto)-1);
00190 if (size == -1)
00191 *result |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00192 else {
00193 linkto[size] = '\0';
00194 if (strcmp(linkto, linktoList[filenum]))
00195 *result |= RPMVERIFY_LINKTO;
00196 }
00197 free(linktoList);
00198 }
00199
00200 if (flags & RPMVERIFY_FILESIZE) {
00201 headerGetEntry(h, RPMTAG_FILESIZES, &type, (void **) &sizeList, &count);
00202 if (sizeList[filenum] != sb.st_size)
00203 *result |= RPMVERIFY_FILESIZE;
00204 }
00205
00206 if (flags & RPMVERIFY_MODE) {
00207 if (modeList[filenum] != sb.st_mode)
00208 *result |= RPMVERIFY_MODE;
00209 }
00210
00211 if (flags & RPMVERIFY_RDEV) {
00212 if (S_ISCHR(modeList[filenum]) != S_ISCHR(sb.st_mode) ||
00213 S_ISBLK(modeList[filenum]) != S_ISBLK(sb.st_mode)) {
00214 *result |= RPMVERIFY_RDEV;
00215 } else if (S_ISDEV(modeList[filenum]) && S_ISDEV(sb.st_mode)) {
00216 headerGetEntry(h, RPMTAG_FILERDEVS, NULL, (void **) &rdevList,
00217 NULL);
00218 if (rdevList[filenum] != sb.st_rdev)
00219 *result |= RPMVERIFY_RDEV;
00220 }
00221 }
00222
00223 if (flags & RPMVERIFY_MTIME) {
00224 headerGetEntry(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtimeList, NULL);
00225 if (mtimeList[filenum] != sb.st_mtime)
00226 *result |= RPMVERIFY_MTIME;
00227 }
00228
00229 if (flags & RPMVERIFY_USER) {
00230 if (headerGetEntry(h, RPMTAG_FILEUSERNAME, NULL, (void **) &unameList,
00231 NULL)) {
00232 name = uidToUname(sb.st_uid);
00233 if (!name || strcmp(unameList[filenum], name))
00234 *result |= RPMVERIFY_USER;
00235 free(unameList);
00236 } else if (headerGetEntry(h, RPMTAG_FILEUIDS, NULL, (void **) &uidList,
00237 &count)) {
00238 if (uidList[filenum] != sb.st_uid)
00239 *result |= RPMVERIFY_GROUP;
00240 } else {
00241 rpmError(RPMERR_INTERNAL, _("package lacks both user name and id "
00242 "lists (this should never happen)\n"));
00243 *result |= RPMVERIFY_GROUP;
00244 }
00245 }
00246
00247 if (flags & RPMVERIFY_GROUP) {
00248 if (headerGetEntry(h, RPMTAG_FILEGROUPNAME, NULL, (void **) &gnameList,
00249 NULL)) {
00250 rc = gnameToGid(gnameList[filenum],&gid);
00251 if (rc || (gid != sb.st_gid))
00252 *result |= RPMVERIFY_GROUP;
00253 free(gnameList);
00254 } else if (headerGetEntry(h, RPMTAG_FILEGIDS, NULL, (void **) &gidList,
00255 &count)) {
00256 if (gidList[filenum] != sb.st_gid)
00257 *result |= RPMVERIFY_GROUP;
00258 } else {
00259 rpmError(RPMERR_INTERNAL, _("package lacks both group name and id "
00260 "lists (this should never happen)\n"));
00261 *result |= RPMVERIFY_GROUP;
00262 }
00263 }
00264
00265 return 0;
00266 }
00267
00276 int rpmVerifyScript(const char * rootDir, Header h, FD_t scriptFd)
00277 {
00278 rpmdb rpmdb = NULL;
00279 rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
00280 int rc;
00281
00282 if (scriptFd)
00283 ts->scriptFd = fdLink(scriptFd, "rpmVerifyScript");
00284 rc = runInstScript(ts, h, RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG,
00285 0, 0);
00286 rpmtransFree(ts);
00287 return rc;
00288 }
00289
00290
00291 static int verifyHeader(QVA_t *qva, Header h)
00292 {
00293 char buf[BUFSIZ];
00294 char * t, * te;
00295
00296 const char ** fileNames = NULL;
00297 int count;
00298 int_32 * fileFlagsList = NULL;
00299 rpmVerifyAttrs verifyResult = 0;
00300 rpmVerifyAttrs omitMask = !(qva->qva_flags & VERIFY_MD5)
00301 ? RPMVERIFY_MD5 : RPMVERIFY_NONE;
00302 int ec = 0;
00303 int i;
00304
00305 te = t = buf;
00306 *te = '\0';
00307
00308 if (!headerGetEntry(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlagsList, NULL))
00309 goto exit;
00310
00311 if (!headerIsEntry(h, RPMTAG_BASENAMES))
00312 goto exit;
00313
00314 rpmBuildFileList(h, &fileNames, &count);
00315
00316 for (i = 0; i < count; i++) {
00317 int rc;
00318
00319 rc = rpmVerifyFile(qva->qva_prefix, h, i, &verifyResult, omitMask);
00320 if (rc) {
00321 sprintf(te, _("missing %s"), fileNames[i]);
00322 te += strlen(te);
00323 ec = rc;
00324 } else if (verifyResult) {
00325 const char * size, * md5, * link, * mtime, * mode;
00326 const char * group, * user, * rdev;
00327 static const char *const aok = ".";
00328 static const char *const unknown = "?";
00329
00330 ec = 1;
00331
00332 #define _verify(_RPMVERIFY_F, _C) \
00333 ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00334 #define _verifylink(_RPMVERIFY_F, _C) \
00335 ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00336 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00337 #define _verifyfile(_RPMVERIFY_F, _C) \
00338 ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00339 (verifyResult & _RPMVERIFY_F) ? _C : aok)
00340
00341 md5 = _verifyfile(RPMVERIFY_MD5, "5");
00342 size = _verify(RPMVERIFY_FILESIZE, "S");
00343 link = _verifylink(RPMVERIFY_LINKTO, "L");
00344 mtime = _verify(RPMVERIFY_MTIME, "T");
00345 rdev = _verify(RPMVERIFY_RDEV, "D");
00346 user = _verify(RPMVERIFY_USER, "U");
00347 group = _verify(RPMVERIFY_GROUP, "G");
00348 mode = _verify(RPMVERIFY_MODE, "M");
00349
00350 #undef _verify
00351 #undef _verifylink
00352 #undef _verifyfile
00353
00354 sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
00355 size, mode, md5, rdev, link, user, group, mtime,
00356 fileFlagsList[i] & RPMFILE_CONFIG ? 'c' : ' ',
00357 fileNames[i]);
00358 te += strlen(te);
00359 }
00360
00361 if (te > t) {
00362 *te++ = '\n';
00363 *te = '\0';
00364 rpmMessage(RPMMESS_NORMAL, "%s", t);
00365 te = t = buf;
00366 *t = '\0';
00367 }
00368 }
00369
00370 exit:
00371 if (fileNames) free(fileNames);
00372 return ec;
00373 }
00374
00375 static int verifyDependencies(rpmdb rpmdb, Header h)
00376 {
00377 rpmTransactionSet rpmdep;
00378 struct rpmDependencyConflict * conflicts;
00379 int numConflicts;
00380 int rc = 0;
00381 int i;
00382
00383 rpmdep = rpmtransCreateSet(rpmdb, NULL);
00384 rpmtransAddPackage(rpmdep, h, NULL, NULL, 0, NULL);
00385
00386 rpmdepCheck(rpmdep, &conflicts, &numConflicts);
00387 rpmtransFree(rpmdep);
00388
00389 if (numConflicts) {
00390 const char * name, * version, * release;
00391 char * t, * te;
00392 int nb = 512;
00393 headerNVR(h, &name, &version, &release);
00394
00395 for (i = 0; i < numConflicts; i++) {
00396 nb += strlen(conflicts[i].needsName) + sizeof(", ") - 1;
00397 if (conflicts[i].needsFlags)
00398 nb += strlen(conflicts[i].needsVersion) + 5;
00399 }
00400 te = t = alloca(nb);
00401 *te = '\0';
00402 sprintf(te, _("Unsatisfied dependencies for %s-%s-%s: "),
00403 name, version, release);
00404 te += strlen(te);
00405 for (i = 0; i < numConflicts; i++) {
00406 if (i) te = stpcpy(te, ", ");
00407 te = stpcpy(te, conflicts[i].needsName);
00408 if (conflicts[i].needsFlags) {
00409 int flags = conflicts[i].needsFlags;
00410 *te++ = ' ';
00411 if (flags & RPMSENSE_LESS) *te++ = '<';
00412 if (flags & RPMSENSE_GREATER) *te++ = '>';
00413 if (flags & RPMSENSE_EQUAL) *te++ = '=';
00414 *te++ = ' ';
00415 te = stpcpy(te, conflicts[i].needsVersion);
00416 }
00417 }
00418 rpmdepFreeConflicts(conflicts, numConflicts);
00419 if (te > t) {
00420 *te++ = '\n';
00421 *te = '\0';
00422 rpmMessage(RPMMESS_NORMAL, "%s", t);
00423 te = t;
00424 *t = '\0';
00425 }
00426 rc = 1;
00427 }
00428 return rc;
00429 }
00430
00431 int showVerifyPackage(QVA_t *qva, rpmdb rpmdb, Header h)
00432 {
00433 FD_t fdo;
00434 int ec = 0;
00435 int rc;
00436
00437 if ((qva->qva_flags & VERIFY_DEPS) &&
00438 (rc = verifyDependencies(rpmdb, h)) != 0)
00439 ec = rc;
00440 if ((qva->qva_flags & VERIFY_FILES) &&
00441 (rc = verifyHeader(qva, h)) != 0)
00442 ec = rc;;
00443 fdo = fdDup(STDOUT_FILENO);
00444 if ((qva->qva_flags & VERIFY_SCRIPT) &&
00445 (rc = rpmVerifyScript(qva->qva_prefix, h, fdo)) != 0)
00446 ec = rc;
00447 Fclose(fdo);
00448 return ec;
00449 }
00450
00451 int rpmVerify(QVA_t *qva, rpmQVSources source, const char *arg)
00452 {
00453 rpmdb rpmdb = NULL;
00454 int rc;
00455
00456 switch (source) {
00457 case RPMQV_RPM:
00458 if (!(qva->qva_flags & VERIFY_DEPS))
00459 break;
00460
00461 default:
00462 if (rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644))
00463 return 1;
00464 break;
00465 }
00466
00467 rc = rpmQueryVerify(qva, source, arg, rpmdb, showVerifyPackage);
00468
00469 if (rpmdb)
00470 rpmdbClose(rpmdb);
00471
00472 return rc;
00473 }