Пример #1
0
/** \ingroup rpmcli
 * Verify file attributes (including file digest).
 * @param vf		file data to verify
 * #param spew		should verify results be printed?
 * @return		0 on success (or not installed), 1 on error
 */
static int rpmvfVerify(rpmvf vf, int spew)
	/*@globals h_errno, fileSystem, internalState @*/
	/*@modifies vf, fileSystem, internalState @*/
{
    rpmVerifyAttrs res = RPMVERIFY_NONE;
    struct stat sb;
    int ec = 0;

    /* Check to see if the file was installed - if not pretend all is OK. */
    switch (vf->fstate) {
    default:
    case RPMFILE_STATE_NETSHARED:
    case RPMFILE_STATE_REPLACED:
    case RPMFILE_STATE_NOTINSTALLED:
    case RPMFILE_STATE_WRONGCOLOR:
	goto exit;
	/*@notreached@*/ break;
    case RPMFILE_STATE_NORMAL:
	break;
    }

assert(vf->fn != NULL);
    if (vf->fn == NULL || Lstat(vf->fn, &sb) != 0) {
	res |= RPMVERIFY_LSTATFAIL;
	ec = 1;
	goto exit;
    }

    /* Not all attributes of non-regular files can be verified. */
    if (S_ISDIR(sb.st_mode))
	vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
			RPMVERIFY_LINKTO | RPMVERIFY_HMAC);
    else if (S_ISLNK(sb.st_mode)) {
	vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
		RPMVERIFY_MODE | RPMVERIFY_HMAC);
#if CHOWN_FOLLOWS_SYMLINK
	vf->vflags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
#endif
    }
    else if (S_ISFIFO(sb.st_mode))
	vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
			RPMVERIFY_LINKTO | RPMVERIFY_HMAC);
    else if (S_ISCHR(sb.st_mode))
	vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
			RPMVERIFY_LINKTO | RPMVERIFY_HMAC);
    else if (S_ISBLK(sb.st_mode))
	vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
			RPMVERIFY_LINKTO | RPMVERIFY_HMAC);
    else
	vf->vflags &= ~(RPMVERIFY_LINKTO);

    if (vf->vflags & (RPMVERIFY_FDIGEST | RPMVERIFY_HMAC)) {
	if (vf->digest == NULL || vf->dlen == 0)
	    res |= RPMVERIFY_FDIGEST;
	else {
	/* XXX If --nofdigest, then prelinked library sizes fail to verify. */
	    unsigned char * fdigest = memset(alloca(vf->dlen), 0, vf->dlen);
	    size_t fsize = 0;
#define	_mask	(RPMVERIFY_FDIGEST|RPMVERIFY_HMAC)
	    unsigned dflags = (vf->vflags & _mask) == RPMVERIFY_HMAC
		? 0x2 : 0x0;
#undef	_mask
	    int rc = dodigest(vf->dalgo, vf->fn, fdigest, dflags, &fsize);
	    sb.st_size = fsize;
	    if (rc)
		res |= (RPMVERIFY_READFAIL|RPMVERIFY_FDIGEST);
	    else
	    if (memcmp(fdigest, vf->digest, vf->dlen))
		res |= RPMVERIFY_FDIGEST;
	}
    }

    if (vf->vflags & RPMVERIFY_LINKTO) {
	char linkto[1024+1];
	int size = 0;

	if ((size = Readlink(vf->fn, linkto, sizeof(linkto)-1)) == -1)
	    res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
	else {
	    linkto[size] = '\0';
	    if (vf->flink == NULL || strcmp(linkto, vf->flink))
		res |= RPMVERIFY_LINKTO;
	}
    }

    if (vf->vflags & RPMVERIFY_FILESIZE) {
	if (sb.st_size != vf->sb.st_size)
	    res |= RPMVERIFY_FILESIZE;
    }

    if (vf->vflags & RPMVERIFY_MODE) {
	/* XXX AIX has sizeof(mode_t) > sizeof(unsigned short) */
	unsigned short metamode = (unsigned short)vf->sb.st_mode;
	unsigned short filemode = (unsigned short)sb.st_mode;

	/* Comparing type of %ghost files is meaningless, but perms are OK. */
	if (vf->fflags & RPMFILE_GHOST) {
	    metamode &= ~0xf000;
	    filemode &= ~0xf000;
	}
	if (metamode != filemode)
	    res |= RPMVERIFY_MODE;
    }

    if (vf->vflags & RPMVERIFY_RDEV) {
	if (S_ISCHR(vf->sb.st_mode) != S_ISCHR(sb.st_mode)
	 || S_ISBLK(vf->sb.st_mode) != S_ISBLK(sb.st_mode))
	    res |= RPMVERIFY_RDEV;
	else if (S_ISDEV(vf->sb.st_mode) && S_ISDEV(sb.st_mode)) {
	    rpmuint16_t st_rdev = (rpmuint16_t)(sb.st_rdev & 0xffff);
	    rpmuint16_t frdev = (rpmuint16_t)(vf->sb.st_rdev & 0xffff);
	    if (st_rdev != frdev)
		res |= RPMVERIFY_RDEV;
	}
    }

    if (vf->vflags & RPMVERIFY_MTIME) {
	if (sb.st_mtime != vf->sb.st_mtime)
	    res |= RPMVERIFY_MTIME;
    }

    if (vf->vflags & RPMVERIFY_USER) {
	const char * fuser = uidToUname(sb.st_uid);
	if (fuser == NULL || vf->fuser == NULL || strcmp(fuser, vf->fuser))
	    res |= RPMVERIFY_USER;
    }

    if (vf->vflags & RPMVERIFY_GROUP) {
	const char * fgroup = gidToGname(sb.st_gid);
	if (fgroup == NULL || vf->fgroup == NULL || strcmp(fgroup, vf->fgroup))
	    res |= RPMVERIFY_GROUP;
    }

exit:

    if (spew) {	/* XXX no output w verify(...) probe. */
	char buf[BUFSIZ];
	char * t = buf;
	char * te = t;
	*te = '\0';
	if (ec) {
	    if (!(vf->fflags & (RPMFILE_MISSINGOK|RPMFILE_GHOST))
	     || rpmIsVerbose())
	    {
		sprintf(te, _("missing   %c %s"),
			((vf->fflags & RPMFILE_CONFIG)	? 'c' :
			 (vf->fflags & RPMFILE_DOC)	? 'd' :
			 (vf->fflags & RPMFILE_GHOST)	? 'g' :
			 (vf->fflags & RPMFILE_LICENSE)	? 'l' :
			 (vf->fflags & RPMFILE_PUBKEY)	? 'P' :
			 (vf->fflags & RPMFILE_README)	? 'r' : ' '),
			vf->fn);
                if ((res & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) {
		    te += strlen(te);
                    sprintf(te, " (%s)", strerror(errno));
                }
	    }
	} else if (res || rpmIsVerbose()) {
	    /*@observer@*/ static const char aok[] = ".";
	    /*@observer@*/ static const char unknown[] = "?";

#define	_verify(_RPMVERIFY_F, _C)	\
	((res & _RPMVERIFY_F) ? _C : aok)
#define	_verifylink(_RPMVERIFY_F, _C)	\
	((res & RPMVERIFY_READLINKFAIL) ? unknown : \
	 (res & _RPMVERIFY_F) ? _C : aok)
#define	_verifyfile(_RPMVERIFY_F, _C)	\
	((res & RPMVERIFY_READFAIL) ? unknown : \
	 (res & _RPMVERIFY_F) ? _C : aok)
	
	    const char * digest = _verifyfile(RPMVERIFY_FDIGEST, "5");
	    const char * size = _verify(RPMVERIFY_FILESIZE, "S");
	    const char * link = _verifylink(RPMVERIFY_LINKTO, "L");
	    const char * mtime = _verify(RPMVERIFY_MTIME, "T");
	    const char * rdev = _verify(RPMVERIFY_RDEV, "D");
	    const char * user = _verify(RPMVERIFY_USER, "U");
	    const char * group = _verify(RPMVERIFY_GROUP, "G");
	    const char * mode = _verify(RPMVERIFY_MODE, "M");

#undef _verifyfile
#undef _verifylink
#undef _verify

	    sprintf(te, "%s%s%s%s%s%s%s%s  %c %s",
		    size, mode, digest, rdev, link, user, group, mtime,
			((vf->fflags & RPMFILE_CONFIG)	? 'c' :
			 (vf->fflags & RPMFILE_DOC)	? 'd' :
			 (vf->fflags & RPMFILE_GHOST)	? 'g' :
			 (vf->fflags & RPMFILE_LICENSE)	? 'l' :
			 (vf->fflags & RPMFILE_PUBKEY)	? 'P' :
			 (vf->fflags & RPMFILE_README)	? 'r' : ' '),
			vf->fn);

	}

	if (t && *t)
	    rpmlog(RPMLOG_NOTICE, "%s\n", t);

    }

    return (res != 0);
}
Пример #2
0
Файл: verify.c Проект: xrg/RPM
int rpmVerifyFile(const rpmts ts, const rpmfi fi,
		rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
{
    rpm_mode_t fmode = rpmfiFMode(fi);
    rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
    rpmVerifyAttrs flags = rpmfiVFlags(fi);
    const char * fn = rpmfiFN(fi);
    struct stat sb;
    int rc;

    *res = RPMVERIFY_NONE;

    /*
     * Check to see if the file was installed - if not pretend all is OK.
     */
    switch (rpmfiFState(fi)) {
    case RPMFILE_STATE_NETSHARED:
    case RPMFILE_STATE_REPLACED:
    case RPMFILE_STATE_NOTINSTALLED:
    case RPMFILE_STATE_WRONGCOLOR:
	return 0;
	break;
    case RPMFILE_STATE_NORMAL:
	break;
    }

    if (fn == NULL || lstat(fn, &sb) != 0) {
	*res |= RPMVERIFY_LSTATFAIL;
	return 1;
    }

    /*
     * Not all attributes of non-regular files can be verified.
     */
    if (S_ISDIR(sb.st_mode))
	flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
			RPMVERIFY_LINKTO | RPMVERIFY_CAPS);
    else if (S_ISLNK(sb.st_mode)) {
	flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
			RPMVERIFY_MODE | RPMVERIFY_CAPS);
#if CHOWN_FOLLOWS_SYMLINK
	    flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
#endif
    }
    else if (S_ISFIFO(sb.st_mode))
	flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
			RPMVERIFY_LINKTO | RPMVERIFY_CAPS);
    else if (S_ISCHR(sb.st_mode))
	flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
			RPMVERIFY_LINKTO | RPMVERIFY_CAPS);
    else if (S_ISBLK(sb.st_mode))
	flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
			RPMVERIFY_LINKTO | RPMVERIFY_CAPS);
    else 
	flags &= ~(RPMVERIFY_LINKTO);

    /*
     * Content checks of %ghost files are meaningless.
     */
    if (fileAttrs & RPMFILE_GHOST)
	flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
			RPMVERIFY_LINKTO);

    /*
     * Don't verify any features in omitMask.
     */
    flags &= ~(omitMask | RPMVERIFY_FAILURES);


    if (flags & RPMVERIFY_MD5) {
	const unsigned char *digest; 
	pgpHashAlgo algo;
	size_t diglen;

	/* XXX If --nomd5, then prelinked library sizes are not corrected. */
	if ((digest = rpmfiFDigest(fi, &algo, &diglen))) {
	    unsigned char fdigest[diglen];
	    rpm_loff_t fsize;

	    rc = rpmDoDigest(algo, fn, 0, fdigest, &fsize);
	    sb.st_size = fsize;
	    if (rc) {
		*res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
	    } else if (memcmp(fdigest, digest, diglen)) {
		*res |= RPMVERIFY_MD5;
	    }
	} else {
	    *res |= RPMVERIFY_MD5;
	} 
    } 

    if (flags & RPMVERIFY_LINKTO) {
	char linkto[1024+1];
	int size = 0;

	if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1)
	    *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
	else {
	    const char * flink = rpmfiFLink(fi);
	    linkto[size] = '\0';
	    if (flink == NULL || strcmp(linkto, flink))
		*res |= RPMVERIFY_LINKTO;
	}
    } 

    if (flags & RPMVERIFY_FILESIZE) {
	if (sb.st_size != rpmfiFSize(fi))
	    *res |= RPMVERIFY_FILESIZE;
    } 

    if (flags & RPMVERIFY_MODE) {
	rpm_mode_t metamode = fmode;
	rpm_mode_t filemode;

	/*
	 * Platforms (like AIX) where sizeof(rpm_mode_t) != sizeof(mode_t)
	 * need the (rpm_mode_t) cast here. 
	 */
	filemode = (rpm_mode_t)sb.st_mode;

	/*
	 * Comparing the type of %ghost files is meaningless, but perms are OK.
	 */
	if (fileAttrs & RPMFILE_GHOST) {
	    metamode &= ~0xf000;
	    filemode &= ~0xf000;
	}

	if (metamode != filemode)
	    *res |= RPMVERIFY_MODE;

#if WITH_ACL
	/*
	 * For now, any non-default acl's on a file is a difference as rpm
	 * cannot have set them.
	 */
	acl_t facl = acl_get_file(fn, ACL_TYPE_ACCESS);
	if (facl) {
	    if (acl_equiv_mode(facl, NULL) == 1) {
		*res |= RPMVERIFY_MODE;
	    }
	    acl_free(facl);
	}
#endif 
    }

    if (flags & RPMVERIFY_RDEV) {
	if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
	 || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
	{
	    *res |= RPMVERIFY_RDEV;
	} else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
	    rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff);
	    rpm_rdev_t frdev = (rpmfiFRdev(fi) & 0xffff);
	    if (st_rdev != frdev)
		*res |= RPMVERIFY_RDEV;
	} 
    }

#if WITH_CAP
    if (flags & RPMVERIFY_CAPS) {
	/*
 	 * Empty capability set ("=") is not exactly the same as no
 	 * capabilities at all but suffices for now... 
 	 */
	cap_t cap, fcap;
	cap = cap_from_text(rpmfiFCaps(fi));
	if (!cap) {
	    cap = cap_from_text("=");
	}
	fcap = cap_get_file(fn);
	if (!fcap) {
	    fcap = cap_from_text("=");
	}
	
	if (cap_compare(cap, fcap) != 0)
	    *res |= RPMVERIFY_CAPS;

	cap_free(fcap);
	cap_free(cap);
    }
#endif

    if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) {
	/* Filter out timestamp differences of shared files */
	rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
	if (rpmdbGetIteratorCount(mi) < 2) 
	    *res |= RPMVERIFY_MTIME;
	rpmdbFreeIterator(mi);
    }

    if (flags & RPMVERIFY_USER) {
	const char * name = uidToUname(sb.st_uid);
	const char * fuser = rpmfiFUser(fi);
	if (name == NULL || fuser == NULL || strcmp(name, fuser))
	    *res |= RPMVERIFY_USER;
    }

    if (flags & RPMVERIFY_GROUP) {
	const char * name = gidToGname(sb.st_gid);
	const char * fgroup = rpmfiFGroup(fi);
	if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
	    *res |= RPMVERIFY_GROUP;
    }

    return 0;
}