示例#1
0
static
void dropCapability(cap_value_t capability)
{
    cap_t caps;
    cap_value_t cap_list[] = { capability };

    caps = cap_get_proc();
    if (caps == nullptr)
    {
        Log::error("Error: cap_get_proc() failed.");
        std::exit(1);
    }

    char *capText = cap_to_text(caps, nullptr);
    Log::info("Capabilities first: " + std::string(capText));
    cap_free(capText);

    if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1 ||
        cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1)
    {
        Log::error("Error: cap_set_flag() failed.");
        std::exit(1);
    }

    if (cap_set_proc(caps) == -1)
    {
        Log::error("Error: cap_set_proc() failed.");
        std::exit(1);
    }

    capText = cap_to_text(caps, nullptr);
    Log::info("Capabilities now: " + std::string(capText));
    cap_free(capText);

    cap_free(caps);
}
void drop_capabilities(void)
{
	/* the capabilities that we *need* in order to operate */
	static cap_value_t suidcaps[] = {
		CAP_CHOWN,
		CAP_KILL,
		CAP_SYS_CHROOT,
		CAP_SETUID,
		CAP_SETGID,
		CAP_NET_BIND_SERVICE,
		/* we may want to open any config/log files */
		CAP_DAC_OVERRIDE
	};
	cap_t caps;

	caps = cap_init();
	cap_clear(caps);
	cap_set_flag(caps, CAP_PERMITTED,
		     N_ELEMENTS(suidcaps), suidcaps, CAP_SET);
	cap_set_flag(caps, CAP_EFFECTIVE,
		     N_ELEMENTS(suidcaps), suidcaps, CAP_SET);
	cap_set_proc(caps);
	cap_free(caps);
}
int main(int argc, char *argv[])
{
#if HAVE_SYS_CAPABILITY_H
#ifdef HAVE_LIBCAP
	int ret = 1;
	cap_flag_value_t f;
	cap_value_t v[1];
	cap_t cur;

	/* Make sure CAP_SYS_ADMIN is not in pI */
	cur = cap_get_proc();
	ret = cap_get_flag(cur, CAP_SYS_ADMIN, CAP_INHERITABLE, &f);
	if (f == CAP_SET) {
		v[0] = CAP_SYS_ADMIN;
		ret = cap_set_flag(cur, CAP_INHERITABLE, 1, v, CAP_CLEAR);
		if (!ret)
			ret = cap_set_proc(cur);
		if (ret) {
			tst_resm(TBROK,
				 "Failed to drop cap_sys_admin from pI\n");
			tst_exit();
		}
	} else if (ret) {
		tst_brkm(TBROK | TERRNO, NULL, "Failed to add \
			CAP_SYS_ADMIN to pI");
	}
	cap_free(cur);

	/* drop the capability from bounding set */
	ret = prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN);
	if (ret) {
		tst_resm(TFAIL,
			 "Failed to drop CAP_SYS_ADMIN from bounding set.\n");
		tst_resm(TINFO, "(ret=%d, errno %d)\n", ret, errno);
		tst_exit();
	}

	/* execute "check_pe 0" */
	execl("check_pe", "check_pe", "0", NULL);
	tst_resm(TBROK, "Failed to execute check_pe (errno %d)\n", errno);
#else /* libcap */
	tst_resm(TCONF, "System doesn't have POSIX capabilities.");
#endif
#else /* capability_h */
	tst_resm(TCONF, "System doesn't have sys/capability.h.");
#endif
	tst_exit();
}
示例#4
0
/**
 * g_process_cap_modify:
 * @capability: capability to turn off or on
 * @onoff: specifies whether the capability should be enabled or disabled
 *
 * This function modifies the current permitted set of capabilities by
 * enabling or disabling the capability specified in @capability.
 *
 * Returns: whether the operation was successful.
 **/
gboolean 
g_process_cap_modify(int capability, int onoff)
{
  cap_t caps;

  if (!process_opts.caps)
    return TRUE;

  /*
   * if libcap or kernel doesn't support cap_syslog, then resort to
   * cap_sys_admin
   */
  if (capability == CAP_SYSLOG && (!have_capsyslog || CAP_SYSLOG == -1))
    capability = CAP_SYS_ADMIN;

  caps = cap_get_proc();
  if (!caps)
    return FALSE;

  if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &capability, onoff) == -1)
    {
      msg_error("Error managing capability set, cap_set_flag returned an error",
                evt_tag_errno("error", errno),
                NULL);
      cap_free(caps);
      return FALSE;
    }

  if (cap_set_proc(caps) == -1)
    {
      gchar *cap_text;

      cap_text = cap_to_text(caps, NULL);
      msg_error("Error managing capability set, cap_set_proc returned an error",
                evt_tag_str("caps", cap_text),
                evt_tag_errno("error", errno),
                NULL);
      cap_free(cap_text);
      cap_free(caps);
      return FALSE;
    }
  cap_free(caps);
  return TRUE;
}
示例#5
0
文件: caps.c 项目: ostap/lxc
int lxc_caps_up(void)
{
	cap_t caps;
	cap_value_t cap;
	int ret;

	/* when we are run as root, we don't want to play
	 * with the capabilities */
	if (!getuid())
		return 0;

	caps = cap_get_proc();
	if (!caps) {
		ERROR("failed to cap_get_proc: %m");
		return -1;
	}

	for (cap = 0; cap <= CAP_LAST_CAP; cap++) {

		cap_flag_value_t flag;

		ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
		if (ret) {
			ERROR("failed to cap_get_flag: %m");
			goto out;
		}

		ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
		if (ret) {
			ERROR("failed to cap_set_flag: %m");
			goto out;
		}
	}

	ret = cap_set_proc(caps);
	if (ret) {
		ERROR("failed to cap_set_proc: %m");
		goto out;
	}

out:
	cap_free(caps);
        return 0;
}
示例#6
0
/* When handling requests on connections authenticated as root, we consider
 * it safe to disable DAC checks on the server and presume the client is
 * doing it.  This is only done if the server sets SRV_FLAGS_DAC_BYPASS.
 */
static int
_chg_privcap (Npsrv *srv, cap_flag_value_t val)
{
    cap_t cap;
    cap_flag_value_t cur;
    cap_value_t cf[] = { CAP_DAC_OVERRIDE, CAP_CHOWN, CAP_FOWNER };
    int need_set = 0;
    int i, ret = -1;

    if (!(cap = cap_get_proc ())) {
        np_uerror (errno);
        np_logerr (srv, "cap_get_proc failed");
        goto done;
    }
    for (i = 0; i < sizeof(cf) / sizeof(cf[0]); i++) {
        if (cap_get_flag (cap, cf[i], CAP_EFFECTIVE, &cur) < 0) {
            np_uerror (errno);
            np_logerr (srv, "cap_get_flag failed");
            goto done;
        }
        if (cur == val)
            continue;
        need_set = 1;
        if (cap_set_flag (cap, CAP_EFFECTIVE, 1, &cf[i], val) < 0) {
            np_uerror (errno);
            np_logerr (srv, "cap_set_flag failed");
            goto done;
        }
    }
    if (need_set && cap_set_proc (cap) < 0) {
        np_uerror (errno);
        np_logerr (srv, "cap_set_proc failed");
        goto done;
    }
    ret = 0;
done:
    if (cap != NULL && cap_free (cap) < 0) {
        np_uerror (errno);
        np_logerr (srv, "cap_free failed");
    }
    return ret;
}
示例#7
0
文件: trace.c 项目: protoben/geotrace
/*
 * Attempt to get the specified libcap(3) capability. Return
 * error code on failure.
 */
int trace_get_cap(cap_value_t cap)
{
  int err;
  cap_t cap_p;
  cap_flag_value_t cflag = CAP_CLEAR;

  /* Initialize a cap with current values for our process. */
  cap_p = cap_get_proc();
  if(!cap_p) return errno;

  /* Make sure we're permitted to obtain this capability. */
  cap_get_flag(cap_p, cap, CAP_PERMITTED, &cflag);
  if(cflag == CAP_CLEAR) return EACCES;

  /* Set the cap and attempt to apply it to our process. */
  cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap, CAP_SET);
  err = cap_set_proc(cap_p);
  if(err) return errno;

  cap_free(cap_p);
  return 0;
}
示例#8
0
/* set the ambient capabilities to match the bitmap capset.
	 the capability #k is active if and only if the (k+1)-th least significative bit in capset is 1.
	 (i.e. if and only if (capset & (1ULL << k)) is not zero. */
void set_ambient_cap(uint64_t capset)
{
	cap_value_t cap;
	cap_t caps=cap_get_proc();
	for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
		int op = (capset & (1ULL << cap)) ? CAP_SET : CAP_CLEAR;
		if (cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, op)) {
			fprintf(stderr, "Cannot %s inheritable cap %s\n",op==CAP_SET?"set":"clear",cap_to_name(cap));
			exit(2);
		}
	}
	cap_set_proc(caps);
	cap_free(caps);

	for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
		int op = (capset & (1ULL << cap)) ? PR_CAP_AMBIENT_RAISE : PR_CAP_AMBIENT_LOWER;
		if (prctl(PR_CAP_AMBIENT, op, cap, 0, 0)) {
			perror("Cannot set cap");
			exit(1);
		}
	}
}
示例#9
0
void drop_ambient_cap(uint64_t capset) {
	cap_value_t cap;
	cap_t caps=cap_get_proc();
	for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
		if (capset & (1ULL << cap)) {
			if (cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR)) {
				fprintf(stderr, "Cannot clear inheritable cap %s\n",cap_to_name(cap));
				exit(2);
			}
		}
	}
	cap_set_proc(caps);
	cap_free(caps);

	for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
		if ((capset & (1ULL << cap))) {
			if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)) {
				perror("Cannot set cap");
				exit(1);
			}
		}
	}
}
示例#10
0
/*
 * Try to obtain the CAP_IPC_LOCK Linux capability.
 * Then, whether or not this is successful, drop root
 * privileges to run as the invoking user. The application is aborted
 * if for any reason we are unable to drop privileges. Note: even gettext
 * is unavailable!
 */
void
gkd_capability_obtain_capability_and_drop_privileges (void)
{
#ifdef HAVE_LIBCAP
	cap_t caps;
	cap_value_t cap_list[1];

	caps = cap_get_proc ();
	if (caps == NULL) {
		early_error ("capability state cannot be allocated");
		goto drop;
	}

	cap_list[0] = CAP_IPC_LOCK;
	if (cap_set_flag (caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) {
		early_error ("error when manipulating capability sets");
		goto drop;
	}

	if (cap_set_proc (caps) == -1) {
		/* Only warn when it's root that's running */
		if (getuid () == 0)
			early_error ("cannot apply capabilities to process");
		goto drop;
	}

	if (cap_free (caps) == -1) {
		early_error ("failed to free capability structure");
		goto drop;
	}
drop:

#endif
	/* Now finally drop the suid by becoming the invoking user */
	if (geteuid () != getuid() || getegid () != getgid ())
		drop_privileges ();
}
示例#11
0
static int
modifyCap(int capability, int setting)
{
    cap_t caps;
    cap_value_t capList[1];

    /* Retrieve caller's current capabilities */

    caps = cap_get_proc();
    if (caps == NULL)
        return 1;

    /* Change setting of 'capability' in the effective set of 'caps'. The
       third argument, 1, is the number of items in the array 'capList'. */

    capList[0] = capability;
    if (cap_set_flag(caps, CAP_EFFECTIVE, 1, capList, setting) == -1) {
        cap_free(caps);
        return 2;
    }

    /* Push modified capability sets back to kernel, to change
       caller's capabilities */

    if (cap_set_proc(caps) == -1) {
        cap_free(caps);
        return 3;
    }

    /* Free the structure that was allocated by libcap */

    if (cap_free(caps) == -1)
        return 4;

    return 0;
}
示例#12
0
void linux_drop_privs(void)
{
	cap_t caps = cap_init();
	int num = 2;

	cap_value_t capList[] = { CAP_NET_ADMIN, CAP_SETUID };

	cap_set_flag(caps, CAP_EFFECTIVE, num, capList, CAP_SET);
        cap_set_flag(caps, CAP_INHERITABLE, num, capList, CAP_SET);
        cap_set_flag(caps, CAP_PERMITTED, num, capList, CAP_SET);

	if (cap_set_proc(caps))
		err(1, "cap_set_flag()");

	if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0))
		err(1, "prctl()");

	cap_free(caps);

	if (setuid(666) == -1)
		err(1, "setuid()");

	caps = cap_init();
	num  = 1;

	cap_set_flag(caps, CAP_EFFECTIVE, num, capList, CAP_SET);
        cap_set_flag(caps, CAP_INHERITABLE, num, capList, CAP_SET);
        cap_set_flag(caps, CAP_PERMITTED, num, capList, CAP_SET);

	if (cap_set_proc(caps))
		err(1, "cap_set_proc()");	

	cap_free(caps);

	/* XXX this really sucks.  The guy can screw with our net =( */
}
示例#13
0
/* turn cap_dac_read_search on and off to have "extra" powers only when needed */
void raise_cap_dac_read_search(void) {
	cap_value_t cap=CAP_DAC_READ_SEARCH;
	cap_t caps=cap_get_proc();
	cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
	cap_set_proc(caps);
}
示例#14
0
文件: capsh.c 项目: Distrotech/libcap
int main(int argc, char *argv[], char *envp[])
{
    pid_t child;
    unsigned i;

    child = 0;

    for (i=1; i<argc; ++i) {
	if (!memcmp("--drop=", argv[i], 4)) {
	    char *ptr;
	    cap_t orig, raised_for_setpcap;

	    /*
	     * We need to do this here because --inh=XXX may have reset
	     * orig and it isn't until we are within the --drop code that
	     * we know what the prevailing (orig) pI value is.
	     */
	    orig = cap_get_proc();
	    if (orig == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }

	    raised_for_setpcap = cap_dup(orig);
	    if (raised_for_setpcap == NULL) {
		fprintf(stderr, "BSET modification requires CAP_SETPCAP\n");
		exit(1);
	    }

	    if (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
			     raise_setpcap, CAP_SET) != 0) {
		perror("unable to select CAP_SETPCAP");
		exit(1);
	    }

	    if (strcmp("all", argv[i]+7) == 0) {
		unsigned j = 0;
		while (CAP_IS_SUPPORTED(j)) {
		    if (cap_drop_bound(j) != 0) {
			char *name_ptr;

			name_ptr = cap_to_name(j);
			fprintf(stderr,
				"Unable to drop bounding capability [%s]\n",
				name_ptr);
			cap_free(name_ptr);
			exit(1);
		    }
		    j++;
		}
	    } else {
		for (ptr = argv[i]+7; (ptr = strtok(ptr, ",")); ptr = NULL) {
		    /* find name for token */
		    cap_value_t cap;
		    int status;

		    if (cap_from_name(ptr, &cap) != 0) {
			fprintf(stderr,
				"capability [%s] is unknown to libcap\n",
				ptr);
			exit(1);
		    }
		    if (cap_set_proc(raised_for_setpcap) != 0) {
			perror("unable to raise CAP_SETPCAP for BSET changes");
			exit(1);
		    }
		    status = prctl(PR_CAPBSET_DROP, cap);
		    if (cap_set_proc(orig) != 0) {
			perror("unable to lower CAP_SETPCAP post BSET change");
			exit(1);
		    }
		    if (status) {
			fprintf(stderr, "failed to drop [%s=%u]\n", ptr, cap);
			exit(1);
		    }
		}
	    }
	    cap_free(raised_for_setpcap);
	    cap_free(orig);
	} else if (!memcmp("--inh=", argv[i], 6)) {
	    cap_t all, raised_for_setpcap;
	    char *text;
	    char *ptr;

	    all = cap_get_proc();
	    if (all == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }
	    if (cap_clear_flag(all, CAP_INHERITABLE) != 0) {
		perror("libcap:cap_clear_flag() internal error");
		exit(1);
	    }

	    raised_for_setpcap = cap_dup(all);
	    if ((raised_for_setpcap != NULL)
		&& (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
				 raise_setpcap, CAP_SET) != 0)) {
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    text = cap_to_text(all, NULL);
	    cap_free(all);
	    if (text == NULL) {
		perror("Fatal error concerning process capabilities");
		exit(1);
	    }
	    ptr = malloc(10 + strlen(argv[i]+6) + strlen(text));
	    if (ptr == NULL) {
		perror("Out of memory for inh set");
		exit(1);
	    }
	    if (argv[i][6] && strcmp("none", argv[i]+6)) {
		sprintf(ptr, "%s %s+i", text, argv[i]+6);
	    } else {
		strcpy(ptr, text);
	    }

	    all = cap_from_text(ptr);
	    if (all == NULL) {
		perror("Fatal error internalizing capabilities");
		exit(1);
	    }
	    cap_free(text);
	    free(ptr);

	    if (raised_for_setpcap != NULL) {
		/*
		 * This is only for the case that pP does not contain
		 * the requested change to pI.. Failing here is not
		 * indicative of the cap_set_proc(all) failing (always).
		 */
		(void) cap_set_proc(raised_for_setpcap);
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    if (cap_set_proc(all) != 0) {
		perror("Unable to set inheritable capabilities");
		exit(1);
	    }
	    /*
	     * Since status is based on orig, we don't want to restore
	     * the previous value of 'all' again here!
	     */

	    cap_free(all);
	} else if (!memcmp("--caps=", argv[i], 7)) {
	    cap_t all, raised_for_setpcap;

	    raised_for_setpcap = cap_get_proc();
	    if (raised_for_setpcap == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }

	    if ((raised_for_setpcap != NULL)
		&& (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
				 raise_setpcap, CAP_SET) != 0)) {
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    all = cap_from_text(argv[i]+7);
	    if (all == NULL) {
		fprintf(stderr, "unable to interpret [%s]\n", argv[i]);
		exit(1);
	    }

	    if (raised_for_setpcap != NULL) {
		/*
		 * This is only for the case that pP does not contain
		 * the requested change to pI.. Failing here is not
		 * indicative of the cap_set_proc(all) failing (always).
		 */
		(void) cap_set_proc(raised_for_setpcap);
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    if (cap_set_proc(all) != 0) {
		fprintf(stderr, "Unable to set capabilities [%s]\n", argv[i]);
		exit(1);
	    }
	    /*
	     * Since status is based on orig, we don't want to restore
	     * the previous value of 'all' again here!
	     */

	    cap_free(all);
	} else if (!memcmp("--keep=", argv[i], 7)) {
	    unsigned value;
	    int set;

	    value = strtoul(argv[i]+7, NULL, 0);
	    set = prctl(PR_SET_KEEPCAPS, value);
	    if (set < 0) {
		fprintf(stderr, "prctl(PR_SET_KEEPCAPS, %u) failed: %s\n",
			value, strerror(errno));
		exit(1);
	    }
	} else if (!memcmp("--chroot=", argv[i], 9)) {
	    int status;
	    cap_t orig, raised_for_chroot;

	    orig = cap_get_proc();
	    if (orig == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }

	    raised_for_chroot = cap_dup(orig);
	    if (raised_for_chroot == NULL) {
		perror("Unable to duplicate capabilities");
		exit(1);
	    }

	    if (cap_set_flag(raised_for_chroot, CAP_EFFECTIVE, 1, raise_chroot,
			     CAP_SET) != 0) {
		perror("unable to select CAP_SET_SYS_CHROOT");
		exit(1);
	    }

	    if (cap_set_proc(raised_for_chroot) != 0) {
		perror("unable to raise CAP_SYS_CHROOT");
		exit(1);
	    }
	    cap_free(raised_for_chroot);

	    status = chroot(argv[i]+9);
	    if (cap_set_proc(orig) != 0) {
		perror("unable to lower CAP_SYS_CHROOT");
		exit(1);
	    }
	    /*
	     * Given we are now in a new directory tree, its good practice
	     * to start off in a sane location
	     */
	    status = chdir("/");

	    cap_free(orig);

	    if (status != 0) {
		fprintf(stderr, "Unable to chroot/chdir to [%s]", argv[i]+9);
		exit(1);
	    }
	} else if (!memcmp("--secbits=", argv[i], 10)) {
	    unsigned value;
	    int status;

	    value = strtoul(argv[i]+10, NULL, 0);
	    status = prctl(PR_SET_SECUREBITS, value);
	    if (status < 0) {
		fprintf(stderr, "failed to set securebits to 0%o/0x%x\n",
			value, value);
		exit(1);
	    }
	} else if (!memcmp("--forkfor=", argv[i], 10)) {
	    unsigned value;

	    value = strtoul(argv[i]+10, NULL, 0);
	    if (value == 0) {
		goto usage;
	    }
	    child = fork();
	    if (child < 0) {
		perror("unable to fork()");
	    } else if (!child) {
		sleep(value);
		exit(0);
	    }
	} else if (!memcmp("--killit=", argv[i], 9)) {
	    int retval, status;
	    pid_t result;
	    unsigned value;

	    value = strtoul(argv[i]+9, NULL, 0);
	    if (!child) {
		fprintf(stderr, "no forked process to kill\n");
		exit(1);
	    }
	    retval = kill(child, value);
	    if (retval != 0) {
		perror("Unable to kill child process");
		exit(1);
	    }
	    result = waitpid(child, &status, 0);
	    if (result != child) {
		fprintf(stderr, "waitpid didn't match child: %u != %u\n",
			child, result);
		exit(1);
	    }
	    if (WTERMSIG(status) != value) {
		fprintf(stderr, "child terminated with odd signal (%d != %d)\n"
			, value, WTERMSIG(status));
		exit(1);
	    }
	} else if (!memcmp("--uid=", argv[i], 6)) {
	    unsigned value;
	    int status;

	    value = strtoul(argv[i]+6, NULL, 0);
	    status = setuid(value);
	    if (status < 0) {
		fprintf(stderr, "Failed to set uid=%u: %s\n",
			value, strerror(errno));
		exit(1);
	    }
	} else if (!memcmp("--gid=", argv[i], 6)) {
	    unsigned value;
	    int status;

	    value = strtoul(argv[i]+6, NULL, 0);
	    status = setgid(value);
	    if (status < 0) {
		fprintf(stderr, "Failed to set gid=%u: %s\n",
			value, strerror(errno));
		exit(1);
	    }
        } else if (!memcmp("--groups=", argv[i], 9)) {
	  char *ptr, *buf;
	  long length, max_groups;
	  gid_t *group_list;
	  int g_count;

	  length = sysconf(_SC_GETGR_R_SIZE_MAX);
	  buf = calloc(1, length);
	  if (NULL == buf) {
	    fprintf(stderr, "No memory for [%s] operation\n", argv[i]);
	    exit(1);
	  }

	  max_groups = sysconf(_SC_NGROUPS_MAX);
	  group_list = calloc(max_groups, sizeof(gid_t));
	  if (NULL == group_list) {
	    fprintf(stderr, "No memory for gid list\n");
	    exit(1);
	  }

	  g_count = 0;
	  for (ptr = argv[i] + 9; (ptr = strtok(ptr, ","));
	       ptr = NULL, g_count++) {
	    if (max_groups <= g_count) {
	      fprintf(stderr, "Too many groups specified (%d)\n", g_count);
	      exit(1);
	    }
	    if (!isdigit(*ptr)) {
	      struct group *g, grp;
	      getgrnam_r(ptr, &grp, buf, length, &g);
	      if (NULL == g) {
		fprintf(stderr, "Failed to identify gid for group [%s]\n", ptr);
		exit(1);
	      }
	      group_list[g_count] = g->gr_gid;
	    } else {
	      group_list[g_count] = strtoul(ptr, NULL, 0);
	    }
	  }
	  free(buf);
	  if (setgroups(g_count, group_list) != 0) {
	    fprintf(stderr, "Failed to setgroups.\n");
	    exit(1);
	  }
	  free(group_list);
	} else if (!memcmp("--user="******"User [%s] not known\n", user);
	      exit(1);
	    }
	    ngroups = MAX_GROUPS;
	    status = getgrouplist(user, pwd->pw_gid, groups, &ngroups);
	    if (status < 1) {
	      perror("Unable to get group list for user");
	      exit(1);
	    }
	    status = setgroups(ngroups, groups);
	    if (status != 0) {
	      perror("Unable to set group list for user");
	      exit(1);
	    }
	    status = setgid(pwd->pw_gid);
	    if (status < 0) {
		fprintf(stderr, "Failed to set gid=%u(user=%s): %s\n",
			pwd->pw_gid, user, strerror(errno));
		exit(1);
	    }
	    status = setuid(pwd->pw_uid);
	    if (status < 0) {
		fprintf(stderr, "Failed to set uid=%u(user=%s): %s\n",
			pwd->pw_uid, user, strerror(errno));
		exit(1);
	    }
	} else if (!memcmp("--decode=", argv[i], 9)) {
	    unsigned long long value;
	    unsigned cap;
	    const char *sep = "";

	    /* Note, if capabilities become longer than 64-bits we'll need
	       to fixup the following code.. */
	    value = strtoull(argv[i]+9, NULL, 16);
	    printf("0x%016llx=", value);

	    for (cap=0; (cap < 64) && (value >> cap); ++cap) {
		if (value & (1ULL << cap)) {
		    char *ptr;

		    ptr = cap_to_name(cap);
		    if (ptr != NULL) {
			printf("%s%s", sep, ptr);
			cap_free(ptr);
		    } else {
			printf("%s%u", sep, cap);
		    }
		    sep = ",";
		}
	    }
	    printf("\n");
        } else if (!memcmp("--supports=", argv[i], 11)) {
示例#15
0
int caps_actually_set_test(void)
{
	int whichcap, finalret = 0, ret;
	cap_t fcap, pcap, cap_fullpi;
	cap_value_t capvalue[1];
	int i;

	fcap = cap_init();
	pcap = cap_init();
	if (!fcap || !pcap) {
		perror("cap_init");
		exit(2);
	}

	create_fifo();

	int num_caps;

	for (num_caps = 0;; num_caps++) {
		ret = prctl(PR_CAPBSET_READ, num_caps);
		/*
		 * Break from the loop in this manner to avoid incrementing,
		 * then having to decrement value.
		 */
		if (ret == -1)
			break;
	}

	/* first, try each bit in fP (forced) with fE on and off. */
	for (whichcap = 0; whichcap < num_caps; whichcap++) {
		/*
		 * fP=whichcap, fE=fI=0
		 * pP'=whichcap, pI'=pE'=0
		 */
		capvalue[0] = whichcap;
		cap_clear(fcap);
		cap_set_flag(fcap, CAP_PERMITTED, 1, capvalue, CAP_SET);
		ret = cap_set_file(TSTPATH, fcap);
		if (ret) {
			tst_resm(TINFO, "%d\n", whichcap);
			continue;
		}
		ret = fork_drop_and_exec(DROP_PERMS, fcap);
		if (ret) {
			tst_resm(TINFO,
				 "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=0\n",
				 whichcap);
			if (!finalret)
				finalret = ret;
		}

/* SERGE here */
		/*
		 * fP = fE = whichcap, fI = 0
		 * pP = pE = whichcap, pI = 0
		 */
		cap_clear(fcap);
		cap_set_flag(fcap, CAP_PERMITTED, 1, capvalue, CAP_SET);
		cap_set_flag(fcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET);
		ret = cap_set_file(TSTPATH, fcap);
		if (ret) {
			tst_resm(TINFO, "%d\n", whichcap);
			continue;
		}
		ret = fork_drop_and_exec(DROP_PERMS, fcap);
		if (ret) {
			tst_resm(TINFO,
				 "Failed CAP_PERMITTED=%d CAP_EFFECTIVE=1\n",
				 whichcap);
			if (!finalret)
				finalret = ret;
		}
	}

	cap_free(pcap);
	cap_free(fcap);
	cap_fullpi = cap_init();
	for (i = 0; i < num_caps; i++) {
		capvalue[0] = i;
		cap_set_flag(cap_fullpi, CAP_INHERITABLE, 1, capvalue, CAP_SET);
	}

	/*
	 * For the inheritable tests, we want to make sure pI starts
	 * filled.
	 */
	ret = cap_set_proc(cap_fullpi);
	if (ret)
		tst_resm(TINFO, "Could not fill pI.  pI tests will fail.\n");

	/*
	 * next try each bit in fI
	 * The first two attemps have the bit which is in fI in pI.
	 *     This should result in the bit being in pP'.
	 *     If fE was set then it should also be in pE'.
	 * The last attempt starts with an empty pI.
	 *     This should result in empty capability, as there were
	 *     no bits to be inherited from the original process.
	 */
	for (whichcap = 0; whichcap < num_caps; whichcap++) {
		cap_t cmpcap;
		capvalue[0] = whichcap;

		/*
		 * fI=whichcap, fP=fE=0
		 * pI=full
		 * pI'=full, pP'=whichcap, pE'=0
		 */
		/* fill pI' */
		pcap = cap_dup(cap_fullpi);
		/* pP' = whichcap */
		cap_set_flag(pcap, CAP_PERMITTED, 1, capvalue, CAP_SET);

		/* fI = whichcap */
		fcap = cap_init();
		cap_set_flag(fcap, CAP_INHERITABLE, 1, capvalue, CAP_SET);
		ret = cap_set_file(TSTPATH, fcap);
		if (ret) {
			tst_resm(TINFO, "%d\n", whichcap);
			continue;
		}
		ret = fork_drop_and_exec(KEEP_PERMS, pcap);
		if (ret) {
			tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d "
				 "CAP_EFFECTIVE=0\n", whichcap);
			if (!finalret)
				finalret = ret;
		}

		/*
		 * fI=fE=whichcap, fP=0
		 * pI=full
		 * pI'=full, pP'=whichcap, pE'=whichcap
		 *
		 * Note that only fE and pE' change, so keep prior
		 * fcap and pcap and set those bits.
		 */

		cap_set_flag(fcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET);
		cap_set_flag(pcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET);
		ret = cap_set_file(TSTPATH, fcap);
		if (ret) {
			tst_resm(TINFO, "%d\n", whichcap);
			continue;
		}
		/* The actual result will be a full pI, with
		 * pE and pP containing just whichcap. */
		cmpcap = cap_dup(cap_fullpi);
		cap_set_flag(cmpcap, CAP_PERMITTED, 1, capvalue, CAP_SET);
		cap_set_flag(cmpcap, CAP_EFFECTIVE, 1, capvalue, CAP_SET);
		ret = fork_drop_and_exec(KEEP_PERMS, cmpcap);
		cap_free(cmpcap);
		if (ret) {
			tst_resm(TINFO, "Failed with_perms CAP_INHERITABLE=%d "
				 "CAP_EFFECTIVE=1\n", whichcap);
			if (!finalret)
				finalret = ret;
		}

		/*
		 * fI=fE=whichcap, fP=0  (so fcap is same as before)
		 * pI=0  (achieved using DROP_PERMS)
		 * pI'=pP'=pE'=0
		 */
		cap_clear(pcap);
		ret = fork_drop_and_exec(DROP_PERMS, pcap);
		if (ret) {
			tst_resm(TINFO,
				 "Failed without_perms CAP_INHERITABLE=%d",
				 whichcap);
			if (!finalret)
				finalret = ret;
		}

		cap_free(fcap);
		cap_free(pcap);
	}

	cap_free(cap_fullpi);

	return finalret;
}
示例#16
0
void limit_capabilities(void)
{
#ifdef CAPABILITIES
	cap_t cap_cur_p;
	cap_t cap_p;
	cap_flag_value_t cap_ok;

	cap_cur_p = cap_get_proc();
	if (!cap_cur_p) {
		perror("ping: cap_get_proc");
		exit(-1);
	}

	cap_p = cap_init();
	if (!cap_p) {
		perror("ping: cap_init");
		exit(-1);
	}

	cap_ok = CAP_CLEAR;
	cap_get_flag(cap_cur_p, CAP_NET_ADMIN, CAP_PERMITTED, &cap_ok);

	if (cap_ok != CAP_CLEAR)
		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_admin, CAP_SET);

	cap_ok = CAP_CLEAR;
	cap_get_flag(cap_cur_p, CAP_NET_RAW, CAP_PERMITTED, &cap_ok);

	if (cap_ok != CAP_CLEAR)
		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_raw, CAP_SET);

	if (cap_set_proc(cap_p) < 0) {
		perror("ping: cap_set_proc");
		exit(-1);
	}

	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
		perror("ping: prctl");
		exit(-1);
	}

	if (setuid(getuid()) < 0) {
		perror("setuid");
		exit(-1);
	}

	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
		perror("ping: prctl");
		exit(-1);
	}

	cap_free(cap_p);
	cap_free(cap_cur_p);
#endif
	uid = getuid();
	euid = geteuid();
#ifndef CAPABILITIES
	if (seteuid(uid)) {
		perror("ping: setuid");
		exit(-1);
	}
#endif
}
示例#17
0
static int reduce_capabilities(void)
{
	int ret = 0;

#ifdef CONFIG_ALFRED_CAPABILITIES
	cap_t cap_cur;
	cap_t cap_new;
	cap_flag_value_t cap_flag;
	cap_value_t cap_net_raw = CAP_NET_RAW;

	/* get current process capabilities */
	cap_cur = cap_get_proc();
	if (!cap_cur) {
		perror("cap_get_proc");
		return -1;
	}

	/* create new capabilities */
	cap_new = cap_init();
	if (!cap_new) {
		perror("cap_init");
		cap_free(cap_new);
		return -1;
	}

	/* copy capability as non-effictive but permitted */
	cap_flag = CAP_CLEAR;
	cap_get_flag(cap_cur, CAP_NET_RAW, CAP_PERMITTED, &cap_flag);
	if (cap_flag != CAP_CLEAR) {
		ret = cap_set_flag(cap_new, CAP_PERMITTED, 1, &cap_net_raw,
				   CAP_SET);
		if (ret < 0) {
			perror("cap_set_flag");
			goto out;
		}
	}

	/* set minimal capabilities field */
	ret = cap_set_proc(cap_new);
	if (ret < 0) {
		perror("cap_set_proc");
		goto out;
	}

	/* don't drop capabilities with setuid */
	ret = prctl(PR_SET_KEEPCAPS, 1);
	if (ret < 0) {
		perror("prctl PR_SET_KEEPCAPS(1)");
		goto out;
	}

	/* drop euid */
	ret = setuid(getuid());
	if (ret < 0) {
		perror("setuid");
		goto out;
	}

	/* drop capabilities with setuid */
	ret = prctl(PR_SET_KEEPCAPS, 0);
	if (ret < 0) {
		perror("prctl PR_SET_KEEPCAPS(0)");
		goto out;
	}

out:
	cap_free(cap_new);
	cap_free(cap_cur);
#endif

	return ret;
}
示例#18
0
int main (int argc, char **argv) {
	unsigned int i;
	unsigned int use_capabilities=0;
	int ret;
	char **newargv;
	char *user=NULL, *tmp=NULL;
	
	struct passwd *pw=NULL;
	struct group *gr=NULL;
	unsigned long ngroups_max=NGROUPS_MAX;
	unsigned long ngroups=0;
	gid_t *gids;
	struct passwd *intpw=NULL; /* for internal_getpwuid() */
	char *jaildir=NULL, *newhome=NULL, *shell=NULL;
	Tiniparser *parser=NULL;
	char **envs=NULL;
	unsigned int relax_home_group_permissions=0;
	unsigned int relax_home_other_permissions=0;
	unsigned int relax_home_group=0;
	char *injail_shell=NULL;
	unsigned int skip_injail_passwd_check=0;

	DEBUG_MSG(PROGRAMNAME", started\n");
	/* open the log facility */
	openlog(PROGRAMNAME, LOG_PID, LOG_AUTH);
	
	/* attach signal handler */
	signal(SIGILL,signal_handler);
	signal(SIGSEGV,signal_handler);
	signal(SIGTERM,signal_handler);
	signal(SIGFPE,signal_handler);
	
	/* check if it PRORAMNAME that the user wants */
	tmp = strrchr(argv[0], '/');
	if (!tmp) {
		tmp = argv[0];
	} else {
		tmp++;
	}
	
	if (strcmp(tmp, PROGRAMNAME) != 0 && strcmp(tmp, "su")!= 0 && (tmp[0] != '-' || strcmp(&tmp[1], PROGRAMNAME))) {
		DEBUG_MSG("wrong name, tmp=%s, &tmp[1]=%s\n", tmp, &tmp[1]);
		syslog(LOG_ERR, "abort, "PROGRAMNAME" is called as %s", argv[0]);
		exit(1);
	}

	/* now test if we are setuid root (the effective user id must be 0, and the real user id > 0 */
	if (geteuid() != 0) {
		if (have_capabilities()) {
			use_capabilities=1;
		} else {
			syslog(LOG_ERR, "abort, effective user ID is not 0, possibly "PROGRAMNAME" is not setuid root");
			exit(11);
		}
	}
	if (getuid() == 0) {
		syslog(LOG_ERR, "abort, "PROGRAMNAME" is run by root, which does not make sense because user root can break out of a jail anyway");
		exit(12);
	}

	DEBUG_MSG("get user info\n");
	/* get user info based on the users name and not on the uid. this enables support
	for systems with multiple users with the same user id */ 
	tmp = getenv("USER");
	if (tmp && strlen(tmp)) {
		user = strdup(tmp);
	}
	if (user) {
		pw = getpwnam(user);
	} else {
		pw = getpwuid(getuid());
	}
	if (!pw) {
		syslog(LOG_ERR, "abort, failed to get user information for user ID %d: %s, check /etc/passwd", getuid(), strerror(errno));
		exit(13);
	}
	if (!pw->pw_name || strlen(pw->pw_name)==0) {
		syslog(LOG_ERR, "abort, got an empty username for user ID %d: %s, check /etc/passwd", getuid(), strerror(errno));
		exit(13);
	}
	if (user && strcmp(user,pw->pw_name)!=0) {
		syslog(LOG_ERR, "abort, asked for user %s, got user info for %s", user, pw->pw_name);
		exit(13);
	}
	if (pw->pw_uid != getuid()) {
		syslog(LOG_ERR, "abort, started by user ID %d, got user info %s with user ID %d,", getuid(), pw->pw_name, pw->pw_uid);
		exit(13);
	}
	DEBUG_MSG("got user %s\nget group info\n",pw->pw_name);
	gr = getgrgid(getgid());
	if (!gr) {
		syslog(LOG_ERR, "abort, failed to get group information for group ID %d: %s, check /etc/group", getgid(), strerror(errno));
		exit(13);
	}
	DEBUG_MSG("get additional groups\n");
	/* ngroups_max = sysconf(_SC_NGROUPS_MAX);*/
	gids = malloc(ngroups_max * sizeof(gid_t));
	ngroups = getgroups(ngroups_max,gids);
	if (ngroups == -1) {
		syslog(LOG_ERR, "abort, failed to get additional group information: %s, check /etc/group", strerror(errno));
		exit(13);
	}
#ifdef DEBUG
	printf("got additional groups ");
	for (i=0;i<ngroups;i++) {
		printf("%d, ",gids[i]);
	}
	printf("\n");
#endif

	/* make sure the jailkit config directory is owned root:root and not writable for others */
	if ( (testsafepath(INIPREFIX, 0, 0) &~TESTPATH_GROUPW) != 0 ) {
		syslog(LOG_ERR, "abort, jailkit configuration directory "INIPREFIX" is not safe; it should be owned 0:0 and not writable for others");
		exit(14);
	}
	parser = new_iniparser(CONFIGFILE);
	if (parser) {
		char *groupsec, *section=NULL, buffer[1024]; /* openbsd complains if this is <1024 */
		groupsec = strcat(strcpy(malloc0(strlen(gr->gr_name)+7), "group "), gr->gr_name);
		if (iniparser_has_section(parser, pw->pw_name)) {
			section = strdup(pw->pw_name);
		} else if (iniparser_has_section(parser, groupsec)) {
			section = groupsec;
		} else if (iniparser_has_section(parser, "DEFAULT")) {
			section = strdup("DEFAULT");
		}
		if (section != groupsec) free(groupsec);
		if (section) {
			unsigned int pos = iniparser_get_position(parser) - strlen(section) - 2;
			
			if (iniparser_get_string_at_position(parser, section, "env", pos, buffer, 1024) > 0) {
				envs = explode_string(buffer, ',');
			}
			relax_home_group_permissions = iniparser_get_int_at_position(parser, section, "relax_home_group_permissions", pos);
			relax_home_other_permissions = iniparser_get_int_at_position(parser, section, "relax_home_other_permissions", pos);
			relax_home_group = iniparser_get_int_at_position(parser, section, "relax_home_group", pos);
			if (iniparser_get_string_at_position(parser, section, "injail_shell", pos, buffer, 1024) > 0) {
				injail_shell = strdup(buffer);
			}
			if (injail_shell) {
				skip_injail_passwd_check = iniparser_get_int_at_position(parser, section, "skip_injail_passwd_check", pos);
			}
			DEBUG_MSG("section %s: relax_home_group_permissions=%d, relax_home_other_permissions=%d, relax_home_group=%d, injail_shell=%s, skip_injail_passwd_check=%d\n",
					section, relax_home_group_permissions, relax_home_other_permissions, 
					relax_home_group, injail_shell, skip_injail_passwd_check);
			free(section);
		} else {
			DEBUG_MSG("no relevant section found in configfile\n");
		}
		iniparser_close(parser);
	} else {
		DEBUG_MSG("no configfile "CONFIGFILE" ??\n");
	}

	DEBUG_MSG("close filedescriptors\n");
	/* open file descriptors can be used to break out of a chroot, so we close all of them, except for stdin,stdout and stderr */
#ifdef OPEN_MAX
    i = OPEN_MAX;
#elif defined(NOFILE)
    i = NOFILE;
#else
    i = getdtablesize();
#endif
	while (--i > 2) {
		/*printf("closing file descriptor %d\n",i);*/
		while (close(i) != 0 && errno == EINTR);
	}
	/* now make sure file descriptors 0 1 and 2 are valid before we (or a child) starts writing to it */
	while (1) {
		int fd;
		fd = open("/dev/null", O_RDWR);
		if (fd < 0)
			exit(10);
		if (fd > 2) {
			close(fd);
			break;
		} else {
			DEBUG_MSG("re-opening file descriptor %d\n",fd);
		}
	}

	/* now we clear the environment, except for values allowed in /etc/jailkit/jk_chrootsh.ini */	
	unset_environ_except(envs);
	if (envs) {
		free_array(envs);
	}
	
	if (pw->pw_gid != getgid()) {
		syslog(LOG_ERR, "abort, the group ID from /etc/passwd (%d) does not match the group ID we run with (%d)", pw->pw_gid, getgid());
		exit(15);
	}
	if (!pw->pw_dir || strlen(pw->pw_dir) ==0) {
		syslog(LOG_ERR, "abort, got an empty home directory for user %s (%d)", pw->pw_name, getuid());
		exit(16);
	}
	if (strstr(pw->pw_dir, "/./") == NULL) {
		syslog(LOG_ERR, "abort, homedir '%s' for user %s (%d) does not contain the jail separator <jail>/./<home>", pw->pw_dir, pw->pw_name, getuid());
		exit(17);
	}
	DEBUG_MSG("get jaildir\n");
	if (!getjaildir(pw->pw_dir, &jaildir, &newhome)) {
		syslog(LOG_ERR, "abort, failed to read the jail and the home from %s for user %s (%d)",pw->pw_dir, pw->pw_name, getuid());
		exit(17);
	}
	DEBUG_MSG("dir=%s,jaildir=%s,newhome=%s\n",pw->pw_dir, jaildir, newhome);
	DEBUG_MSG("get chdir()\n");
	if (chdir(jaildir) != 0) {
		syslog(LOG_ERR, "abort, chdir(%s) failed: %s, check the permissions for %s",jaildir,strerror(errno),jaildir);
		exit(19);
	} else {
		char test[1024];
		/* test if it really succeeded */
		if (getcwd(test, 1024)==NULL || !dirs_equal(jaildir, test)) {
			syslog(LOG_ERR, "abort, the current dir is %s after chdir(%s), but it should be %s",test,jaildir,jaildir);
			exit(21);
		}		
	}		
	
	/* here do test the ownership of the jail and the homedir and such
	the function testsafepath doe exit itself on any failure */
	if (!basicjailissafe(jaildir)) {
		syslog(LOG_ERR, "abort, %s is not a safe chroot jail.", jaildir);
		exit(53);
	} 
	ret = testsafepath(pw->pw_dir, getuid(), getgid());
	if ((ret & TESTPATH_NOREGPATH) ) {
		syslog(LOG_ERR, "abort, path %s is not a directory", pw->pw_dir);
		exit(53);	
	}
	if ((ret & TESTPATH_OWNER) ) {
		syslog(LOG_ERR, "abort, path %s is not owned by %d", pw->pw_dir,getuid());
		exit(53);
	}
	if (!relax_home_group && (ret & TESTPATH_GROUP)) {
		syslog(LOG_ERR, "abort, path %s does not have group owner %d, set option 'relax_home_group' to relax this check", pw->pw_dir,getgid());
		exit(53);
	}
	if (!relax_home_group_permissions && (ret & TESTPATH_GROUPW)) {
		syslog(LOG_ERR, "abort, path %s is group writable, set option 'relax_home_group_permissions' to relax this check", pw->pw_dir);
		exit(53);
	}
	if (!relax_home_other_permissions && (ret & TESTPATH_OTHERW)) {
		syslog(LOG_ERR, "abort, path %s is writable for other, set option 'relax_home_other_permissions' to relax this check", pw->pw_dir);
		exit(53);
	}
	/* do a final log message */
	tmp = implode_array(&argv[1], argc-1, " ");
	syslog(LOG_INFO, "now entering jail %s for user %s (%d) with arguments %s", jaildir, pw->pw_name, getuid(), tmp);
	free(tmp);
	
	DEBUG_MSG("chroot()\n");
	/* do the chroot() call */
	if (chroot(jaildir)) {
		syslog(LOG_ERR, "abort, chroot(%s) failed: %s, check the permissions for %s", jaildir, strerror(errno), jaildir);
		exit(33);
	}
	
	if (use_capabilities) {
#ifdef HAVE_CAP_GET_PROC
		cap_t caps;
		cap_value_t capv[1];
		/* drop chroot capability, should we drop all other capabilities that may be used to escape from the jail too ?  */
		if ((caps = cap_get_proc()) == NULL) {
			syslog(LOG_ERR, "abort, failed to retrieve current capabilities: %s", strerror(errno));
			exit(101);
		}
		capv[0] = CAP_SYS_CHROOT;
		/* other capabilities that should/could be dropped:
		CAP_SETPCAP, CAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_SYS_PTRACE, CAP_SYS_ADMIN */
		if (cap_set_flag(caps, CAP_PERMITTED, 1, capv, CAP_CLEAR)) {
			syslog(LOG_ERR, "abort, failed to set PERMITTED capabilities: %s", strerror(errno));
			exit(102);
		}
		if (cap_set_flag(caps, CAP_EFFECTIVE, 1, capv, CAP_CLEAR)) {
			syslog(LOG_ERR, "abort, failed to set effective capabilities: %s", strerror(errno));
			exit(103);
		}
		if (cap_set_flag(caps, CAP_INHERITABLE, 1, capv, CAP_CLEAR)) {
			syslog(LOG_ERR, "abort, failed to set INHERITABLE capabilities: %s", strerror(errno));
			exit(104);
		}
		if (cap_set_proc(caps)) {
			syslog(LOG_ERR, "abort, failed to apply new capabilities: %s", strerror(errno));
			exit(105);
		}
#else
		/* we should never get here */
		exit(333);
#endif
	} else {
		/* drop all privileges, it seems that we first have to setgid(), 
			then we have to call initgroups(), 
			then we call setuid() */
		if (setgid(getgid())) {
			syslog(LOG_ERR, "abort, failed to set effective group ID %d: %s", getgid(), strerror(errno));
			exit(34);
		}
		if (setgroups(ngroups, gids)==-1) {
			syslog(LOG_ERR, "abort, failed to set additional groups: %s", strerror(errno));
			exit(35);
		}
		free(gids);
	/*	if (initgroups(pw->pw_name, getgid())) {
			syslog(LOG_ERR, "abort, failed to init groups for user %s (%d), check %s/etc/group", pw->pw_name,getuid(),jaildir);
			exit(35);
		}*/
		if (setuid(getuid())) {
			syslog(LOG_ERR, "abort, failed to set effective user ID %d: %s", getuid(), strerror(errno));
			exit(36);
		}
	}
	/* test for user and group info, is it the same? checks username, groupname and home */
	if (!skip_injail_passwd_check){
		char *oldpw_name,*oldgr_name;
		oldpw_name = strdup(pw->pw_name);
		oldgr_name = strdup(gr->gr_name);
		
		if (user) {
			pw = getpwnam(user);
		} else {
			pw = getpwuid(getuid());
		}
		if (!pw) {
			syslog(LOG_ERR, "abort, failed to get user information in the jail for user ID %d: %s, check %s/etc/passwd",getuid(),strerror(errno),jaildir);
			exit(35);
		}
		if (pw->pw_uid != getuid()) {
			syslog(LOG_ERR, "abort, got user information in the jail for user ID %d instead of user ID %d, check %s/etc/passwd",pw->pw_uid,getuid(),jaildir);
			exit(35);
		}
		DEBUG_MSG("got %s as pw_dir\n",pw->pw_dir);
		gr = getgrgid(getgid());
		if (!gr) {
			syslog(LOG_ERR, "abort, failed to get group information in the jail for group ID %d: %s, check %s/etc/group",getgid(),strerror(errno),jaildir);
			exit(35);
		}
		if (strcmp(pw->pw_name, oldpw_name)!=0) {
			syslog(LOG_ERR, "abort, username %s differs from jail username %s for user ID %d, check /etc/passwd and %s/etc/passwd", oldpw_name, pw->pw_name, getuid(), jaildir);
			exit(37);
		}
		if (strcmp(gr->gr_name, oldgr_name)!=0) {
			syslog(LOG_ERR, "abort, groupname %s differs from jail groupname %s for group ID %d, check /etc/passwd and %s/etc/passwd", oldgr_name, gr->gr_name, getgid(), jaildir);
			exit(37);
		}
		if (strcmp(pw->pw_dir, newhome)!=0) {
			DEBUG_MSG("%s!=%s\n",pw->pw_dir, newhome);
			/* if these are different, it could be that getpwuid() gets the real user 
			info (from for example ldap or nscd), and not the info inside the jail, lets 
			test that, and if true, we should use the	shell from the internal function as well*/
			intpw = internal_getpwuid("/etc/passwd", getuid());
			if (!intpw) {
				DEBUG_MSG("%s!=%s\n",intpw->pw_dir, newhome);
				syslog(LOG_ERR, "abort, failed to find user %d in %s/etc/passwd", getuid(), jaildir);
				exit(39);
			}
			if (!dirs_equal(intpw->pw_dir, newhome)) {
				DEBUG_MSG("%s!=%s\n",intpw->pw_dir, newhome);
				syslog(LOG_ERR, "abort, home directory %s differs from jail home directory %s for user %s (%d), check /etc/passwd and %s/etc/passwd", newhome, pw->pw_dir, pw->pw_name, getuid(), jaildir);
				exit(39);
			}
		}
		free(oldpw_name);
		free(oldgr_name);
	}
	if (injail_shell) {
		shell = injail_shell;
	} else if (intpw) {
		shell = intpw->pw_shell;
	} else {
		shell = pw->pw_shell;
	}
	/* test the shell in the jail, it is not allowed to be setuid() root */
	testsafepath(shell,0,0);

	/* prepare the new environment */
	setenv("HOME",newhome,1);
	setenv("USER",pw->pw_name,1);
	setenv("USERNAME",pw->pw_name,1);
	setenv("SHELL",shell,1);
	if (chdir(newhome) != 0) {
		syslog(LOG_ERR, "abort, chdir(%s) failed inside the jail %s: %s, check the permissions for %s/%s",newhome,jaildir,strerror(errno),jaildir,newhome);
		exit(41);
	}

	/* cleanup before execution */
	free(newhome);
	
	/* now execute the jailed shell */
	/*execl(pw->pw_shell, pw->pw_shell, NULL);*/
	newargv = malloc0((argc+1)*sizeof(char *));
	newargv[0] = shell;
	for (i=1;i<argc;i++) {
		newargv[i] = argv[i];
	}
	execv(shell, newargv);
	DEBUG_MSG(strerror(errno));
	syslog(LOG_ERR, "ERROR: failed to execute shell %s for user %s (%d), check the permissions and libraries of %s/%s",shell,pw->pw_name,getuid(),jaildir,shell);

	free(jaildir);
	exit(111);
}
static int process_security_set_cap(request_rec *r)
{

    int ncap;
    cap_t cap;
    cap_value_t capval[3];
    gid_t gid;
    uid_t uid;

    ncap = 2;

    process_security_dir_config_t *dconf = ap_get_module_config(r->per_dir_config, &process_security_module);
    process_security_config_t *conf = ap_get_module_config(r->server->module_config, &process_security_module);

    if (dconf->process_security_mode==PS_MODE_STAT || dconf->process_security_mode==PS_MODE_UNDEFINED) {
        gid = r->finfo.group;
        uid = r->finfo.user;
    } else {
        gid = conf->default_gid;
        uid = conf->default_uid;
    }

    cap       = cap_init();
    capval[0] = CAP_SETUID;
    capval[1] = CAP_SETGID;
    cap_set_flag(cap, CAP_PERMITTED, ncap, capval, CAP_SET);

    if (cap_set_proc(cap) != 0)
        ap_log_error(APLOG_MARK
            , APLOG_ERR
            , 0
            , NULL
            , "%s ERROR %s:cap_set_proc failed"
            , MODULE_NAME
            , __func__
        );

    cap_free(cap);
    coredump = prctl(PR_GET_DUMPABLE);

    cap = cap_get_proc();
    cap_set_flag(cap, CAP_EFFECTIVE, ncap, capval, CAP_SET);

    if (cap_set_proc(cap) != 0)
        ap_log_error (APLOG_MARK
            , APLOG_ERR
            , 0
            , NULL
            , "%s ERROR %s:cap_set_proc failed before setuid"
            , MODULE_NAME
            , __func__
        );

    cap_free(cap);

    setgroups(0, NULL);
    setgid(gid);
    setuid(uid);

    cap = cap_get_proc();
    cap_set_flag(cap, CAP_EFFECTIVE, ncap, capval, CAP_CLEAR);
    cap_set_flag(cap, CAP_PERMITTED, ncap, capval, CAP_CLEAR);
    if (cap_set_proc(cap) != 0) {
        ap_log_error (APLOG_MARK
            , APLOG_ERR
            , 0
            , NULL
            , "%s ERROR %s:cap_set_proc failed after setuid"
            , MODULE_NAME
            , __func__
        );
    }
    cap_free(cap);

    if (coredump)
        prctl(PR_SET_DUMPABLE, 1);

    return OK;

}
示例#20
0
int main(int argc,
         char *arg[]) {

  cap_t capabilities;
  cap_value_t capabilies_list[1];

  capabilities = cap_get_proc();
  if (NULL == capabilities) {
    printf("Could not get capabilities\n");
    exit(0);
  }

  capabilies_list[0] = CAP_NET_RAW;
  if (-1
      == cap_set_flag(capabilities, CAP_EFFECTIVE, 1, capabilies_list,
                      CAP_SET) ) {
    cap_free(capabilities);
    printf("Could not set CAP_NET_RAW capability\n");
    exit(0);
  }

  if (-1 == cap_set_proc(capabilities) ) {
    cap_free(capabilities);
    printf("Could not push CAP_NET_RAW capability to process\n");
    exit(0);
  }

  if (-1 == cap_free(capabilities) ) {
    printf("Could not free capabilites value\n");
    exit(0);
  }

  if (argc != 2) {
    printf("Wrong number of command line parameters!\n");
    printf("The correct command line parameters are:\n");
    printf("./OpENer interfacename\n");
    printf("    e.g. ./OpENer eth1\n");
    exit(0);
  } else {
    DoublyLinkedListInitialize(&connection_list,
                               CipConnectionObjectListArrayAllocator,
                               CipConnectionObjectListArrayFree);
    /* fetch Internet address info from the platform */
    if (kEipStatusError == ConfigureNetworkInterface(arg[1]) ) {
      printf("Network interface %s not found.\n", arg[1]);
      exit(0);
    }
    ConfigureDomainName();
    ConfigureHostName();

    ConfigureMacAddress(arg[1]);
  }

  /* for a real device the serial number should be unique per device */
  SetDeviceSerialNumber(123456789);

  /* unique_connection_id should be sufficiently random or incremented and stored
   *  in non-volatile memory each time the device boots.
   */
  EipUint16 unique_connection_id = rand();

  /* Setup the CIP Layer */
  CipStackInit(unique_connection_id);

  /* Setup Network Handles */
  if (kEipStatusOk == NetworkHandlerInitialize() ) {
    g_end_stack = 0;
#ifndef WIN32
    /* register for closing signals so that we can trigger the stack to end */
    signal(SIGHUP, LeaveStack);
#endif
#ifdef OPENER_RT
    /* Memory lock all*/
    if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
      OPENER_TRACE_ERR("mlockall failed: %m\n");
      exit(-2);
    }

    struct sched_param param;
    pthread_attr_t attr;
    pthread_t thread;
    CipUint ret = pthread_attr_init(&attr);
    if (ret) {
      OPENER_TRACE_ERR("init pthread attributes failed\n");
      exit(-2);
    }

    /* Set stack size  */
    ret = pthread_attr_setstacksize(&attr,
                                    PTHREAD_STACK_MIN + OPENER_RT_THREAD_SIZE);
    if (ret) {
      OPENER_TRACE_ERR("setstacksize failed\n");
      exit(-2);
    }

    /* Set policy and priority of the thread */
    ret = pthread_attr_setschedpolicy(&attr, SCHED_RR);
    if (ret) {
      OPENER_TRACE_ERR("setschedpolicy failed\n");
      exit(-2);
    }
    param.sched_priority = 80;
    ret = pthread_attr_setschedparam(&attr, &param);
    if (ret) {
      OPENER_TRACE_ERR("pthread setschedparam failed\n");
      exit(-2);
    }
    /* scheduling parameters */
    ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    if (ret) {
      OPENER_TRACE_ERR("setinheritsched failed\n");
      exit(-2);
    }

    /* Create a thread with the specified attributes */
    ret = pthread_create(&thread, &attr, executeEventLoop, NULL);
    if (ret) {
      OPENER_TRACE_ERR("create pthread failed\n");
      exit(-2);
    }

    /* Join the thread */
    ret = pthread_join(thread, NULL);
    if (ret) {
      OPENER_TRACE_ERR("join pthread failed: %m\n");
    }
    /* Unlock memory */
    munlockall();
#else
    executeEventLoop();
#endif
    /* clean up network state */
    NetworkHandlerFinish();
  }
  /* close remaining sessions and connections, cleanup used data */
  ShutdownCipStack();

  return -1;
}
示例#21
0
int main(int argc, char **argv)
{
	bool fork_desired = TRUE;
	bool log_to_stderr_desired = FALSE;
	bool nat_traversal = FALSE;
	bool nat_t_spf = TRUE;  /* support port floating */
	unsigned int keep_alive = 0;
	bool force_keepalive = FALSE;
	char *virtual_private = NULL;
	int lockfd;
#ifdef CAPABILITIES
	int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
#endif /* CAPABILITIES */

	/* initialize library and optionsfrom */
	if (!library_init(NULL))
	{
		library_deinit();
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (!libhydra_init("pluto"))
	{
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	if (!pluto_init(argv[0]))
	{
		pluto_deinit();
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_DAEMON_INTEGRITY);
	}
	options = options_create();

	/* handle arguments */
	for (;;)
	{
#       define DBG_OFFSET 256
		static const struct option long_opts[] = {
			/* name, has_arg, flag, val */
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "optionsfrom", required_argument, NULL, '+' },
			{ "nofork", no_argument, NULL, 'd' },
			{ "stderrlog", no_argument, NULL, 'e' },
			{ "nocrsend", no_argument, NULL, 'c' },
			{ "strictcrlpolicy", no_argument, NULL, 'r' },
			{ "crlcheckinterval", required_argument, NULL, 'x'},
			{ "cachecrls", no_argument, NULL, 'C' },
			{ "uniqueids", no_argument, NULL, 'u' },
      { "disableuniqreqids", no_argument, NULL, 'Z'},			
			{ "interface", required_argument, NULL, 'i' },
			{ "ikeport", required_argument, NULL, 'p' },
			{ "ctlbase", required_argument, NULL, 'b' },
			{ "secretsfile", required_argument, NULL, 's' },
			{ "foodgroupsdir", required_argument, NULL, 'f' },
			{ "perpeerlogbase", required_argument, NULL, 'P' },
			{ "perpeerlog", no_argument, NULL, 'l' },
			{ "policygroupsdir", required_argument, NULL, 'f' },
#ifdef USE_LWRES
			{ "lwdnsq", required_argument, NULL, 'a' },
#else /* !USE_LWRES */
			{ "adns", required_argument, NULL, 'a' },
#endif /* !USE_LWRES */
			{ "pkcs11module", required_argument, NULL, 'm' },
			{ "pkcs11keepstate", no_argument, NULL, 'k' },
			{ "pkcs11initargs", required_argument, NULL, 'z' },
			{ "pkcs11proxy", no_argument, NULL, 'y' },
			{ "nat_traversal", no_argument, NULL, '1' },
			{ "keep_alive", required_argument, NULL, '2' },
			{ "force_keepalive", no_argument, NULL, '3' },
			{ "disable_port_floating", no_argument, NULL, '4' },
			{ "debug-natt", no_argument, NULL, '5' },
			{ "virtual_private", required_argument, NULL, '6' },
#ifdef DEBUG
			{ "debug-none", no_argument, NULL, 'N' },
			{ "debug-all", no_argument, NULL, 'A' },
			{ "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
			{ "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET },
			{ "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
			{ "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET },
			{ "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET },
			{ "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET },
			{ "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET },
			{ "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET },
			{ "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET },
			{ "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET },
			{ "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET },
			{ "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },

			{ "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET },
			{ "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET },
			{ "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
			{ "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
#endif
			{ 0,0,0,0 }
			};
		/* Note: we don't like the way short options get parsed
		 * by getopt_long, so we simply pass an empty string as
		 * the list.  It could be "hvdenp:l:s:" "NARXPECK".
		 */
		int c = getopt_long(argc, argv, "", long_opts, NULL);

		/* Note: "breaking" from case terminates loop */
		switch (c)
		{
		case EOF:       /* end of flags */
			break;

		case 0: /* long option already handled */
			continue;

		case ':':       /* diagnostic already printed by getopt_long */
		case '?':       /* diagnostic already printed by getopt_long */
			usage("");
			break;   /* not actually reached */

		case 'h':       /* --help */
			usage(NULL);
			break;      /* not actually reached */

		case 'v':       /* --version */
			{
				const char **sp = ipsec_copyright_notice();

				printf("strongSwan "VERSION"%s\n", compile_time_interop_options);
				for (; *sp != NULL; sp++)
					puts(*sp);
			}
			exit_pluto(0);
			break;      /* not actually reached */

		case '+':       /* --optionsfrom <filename> */
			if (!options->from(options, optarg, &argc, &argv, optind))
			{
				exit_pluto(1);
			}
			continue;

		case 'd':       /* --nofork*/
			fork_desired = FALSE;
			continue;

		case 'e':       /* --stderrlog */
			log_to_stderr_desired = TRUE;
			continue;

		case 'c':       /* --nocrsend */
			no_cr_send = TRUE;
			continue;

		case 'r':       /* --strictcrlpolicy */
			strict_crl_policy = TRUE;
			continue;

		case 'x':       /* --crlcheckinterval <time>*/
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing interval time");

			{
				char *endptr;
				long interval = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| interval <= 0)
					usage("<interval-time> must be a positive number");
				crl_check_interval = interval;
			}
			continue;

		case 'C':       /* --cachecrls */
			cache_crls = TRUE;
			continue;

		case 'u':       /* --uniqueids */
			uniqueIDs = TRUE;
			continue;
	
	  case 'Z':       /* --disableuniqreqids */
	    disable_uniqreqids = TRUE;
	    continue;

		case 'i':       /* --interface <ifname> */
			if (!use_interface(optarg))
				usage("too many --interface specifications");
			continue;

		case 'p':       /* --port <portnumber> */
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing port number");

			{
				char *endptr;
				long port = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| port <= 0 || port > 0x10000)
					usage("<port-number> must be a number between 1 and 65535");
				pluto_port = port;
			}
			continue;

		case 'b':       /* --ctlbase <path> */
			if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
			, "%s%s", optarg, CTL_SUFFIX) == -1)
				usage("<path>" CTL_SUFFIX " too long for sun_path");
			if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path)
			, "%s%s", optarg, INFO_SUFFIX) == -1)
				usage("<path>" INFO_SUFFIX " too long for sun_path");
			if (snprintf(pluto_lock, sizeof(pluto_lock)
			, "%s%s", optarg, LOCK_SUFFIX) == -1)
				usage("<path>" LOCK_SUFFIX " must fit");
			continue;

		case 's':       /* --secretsfile <secrets-file> */
			shared_secrets_file = optarg;
			continue;

		case 'f':       /* --policygroupsdir <policygroups-dir> */
			policygroups_dir = optarg;
			continue;

		case 'a':       /* --adns <pathname> */
			pluto_adns_option = optarg;
			continue;

		case 'm':       /* --pkcs11module <pathname> */
			pkcs11_module_path = optarg;
			continue;

		case 'k':       /* --pkcs11keepstate */
			pkcs11_keep_state = TRUE;
			continue;

		case 'y':       /* --pkcs11proxy */
			pkcs11_proxy = TRUE;
			continue;

		case 'z':       /* --pkcs11initargs */
			pkcs11_init_args = optarg;
			continue;

#ifdef DEBUG
		case 'N':       /* --debug-none */
			base_debugging = DBG_NONE;
			continue;

		case 'A':       /* --debug-all */
			base_debugging = DBG_ALL;
			continue;
#endif

		case 'P':       /* --perpeerlogbase */
			base_perpeer_logdir = optarg;
			continue;

		case 'l':
			log_to_perpeer = TRUE;
			continue;

		case '1':       /* --nat_traversal */
			nat_traversal = TRUE;
			continue;
		case '2':       /* --keep_alive */
			keep_alive = atoi(optarg);
			continue;
		case '3':       /* --force_keepalive */
			force_keepalive = TRUE;
			continue;
		case '4':       /* --disable_port_floating */
			nat_t_spf = FALSE;
			continue;
		case '5':       /* --debug-nat_t */
			base_debugging |= DBG_NATT;
			continue;
		case '6':       /* --virtual_private */
			virtual_private = optarg;
			continue;

		default:
#ifdef DEBUG
			if (c >= DBG_OFFSET)
			{
				base_debugging |= c - DBG_OFFSET;
				continue;
			}
#       undef DBG_OFFSET
#endif
			bad_case(c);
		}
		break;
	}
	if (optind != argc)
		usage("unexpected argument");
	reset_debugging();
	lockfd = create_lock();

	/* select between logging methods */

	if (log_to_stderr_desired)
	{
		log_to_syslog = FALSE;
	}
	else
	{
		log_to_stderr = FALSE;
	}

	/* set the logging function of pfkey debugging */
#ifdef DEBUG
	pfkey_debug_func = DBG_log;
#else
	pfkey_debug_func = NULL;
#endif

	/* create control socket.
	 * We must create it before the parent process returns so that
	 * there will be no race condition in using it.  The easiest
	 * place to do this is before the daemon fork.
	 */
	{
		err_t ugh = init_ctl_socket();

		if (ugh != NULL)
		{
			fprintf(stderr, "pluto: %s", ugh);
			exit_pluto(1);
		}
	}

	/* If not suppressed, do daemon fork */

	if (fork_desired)
	{
		{
			pid_t pid = fork();

			if (pid < 0)
			{
				int e = errno;

				fprintf(stderr, "pluto: fork failed (%d %s)\n",
					errno, strerror(e));
				exit_pluto(1);
			}

			if (pid != 0)
			{
				/* parent: die, after filling PID into lock file.
				 * must not use exit_pluto: lock would be removed!
				 */
				exit(fill_lock(lockfd, pid)? 0 : 1);
			}
		}

		if (setsid() < 0)
		{
			int e = errno;

			fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n",
				errno, strerror(e));
			exit_pluto(1);
		}
	}
	else
	{
		/* no daemon fork: we have to fill in lock file */
		(void) fill_lock(lockfd, getpid());
		fprintf(stdout, "Pluto initialized\n");
		fflush(stdout);
	}

	/* Redirect stdin, stdout and stderr to /dev/null
	 */
	{
		int fd;
		if ((fd = open("/dev/null", O_RDWR)) == -1)
			abort();
		if (dup2(fd, 0) != 0)
			abort();
		if (dup2(fd, 1) != 1)
			abort();
		if (!log_to_stderr && dup2(fd, 2) != 2)
			abort();
		close(fd);
	}

	init_constants();
	init_log("pluto");

	/* Note: some scripts may look for this exact message -- don't change
	 * ipsec barf was one, but it no longer does.
	 */
	plog("Starting IKEv1 pluto daemon (strongSwan "VERSION")%s",
		 compile_time_interop_options);

	if (lib->integrity)
	{
		plog("integrity tests enabled:");
		plog("lib    'libstrongswan': passed file and segment integrity tests");
		plog("lib    'libhydra': passed file and segment integrity tests");
		plog("daemon 'pluto': passed file integrity test");
	}

	/* load plugins, further infrastructure may need it */
	if (!lib->plugins->load(lib->plugins, NULL,
			lib->settings->get_str(lib->settings, "pluto.load", PLUGINS)))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	print_plugins();

	init_builder();
	if (!init_secret() || !init_crypto())
	{
		plog("initialization failed - aborting pluto");
		exit_pluto(SS_RC_INITIALIZATION_FAILED);
	}
	init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
	init_virtual_ip(virtual_private);
	scx_init(pkcs11_module_path, pkcs11_init_args);
	init_states();
	init_demux();
	init_kernel();
	init_adns();
	init_myid();
	fetch_initialize();
	ac_initialize();
	whack_attribute_initialize();

	/* drop unneeded capabilities and change UID/GID */
	prctl(PR_SET_KEEPCAPS, 1);

#ifdef IPSEC_GROUP
	{
		struct group group, *grp;
	char buf[1024];

		if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
				grp == NULL || setgid(grp->gr_gid) != 0)
		{
			plog("unable to change daemon group");
			abort();
		}
	}
#endif
#ifdef IPSEC_USER
	{
		struct passwd passwd, *pwp;
	char buf[1024];

		if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
				pwp == NULL || setuid(pwp->pw_uid) != 0)
		{
			plog("unable to change daemon user");
			abort();
		}
		}
#endif

#ifdef CAPABILITIES_LIBCAP
	{
		cap_t caps;
		caps = cap_init();
		cap_set_flag(caps, CAP_EFFECTIVE, countof(keep), keep, CAP_SET);
		cap_set_flag(caps, CAP_INHERITABLE, countof(keep), keep, CAP_SET);
		cap_set_flag(caps, CAP_PERMITTED, countof(keep), keep, CAP_SET);
		if (cap_set_proc(caps) != 0)
		{
			plog("unable to drop daemon capabilities");
			abort();
		}
		cap_free(caps);
	}
#endif /* CAPABILITIES_LIBCAP */
#ifdef CAPABILITIES_NATIVE
	{
		struct __user_cap_data_struct caps = { .effective = 0 };
		struct __user_cap_header_struct header = {
			.version = _LINUX_CAPABILITY_VERSION,
		};
		int i;
		for (i = 0; i < countof(keep); i++)
		{
			caps.effective |= 1 << keep[i];
			caps.permitted |= 1 << keep[i];
			caps.inheritable |= 1 << keep[i];
		}
		if (capset(&header, &caps) != 0)
		{
			plog("unable to drop daemon capabilities");
			abort();
		}
	}
#endif /* CAPABILITIES_NATIVE */

	/* loading X.509 CA certificates */
	load_authcerts("ca", CA_CERT_PATH, X509_CA);
	/* loading X.509 AA certificates */
	load_authcerts("aa", AA_CERT_PATH, X509_AA);
	/* loading X.509 OCSP certificates */
	load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER);
	/* loading X.509 CRLs */
	load_crls();
	/* loading attribute certificates (experimental) */
	ac_load_certs();

	lib->processor->set_threads(lib->processor,
			lib->settings->get_int(lib->settings, "pluto.threads",
								   DEFAULT_THREADS));

	daily_log_event();
	call_server();
	return -1;  /* Shouldn't ever reach this */
}

/* leave pluto, with status.
 * Once child is launched, parent must not exit this way because
 * the lock would be released.
 *
 *  0 OK
 *  1 general discomfort
 * 10 lock file exists
 */
void exit_pluto(int status)
{
	lib->processor->set_threads(lib->processor, 0);
	reset_globals();    /* needed because we may be called in odd state */
	free_preshared_secrets();
	free_remembered_public_keys();
	delete_every_connection();
	whack_attribute_finalize(); /* free in-memory pools */
	kernel_finalize();
	fetch_finalize();           /* stop fetching thread */
	free_crl_fetch();           /* free chain of crl fetch requests */
	free_ocsp_fetch();          /* free chain of ocsp fetch requests */
	free_authcerts();           /* free chain of X.509 authority certificates */
	free_crls();                /* free chain of X.509 CRLs */
	free_ca_infos();            /* free chain of X.509 CA information records */
	free_ocsp();                /* free ocsp cache */
	free_ifaces();
	ac_finalize();              /* free X.509 attribute certificates */
	scx_finalize();             /* finalize and unload PKCS #11 module */
	stop_adns();
	free_md_pool();
	free_crypto();
	free_myid();                /* free myids */
	free_events();              /* free remaining events */
	free_vendorid();            /* free all vendor id records */
	free_builder();
	delete_lock();
	options->destroy(options);
	pluto_deinit();
	lib->plugins->unload(lib->plugins);
	libhydra_deinit();
	library_deinit();
	close_log();
	exit(status);
}
示例#22
0
/* run in post_read_request hook */
static int ruid_setup (request_rec *r)
{
	/* We decline when we are in a subrequest. The ruid_setup function was
	 * already executed in the main request. */
	if (!ap_is_initial_req(r)) {
		return DECLINED;
	}

	ruid_config_t *conf = ap_get_module_config (r->server->module_config,  &ruid2_module);
	ruid_dir_config_t *dconf = ap_get_module_config(r->per_dir_config, &ruid2_module);
	core_server_config *core = (core_server_config *) ap_get_module_config(r->server->module_config, &core_module);

	int ncap=0;
	cap_t cap;
	cap_value_t capval[2];

	if (dconf->ruid_mode==RUID_MODE_STAT) capval[ncap++] = CAP_DAC_READ_SEARCH;
	if (root_handle != UNSET) capval[ncap++] = CAP_SYS_CHROOT;
	if (ncap) {
		cap=cap_get_proc();
		cap_set_flag(cap, CAP_EFFECTIVE, ncap, capval, CAP_SET);
		if (cap_set_proc(cap)!=0) {
			ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s CRITICAL ERROR %s:cap_set_proc failed", MODULE_NAME, __func__);
		}
		cap_free(cap);
	}

	/* do chroot trick only if chrootdir is defined */
	if (conf->chroot_dir)
	{
		old_root = ap_document_root(r);
		core->ap_document_root = conf->document_root;
		if (chdir(conf->chroot_dir) != 0)
		{
			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"%s %s %s chdir to %s failed", MODULE_NAME, ap_get_server_name (r), r->the_request, conf->chroot_dir);
			return HTTP_FORBIDDEN;
		}
		if (chroot(conf->chroot_dir) != 0)
		{
			ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL,"%s %s %s chroot to %s failed", MODULE_NAME, ap_get_server_name (r), r->the_request, conf->chroot_dir);
			return HTTP_FORBIDDEN;
		}

		cap = cap_get_proc();
		capval[0] = CAP_SYS_CHROOT;
		cap_set_flag(cap, CAP_EFFECTIVE, 1, capval, CAP_CLEAR);
		if (cap_set_proc(cap) != 0 )
		{
			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s CRITICAL ERROR %s:cap_set_proc failed", MODULE_NAME, __func__);
		}
		cap_free(cap);
	}

	/* register suidback function */
	apr_pool_cleanup_register(r->pool, r, ruid_suidback, apr_pool_cleanup_null);

	if (dconf->ruid_mode==RUID_MODE_CONF)
	{
		return ruid_set_perm(r, __func__);
	} else {
		return DECLINED;
	}
}
示例#23
0
文件: cage.c 项目: anthonyu/cage
int main(int argc, char *argv[])
{

	int num;
	char *dir, **cmd;

#ifdef HAVE_LIBCAP
	cap_t caps;
	cap_value_t capv[7];
	int flags;
#else
	cap_user_header_t head;
	cap_user_data_t data;
	__u32 mask;
#endif


	uid = 0;
	gid = 0;
#if 0
	euid = geteuid();
	egid = getegid();
#endif

	num = decode_switches(argc, argv);

	dir = argv[num++];
	cmd = argv + num;

	if (dir == NULL)
		usage(EXIT_FAILURE);

	if (chdir(dir))
		die(dir);

	if (chroot(dir))
		die("chroot");

#ifdef HAVE_LIBCAP
	if (captxt != NULL) {
		if ((caps = cap_from_text(captxt)) == NULL)
		       die("cap_from_text");
	} else {
		if ((caps = cap_get_proc()) == NULL)
			die("cap_get_proc");
 
		capv[0] = CAP_SETPCAP;	  /* give caps to non-chrooted tasks */
		capv[1] = CAP_SYS_MODULE; /* hijack syscalls like chroot() */
		capv[2] = CAP_SYS_RAWIO;  /* raw disk access (needed?) */
		capv[3] = CAP_SYS_CHROOT; /* can't have this, obviously... */
		capv[4] = CAP_SYS_PTRACE; /* control other, non-caged tasks */
		capv[5] = CAP_SYS_ADMIN;  /* mount proc and mess with kmem */
#ifdef CAP_MKNOD
		capv[6] = CAP_MKNOD;      /* create block devices */

		flags = 7;
#else
		flags = 6;
#endif /* CAP_MKNOD */

		if (cap_set_flag(caps, CAP_EFFECTIVE, flags, capv, CAP_CLEAR))
		 	die("cap_set_flag");
	
		if (cap_set_flag(caps, CAP_PERMITTED, flags, capv, CAP_CLEAR))
			die("cap_set_flag");
	
		if (cap_set_flag(caps, CAP_INHERITABLE, flags, capv, CAP_CLEAR))
			die("cap_set_flag");

	}

	if (cap_set_proc(caps))
		die("cap_set_proc");
	
	cap_free(&caps);
#else 
	if ((head = malloc(8)) == NULL)
		die("malloc()");

	if ((data = malloc(3 * 4)) == NULL)
		die("malloc()");

	head->pid = 0;
	head->version = _LINUX_CAPABILITY_VERSION;

	if (capget(head, data))
		die("capget");

 	mask  = (1 << CAP_SETPCAP);	/* give caps to non-chrooted tasks */
 	mask |= (1 << CAP_SYS_MODULE);	/* hijack syscalls such as chroot() */
 	mask |= (1 << CAP_SYS_RAWIO);	/* raw disk access (needed?) */
 	mask |= (1 << CAP_SYS_CHROOT);  /* can't have this, obviously... */
 	mask |= (1 << CAP_SYS_PTRACE);	/* control other, non-caged tasks */
 	mask |= (1 << CAP_SYS_ADMIN);   /* mount proc and mess with kmem */
#ifdef CAP_MKNOD
 	mask |= (1 << CAP_MKNOD);	/* create block devices */
#endif /* CAP_MKNOD */

	data->permitted &= ~mask;
	data->effective &= ~mask;
	data->inheritable &= ~mask;

	if (capset(head, data))
		die("capset()");

#endif /* HAVE_LIBCAP */

	if ((gid) && (setgid(gid)))
		die("setgid");

	if ((uid) && (setuid(uid)))
		die("setuid");

	execvp(cmd[0], cmd);
	
	die(cmd[0]);
}
示例#24
0
static
void dropCapability(
#ifdef __linux
                    cap_value_t capability
#endif
                    )
{
#ifdef __linux
    cap_t caps;
    cap_value_t cap_list[] = { capability };

    caps = cap_get_proc();
    if (caps == nullptr)
    {
        Log::error("Error: cap_get_proc() failed.");
        exit(1);
    }

    if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1 ||
        cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1)
    {
        Log::error("Error: cap_set_flag() failed.");
        exit(1);
    }

    if (cap_set_proc(caps) == -1)
    {
        Log::error("Error: cap_set_proc() failed.");
        exit(1);
    }

    char *capText = cap_to_text(caps, nullptr);
    Log::info("Capabilities now: " + std::string(capText));
    cap_free(capText);

    cap_free(caps);
#endif
    // We assume that on non-Linux we don't need to be root to be able to hardlink to files we
    // don't own, so drop root.
    if (geteuid() == 0 && getuid() != 0)
    {
        // The program is setuid root. Not normal on Linux where we use setcap, but if this
        // needs to run on non-Linux Unixes, setuid root is what it will bneed to be to be able
        // to do chroot().
        if (setuid(getuid()) != 0)
        {
            Log::error("Error: setuid() failed.");
        }
    }
#if ENABLE_DEBUG
    if (geteuid() == 0 && getuid() == 0)
    {
#ifdef __linux
        // Argh, awful hack
        if (capability == CAP_FOWNER)
            return;
#endif

        // Running under sudo, probably because being debugged? Let's drop super-user rights.
        if (uid == 0)
        {
            struct passwd *nobody = getpwnam("nobody");
            if (nobody)
                uid = nobody->pw_uid;
            else
                uid = 65534;
        }
        if (setuid(uid) != 0)
        {
            Log::error("setuid() failed.");
        }
    }
#endif
}
int main() {
  char str[100];
  int listen_fd, comm_fd;
  struct sockaddr_in servaddr;
  struct passwd *pw = NULL;
  cap_value_t cap_values[] = {CAP_NET_BIND_SERVICE};
  cap_t caps;

  if(getgid() && getuid()) {
    printf("Privileges are not dropped as we're not superuser.\n");
    exit(EXIT_FAILURE);
  }

  /* Add the capability of interest to the perimitted capabilities  */
  caps = cap_get_proc();
  cap_set_flag(caps, CAP_PERMITTED, 1, cap_values, CAP_SET);
  cap_set_proc(caps);

  /* Tell the kernel to retain permitted capabilities */
  if(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
    printf("Unable to retain permitted capabilities [%s]\n", strerror(errno));
    exit(EXIT_FAILURE);
  }

  /* Cleanup */
  cap_free(caps);

  /* Drop privileges to user nobody */
  pw = getpwnam("nobody");
  if(pw == NULL) {
    printf("Unable to get information for user nobody");
    exit(EXIT_FAILURE);
  }

  /* Drop privileges */
  if((setgid(pw->pw_gid) != 0) || (setuid(pw->pw_uid) != 0)) {
    printf("Unable to drop privileges [%s]\n", strerror(errno));
    exit(EXIT_FAILURE);
  }

  /* Double check that privileges have been dropped */
  if (setuid(0) != -1) {
    printf("Managed to regain root privileges?\n");
    exit(EXIT_FAILURE);
  }

  /* Add the new capabilities to the effective capabilities
     Note that PR_SET_KEEPCAPS only preserves permitted capabilities
     so it is necessary to do this step
  */
  caps = cap_get_proc();
  cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_values, CAP_SET);
  cap_set_proc(caps);
  /* cap_to_text shoud output, among other text, the string
     cap_net_bind_service+ep to confirm the capability
     is effective (e)  and permitted (p)
     printf("caps_to_text() returned \"%s\"\n", cap_to_text(caps, NULL));
  */
  cap_free(caps);

  /* The following is just an echo server
     to test that nobody can actually bind and
     listen to sockets on ports < 1024
  */

  listen_fd = socket(AF_INET, SOCK_STREAM, 0);
  bzero( &servaddr, sizeof(servaddr));

  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htons(INADDR_ANY);
  servaddr.sin_port = htons(81); /* Use a port < 1024 to test the effectiveness of this script */

  if(bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1
     || listen(listen_fd, 10) == -1){
    printf("Something went wrong with bind() or listen() [%s]\n", strerror(errno));
    exit(EXIT_FAILURE);
  }
 
  comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL); 
  while(1) {
    bzero( str, 100);
    read(comm_fd,str,100);
    printf("Echoing back - %s",str);
    write(comm_fd, str, strlen(str)+1);
  }
}
示例#26
0
int main(int argc, char **argv)
{
	bool fork_desired = TRUE;
	bool log_to_stderr_desired = FALSE;
	bool nat_traversal = FALSE;
	bool nat_t_spf = TRUE;  /* support port floating */
	unsigned int keep_alive = 0;
	bool force_keepalive = FALSE;
	char *virtual_private = NULL;
	int lockfd;
#ifdef CAPABILITIES
	cap_t caps;
	int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
#endif /* CAPABILITIES */

	/* initialize library and optionsfrom */
	if (!library_init(NULL))
	{
		library_deinit();
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (!libhydra_init("pluto"))
	{
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	if (!pluto_init(argv[0]))
	{
		pluto_deinit();
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_DAEMON_INTEGRITY);
	}
	options = options_create();

	ha_mcast_addr.s_addr = inet_addr(SA_SYNC_MULTICAST);

	/* handle arguments */
	for (;;)
	{
#       define DBG_OFFSET 256
		static const struct option long_opts[] = {
			/* name, has_arg, flag, val */
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "optionsfrom", required_argument, NULL, '+' },
			{ "nofork", no_argument, NULL, 'd' },
			{ "stderrlog", no_argument, NULL, 'e' },
			{ "noklips", no_argument, NULL, 'n' },
			{ "nocrsend", no_argument, NULL, 'c' },
			{ "strictcrlpolicy", no_argument, NULL, 'r' },
			{ "crlcheckinterval", required_argument, NULL, 'x'},
			{ "cachecrls", no_argument, NULL, 'C' },
			{ "probe-psk", no_argument, NULL, 'o' },
			{ "uniqueids", no_argument, NULL, 'u' },
			{ "interface", required_argument, NULL, 'i' },
			{ "ha_interface", required_argument, NULL, 'H' },
			{ "ha_multicast", required_argument, NULL, 'M' },
			{ "ha_vips", required_argument, NULL, 'V' },
			{ "ha_seqdiff_in", required_argument, NULL, 'S' },
			{ "ha_seqdiff_out", required_argument, NULL, 'O' },
			{ "ikeport", required_argument, NULL, 'p' },
			{ "ctlbase", required_argument, NULL, 'b' },
			{ "secretsfile", required_argument, NULL, 's' },
			{ "foodgroupsdir", required_argument, NULL, 'f' },
			{ "perpeerlogbase", required_argument, NULL, 'P' },
			{ "perpeerlog", no_argument, NULL, 'l' },
			{ "policygroupsdir", required_argument, NULL, 'f' },
#ifdef USE_LWRES
			{ "lwdnsq", required_argument, NULL, 'a' },
#else /* !USE_LWRES */
			{ "adns", required_argument, NULL, 'a' },
#endif /* !USE_LWRES */
			{ "pkcs11module", required_argument, NULL, 'm' },
			{ "pkcs11keepstate", no_argument, NULL, 'k' },
			{ "pkcs11initargs", required_argument, NULL, 'z' },
			{ "pkcs11proxy", no_argument, NULL, 'y' },
			{ "nat_traversal", no_argument, NULL, '1' },
			{ "keep_alive", required_argument, NULL, '2' },
			{ "force_keepalive", no_argument, NULL, '3' },
			{ "disable_port_floating", no_argument, NULL, '4' },
			{ "debug-natt", no_argument, NULL, '5' },
			{ "virtual_private", required_argument, NULL, '6' },
#ifdef DEBUG
			{ "debug-none", no_argument, NULL, 'N' },
			{ "debug-all", no_argument, NULL, 'A' },
			{ "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
			{ "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET },
			{ "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
			{ "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET },
			{ "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET },
			{ "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET },
			{ "debug-klips", no_argument, NULL, DBG_KLIPS + DBG_OFFSET },
			{ "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET },
			{ "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET },
			{ "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET },
			{ "debug-ha", no_argument, NULL, DBG_HA + DBG_OFFSET },
			{ "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },

			{ "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET },
			{ "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET },
			{ "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
			{ "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
#endif
			{ 0,0,0,0 }
			};
		/* Note: we don't like the way short options get parsed
		 * by getopt_long, so we simply pass an empty string as
		 * the list.  It could be "hvdenp:l:s:" "NARXPECK".
		 */
		int c = getopt_long(argc, argv, "", long_opts, NULL);

		/* Note: "breaking" from case terminates loop */
		switch (c)
		{
		case EOF:       /* end of flags */
			break;

		case 0: /* long option already handled */
			continue;

		case ':':       /* diagnostic already printed by getopt_long */
		case '?':       /* diagnostic already printed by getopt_long */
			usage("");
			break;   /* not actually reached */

		case 'h':       /* --help */
			usage(NULL);
			break;      /* not actually reached */

		case 'v':       /* --version */
			{
				const char **sp = ipsec_copyright_notice();

				printf("strongSwan "VERSION"%s\n", compile_time_interop_options);
				for (; *sp != NULL; sp++)
					puts(*sp);
			}
			exit_pluto(0);
			break;      /* not actually reached */

		case '+':       /* --optionsfrom <filename> */
			if (!options->from(options, optarg, &argc, &argv, optind))
			{
				exit_pluto(1);
			}
			continue;

		case 'd':       /* --nofork*/
			fork_desired = FALSE;
			continue;

		case 'e':       /* --stderrlog */
			log_to_stderr_desired = TRUE;
			continue;

		case 'n':       /* --noklips */
			no_klips = TRUE;
			continue;

		case 'c':       /* --nocrsend */
			no_cr_send = TRUE;
			continue;

		case 'r':       /* --strictcrlpolicy */
			strict_crl_policy = TRUE;
			continue;

		case 'x':       /* --crlcheckinterval <time>*/
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing interval time");

			{
				char *endptr;
				long interval = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| interval <= 0)
					usage("<interval-time> must be a positive number");
				crl_check_interval = interval;
			}
			continue;

		case 'C':       /* --cachecrls */
			cache_crls = TRUE;
			continue;

		case 'o':       /* --probe-psk */
			probe_psk = TRUE;
			continue;

		case 'u':       /* --uniqueids */
			uniqueIDs = TRUE;
			continue;

		case 'i':       /* --interface <ifname> */
			if (!use_interface(optarg))
				usage("too many --interface specifications");
			continue;

		case 'H':       /* --ha_interface <ifname> */
			if (optarg && strcmp(optarg, "none") != 0)
				ha_interface = optarg;
			continue;

		case 'M':	/* --ha_multicast <ip> */
			ha_mcast_addr.s_addr = inet_addr(optarg);
			if (ha_mcast_addr.s_addr == INADDR_NONE ||
				(((unsigned char *) &ha_mcast_addr.s_addr)[0] & 0xF0) != 0xE0)
				ha_mcast_addr.s_addr = inet_addr(SA_SYNC_MULTICAST);
			continue;

		case 'V':	/* --ha_vips <ip addresses> */
			if(add_ha_vips(optarg))
				usage("misconfigured ha_vip addresses");
			continue;

		case 'S':	/* --ha_seqdiff_in <diff> */
			ha_seqdiff_in = strtoul(optarg, NULL, 0);
			continue;

		case 'O':       /* --ha_seqdiff_out <diff> */
			ha_seqdiff_out = strtoul(optarg, NULL, 0);
			continue;

		case 'p':       /* --port <portnumber> */
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing port number");

			{
				char *endptr;
				long port = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| port <= 0 || port > 0x10000)
					usage("<port-number> must be a number between 1 and 65535");
				pluto_port = port;
			}
			continue;

		case 'b':       /* --ctlbase <path> */
			if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
			, "%s%s", optarg, CTL_SUFFIX) == -1)
				usage("<path>" CTL_SUFFIX " too long for sun_path");
			if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path)
			, "%s%s", optarg, INFO_SUFFIX) == -1)
				usage("<path>" INFO_SUFFIX " too long for sun_path");
			if (snprintf(pluto_lock, sizeof(pluto_lock)
			, "%s%s", optarg, LOCK_SUFFIX) == -1)
				usage("<path>" LOCK_SUFFIX " must fit");
			continue;

		case 's':       /* --secretsfile <secrets-file> */
			shared_secrets_file = optarg;
			continue;

		case 'f':       /* --policygroupsdir <policygroups-dir> */
			policygroups_dir = optarg;
			continue;

		case 'a':       /* --adns <pathname> */
			pluto_adns_option = optarg;
			continue;

		case 'm':       /* --pkcs11module <pathname> */
			pkcs11_module_path = optarg;
			continue;

		case 'k':       /* --pkcs11keepstate */
			pkcs11_keep_state = TRUE;
			continue;

		case 'y':       /* --pkcs11proxy */
			pkcs11_proxy = TRUE;
			continue;

		case 'z':       /* --pkcs11initargs */
			pkcs11_init_args = optarg;
			continue;

#ifdef DEBUG
		case 'N':       /* --debug-none */
			base_debugging = DBG_NONE;
			continue;

		case 'A':       /* --debug-all */
			base_debugging = DBG_ALL;
			continue;
#endif

		case 'P':       /* --perpeerlogbase */
			base_perpeer_logdir = optarg;
			continue;

		case 'l':
			log_to_perpeer = TRUE;
			continue;

		case '1':       /* --nat_traversal */
			nat_traversal = TRUE;
			continue;
		case '2':       /* --keep_alive */
			keep_alive = atoi(optarg);
			continue;
		case '3':       /* --force_keepalive */
			force_keepalive = TRUE;
			continue;
		case '4':       /* --disable_port_floating */
			nat_t_spf = FALSE;
			continue;
		case '5':       /* --debug-nat_t */
			base_debugging |= DBG_NATT;
			continue;
		case '6':       /* --virtual_private */
			virtual_private = optarg;
			continue;

		default:
#ifdef DEBUG
			if (c >= DBG_OFFSET)
			{
				base_debugging |= c - DBG_OFFSET;
				continue;
			}
#       undef DBG_OFFSET
#endif
			bad_case(c);
		}
		break;
	}
	if (optind != argc)
		usage("unexpected argument");
	reset_debugging();
	lockfd = create_lock();

	/* select between logging methods */

	if (log_to_stderr_desired)
	{
		log_to_syslog = FALSE;
	}
	else
	{
		log_to_stderr = FALSE;
	}

	/* set the logging function of pfkey debugging */
#ifdef DEBUG
	pfkey_debug_func = DBG_log;
#else
	pfkey_debug_func = NULL;
#endif

	/* create control socket.
	 * We must create it before the parent process returns so that
	 * there will be no race condition in using it.  The easiest
	 * place to do this is before the daemon fork.
	 */
	{
		err_t ugh = init_ctl_socket();

		if (ugh != NULL)
		{
			fprintf(stderr, "pluto: %s", ugh);
			exit_pluto(1);
		}
	}

	/* If not suppressed, do daemon fork */

	if (fork_desired)
	{
		{
			pid_t pid = fork();

			if (pid < 0)
			{
				int e = errno;

				fprintf(stderr, "pluto: fork failed (%d %s)\n",
					errno, strerror(e));
				exit_pluto(1);
			}

			if (pid != 0)
			{
				/* parent: die, after filling PID into lock file.
				 * must not use exit_pluto: lock would be removed!
				 */
				exit(fill_lock(lockfd, pid)? 0 : 1);
			}
		}

		if (setsid() < 0)
		{
			int e = errno;

			fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n",
				errno, strerror(e));
			exit_pluto(1);
		}
	}
	else
	{
		/* no daemon fork: we have to fill in lock file */
		(void) fill_lock(lockfd, getpid());
		fprintf(stdout, "Pluto initialized\n");
		fflush(stdout);
	}

	/* Close everything but ctl_fd and (if needed) stderr.
	 * There is some danger that a library that we don't know
	 * about is using some fd that we don't know about.
	 * I guess we'll soon find out.
	 */
	{
		int i;

		for (i = getdtablesize() - 1; i >= 0; i--)  /* Bad hack */
		{
			if ((!log_to_stderr || i != 2) && i != ctl_fd)
				close(i);
		}

		/* make sure that stdin, stdout, stderr are reserved */
		if (open("/dev/null", O_RDONLY) != 0)
			abort();
		if (dup2(0, 1) != 1)
			abort();
		if (!log_to_stderr && dup2(0, 2) != 2)
			abort();
	}

	init_constants();
	init_log("pluto");

	/* Note: some scripts may look for this exact message -- don't change
	 * ipsec barf was one, but it no longer does.
	 */
	plog("Starting IKEv1 pluto daemon (strongSwan "VERSION")%s",
		 compile_time_interop_options);

	if (lib->integrity)
	{
		plog("integrity tests enabled:");
		plog("lib    'libstrongswan': passed file and segment integrity tests");
		plog("lib    'libhydra': passed file and segment integrity tests");
		plog("daemon 'pluto': passed file integrity test");
	}

	/* load plugins, further infrastructure may need it */
	if (!lib->plugins->load(lib->plugins, NULL,
			lib->settings->get_str(lib->settings, "pluto.load", PLUGINS)))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	print_plugins();

	init_builder();
	if (!init_secret() || !init_crypto())
	{
		plog("initialization failed - aborting pluto");
		exit_pluto(SS_RC_INITIALIZATION_FAILED);
	}
	init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
	init_virtual_ip(virtual_private);
	scx_init(pkcs11_module_path, pkcs11_init_args);
	init_states();
	init_demux();
	init_kernel();
	init_adns();
	init_myid();
	fetch_initialize();
	ac_initialize();
	whack_attribute_initialize();

	/* HA System: set sequence number delta and open HA interface */
	if (ha_interface != NULL)
	{
		int version;

		if (kernel_ops->type == KERNEL_TYPE_LINUX
		&& (version = xfrm_aevent_version()) != XFRM_AEVENT_VERSION)
		{
			if (version == 0)
				plog("HA system: XFRM sequence number updates only "
				     "supported with kernel version 2.6.17 and later.");
			else if (version == -1)
				plog("HA system: error reading kernel version. "
				     "Sequence number updates disabled.");
			else
				plog("HA system: Strongswan compiled for wrong kernel "
				     "AEVENT version! Please set XFRM_AEVENT_VERSION "
				     "to %d in src/include/linux/xfrm.h", version);

			ha_seqdiff_in = 0;
			ha_seqdiff_out = 0;
		}
		else
		{
			FILE *etime = fopen("/proc/sys/net/core/xfrm_aevent_etime", "w");
			FILE *rseqth = fopen("/proc/sys/net/core/xfrm_aevent_rseqth", "w");

			if (etime == NULL || rseqth == NULL)
			{
				plog("HA System: no sequence number support in Kernel! "
					"Please use at least kernel 2.6.17.");
				ha_seqdiff_in = 0;
				ha_seqdiff_out = 0;
			}
			else
			{
				/*
				 * Disable etime (otherwise set to a multiple of 100ms,
				 * e.g. 300 for 30 seconds). Using ha_seqdiff_out.
				 */
				fprintf(etime, "0");
				fprintf(rseqth, "%d", ha_seqdiff_out);
			}

			fclose(etime);
			fclose(rseqth);
		}

		if (open_ha_iface() >= 0)
		{
			plog("HA system enabled and listening on interface %s", ha_interface);
			if (access("/var/master", F_OK) == 0)
			{
				plog("Initial HA switch to master mode");
				ha_master = 1;
				event_schedule(EVENT_SA_SYNC_UPDATE, 30, NULL);
			}
		}
		else
		{
			plog("HA system failed to listen on interface %s. "
			     "HA system disabled.", ha_interface);
			ha_interface = NULL;
		}
	}

	/* drop unneeded capabilities and change UID/GID */
	prctl(PR_SET_KEEPCAPS, 1);

#ifdef IPSEC_GROUP
	{
		struct group group, *grp;
	char buf[1024];

		if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
				grp == NULL || setgid(grp->gr_gid) != 0)
		{
			plog("unable to change daemon group");
			abort();
		}
	}
#endif
#ifdef IPSEC_USER
	{
		struct passwd passwd, *pwp;
	char buf[1024];

		if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
				pwp == NULL || setuid(pwp->pw_uid) != 0)
		{
			plog("unable to change daemon user");
			abort();
		}
		}
#endif

#ifdef CAPABILITIES
	caps = cap_init();
	cap_set_flag(caps, CAP_EFFECTIVE, 2, keep, CAP_SET);
	cap_set_flag(caps, CAP_INHERITABLE, 2, keep, CAP_SET);
	cap_set_flag(caps, CAP_PERMITTED, 2, keep, CAP_SET);
	if (cap_set_proc(caps) != 0)
	{
		plog("unable to drop daemon capabilities");
		abort();
	}
	cap_free(caps);
#endif /* CAPABILITIES */

	/* loading X.509 CA certificates */
	load_authcerts("ca", CA_CERT_PATH, X509_CA);
	/* loading X.509 AA certificates */
	load_authcerts("aa", AA_CERT_PATH, X509_AA);
	/* loading X.509 OCSP certificates */
	load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER);
	/* loading X.509 CRLs */
	load_crls();
	/* loading attribute certificates (experimental) */
	ac_load_certs();

	daily_log_event();
	call_server();
	return -1;  /* Shouldn't ever reach this */
}
示例#27
0
int main(void)
{
    uid_t       user;
    cap_value_t root_caps[2] = { CAP_SYS_NICE, CAP_SETUID };
    cap_value_t user_caps[1] = { CAP_SYS_NICE, CAP_SYS_ADMIN };
    cap_t       capabilities;

    /* Get real user ID. */
    //user = getuid();
	user = 1000;

    /* Get full root privileges. Normally being effectively root
     * (see man 7 credentials, User and Group Identifiers, for explanation
     *  for effective versus real identity) is enough, but some security
     * modules restrict actions by processes that are only effectively root.
     * To make sure we don't hit those problems, we switch to root fully. */
    if (setresuid(0, 0, 0)) {
        fprintf(stderr, "Cannot switch to root: %s.\n", strerror(errno));
        return 1;
    }

    /* Create an empty set of capabilities. */
    capabilities = cap_init();

    /* Capabilities have three subsets:
     *      INHERITABLE:    Capabilities permitted after an execv()
     *      EFFECTIVE:      Currently effective capabilities
     *      PERMITTED:      Limiting set for the two above.
     * See man 7 capabilities for details, Thread Capability Sets.
     *
     * We need the following capabilities:
     *      CAP_SYS_NICE    For nice(2), setpriority(2),
     *                      sched_setscheduler(2), sched_setparam(2),
     *                      sched_setaffinity(2), etc.
     *      CAP_SETUID      For setuid(), setresuid()
     * in the last two subsets. We do not need to retain any capabilities
     * over an exec().
    */
    if (cap_set_flag(capabilities, CAP_PERMITTED, sizeof root_caps / sizeof root_caps[0], root_caps, CAP_SET) ||
        cap_set_flag(capabilities, CAP_EFFECTIVE, sizeof root_caps / sizeof root_caps[0], root_caps, CAP_SET)) {
        fprintf(stderr, "Cannot manipulate capability data structure as root: %s.\n", strerror(errno));
        return 1;
    }

    /* Above, we just manipulated the data structure describing the flags,
     * not the capabilities themselves. So, set those capabilities now. */
    if (cap_set_proc(capabilities)) {
        fprintf(stderr, "Cannot set capabilities as root: %s.\n", strerror(errno));
        return 1;
    }

    /* We wish to retain the capabilities across the identity change,
     * so we need to tell the kernel. */
    if (prctl(PR_SET_KEEPCAPS, 1L)) {
        fprintf(stderr, "Cannot keep capabilities after dropping privileges: %s.\n", strerror(errno));
        return 1;
    }

    /* Drop extra privileges (aside from capabilities) by switching
     * to the original real user. */
    if (setresuid(user, user, user)) {
        fprintf(stderr, "Cannot drop root privileges: %s.\n", strerror(errno));
        return 1;
    }

    /* We can still switch to a different user due to having the CAP_SETUID
     * capability. Let's clear the capability set, except for the CAP_SYS_NICE
     * in the permitted and effective sets. */
    if (cap_clear(capabilities)) {
        fprintf(stderr, "Cannot clear capability data structure: %s.\n", strerror(errno));
        return 1;
    }
    if (cap_set_flag(capabilities, CAP_PERMITTED, sizeof user_caps / sizeof user_caps[0], user_caps, CAP_SET) ||
        cap_set_flag(capabilities, CAP_EFFECTIVE, sizeof user_caps / sizeof user_caps[0], user_caps, CAP_SET)) {
        fprintf(stderr, "Cannot manipulate capability data structure as user: %s.\n", strerror(errno));
        return 1;
    }

    /* Apply modified capabilities. */
    if (cap_set_proc(capabilities)) {
        fprintf(stderr, "Cannot set capabilities as user: %s.\n", strerror(errno));
        return 1;
    }

    /*
     * Now we have just the normal user privileges,
     * plus user_caps.
    */

    test_priority("SCHED_OTHER", SCHED_OTHER);
    test_priority("SCHED_FIFO", SCHED_FIFO);
    test_priority("SCHED_RR", SCHED_RR);

	int ret;
	ret = nice(-20);
	printf("nice: %d\n", ret);

	while(1)
	{
		sleep(1);
	}
    return 0;
}
示例#28
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);
}
示例#29
0
static int drop_privs(bool klogd, bool auditd) {
    // Tricky, if ro.build.type is "eng" then this is true because of the
    // side effect that ro.debuggable == 1 as well, else it is false.
    bool eng =
        __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);

    struct sched_param param;
    memset(&param, 0, sizeof(param));

    if (set_sched_policy(0, SP_BACKGROUND) < 0) {
        android::prdebug("failed to set background scheduling policy");
        if (!eng) return -1;
    }

    if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
        android::prdebug("failed to set batch scheduler");
        if (!eng) return -1;
    }

    if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
        android::prdebug("failed to set background cgroup");
        if (!eng) return -1;
    }

    if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
        android::prdebug("failed to clear PR_SET_DUMPABLE");
        return -1;
    }

    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
        android::prdebug("failed to set PR_SET_KEEPCAPS");
        if (!eng) return -1;
    }

    std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(),
                                                             cap_free);
    if (cap_clear(caps.get()) < 0) return -1;
    cap_value_t cap_value[] = { CAP_SETGID,  // must be first for below
                                klogd ? CAP_SYSLOG : CAP_SETGID,
                                auditd ? CAP_AUDIT_CONTROL : CAP_SETGID };
    if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(cap_value), cap_value,
                     CAP_SET) < 0) {
        return -1;
    }
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(cap_value), cap_value,
                     CAP_SET) < 0) {
        return -1;
    }
    if (cap_set_proc(caps.get()) < 0) {
        android::prdebug(
            "failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)",
            errno);
        if (!eng) return -1;
    }

    gid_t groups[] = { AID_READPROC };

    if (setgroups(arraysize(groups), groups) == -1) {
        android::prdebug("failed to set AID_READPROC groups");
        if (!eng) return -1;
    }

    if (setgid(AID_LOGD) != 0) {
        android::prdebug("failed to set AID_LOGD gid");
        if (!eng) return -1;
    }

    if (setuid(AID_LOGD) != 0) {
        android::prdebug("failed to set AID_LOGD uid");
        if (!eng) return -1;
    }

    if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) {
        return -1;
    }
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) {
        return -1;
    }
    if (cap_set_proc(caps.get()) < 0) {
        android::prdebug("failed to clear CAP_SETGID (%d)", errno);
        if (!eng) return -1;
    }

    return 0;
}
示例#30
0
static int ruid_set_perm (request_rec *r, const char *from_func)
{
	ruid_config_t *conf = ap_get_module_config(r->server->module_config, &ruid2_module);
	ruid_dir_config_t *dconf = ap_get_module_config(r->per_dir_config, &ruid2_module);

	int retval = DECLINED;
	gid_t gid;
	uid_t uid;
	gid_t groups[RUID_MAXGROUPS];
	int groupsnr;

	cap_t cap;
	cap_value_t capval[3];

	cap=cap_get_proc();
	capval[0]=CAP_SETUID;
	capval[1]=CAP_SETGID;
	cap_set_flag(cap,CAP_EFFECTIVE,2,capval,CAP_SET);
	if (cap_set_proc(cap)!=0) {
		ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s CRITICAL ERROR %s>%s:cap_set_proc failed before setuid", MODULE_NAME, from_func, __func__);
	}
	cap_free(cap);

	if (dconf->ruid_mode==RUID_MODE_STAT) {
		/* set uid,gid to uid,gid of file
		 * if file does not exist, finfo.user and finfo.group is set to uid,gid of parent directory
		 */
		gid=r->finfo.group;
		uid=r->finfo.user;

		/* if uid of filename is less than conf->min_uid then set to conf->default_uid */
		if (uid < conf->min_uid) {
			uid=conf->default_uid;
		}
		if (gid < conf->min_gid) {
			gid=conf->default_gid;
		}
	} else {
		gid=(dconf->ruid_gid == UNSET) ? ap_unixd_config.group_id : dconf->ruid_gid;
		uid=(dconf->ruid_uid == UNSET) ? ap_unixd_config.user_id : dconf->ruid_uid;
	}

	/* set supplementary groups */
	if ((dconf->groupsnr == UNSET) && (startup_groupsnr > 0)) {
		memcpy(groups, startup_groups, sizeof(groups));
		groupsnr = startup_groupsnr;
	} else if (dconf->groupsnr > 0) {
		for (groupsnr = 0; groupsnr < dconf->groupsnr; groupsnr++) {
			groups[groupsnr] = dconf->groups[groupsnr];
		}
	} else {
		groupsnr = 0;
	}
	setgroups(groupsnr, groups);

	/* final set[ug]id */
	if (setgid(gid) != 0)
	{
		ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s %s %s %s>%s:setgid(%d) failed. getgid=%d getuid=%d", MODULE_NAME, ap_get_server_name(r), r->the_request, from_func, __func__, dconf->ruid_gid, getgid(), getuid());
		retval = HTTP_FORBIDDEN;
	} else {
		if (setuid(uid) != 0)
		{
			ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s %s %s %s>%s:setuid(%d) failed. getuid=%d", MODULE_NAME, ap_get_server_name(r), r->the_request, from_func, __func__, dconf->ruid_uid, getuid());
			retval = HTTP_FORBIDDEN;
		}
	}

	/* set httpd process dumpable after setuid */
	if (coredump) {
		prctl(PR_SET_DUMPABLE,1);
	}

	/* clear capabilties from effective set */
	cap=cap_get_proc();
	capval[0]=CAP_SETUID;
	capval[1]=CAP_SETGID;
	capval[2]=CAP_DAC_READ_SEARCH;
	cap_set_flag(cap,CAP_EFFECTIVE,3,capval,CAP_CLEAR);

	if (cap_set_proc(cap)!=0) {
		ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s CRITICAL ERROR %s>%s:cap_set_proc failed after setuid", MODULE_NAME, from_func, __func__);
		retval = HTTP_FORBIDDEN;
	}
	cap_free(cap);

	return retval;
}