Beispiel #1
0
static int
external_passwd_quality (krb5_context context,
			 krb5_principal principal,
			 krb5_data *pwd,
			 const char *opaque,
			 char *message,
			 size_t length)
{
    krb5_error_code ret;
    const char *program;
    char *p;
    pid_t child;
    int status;
    char reply[1024];
    FILE *in = NULL, *out = NULL, *error = NULL;

    if (memchr(pwd->data, '\n', pwd->length) != NULL) {
	snprintf(message, length, "password contains newline, "
		 "not valid for external test");
	return 1;
    }

    program = krb5_config_get_string(context, NULL,
				     "password_quality",
				     "external_program",
				     NULL);
    if (program == NULL) {
	snprintf(message, length, "external password quality "
		 "program not configured");
	return 1;
    }

    ret = krb5_unparse_name(context, principal, &p);
    if (ret) {
	strlcpy(message, "out of memory", length);
	return 1;
    }

    child = pipe_execv(&in, &out, &error, program, program, p, NULL);
    if (child < 0) {
	snprintf(message, length, "external password quality "
		 "program failed to execute for principal %s", p);
	free(p);
	return 1;
    }

    fprintf(in, "principal: %s\n"
	    "new-password: %.*s\n"
	    "end\n",
	    p, (int)pwd->length, (char *)pwd->data);

    fclose(in);

    if (fgets(reply, sizeof(reply), out) == NULL) {

	if (fgets(reply, sizeof(reply), error) == NULL) {
	    snprintf(message, length, "external password quality "
		     "program failed without error");

	} else {
	    reply[strcspn(reply, "\n")] = '\0';
	    snprintf(message, length, "External password quality "
		     "program failed: %s", reply);
	}

	fclose(out);
	fclose(error);
	wait_for_process(child);
	return 1;
    }
    reply[strcspn(reply, "\n")] = '\0';

    fclose(out);
    fclose(error);

    status = wait_for_process(child);

    if (SE_IS_ERROR(status) || SE_PROCSTATUS(status) != 0) {
	snprintf(message, length, "external program failed: %s", reply);
	free(p);
	return 1;
    }

    if (strcmp(reply, "APPROVED") != 0) {
	snprintf(message, length, "%s", reply);
	free(p);
	return 1;
    }

    free(p);

    return 0;
}
Beispiel #2
0
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
roken_detach_prep(int argc, char **argv, char *special_arg)
{
    pid_t child;
    char buf[1];
    ssize_t bytes;
    int status;

    pipefds[0] = -1;
    pipefds[1] = -1;

#ifdef WIN32
    if (_pipe(pipefds, 4, O_BINARY) == -1)
        err(1, "failed to setup to detach daemon (_pipe failed)");
#else
    if (pipe(pipefds) == -1)
        err(1, "failed to setup to detach daemon (pipe failed)");
#endif

#ifndef WIN32
    fflush(stdout);
    child = fork();
#else
    {
        intptr_t child_handle;
	int write_side;
        size_t i;
	char *fildes;
        char **new_argv;

        new_argv = calloc(argc + 2, sizeof(*new_argv));
        if (new_argv == NULL)
            err(1, "Out of memory");

	write_side = _dup(pipefds[1]); /* The new fd will be inherited */
	if (write_side == -1)
            err(1, "Out of memory");

	if (asprintf(&fildes, "%d", write_side) == -1 ||
	    fildes == NULL)
            err(1, "failed to setup to detach daemon (_dup failed)");

        new_argv[0] = argv[0];
        new_argv[1] = special_arg;
        new_argv[2] = fildes;
        for (i = 1; argv[i] != NULL; i++)
            new_argv[i + 1] = argv[i];
	new_argv[argc + 2] = NULL;

	_flushall();
	child_handle = spawnvp(_P_NOWAIT, argv[0], new_argv);
	if (child_handle == -1)
	  child = (pid_t)-1;
	else
	  child = GetProcessId((HANDLE)child_handle);
    }
#endif
    if (child == (pid_t)-1)
        err(1, "failed to setup to fork daemon (fork failed)");

#ifndef WIN32
    if (child == 0) {
        int fd;

        (void) close(pipefds[0]);
        pipefds[0] = -1;
        /*
         * Keep stdout/stderr for now so output and errors prior to
         * detach_finish() can be seen by the user.
         */
        fd = open(_PATH_DEVNULL, O_RDWR, 0);
        if (fd == -1)
            err(1, "failed to open /dev/null");
        (void) dup2(fd, STDIN_FILENO);
        if (fd > STDERR_FILENO)
            (void) close(fd);
        return;
    }
#endif

    (void) close(pipefds[1]);
    pipefds[1] = -1;
    do {
        bytes = read(pipefds[0], buf, sizeof(buf));
    } while (bytes == -1 && errno == EINTR);
    (void) close(pipefds[0]);
    pipefds[0] = -1;
    if (bytes == -1) {
        /*
         * No need to wait for the process.  We've killed it.  If it
         * doesn't want to exit, we'd have to wait potentially forever,
         * but we want to indicate failure to the user as soon as
         * possible.  A wait with timeout would end the same way
         * (attempting to kill the process).
         */
        err(1, "failed to setup daemon child (read from child pipe)");
    }
    if (bytes == 0) {
        warnx("daemon child preparation failed, waiting for child");
        status = wait_for_process(child);
        if (SE_IS_ERROR(status) || SE_PROCSTATUS(status) != 0)
            errx(SE_PROCSTATUS(status),
                 "daemon child preparation failed (child exited)");
    }
    _exit(0);
}