Example #1
0
File: strcaps.c Project: mk-fg/fgc
static PyObject *
strcaps_get_file(PyObject *self, PyObject *args) { // (int) fd / (str) path / (file) file
	PyObject *file;
	if (!PyArg_ParseTuple(args, "O", &file)) return NULL;
	cap_t caps;
	if (PyFile_Check(file)) caps = cap_get_fd(PyObject_AsFileDescriptor(file));
	else if (PyInt_Check(file)) caps = cap_get_fd(PyInt_AsLong(file));
	else if (PyString_Check(file)) caps = cap_get_file(PyString_AsString(file));
	else if (PyUnicode_Check(file)) {
		PyObject *file_dec = PyUnicode_AsEncodedString(
			file, Py_FileSystemDefaultEncoding, "strict" );
		if (file_dec == NULL) return NULL;
		caps = cap_get_file(PyString_AsString(file_dec));
		Py_DECREF(file_dec); }
	else {
		PyErr_SetString( PyExc_TypeError,
			"Expecting file object, descriptor int or path string" );
		return NULL; }
	size_t strcaps_len; char *strcaps;
	if (caps == NULL) {
		if (errno == ENODATA) { strcaps = "\0"; strcaps_len = 0; }
		else {
			PyErr_SetFromErrno(PyExc_OSError);
			return NULL; } }
	else strcaps = cap_to_text(caps, &strcaps_len);
	cap_free(caps);
	return Py_BuildValue("s#", strcaps, strcaps_len); }; // (str) caps
Example #2
0
File: cap2.c Project: lmars/cap2
/*
 * Return a caps hash containing the capabilities of self.
 */
VALUE cap2_file_getcaps(VALUE self) {
    cap_t cap_d;
    char *filename;
    VALUE result;

    filename = cap2_file_filename(self);

    cap_d = cap_get_file(filename);

    if (cap_d == NULL && errno != ENODATA) {
        rb_raise(
            rb_eRuntimeError,
            "Failed to get capabilities for file %s: (%s)\n",
            filename, strerror(errno)
        );
    } else {
        result = cap2_caps_to_hash(cap_d);
        cap_free(cap_d);
        return result;
    }
}
Example #3
0
File: cap.c Project: AMDmi3/zsh
static int
bin_getcap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
{
    int ret = 0;

    do {
	char *result = NULL;
	ssize_t length;
	cap_t caps;

	caps = cap_get_file(unmetafy(dupstring(*argv), NULL));
	if(caps)
	    result = cap_to_text(caps, &length);
	if (!caps || !result) {
	    zwarnnam(nam, "%s: %e", *argv, errno);
	    ret = 1;
	} else
	    printf("%s %s\n", *argv, result);
	cap_free(caps);
    } while(*++argv);
    return ret;
}
Example #4
0
char *
do_cap_get_file (const char *path)
{
  cap_t cap;
  char *r, *ret;

  CHROOT_IN;
  cap = cap_get_file (path);
  CHROOT_OUT;

  if (cap == NULL) {
    reply_with_perror ("%s", path);
    return NULL;
  }

  r = cap_to_text (cap, NULL);
  if (r == NULL) {
    reply_with_perror ("cap_to_text");
    cap_free (cap);
    return NULL;
  }

  cap_free (cap);

  /* 'r' is not an ordinary pointer that can be freed with free(3)!
   * In the current implementation of libcap, if you try to do that it
   * will segfault.  We have to duplicate this into an ordinary
   * buffer, then call cap_free (r).
   */
  ret = strdup (r);
  if (ret == NULL) {
    reply_with_perror ("strdup");
    cap_free (r);
    return NULL;
  }
  cap_free (r);

  return ret;                   /* caller frees */
}
Example #5
0
File: verify.c Project: nforro/rpm
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;
}
Example #6
0
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);
}
Example #7
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);
}
Example #8
0
File: verify.c Project: 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;
}
Example #9
0
// Given the path to this program, fetch its configured capability set
// (as set by `setcap ... /path/to/file`) and raise those capabilities
// into the Ambient set.
static int make_caps_ambient(const char *selfPath)
{
    cap_t caps = cap_get_file(selfPath);

    if(!caps)
    {
        if(getenv(wrapperDebug))
            fprintf(stderr, "no caps set or could not retrieve the caps for this file, not doing anything...");

        return 1;
    }

    // We use `cap_to_text` and iteration over the tokenized result
    // string because, as of libcap's current release, there is no
    // facility for retrieving an array of `cap_value_t`'s that can be
    // given to `prctl` in order to lift that capability into the
    // Ambient set.
    //
    // Some discussion was had around shot-gunning all of the
    // capabilities we know about into the Ambient set but that has a
    // security smell and I deemed the risk of the current
    // implementation crashing the program to be lower than the risk
    // of a privilege escalation security hole being introduced by
    // raising all capabilities, even ones we didn't intend for the
    // program, into the Ambient set.
    //
    // `cap_t` which is returned by `cap_get_*` is an opaque type and
    // even if we could retrieve the bitmasks (which, as far as I can
    // tell we cannot) in order to get the `cap_value_t`
    // representation for each capability we would have to take the
    // total number of capabilities supported and iterate over the
    // sequence of integers up-to that maximum total, testing each one
    // against the bitmask ((bitmask >> n) & 1) to see if it's set and
    // aggregating each "capability integer n" that is set in the
    // bitmask.
    //
    // That, combined with the fact that we can't easily get the
    // bitmask anyway seemed much more brittle than fetching the
    // `cap_t`, transforming it into a textual representation,
    // tokenizing the string, and using `cap_from_name` on the token
    // to get the `cap_value_t` that we need for `prctl`. There is
    // indeed risk involved if the output string format of
    // `cap_to_text` ever changes but at this time the combination of
    // factors involving the below list have led me to the conclusion
    // that the best implementation at this time is reading then
    // parsing with *lots of documentation* about why we're doing it
    // this way.
    //
    // 1. No explicit API for fetching an array of `cap_value_t`'s or
    //    for transforming a `cap_t` into such a representation
    // 2. The risk of a crash is lower than lifting all capabilities
    //    into the Ambient set
    // 3. libcap is depended on heavily in the Linux ecosystem so
    //    there is a high chance that the output representation of
    //    `cap_to_text` will not change which reduces our risk that
    //    this parsing step will cause a crash
    //
    // The preferred method, should it ever be available in the
    // future, would be to use libcap API's to transform the result
    // from a `cap_get_*` into an array of `cap_value_t`'s that can
    // then be given to prctl.
    //
    // - Parnell
    ssize_t capLen;
    char* capstr = cap_to_text(caps, &capLen);
    cap_free(caps);
    
    // TODO: For now, we assume that cap_to_text always starts its
    // result string with " =" and that the first capability is listed
    // immediately after that. We should verify this.
    assert(capLen >= 2);
    capstr += 2;

    char* saveptr = NULL;
    for(char* tok = strtok_r(capstr, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr))
    {
      cap_value_t capnum;
      if (cap_from_name(tok, &capnum))
      {
          if(getenv(wrapperDebug))
              fprintf(stderr, "cap_from_name failed, skipping: %s", tok);
      }
      else if (capnum == CAP_SETPCAP)
      {
          // Check for the cap_setpcap capability, we set this on the
          // wrapper so it can elevate the capabilities to the Ambient
          // set but we do not want to propagate it down into the
          // wrapped program.
          //
          // TODO: what happens if that's the behavior you want
          // though???? I'm preferring a strict vs. loose policy here.
          if(getenv(wrapperDebug))
              fprintf(stderr, "cap_setpcap in set, skipping it\n");
      }
      else
      {
          set_ambient_cap(capnum);

          if(getenv(wrapperDebug))
              fprintf(stderr, "raised %s into the Ambient capability set\n", tok);
      }
    }
    cap_free(capstr);

    return 0;
}