int fork_drop_and_exec(int keepperms, cap_t expected_caps) { int pid; int ret = 0; char buf[200], *p; char *capstxt; cap_t actual_caps; static int seqno; pid = fork(); if (pid < 0) tst_brkm(TFAIL | TERRNO, NULL, "%s: failed fork\n", __func__); if (pid == 0) { drop_root(keepperms); print_my_caps(); sprintf(buf, "%d", seqno); ret = execlp(TSTPATH, TSTPATH, buf, NULL); capstxt = cap_to_text(expected_caps, NULL); snprintf(buf, 200, "failed to run as %s\n", capstxt); cap_free(capstxt); write_to_fifo(buf); tst_brkm(TFAIL, NULL, "%s: exec failed\n", __func__); } else { p = buf; while (1) { int c, s; read_from_fifo(buf); c = sscanf(buf, "%d", &s); if (c == 1 && s == seqno) break; tst_resm(TINFO, "got a bad seqno (c=%d, s=%d, seqno=%d)", c, s, seqno); } p = index(buf, '.'); if (!p) tst_brkm(TFAIL, NULL, "got a bad message from print_caps\n"); p += 1; actual_caps = cap_from_text(p); if (cap_compare(actual_caps, expected_caps) != 0) { capstxt = cap_to_text(expected_caps, NULL); tst_resm(TINFO, "Expected to run as .%s., ran as .%s..\n", capstxt, p); tst_resm(TINFO, "those are not the same\n"); cap_free(capstxt); ret = -1; } cap_free(actual_caps); seqno++; } return ret; }
int main() { #ifdef HAVE_LIBCAP cap_t caps, caps2; int ret; caps = cap_from_text("cap_setpcap+ep"); caps2 = cap_from_text("cap_setpcap+ep"); ret = cap_set_proc(caps); ret = cap_compare(caps, caps2); printf("Caps were %sthe same\n", ret ? "not " : ""); cap_free(caps); cap_free(caps2); return ret; #else printf("System doesn't support full POSIX capabilities.\n"); return 1; #endif }
rpmVerifyAttrs rpmfilesVerify(rpmfiles fi, int ix, rpmVerifyAttrs omitMask) { rpmfileAttrs fileAttrs = rpmfilesFFlags(fi, ix); rpmVerifyAttrs flags = rpmfilesVFlags(fi, ix); const char * fn = rpmfilesFN(fi, ix); struct stat sb, fsb; rpmVerifyAttrs vfy = RPMVERIFY_NONE; /* * Check to see if the file was installed - if not pretend all is OK. */ switch (rpmfilesFState(fi, ix)) { case RPMFILE_STATE_NETSHARED: case RPMFILE_STATE_NOTINSTALLED: goto exit; break; case RPMFILE_STATE_REPLACED: /* For replaced files we can only verify if it exists at all */ flags = RPMVERIFY_LSTATFAIL; break; case RPMFILE_STATE_WRONGCOLOR: /* * Files with wrong color are supposed to share some attributes * with the actually installed file - verify what we can. */ flags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_RDEV); break; case RPMFILE_STATE_NORMAL: /* File from a non-installed package, try to verify nevertheless */ case RPMFILE_STATE_MISSING: break; } if (fn == NULL || lstat(fn, &sb) != 0 || rpmfilesStat(fi, ix, 0, &fsb)) { vfy |= RPMVERIFY_LSTATFAIL; goto exit; } /* If we expected a directory but got a symlink to one, follow the link */ if (S_ISDIR(fsb.st_mode) && S_ISLNK(sb.st_mode)) { struct stat dsb; /* ...if it actually points to a directory */ if (stat(fn, &dsb) == 0 && S_ISDIR(dsb.st_mode)) { /* ...and is by a legit user, to match fsmVerify() behavior */ if (sb.st_uid == 0 || sb.st_uid == fsb.st_uid) sb = dsb; /* struct assignment */ } } /* Links have no mode, other types have no linkto */ if (S_ISLNK(sb.st_mode)) flags &= ~(RPMVERIFY_MODE); else flags &= ~(RPMVERIFY_LINKTO); /* Not all attributes of non-regular files can be verified */ if (!S_ISREG(sb.st_mode)) flags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_CAPS); /* Content checks of %ghost files are meaningless. */ if (fileAttrs & RPMFILE_GHOST) flags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO); /* Don't verify any features in omitMask. */ flags &= ~(omitMask | RPMVERIFY_FAILURES); if (flags & RPMVERIFY_FILEDIGEST) { const unsigned char *digest; int algo; size_t diglen; /* XXX If --nomd5, then prelinked library sizes are not corrected. */ if ((digest = rpmfilesFDigest(fi, ix, &algo, &diglen))) { unsigned char fdigest[diglen]; rpm_loff_t fsize; if (rpmDoDigest(algo, fn, 0, fdigest, &fsize)) { vfy |= (RPMVERIFY_READFAIL|RPMVERIFY_FILEDIGEST); } else { sb.st_size = fsize; if (memcmp(fdigest, digest, diglen)) vfy |= RPMVERIFY_FILEDIGEST; } } else { vfy |= RPMVERIFY_FILEDIGEST; } } if (flags & RPMVERIFY_LINKTO) { char linkto[1024+1]; int size = 0; if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1) vfy |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); else { const char * flink = rpmfilesFLink(fi, ix); linkto[size] = '\0'; if (flink == NULL || !rstreq(linkto, flink)) vfy |= RPMVERIFY_LINKTO; } } if ((flags & RPMVERIFY_FILESIZE) && (sb.st_size != fsb.st_size)) vfy |= RPMVERIFY_FILESIZE; if (flags & RPMVERIFY_MODE) { mode_t metamode = fsb.st_mode; mode_t filemode = sb.st_mode; /* * Comparing the type of %ghost files is meaningless, but perms are OK. */ if (fileAttrs & RPMFILE_GHOST) { metamode &= ~S_IFMT; filemode &= ~S_IFMT; } if (metamode != filemode) vfy |= 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) { vfy |= RPMVERIFY_MODE; } acl_free(facl); } #endif } if (flags & RPMVERIFY_RDEV) { if (S_ISCHR(fsb.st_mode) != S_ISCHR(sb.st_mode) || S_ISBLK(fsb.st_mode) != S_ISBLK(sb.st_mode)) { vfy |= RPMVERIFY_RDEV; } else if (S_ISDEV(fsb.st_mode) && S_ISDEV(sb.st_mode)) { rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff); rpm_rdev_t frdev = (fsb.st_rdev & 0xffff); if (st_rdev != frdev) vfy |= 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(rpmfilesFCaps(fi, ix)); if (!cap) { cap = cap_from_text("="); } fcap = cap_get_file(fn); if (!fcap) { fcap = cap_from_text("="); } if (cap_compare(cap, fcap) != 0) vfy |= RPMVERIFY_CAPS; cap_free(fcap); cap_free(cap); } #endif if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != fsb.st_mtime)) vfy |= RPMVERIFY_MTIME; if ((flags & RPMVERIFY_USER) && (sb.st_uid != fsb.st_uid)) vfy |= RPMVERIFY_USER; if ((flags & RPMVERIFY_GROUP) && (sb.st_gid != fsb.st_gid)) vfy |= RPMVERIFY_GROUP; exit: return vfy; }
int main(int argc, char **argv) { char *opt, *p, *str; int told = 0; int use_checklist = 0; int systemmode = 0; int suseconfig = 0; FILE *fp; char line[512]; char *part[4]; int i, pcnt, lcnt; int inpart; mode_t mode; struct perm *e; struct stat stb, stb2; struct passwd *pwd = 0; struct group *grp = 0; uid_t uid; gid_t gid; int fd, r; int errors = 0; cap_t caps = NULL; while (argc > 1) { opt = argv[1]; if (!strcmp(opt, "--")) break; if (*opt == '-' && opt[1] == '-') opt++; if (!strcmp(opt, "-system")) { argc--; argv++; systemmode = 1; continue; } // hidden option for use by suseconfig only if (!strcmp(opt, "-suseconfig")) { argc--; argv++; suseconfig = 1; systemmode = 1; continue; } if (!strcmp(opt, "-fscaps")) { argc--; argv++; have_fscaps = 1; continue; } if (!strcmp(opt, "-no-fscaps")) { argc--; argv++; have_fscaps = 0; continue; } if (!strcmp(opt, "-s") || !strcmp(opt, "-set")) { do_set=1; argc--; argv++; continue; } if (!strcmp(opt, "-warn")) { do_set=0; argc--; argv++; continue; } if (!strcmp(opt, "-n") || !strcmp(opt, "-noheader")) { told = 1; argc--; argv++; continue; } if (!strcmp(opt, "-e") || !strcmp(opt, "-examine")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "examine: argument required\n"); exit(1); } add_checklist(argv[1]); use_checklist = 1; argc--; argv++; continue; } if (!strcmp(opt, "-level")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "level: argument required\n"); exit(1); } force_level = argv[1]; argc--; argv++; continue; } if (!strcmp(opt, "-f") || !strcmp(opt, "-files")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "files: argument required\n"); exit(1); } if ((fp = fopen(argv[1], "r")) == 0) { fprintf(stderr, "files: %s: %s\n", argv[1], strerror(errno)); exit(1); } while (readline(fp, line, sizeof(line))) { if (!*line) continue; add_checklist(line); } fclose(fp); use_checklist = 1; argc--; argv++; continue; } if (!strcmp(opt, "-r") || !strcmp(opt, "-root")) { argc--; argv++; if (argc == 1) { fprintf(stderr, "root: argument required\n"); exit(1); } root = argv[1]; rootl = strlen(root); if (*root != '/') { fprintf(stderr, "root: must begin with '/'\n"); exit(1); } argc--; argv++; continue; } if (*opt == '-') usage(!strcmp(opt, "-h") || !strcmp(opt, "-help") ? 0 : 1); break; } if (systemmode) { const char file[] = "/etc/sysconfig/security"; parse_sysconf(file); if(do_set == -1) { if (default_set < 0) { fprintf(stderr, "permissions handling disabled in %s\n", file); exit(0); } if (suseconfig && default_set) { char* module = getenv("ONLY_MODULE"); if (!module || strcmp(module, "permissions")) { puts("no permissions will be changed if not called explicitly"); default_set = 0; } } do_set = default_set; } if (force_level) { char *p = strtok(force_level, " "); do { add_level(p); } while ((p = strtok(NULL, " "))); } if (!nlevel) add_level("secure"); add_level("local"); // always add local for (i = 1; i < argc; i++) { add_checklist(argv[i]); use_checklist = 1; continue; } collect_permfiles(); } else if (argc <= 1) usage(1); else { npermfiles = argc-1; permfiles = &argv[1]; } if (have_fscaps == 1 && !check_fscaps_enabled()) { fprintf(stderr, "Warning: running kernel does not support fscaps\n"); } if (do_set == -1) do_set = 0; // add fake list entries for all files to check for (i = 0; i < nchecklist; i++) add_permlist(checklist[i], "unknown", "unknown", 0); for (i = 0; i < npermfiles; i++) { if ((fp = fopen(permfiles[i], "r")) == 0) { perror(argv[i]); exit(1); } lcnt = 0; struct perm* last = NULL; int extline; while (readline(fp, line, sizeof(line))) { extline = 0; lcnt++; if (*line == 0 || *line == '#' || *line == '$') continue; inpart = 0; pcnt = 0; for (p = line; *p; p++) { if (*p == ' ' || *p == '\t') { *p = 0; if (inpart) { pcnt++; inpart = 0; } continue; } if (pcnt == 0 && !inpart && *p == '+') { extline = 1; break; } if (!inpart) { inpart = 1; if (pcnt == 3) break; part[pcnt] = p; } } if (extline) { if (!last) { BAD_LINE(); continue; } if (!strncmp(p, "+capabilities ", 14)) { if (have_fscaps != 1) continue; p += 14; caps = cap_from_text(p); if (caps) { cap_free(last->caps); last->caps = caps; } continue; } BAD_LINE(); continue; } if (inpart) pcnt++; if (pcnt != 3) { BAD_LINE(); continue; } part[3] = part[2]; part[2] = strchr(part[1], ':'); if (!part[2]) part[2] = strchr(part[1], '.'); if (!part[2]) { BAD_LINE(); continue; } *part[2]++ = 0; mode = strtoul(part[3], part + 3, 8); if (mode > 07777 || part[3][0]) { BAD_LINE(); continue; } last = add_permlist(part[0], part[1], part[2], mode); } fclose(fp); } euid = geteuid(); for (e = permlist; e; e = e->next) { if (use_checklist && !in_checklist(e->file+rootl)) continue; if (lstat(e->file, &stb)) continue; if (S_ISLNK(stb.st_mode)) continue; if (!e->mode && !strcmp(e->owner, "unknown")) { char uids[16], gids[16]; pwd = getpwuid(stb.st_uid); grp = getgrgid(stb.st_gid); if (!pwd) sprintf(uids, "%d", stb.st_uid); if (!grp) sprintf(gids, "%d", stb.st_gid); fprintf(stderr, "%s: cannot verify %s:%s %04o - not listed in /etc/permissions\n", e->file+rootl, pwd?pwd->pw_name:uids, grp?grp->gr_name:gids, (int)(stb.st_mode&07777)); pwd = 0; grp = 0; continue; } if ((!pwd || strcmp(pwd->pw_name, e->owner)) && (pwd = getpwnam(e->owner)) == 0) { fprintf(stderr, "%s: unknown user %s\n", e->file+rootl, e->owner); continue; } if ((!grp || strcmp(grp->gr_name, e->group)) && (grp = getgrnam(e->group)) == 0) { fprintf(stderr, "%s: unknown group %s\n", e->file+rootl, e->group); continue; } uid = pwd->pw_uid; gid = grp->gr_gid; caps = cap_get_file(e->file); if (!caps) { cap_free(caps); caps = NULL; if (errno == EOPNOTSUPP) { //fprintf(stderr, "%s: fscaps not supported\n", e->file+rootl); cap_free(e->caps); e->caps = NULL; } } if (e->caps) { e->mode &= 0777; } int perm_ok = (stb.st_mode & 07777) == e->mode; int owner_ok = stb.st_uid == uid && stb.st_gid == gid; int caps_ok = 0; if (!caps && !e->caps) caps_ok = 1; else if (caps && e->caps && !cap_compare(e->caps, caps)) caps_ok = 1; if (perm_ok && owner_ok && caps_ok) continue; if (!told) { told = 1; printf("Checking permissions and ownerships - using the permissions files\n"); for (i = 0; i < npermfiles; i++) printf("\t%s\n", permfiles[i]); if (rootl) { printf("Using root %s\n", root); } } if (!do_set) printf("%s should be %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode); else printf("setting %s to %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode); if (!caps_ok && e->caps) { str = cap_to_text(e->caps, NULL); printf(" \"%s\"", str); cap_free(str); } printf(". (wrong"); if (!owner_ok) { pwd = getpwuid(stb.st_uid); grp = getgrgid(stb.st_gid); if (pwd) printf(" owner/group %s", pwd->pw_name); else printf(" owner/group %d", stb.st_uid); if (grp) printf(":%s", grp->gr_name); else printf(":%d", stb.st_gid); pwd = 0; grp = 0; } if (!perm_ok) printf(" permissions %04o", (int)(stb.st_mode & 07777)); if (!caps_ok) { if (!perm_ok || !owner_ok) { fputc(',', stdout); } if (caps) { str = cap_to_text(caps, NULL); printf(" capabilities \"%s\"", str); cap_free(str); } else fputs(" missing capabilities", stdout); } putchar(')'); putchar('\n'); if (!do_set) continue; fd = -1; if (S_ISDIR(stb.st_mode)) { fd = open(e->file, O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_NOFOLLOW); if (fd == -1) { perror(e->file); errors++; continue; } } else if (S_ISREG(stb.st_mode)) { fd = open(e->file, O_RDONLY|O_NONBLOCK|O_NOFOLLOW); if (fd == -1) { perror(e->file); errors++; continue; } if (fstat(fd, &stb2)) continue; if (stb.st_mode != stb2.st_mode || stb.st_nlink != stb2.st_nlink || stb.st_dev != stb2.st_dev || stb.st_ino != stb2.st_ino) { fprintf(stderr, "%s: too fluctuating\n", e->file+rootl); errors++; continue; } if (stb.st_nlink > 1 && !safepath(e->file, 0, 0)) { fprintf(stderr, "%s: on an insecure path\n", e->file+rootl); errors++; continue; } else if (e->mode & 06000) { /* extra checks for s-bits */ if (!safepath(e->file, (e->mode & 02000) == 0 ? uid : 0, (e->mode & 04000) == 0 ? gid : 0)) { fprintf(stderr, "%s: will not give away s-bits on an insecure path\n", e->file+rootl); errors++; continue; } } } else if (strncmp(e->file, "/dev/", 5) != 0) // handle special files only in /dev { fprintf(stderr, "%s: don't know what to do with that type of file\n", e->file+rootl); errors++; continue; } if (euid == 0 && !owner_ok) { /* if we change owner or group of a setuid file the bit gets reset so also set perms again */ if (e->mode & 06000) perm_ok = 0; if (fd >= 0) r = fchown(fd, uid, gid); else r = chown(e->file, uid, gid); if (r) { fprintf(stderr, "%s: chown: %s\n", e->file+rootl, strerror(errno)); errors++; } if (fd >= 0) r = fstat(fd, &stb); else r = lstat(e->file, &stb); if (r) { fprintf(stderr, "%s: too fluctuating\n", e->file+rootl); errors++; continue; } } if (!perm_ok) { if (fd >= 0) r = fchmod(fd, e->mode); else r = chmod(e->file, e->mode); if (r) { fprintf(stderr, "%s: chmod: %s\n", e->file+rootl, strerror(errno)); errors++; } } if (!caps_ok) { if (fd >= 0) r = cap_set_fd(fd, e->caps); else r = cap_set_file(e->file, e->caps); if (r) { fprintf(stderr, "%s: cap_set_file: %s\n", e->file+rootl, strerror(errno)); errors++; } } if (fd >= 0) close(fd); } if (errors) { fprintf(stderr, "ERROR: not all operations were successful.\n"); exit(1); } exit(0); }
int main(int argc, char **argv) { int tried_to_cap_setfcap = 0; char buffer[MAXCAP+1]; int retval, quiet=0, verify=0; cap_t mycaps; cap_value_t capflag; if (argc < 3) { usage(); } mycaps = cap_get_proc(); if (mycaps == NULL) { fprintf(stderr, "warning - unable to get process capabilities" " (old libcap?)\n"); } while (--argc > 0) { const char *text; cap_t cap_d; if (!strcmp(*++argv, "-q")) { quiet = 1; continue; } if (!strcmp(*argv, "-v")) { verify = 1; continue; } if (!strcmp(*argv, "-r")) { cap_d = NULL; } else { if (!strcmp(*argv,"-")) { retval = read_caps(quiet, *argv, buffer); if (retval) usage(); text = buffer; } else { text = *argv; } cap_d = cap_from_text(text); if (cap_d == NULL) { perror("fatal error"); usage(); } #ifdef DEBUG { ssize_t length; const char *result; result = cap_to_text(cap_d, &length); fprintf(stderr, "caps set to: [%s]\n", result); } #endif } if (--argc <= 0) usage(); /* * Set the filesystem capability for this file. */ if (verify) { cap_t cap_on_file; int cmp; if (cap_d == NULL) { cap_d = cap_from_text("="); } cap_on_file = cap_get_file(*++argv); if (cap_on_file == NULL) { cap_on_file = cap_from_text("="); } cmp = cap_compare(cap_on_file, cap_d); cap_free(cap_on_file); if (cmp != 0) { if (!quiet) { printf("%s differs in [%s%s%s]\n", *argv, CAP_DIFFERS(cmp, CAP_PERMITTED) ? "p" : "", CAP_DIFFERS(cmp, CAP_INHERITABLE) ? "i" : "", CAP_DIFFERS(cmp, CAP_EFFECTIVE) ? "e" : ""); } exit(1); } if (!quiet) { printf("%s: OK\n", *argv); } } else { if (!tried_to_cap_setfcap) { capflag = CAP_SETFCAP; /* * Raise the effective CAP_SETFCAP. */ if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET) != 0) { perror("unable to manipulate CAP_SETFCAP - " "try a newer libcap?"); exit(1); } if (cap_set_proc(mycaps) != 0) { perror("unable to set CAP_SETFCAP effective capability"); exit(1); } tried_to_cap_setfcap = 1; } retval = cap_set_file(*++argv, cap_d); if (retval != 0) { fprintf(stderr, "Failed to set capabilities on file `%s' (%s)\n", argv[0], strerror(errno)); usage(); } } if (cap_d) { cap_free(cap_d); } } exit(0); }
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; }