Example #1
0
/*
 * Test the network write function with a timeout.  We fork off a child
 * process that runs delay_reader, and then we write 64KB to the network in
 * two chunks, once with a timeout and once without, and then try a third time
 * when we should time out.
 */
static void
test_network_write(void)
{
    socket_type fd, c;
    pid_t child;
    struct sockaddr_in sin;
    socklen_t slen;
    char *buffer;

    /* Create the data that we're going to send. */
    buffer = bmalloc(4096 * 1024);
    memset(buffer, 'a', 4096 * 1024);

    /* Create the listening socket. */
    fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119);
    if (fd == INVALID_SOCKET)
        sysbail("cannot create or bind socket");
    if (listen(fd, 1) < 0)
        sysbail("cannot listen to socket");

    /* Create the child, which will connect and then read data with delay. */
    child = fork();
    if (child < 0)
        sysbail("cannot fork");
    else if (child == 0) {
        socket_close(fd);
        client_delay_reader("127.0.0.1");
    }

    /* Set an alarm just in case our timeouts don't work. */
    alarm(10);

    /* Accept the client connection. */
    slen = sizeof(struct sockaddr_in);
    c = accept(fd, &sin, &slen);
    if (c == INVALID_SOCKET)
        sysbail("cannot accept on socket");

    /* Test some successful writes with and without a timeout. */
    socket_set_errno(0);
    ok(network_write(c, buffer, 32 * 1024, 0), "network_write");
    ok(network_write(c, buffer, 32 * 1024, 1),
       "network_write with timeout");

    /*
     * A longer write cannot be completely absorbed before the client sleep,
     * so should fail with a timeout.
     */
    ok(!network_write(c, buffer, 4096 * 1024, 1),
       "network_write aborted with timeout");
    is_int(ETIMEDOUT, socket_errno, "...with correct error");
    alarm(0);

    /* Clean up. */
    socket_close(c);
    kill(child, SIGTERM);
    waitpid(child, NULL, 0);
    socket_close(fd);
    free(buffer);
}
Example #2
0
/*
 * Create a server socket, wait for a connection, and return the connected
 * socket.
 */
static socket_type
create_server(void)
{
    socket_type fd, conn;
    int marker;
    struct sockaddr_in saddr;
    int on = 1;
    const void *onaddr = &on;

    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(0x7f000001UL);
    saddr.sin_port = htons(14373);
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == INVALID_SOCKET)
        sysbail("error creating socket");
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, onaddr, sizeof(on));
    if (bind(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
        sysbail("error binding socket");
    if (listen(fd, 1) < 0)
        sysbail("error listening on socket");
    marker = open("server-ready", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (marker < 0)
        sysbail("cannot create marker file");
    close(marker);
    conn = accept(fd, NULL, 0);
    if (conn == INVALID_SOCKET)
        sysbail("error accepting connection");
    socket_close(fd);
    return conn;
}
Example #3
0
/*
 * Bring up a server on port 11119 on the loopback address and test connecting
 * to it via IPv4 using network_client_create.  Takes an optional source
 * address to use for client connections.
 */
static void
test_create_ipv4(const char *source)
{
    socket_type fd;
    pid_t child;
    int status;

    /* Create the socket and listen to it. */
    fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119);
    if (fd == INVALID_SOCKET)
        sysbail("cannot create or bind socket");
    ok(fd != INVALID_SOCKET, "IPv4 network client");
    if (listen(fd, 1) < 0)
        sysbail("cannot listen to socket");

    /* Fork off a child that uses network_client_create. */
    child = fork();
    if (child < 0)
        sysbail("cannot fork");
    else if (child == 0)
        client_create_writer(source);
    else {
        test_server_accept(fd);
        waitpid(child, &status, 0);
        is_int(0, status, "client made correct connections");
    }
}
Example #4
0
/*
 * Test the network read function with a timeout.  We fork off a child process
 * that runs delay_writer, and then we read from the network twice, once with
 * a timeout and once without, and then try a third time when we should time
 * out.
 */
static void
test_network_read(void)
{
    socket_type fd, c;
    pid_t child;
    struct sockaddr_in sin;
    socklen_t slen;
    char buffer[4];

    /* Create the listening socket. */
    fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119);
    if (fd == INVALID_SOCKET)
        sysbail("cannot create or bind socket");
    if (listen(fd, 1) < 0)
        sysbail("cannot listen to socket");

    /* Fork off a child process that writes some data with delays. */
    child = fork();
    if (child < 0)
        sysbail("cannot fork");
    else if (child == 0) {
        socket_close(fd);
        client_delay_writer("127.0.0.1");
    }

    /* Set an alarm just in case our timeouts don't work. */
    alarm(10);

    /* Accept the client connection. */
    slen = sizeof(sin);
    c = accept(fd, &sin, &slen);
    if (c == INVALID_SOCKET)
        sysbail("cannot accept on socket");

    /* Now test a couple of simple reads, with and without timeout. */
    socket_set_errno(0);
    ok(network_read(c, buffer, sizeof(buffer), 0), "network_read");
    ok(memcmp("one\n", buffer, sizeof(buffer)) == 0, "...with good data");
    ok(network_read(c, buffer, sizeof(buffer), 1),
       "network_read with timeout");
    ok(memcmp("two\n", buffer, sizeof(buffer)) == 0, "...with good data");

    /*
     * The third read should abort with a timeout, since the writer is writing
     * with a ten second delay.
     */
    ok(!network_read(c, buffer, sizeof(buffer), 1),
       "network_read aborted with timeout");
    is_int(ETIMEDOUT, socket_errno, "...with correct error");
    ok(memcmp("two\n", buffer, sizeof(buffer)) == 0, "...and data unchanged");
    alarm(0);

    /* Clean up. */
    socket_close(c);
    kill(child, SIGTERM);
    waitpid(child, NULL, 0);
    socket_close(fd);
}
Example #5
0
/*
 * Kill a process and wait for it to exit.  Returns the status of the process.
 * Calls bail on a system failure or a failure of the process to exit.
 *
 * We are quite aggressive with error reporting here because child processes
 * that don't exit or that don't exist often indicate some form of test
 * failure.
 */
static int
process_kill(struct process *process)
{
    int result, i;
    int status = -1;
    struct timeval tv;
    unsigned long pid = process->pid;

    /* If the process is not a child, just kill it and hope. */
    if (!process->is_child) {
        if (kill(process->pid, SIGTERM) < 0 && errno != ESRCH)
            sysbail("cannot send SIGTERM to process %lu", pid);
        return 0;
    }

    /* Check if the process has already exited. */
    result = waitpid(process->pid, &status, WNOHANG);
    if (result < 0)
        sysbail("cannot wait for child process %lu", pid);
    else if (result > 0)
        return status;

    /*
     * Kill the process and wait for it to exit.  I don't want to go to the
     * work of setting up a SIGCHLD handler or a full event loop here, so we
     * effectively poll every tenth of a second for process exit (and
     * hopefully faster when it does since the SIGCHLD may interrupt our
     * select, although we're racing with it.
     */
    if (kill(process->pid, SIGTERM) < 0 && errno != ESRCH)
        sysbail("cannot send SIGTERM to child process %lu", pid);
    for (i = 0; i < PROCESS_WAIT * 10; i++) {
        tv.tv_sec = 0;
        tv.tv_usec = 100000;
        select(0, NULL, NULL, NULL, &tv);
        result = waitpid(process->pid, &status, WNOHANG);
        if (result < 0)
            sysbail("cannot wait for child process %lu", pid);
        else if (result > 0)
            return status;
    }

    /* The process still hasn't exited.  Bail. */
    bail("child process %lu did not exit on SIGTERM", pid);

    /* Not reached, but some compilers may get confused. */
    return status;
}
Example #6
0
/*
 * Reallocate memory, reporting a fatal error with bail on failure.
 */
void *
brealloc(void *p, size_t size)
{
    p = realloc(p, size);
    if (p == NULL)
        sysbail("failed to realloc %lu bytes", (unsigned long) size);
    return p;
}
Example #7
0
int
main(void)
{
    pam_handle_t *pamh;
    struct pam_args *args;
    struct pam_conv conv = { NULL, NULL };
    char *expected;
    struct output *seen;
#ifdef HAVE_KRB5
    krb5_error_code code;
    krb5_principal princ;
#endif

    plan(27);

    if (pam_start("test", NULL, &conv, &pamh) != PAM_SUCCESS)
        sysbail("Fake PAM initialization failed");
    args = putil_args_new(pamh, 0);
    if (args == NULL)
        bail("cannot create PAM argument struct");
    TEST(putil_crit,  LOG_CRIT,  "putil_crit");
    TEST(putil_err,   LOG_ERR,   "putil_err");
    putil_debug(args, "%s", "foo");
    ok(pam_output() == NULL, "putil_debug without debug on");
    args->debug = true;
    TEST(putil_debug, LOG_DEBUG, "putil_debug");
    args->debug = false;

    TEST_PAM(putil_crit_pam,  PAM_SYSTEM_ERR, LOG_CRIT,  "putil_crit_pam S");
    TEST_PAM(putil_crit_pam,  PAM_BUF_ERR,    LOG_CRIT,  "putil_crit_pam B");
    TEST_PAM(putil_crit_pam,  PAM_SUCCESS,    LOG_CRIT,  "putil_crit_pam ok");
    TEST_PAM(putil_err_pam,   PAM_SYSTEM_ERR, LOG_ERR,   "putil_err_pam");
    putil_debug_pam(args, PAM_SYSTEM_ERR, "%s", "bar");
    ok(pam_output() == NULL, "putil_debug_pam without debug on");
    args->debug = true;
    TEST_PAM(putil_debug_pam, PAM_SYSTEM_ERR, LOG_DEBUG, "putil_debug_pam");
    TEST_PAM(putil_debug_pam, PAM_SUCCESS,    LOG_DEBUG, "putil_debug_pam ok");
    args->debug = false;

#ifdef HAVE_KRB5
    TEST_KRB5(putil_crit_krb5,  LOG_CRIT,  "putil_crit_krb5");
    TEST_KRB5(putil_err_krb5,   LOG_ERR,   "putil_err_krb5");
    code = krb5_parse_name(args->ctx, "foo@[email protected]", &princ);
    putil_debug_krb5(args, code, "%s", "krb");
    ok(pam_output() == NULL, "putil_debug_krb5 without debug on");
    args->debug = true;
    TEST_KRB5(putil_debug_krb5, LOG_DEBUG, "putil_debug_krb5");
    args->debug = false;
#else
    skip_block(4, "not built with Kerberos support");
#endif

    putil_args_free(args);
    pam_end(pamh, 0);

    return 0;
}
Example #8
0
/*
 * Read the PID of a process from a file.  This is necessary when running
 * under fakeroot to get the actual PID of the remctld process.
 */
static long
read_pidfile(const char *path)
{
    FILE *file;
    char buffer[BUFSIZ];
    long pid;

    file = fopen(path, "r");
    if (file == NULL)
        sysbail("cannot open %s", path);
    if (fgets(buffer, sizeof(buffer), file) == NULL)
        sysbail("cannot read from %s", path);
    fclose(file);
    pid = strtol(buffer, NULL, 10);
    if (pid <= 0)
        bail("cannot read PID from %s", path);
    return pid;
}
Example #9
0
/*
 * vsprintf into a newly allocated string, reporting a fatal error with bail
 * on failure.
 */
void
bvasprintf(char **strp, const char *fmt, va_list args)
{
    int status;

    status = vasprintf(strp, fmt, args);
    if (status < 0)
        sysbail("failed to allocate memory for vasprintf");
}
Example #10
0
/*
 * Allocate cleared memory, reporting a fatal error with bail on failure.
 */
void *
bcalloc(size_t n, size_t size)
{
    void *p;

    p = calloc(n, size);
    if (p == NULL)
        sysbail("failed to calloc %lu", (unsigned long)(n * size));
    return p;
}
Example #11
0
/*
 * Allocate memory, reporting a fatal error with bail on failure.
 */
void *
bmalloc(size_t size)
{
    void *p;

    p = malloc(size);
    if (p == NULL)
        sysbail("failed to malloc %lu", (unsigned long) size);
    return p;
}
Example #12
0
/*
 * Copy a string, reporting a fatal error with bail on failure.
 */
char *
bstrdup(const char *s)
{
    char *p;
    size_t len;

    len = strlen(s) + 1;
    p = malloc(len);
    if (p == NULL)
        sysbail("failed to strdup %lu bytes", (unsigned long) len);
    memcpy(p, s, len);
    return p;
}
Example #13
0
int
main(void)
{
    struct kerberos_config *config;
    struct remctl *r;
    struct remctl_output *output;
    char *tmpdir, *confpath;
    FILE *conf;
    const char *test[] = { "test", "test", NULL };

    /* Unless we have Kerberos available, we can't really do anything. */
    config = kerberos_setup(TAP_KRB_NEEDS_KEYTAB);

    /* Write out our empty configuration file. */
    tmpdir = test_tmpdir();
    basprintf(&confpath, "%s/conf-empty", tmpdir);
    conf = fopen(confpath, "w");
    if (conf == NULL)
        sysbail("cannot create %s", confpath);
    fclose(conf);

    /* Now we can start remctl with our temporary configuration file. */
    remctld_start(config, "tmp/conf-empty", NULL);

    plan(7);

    /* Test that we get a valid UNKNOWN_COMMAND error. */
    r = remctl_new();
    ok(remctl_open(r, "localhost", 14373, config->principal), "remctl_open");
    ok(remctl_command(r, test), "remctl_command");
    output = remctl_output(r);
    ok(output != NULL, "first output token is not null");
    if (output == NULL)
        ok_block(4, 0, "...and has correct content");
    else {
        is_int(REMCTL_OUT_ERROR, output->type, "...and is an error");
        is_int(15, output->length, "...and is right length");
        if (output->data == NULL)
            ok(0, "...and has the right error message");
        else
            ok(memcmp("Unknown command", output->data, 15) == 0,
               "...and has the right error message");
        is_int(ERROR_UNKNOWN_COMMAND, output->error, "...and error number");
    }
    remctl_close(r);
    unlink(confpath);
    free(confpath);
    test_tmpdir_free(tmpdir);
    return 0;
}
Example #14
0
int
main(void)
{
    char *path, *tmp;
    FILE *output;
    const char *build;
    struct stat st;
    size_t length;

    output = fopen("c-tmpdir.output", "w");
    if (output == NULL)
        sysbail("cannot create c-tmpdir.output");
    fprintf(output, "Path to temporary directory: %s/tmp\n",
            getenv("C_TAP_BUILD"));
    fclose(output);
    build = getenv("C_TAP_BUILD");
    length = strlen(build) + strlen("/tmp") + 1;
    path = bcalloc_type(length, char);
    sprintf(path, "%s/tmp", build);
    if (access(path, F_OK) == 0)
        bail("%s already exists", path);
    free(path);
    path = test_tmpdir();
    printf("Path to temporary directory: %s\n", path);
    if (stat(path, &st) < 0)
        sysbail("cannot stat %s", path);
    if (!S_ISDIR(st.st_mode))
        sysbail("%s is not a directory", path);
    tmp = bstrdup(path);
    test_tmpdir_free(path);
    if (stat(tmp, &st) == 0)
        bail("temporary directory not removed");
    free(tmp);

    return 0;
}
Example #15
0
/*
 * Create a client socket, it for a connection, and return the connected
 * socket.
 */
static socket_type
create_client(void)
{
    socket_type fd;
    struct sockaddr_in saddr;
    struct timeval tv;

    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(0x7f000001UL);
    saddr.sin_port = htons(14373);
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == INVALID_SOCKET)
        sysbail("error creating socket");
    alarm(1);
    while (access("server-ready", F_OK) != 0) {
        tv.tv_sec = 0;
        tv.tv_usec = 10000;
        select(0, NULL, NULL, NULL, &tv);
    }
    alarm(0);
    if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
        sysbail("error connecting");
    return fd;
}
Example #16
0
int
main(void)
{
    pam_handle_t *pamh;
    struct pam_conv conv = { NULL, NULL };
    struct pam_args *args;

    plan(12);

    if (pam_start("test", NULL, &conv, &pamh) != PAM_SUCCESS)
        sysbail("Fake PAM initialization failed");
    args = putil_args_new(pamh, 0);
    ok(args != NULL, "New args struct is not NULL");
    if (args == NULL)
        ok_block(7, 0, "...args struct is NULL");
    else {
        ok(args->pamh == pamh, "...and pamh is correct");
        ok(args->config == NULL, "...and config is NULL");
        ok(args->user == NULL, "...and user is NULL");
        is_int(args->debug, false, "...and debug is false");
        is_int(args->silent, false, "...and silent is false");
#ifdef HAVE_KRB5
        ok(args->ctx != NULL, "...and the Kerberos context is initialized");
        ok(args->realm == NULL, "...and realm is NULL");
#else
        skip_block(2, "Kerberos support not configured");
#endif
    }
    putil_args_free(args);
    ok(1, "Freeing the args struct works");

    args = putil_args_new(pamh, PAM_SILENT);
    ok(args != NULL, "New args struct with PAM_SILENT is not NULL");
    if (args == NULL)
        ok(0, "...args is NULL");
    else
        is_int(args->silent, true, "...and silent is true");
    putil_args_free(args);

    putil_args_free(NULL);
    ok(1, "Freeing a NULL args struct works");

    pam_end(pamh, 0);

    return 0;
}
Example #17
0
/*
 * Copy up to n characters of a string, reporting a fatal error with bail on
 * failure.  Don't use the system strndup function, since it may not exist and
 * the TAP library doesn't assume any portability support.
 */
char *
bstrndup(const char *s, size_t n)
{
    const char *p;
    char *copy;
    size_t length;

    /* Don't assume that the source string is nul-terminated. */
    for (p = s; (size_t) (p - s) < n && *p != '\0'; p++)
        ;
    length = p - s;
    copy = malloc(length + 1);
    if (p == NULL)
        sysbail("failed to strndup %lu bytes", (unsigned long) length);
    memcpy(copy, s, length);
    copy[length] = '\0';
    return copy;
}
Example #18
0
/*
 * Create a temporary directory, tmp, under BUILD if set and the current
 * directory if it does not.  Returns the path to the temporary directory in
 * newly allocated memory, and calls bail on any failure.  The return value
 * should be freed with test_tmpdir_free.
 *
 * This function uses sprintf because it attempts to be independent of all
 * other portability layers.  The use immediately after a memory allocation
 * should be safe without using snprintf or strlcpy/strlcat.
 */
char *
test_tmpdir(void)
{
    const char *build;
    char *path = NULL;
    size_t length;

    build = getenv("BUILD");
    if (build == NULL)
        build = ".";
    length = strlen(build) + strlen("/tmp") + 1;
    path = bmalloc(length);
    snprintf(path, length, "%s/tmp", build);
    if (access(path, X_OK) < 0)
        if (mkdir(path, 0777) < 0)
            sysbail("error creating temporary directory %s", path);
    return path;
}
Example #19
0
/*
 * Read a line from a file into a BUFSIZ buffer, failing if the line was too
 * long to fit into the buffer, and returns a copy of that line in newly
 * allocated memory.  Ignores blank lines and comments.  Caller is responsible
 * for freeing.  Returns NULL on end of file and fails on read errors.
 */
static char *
readline(FILE *file)
{
    char buffer[BUFSIZ];
    char *line, *first;

    do {
        line = fgets(buffer, sizeof(buffer), file);
        if (line == NULL) {
            if (feof(file))
                return NULL;
            sysbail("cannot read line from script");
        }
        if (buffer[strlen(buffer) - 1] != '\n')
            bail("script line too long");
        buffer[strlen(buffer) - 1] = '\0';
        first = skip_whitespace(buffer);
    } while (first[0] == '#' || first[0] == '\0');
    line = bstrdup(buffer);
    return line;
}
Example #20
0
int
main(void)
{
    struct buffer one = { 0, 0, 0, NULL };
    struct buffer two = { 0, 0, 0, NULL };
    struct buffer *three;
    int fd;
    char *data;
    ssize_t count;
    size_t offset;

    plan(89);

    /* buffer_set, buffer_append, buffer_swap */
    buffer_set(&one, test_string1, sizeof(test_string1));
    is_int(1024, one.size, "minimum size is 1024");
    is_int(0, one.used, "used starts at 0");
    is_int(sizeof(test_string1), one.left, "left is correct");
    is_string(test_string1, one.data, "data is corect");
    buffer_append(&one, test_string2, sizeof(test_string2));
    is_int(1024, one.size, "appended data doesn't change size");
    is_int(0, one.used, "or used");
    is_int(sizeof(test_string3), one.left, "but left is the right size");
    ok(memcmp(one.data, test_string3, sizeof(test_string3)) == 0,
       "and the resulting data is correct");
    one.left -= sizeof(test_string1);
    one.used += sizeof(test_string1);
    buffer_append(&one, test_string1, sizeof(test_string1));
    is_int(1024, one.size, "size still isn't larger after adding data");
    is_int(sizeof(test_string1), one.used, "and used is preserved on append");
    is_int(sizeof(test_string3), one.left, "and left is updated properly");
    ok(memcmp(one.data + one.used, test_string2, sizeof(test_string2)) == 0,
       "and the middle data is unchanged");
    ok(memcmp(one.data + one.used + sizeof(test_string2), test_string1,
              sizeof(test_string1)) == 0, "and the final data is correct");
    buffer_set(&one, test_string1, sizeof(test_string1));
    buffer_set(&two, test_string2, sizeof(test_string2));
    buffer_swap(&one, &two);
    is_int(1024, one.size, "swap #1 size is correct");
    is_int(0, one.used, "swap #1 used is correct");
    is_int(sizeof(test_string2), one.left, "swap #1 left is correct");
    is_string(test_string2, one.data, "swap #1 data is correct");
    is_int(1024, two.size, "swap #2 size is correct");
    is_int(0, two.used, "swap #2 used is correct");
    is_int(sizeof(test_string1), two.left, "swap #2 left is correct");
    is_string(test_string1, two.data, "swap #2 data is correct");
    free(one.data);
    free(two.data);
    one.data = NULL;
    two.data = NULL;
    one.size = 0;
    two.size = 0;

    /* buffer_resize */
    three = buffer_new();
    ok(three != NULL, "buffer_new works");
    if (three == NULL)
        bail("buffer_new returned NULL");
    is_int(0, three->size, "initial size is 0");
    buffer_set(three, test_string1, sizeof(test_string1));
    is_int(1024, three->size, "size becomes 1024 when adding data");
    buffer_resize(three, 512);
    is_int(1024, three->size, "resizing to something smaller doesn't change");
    buffer_resize(three, 1025);
    is_int(2048, three->size, "resizing to something larger goes to 2048");
    buffer_free(three);

    /* buffer_read, buffer_find_string, buffer_compact */
    fd = open("buffer-test", O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
        sysbail("cannot create buffer-test");
    data = bmalloc(2048);
    memset(data, 'a', 1023);
    data[1023] = '\r';
    data[1024] = '\n';
    memset(data + 1025, 'b', 1023);
    if (xwrite(fd, data, 2048) < 2048)
        sysbail("cannot write to buffer-test");
    if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
        sysbail("cannot rewind buffer-test");
    three = buffer_new();
    ok(three != NULL, "buffer_new works");
    if (three == NULL)
        bail("buffer_new returned NULL");
    is_int(0, three->size, "and initial size is 0");
    buffer_resize(three, 1024);
    is_int(1024, three->size, "resize to 1024 works");
    count = buffer_read(three, fd);
    is_int(1024, count, "reading into a buffer of size 1024 reads 1024");
    offset = 0;
    ok(!buffer_find_string(three, "\r\n", 0, &offset),
       "buffer_find_string with truncated string fails");
    is_int(0, offset, "and offset is unchanged");
    ok(memcmp(three->data, data, three->size) == 0, "buffer data is correct");
    buffer_resize(three, 2048);
    is_int(2048, three->size, "resizing the buffer to 2048 works");
    count = buffer_read(three, fd);
    is_int(1024, count, "and now we can read the rest of the data");
    ok(memcmp(three->data, data, 2048) == 0, "and it's all there");
    ok(!buffer_find_string(three, "\r\n", 1024, &offset),
       "buffer_find_string with a string starting before offset fails");
    is_int(0, offset, "and offset is unchanged");
    ok(buffer_find_string(three, "\r\n", 0, &offset),
       "finding the string on the whole buffer works");
    is_int(1023, offset, "and returns the correct location");
    three->used += 400;
    three->left -= 400;
    buffer_compact(three);
    is_int(2048, three->size, "compacting buffer doesn't change the size");
    is_int(0, three->used, "but used is now zero");
    is_int(1648, three->left, "and left is decreased appropriately");
    ok(memcmp(three->data, data + 400, 1648) == 0, "and the data is correct");
    count = buffer_read(three, fd);
    is_int(0, count, "reading at EOF returns 0");
    close(fd);
    unlink("buffer-test");
    free(data);
    buffer_free(three);

    /* buffer_sprintf and buffer_append_sprintf */
    three = buffer_new();
    buffer_append_sprintf(three, "testing %d testing", 6);
    is_int(0, three->used, "buffer_append_sprintf doesn't change used");
    is_int(17, three->left, "but sets left correctly");
    buffer_append(three, "", 1);
    is_int(18, three->left, "appending a nul works");
    is_string("testing 6 testing", three->data, "and the data is correct");
    three->left--;
    three->used += 5;
    three->left -= 5;
    buffer_append_sprintf(three, " %d", 7);
    is_int(14, three->left, "appending a digit works");
    buffer_append(three, "", 1);
    is_string("testing 6 testing 7", three->data, "and the data is correct");
    buffer_sprintf(three, "%d testing", 8);
    is_int(9, three->left, "replacing the buffer works");
    is_string("8 testing", three->data, "and the results are correct");
    data = bmalloc(1050);
    memset(data, 'a', 1049);
    data[1049] = '\0';
    is_int(1024, three->size, "size before large sprintf is 1024");
    buffer_sprintf(three, "%s", data);
    is_int(2048, three->size, "size after large sprintf is 2048");
    is_int(1049, three->left, "and left is correct");
    buffer_append(three, "", 1);
    is_string(data, three->data, "and data is correct");
    free(data);
    buffer_free(three);

    /* buffer_read_all */
    fd = open("buffer-test", O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
        sysbail("cannot create buffer-test");
    data = bmalloc(2049);
    memset(data, 'a', 2049);
    if (xwrite(fd, data, 2049) < 2049)
        sysbail("cannot write to buffer-test");
    if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
        sysbail("cannot rewind buffer-test");
    three = buffer_new();
    ok(buffer_read_all(three, fd), "buffer_read_all succeeds");
    is_int(0, three->used, "and unused is zero");
    is_int(2049, three->left, "and left is correct");
    is_int(4096, three->size, "and size is correct");
    ok(memcmp(data, three->data, 2049) == 0, "and data is correct");
    if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
        sysbail("cannot rewind buffer-test");
    ok(buffer_read_all(three, fd), "reading again succeeds");
    is_int(0, three->used, "and used is correct");
    is_int(4098, three->left, "and left is now larger");
    is_int(8192, three->size, "and size doubled");
    ok(memcmp(data, three->data + 2049, 2049) == 0, "and data is correct");

    /* buffer_read_file */
    if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
        sysbail("cannot rewind buffer-test");
    buffer_free(three);
    three = buffer_new();
    ok(buffer_read_file(three, fd), "buffer_read_file succeeds");
    is_int(0, three->used, "and leaves unused at 0");
    is_int(2049, three->left, "and left is correct");
    is_int(3072, three->size, "and size is a multiple of 1024");
    ok(memcmp(data, three->data, 2049) == 0, "and the data is correct");

    /* buffer_read_all and buffer_read_file errors */
    close(fd);
    ok(!buffer_read_all(three, fd), "buffer_read_all on closed fd fails");
    is_int(3072, three->size, "and size is unchanged");
    ok(!buffer_read_file(three, fd), "buffer_read_file on closed fd fails");
    is_int(3072, three->size, "and size is unchanged");
    is_int(2049, three->left, "and left is unchanged");
    unlink("buffer-test");
    free(data);
    buffer_free(three);

    /* buffer_vsprintf and buffer_append_vsprintf */
    three = buffer_new();
    test_append_vsprintf(three, "testing %d testing", 6);
    is_int(0, three->used, "buffer_append_vsprintf leaves used as 0");
    is_int(17, three->left, "and left is correct");
    buffer_append(three, "", 1);
    is_int(18, three->left, "and left is correct after appending a nul");
    is_string("testing 6 testing", three->data, "and data is correct");
    three->left--;
    three->used += 5;
    three->left -= 5;
    test_append_vsprintf(three, " %d", 7);
    is_int(14, three->left, "and appending results in the correct left");
    buffer_append(three, "", 1);
    is_string("testing 6 testing 7", three->data, "and the right data");
    test_vsprintf(three, "%d testing", 8);
    is_int(9, three->left, "replacing the buffer results in the correct size");
    is_string("8 testing", three->data, "and the correct data");
    data = bmalloc(1050);
    memset(data, 'a', 1049);
    data[1049] = '\0';
    is_int(1024, three->size, "size is 1024 before large vsprintf");
    test_vsprintf(three, "%s", data);
    is_int(2048, three->size, "and 2048 afterwards");
    is_int(1049, three->left, "and left is correct");
    buffer_append(three, "", 1);
    is_string(data, three->data, "and data is correct");
    free(data);
    buffer_free(three);

    /* Test buffer_free with NULL and ensure it doesn't explode. */
    buffer_free(NULL);

    return 0;
}
Example #21
0
/*
 * Test connect timeouts using IPv4.  Bring up a server on port 11119 on the
 * loopback address and test connections to it.  The server only accepts one
 * connection at a time, so a subsequent connection will time out.
 */
static void
test_timeout_ipv4(void)
{
    socket_type fd, c;
    pid_t child;
    socket_type block[20];
    int i, err;

    /*
     * Create the listening socket.  We set the listening queue size to 1,
     * but some operating systems, including Linux, will allow more
     * connection attempts to succeed than the backlog size.  We'll therefore
     * have to hammer this server with connections to try to get it to fail.
     */
    fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119);
    if (fd == INVALID_SOCKET)
        sysbail("cannot create or bind socket");
    if (listen(fd, 1) < 0)
        sysbail("cannot listen to socket");

    /* Fork off a child that just runs accept once and then sleeps. */
    child = fork();
    if (child < 0)
        sysbail("cannot fork");
    else if (child == 0) {
        alarm(10);
        c = accept(fd, NULL, 0);
        if (c == INVALID_SOCKET)
            _exit(1);
        sleep(9);
        _exit(0);
    }

    /* In the parent.  Open that first connection. */
    socket_close(fd);
    c = network_connect_host("127.0.0.1", 11119, NULL, 1);
    ok(c != INVALID_SOCKET, "Timeout: first connection worked");

    /*
     * It can take up to fifteen connections on Linux before connections start
     * actually timing out, and sometimes they never do.
     */
    alarm(20);
    for (i = 0; i < (int) ARRAY_SIZE(block); i++) {
        block[i] = network_connect_host("127.0.0.1", 11119, NULL, 1);
        if (block[i] == INVALID_SOCKET)
            break;
    }
    err = socket_errno;

    /*
     * If we reached the end of the array, we can't force a connection
     * timeout, so just skip this test.  It's also possible that the
     * connection will fail with ECONNRESET or ECONNREFUSED if the nine second
     * sleep in the child passed, so skip in that case as well.  Otherwise,
     * expect a failure due to timeout in a reasonable amount of time (less
     * than our 20-second alarm).
     */
    if (i == ARRAY_SIZE(block))
        skip_block(2, "short listen queue does not prevent connections");
    else {
        diag("Finally timed out on socket %d", i);
        ok(block[i] == INVALID_SOCKET, "Later connection timed out");
        if (err == ECONNRESET || err == ECONNREFUSED)
            skip("connections rejected without timeout");
        else
            is_int(ETIMEDOUT, err, "...with correct error code");
    }
    alarm(0);

    /* Shut down the client and clean up resources. */
    kill(child, SIGTERM);
    waitpid(child, NULL, 0);
    socket_close(c);
    for (i--; i >= 0; i--)
        if (block[i] != INVALID_SOCKET)
            socket_close(block[i]);
    socket_close(fd);
}
Example #22
0
int
main(void)
{
    int master, data, out1, out2;
    socklen_t size;
    ssize_t status;
    struct sockaddr_in sin;
    pid_t child;
    char buffer[] = "D";

    plan(8);

    /* Parent will create the socket first to get the port number. */
    memset(&sin, '\0', sizeof(sin));
    sin.sin_family = AF_INET;
    master = socket(AF_INET, SOCK_STREAM, 0);
    if (master == -1)
        sysbail("socket creation failed");
    if (bind(master, (struct sockaddr *) &sin, sizeof(sin)) < 0)
        sysbail("bind failed");
    size = sizeof(sin);
    if (getsockname(master, (struct sockaddr *) &sin, &size) < 0)
        sysbail("getsockname failed");
    if (listen(master, 1) < 0)
        sysbail("listen failed");

    /* Duplicate standard output to test close-on-exec. */
    out1 = 8;
    out2 = 9;
    if (dup2(fileno(stdout), out1) < 0)
        sysbail("cannot dup stdout to fd 8");
    if (dup2(fileno(stdout), out2) < 0)
        sysbail("cannot dup stdout to fd 9");
    ok(fdflag_close_exec(out1, true), "set fd 8 to close-on-exec");
    ok(fdflag_close_exec(out2, true), "set fd 9 to close-on-exec");
    ok(fdflag_close_exec(out2, false), "set fd 9 back to regular");

    /*
     * Fork, child closes the open socket and then tries to connect, parent
     * calls listen() and accept() on it.  Parent will then set the socket
     * non-blocking and try to read from it to see what happens, then write to
     * the socket and close it, triggering the child close and exit.
     *
     * Before the child exits, it will exec a shell that will print "no" to
     * the duplicate of stdout that the parent created and then the ok to
     * regular stdout.
     */
    child = fork();
    if (child < 0) {
        sysbail("fork failed");
    } else if (child != 0) {
        size = sizeof(sin);
        data = accept(master, (struct sockaddr *) &sin, &size);
        close(master);
        if (data < 0)
            sysbail("accept failed");
        ok(fdflag_nonblocking(data, true), "set socket non-blocking");
        status = read(data, buffer, sizeof(buffer));
        is_int(-1, status, "got -1 from non-blocking read");
        is_int(EAGAIN, errno, "...with EAGAIN errno");
        if (write(data, buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer))
            sysbail("write failed");
        close(data);
        testnum += 2;
    } else {
        data = socket(AF_INET, SOCK_STREAM, 0);
        if (data < 0)
            sysbail("child socket failed");
        if (connect(data, (struct sockaddr *) &sin, sizeof(sin)) < 0)
            sysbail("child connect failed");
        if (read(data, buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer))
            sysbail("read failed");
        fclose(stderr);
        execlp("sh", "sh", "-c",
               "printf 'not ' >&8; echo ok 7; echo 'ok 8' >&9", (char *) 0);
        sysbail("exec failed");
    }
    waitpid(child, NULL, 0);
    exit(0);
}
Example #23
0
int
main(void)
{
    struct script_config config;
    struct kerberos_config *krbconf;
    char *k5login;
    struct extra extra;
    struct passwd pwd;
    FILE *file;

    /* Load the Kerberos principal and password from a file. */
    krbconf = kerberos_setup(TAP_KRB_NEEDS_PASSWORD);
    memset(&config, 0, sizeof(config));
    config.user = krbconf->username;
    extra.realm = krbconf->realm;
    config.authtok = krbconf->password;
    config.extra[0] = krbconf->userprinc;

    /* Generate a testing krb5.conf file. */
    kerberos_generate_conf(krbconf->realm);

    /* Create a fake passwd struct for our user. */
    memset(&pwd, 0, sizeof(pwd));
    pwd.pw_name = krbconf->username;
    pwd.pw_uid = getuid();
    pwd.pw_gid = getgid();
    basprintf(&pwd.pw_dir, "%s/tmp", getenv("BUILD"));
    pam_set_pwd(&pwd);

    plan_lazy();

    /* Basic test. */
    run_script("data/scripts/cache/basic", &config);

    /* Check the cache status before the session is closed. */
    config.callback = check_cache;
    config.data = &extra;
    run_script("data/scripts/cache/open-session", &config);

    /* Change the authenticating user and test search_k5login. */
    pwd.pw_name = (char *) "testuser";
    config.user = "******";
    basprintf(&k5login, "%s/.k5login", pwd.pw_dir);
    file = fopen(k5login, "w");
    if (file == NULL)
        sysbail("cannot create %s", k5login);
    if (fprintf(file, "%s\n", krbconf->userprinc) < 0)
        sysbail("cannot write to %s", k5login);
    if (fclose(file) < 0)
        sysbail("cannot flush %s", k5login);
    run_script("data/scripts/cache/search-k5login", &config);
    config.callback = NULL;
    run_script("data/scripts/cache/search-k5login-debug", &config);
    unlink(k5login);
    free(k5login);

    /* Test search_k5login when no .k5login file exists. */
    pwd.pw_name = krbconf->username;
    config.user = krbconf->username;
    diag("testing search_k5login with no .k5login file");
    run_script("data/scripts/cache/search-k5login", &config);

    free(pwd.pw_dir);
    return 0;
}
Example #24
0
int
main(void)
{
    int flag, status;
    socklen_t flaglen;
    struct addrinfo *ai4, *ai6;
    struct addrinfo hints;
    char addr[INET6_ADDRSTRLEN];
    char *p;
    socket_type fd;
    static const char *port = "119";
    static const char *ipv6_addr = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210";

#ifndef HAVE_INET6
    skip_all("IPv6 not supported");
#endif

    /* Set up the plan. */
    plan(34);

    /* Get IPv4 and IPv6 sockaddrs to use for subsequent tests. */
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_NUMERICHOST;
    hints.ai_socktype = SOCK_STREAM;
    status = getaddrinfo("127.0.0.1", port, &hints, &ai4);
    if (status != 0)
        bail("getaddrinfo on 127.0.0.1 failed: %s", gai_strerror(status));
    status = getaddrinfo(ipv6_addr, port, &hints, &ai6);
    if (status != 0)
        bail("getaddr on %s failed: %s", ipv6_addr, gai_strerror(status));

    /* Test network_sockaddr_sprint. */
    ok(network_sockaddr_sprint(addr, sizeof(addr), ai6->ai_addr),
       "sprint of IPv6 address");
    for (p = addr; *p != '\0'; p++)
        if (islower((unsigned char) *p))
            *p = toupper((unsigned char) *p);
    is_string(ipv6_addr, addr, "...with right results");

    /* Test network_sockaddr_port. */
    is_int(119, network_sockaddr_port(ai6->ai_addr), "sockaddr_port IPv6");

    /* Test network_sockaddr_equal. */
    ok(network_sockaddr_equal(ai6->ai_addr, ai6->ai_addr),
       "sockaddr_equal IPv6");
    ok(!network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr),
       "...and not equal to IPv4");
    ok(!network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr),
       "...other way around");
    freeaddrinfo(ai6);

    /* Test IPv4 mapped addresses. */
    status = getaddrinfo("::ffff:7f00:1", NULL, &hints, &ai6);
    if (status != 0)
        bail("getaddr on ::ffff:7f00:1 failed: %s", gai_strerror(status));
    ok(network_sockaddr_sprint(addr, sizeof(addr), ai6->ai_addr),
       "sprint of IPv4-mapped address");
    is_string("127.0.0.1", addr, "...with right IPv4 result");
    ok(network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr),
       "sockaddr_equal of IPv4-mapped address");
    ok(network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr),
       "...and other way around");
    freeaddrinfo(ai4);
    status = getaddrinfo("127.0.0.2", NULL, &hints, &ai4);
    if (status != 0)
        bail("getaddrinfo on 127.0.0.2 failed: %s", gai_strerror(status));
    ok(!network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr),
       "...but not some other address");
    ok(!network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr),
       "...and the other way around");
    freeaddrinfo(ai6);
    freeaddrinfo(ai4);

    /* Tests for network_addr_compare. */
    is_addr_compare(1, ipv6_addr,   ipv6_addr,     NULL);
    is_addr_compare(1, ipv6_addr,   ipv6_addr,     "128");
    is_addr_compare(1, ipv6_addr,   ipv6_addr,     "60");
    is_addr_compare(1, "::127",     "0:0::127",    "128");
    is_addr_compare(1, "::127",     "0:0::128",    "120");
    is_addr_compare(0, "::127",     "0:0::128",    "128");
    is_addr_compare(0, "::7fff",    "0:0::8000",   "113");
    is_addr_compare(1, "::7fff",    "0:0::8000",   "112");
    is_addr_compare(0, "::3:ffff",  "::2:ffff",    "120");
    is_addr_compare(0, "::3:ffff",  "::2:ffff",    "119");
    is_addr_compare(0, "ffff::1",   "7fff::1",     "1");
    is_addr_compare(1, "ffff::1",   "7fff::1",     "0");
    is_addr_compare(0, "fffg::1",   "fffg::1",     NULL);
    is_addr_compare(0, "ffff::1",   "7fff::1",     "-1");
    is_addr_compare(0, "ffff::1",   "ffff::1",     "-1");
    is_addr_compare(0, "ffff::1",   "ffff::1",     "129");

    /* Test setting various socket options. */
    fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_IP);
    if (fd == INVALID_SOCKET)
        sysbail("cannot create socket");
    network_set_reuseaddr(fd);
#ifdef SO_REUSEADDR
    flag = 0;
    flaglen = sizeof(flag);
    is_int(0, getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, &flaglen),
           "Getting SO_REUSEADDR works");
    ok(flag, "...and it is set");
#else
    skip_block(2, "SO_REUSEADDR not supported");
#endif
    network_set_v6only(fd);
#ifdef IPV6_V6ONLY
    flag = 0;
    flaglen = sizeof(flag);
    is_int(0, getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, &flaglen),
           "Getting IPV6_V6ONLY works");
    ok(flag, "...and it is set");
#else
    skip_block(2, "IPV6_V6ONLY not supported");
#endif
    network_set_freebind(fd);
#ifdef IP_FREEBIND
    flag = 0;
    flaglen = sizeof(flag);
    is_int(0, getsockopt(fd, IPPROTO_IP, IP_FREEBIND, &flag, &flaglen),
           "Getting IP_FREEBIND works");
    ok(flag, "...and it is set");
#else
    skip_block(2, "IP_FREEBIND not supported");
#endif
    close(fd);

    return 0;
}
Example #25
0
File: basic-t.c Project: rra/lbcd
int
main(void)
{
    socket_type fd;
    struct sockaddr_in sin;
    size_t size;
    ssize_t result;
    struct lbcd_reply reply;
    struct lbcd_request request;

    /* Declare a plan. */
    plan(65);

    /* Start the lbcd daemon, allowing load and rr services. */
    lbcd_start("-a", "load", "-a", "rr", NULL);

    /* Set up our client socket. */
    fd = network_client_create(PF_INET, SOCK_DGRAM, "127.0.0.1");
    if (fd == INVALID_SOCKET)
        sysbail("cannot create client socket");
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(14330);
    sin.sin_addr.s_addr = htonl(0x7f000001UL);
    if (connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
        sysbail("cannot connect client socket");

    /* Send a simple version three query and get the reply. */
    memset(&request, 0, sizeof(request));
    request.h.version = htons(3);
    request.h.id = htons(10);
    request.h.op = htons(LBCD_OP_LBINFO);
    result = send(fd, &request, sizeof(struct lbcd_header), 0);
    if (result != (ssize_t) sizeof(struct lbcd_header))
        sysbail("cannot send simple version 3 query");
    memset(&reply, 0, sizeof(reply));
    result = recv(fd, &reply, sizeof(reply), 0);

    /* Check that the reply is what we expect. */
    is_sane_reply(&request, &reply, result, "simple protocol three query");

    /* Send a version two query and get the reply. */
    request.h.version = htons(2);
    request.h.id = htons(20);
    request.h.status = htons(200);
    result = send(fd, &request, sizeof(struct lbcd_header), 0);
    if (result != (ssize_t) sizeof(struct lbcd_header))
        sysbail("cannot send version 2 query");
    memset(&reply, 0, sizeof(reply));
    result = recv(fd, &reply, sizeof(reply), 0);

    /* Check that the reply is what we expect. */
    is_sane_reply(&request, &reply, result, "protocol two query");

    /*
     * Send a more complex version three query with three requested services:
     * default, which should always be allowed, load, which should match
     * default, and rr.
     */
    request.h.version = htons(3);
    request.h.status = htons(3);
    strlcpy(request.names[0], "default", sizeof(request.names[0]));
    strlcpy(request.names[1], "load", sizeof(request.names[0]));
    strlcpy(request.names[2], "rr", sizeof(request.names[0]));
    size = sizeof(struct lbcd_header) + 3 * sizeof(lbcd_name_type);
    result = send(fd, &request, size, 0);
    if (result != (ssize_t) size)
        sysbail("cannot send complex version 3 query");
    memset(&reply, 0, sizeof(reply));
    result = recv(fd, &reply, sizeof(reply), 0);

    /* Check that the reply is what we expect. */
    is_sane_reply(&request, &reply, result, "complex protocol three query");
    is_int(ntohl(reply.weights[0].host_weight),
           ntohl(reply.weights[1].host_weight),
           "...default service weight matches first weight");
    is_int(ntohl(reply.weights[0].host_incr),
           ntohl(reply.weights[1].host_incr),
           "...default service increment matches first increment");
    is_int(ntohl(reply.weights[0].host_weight),
           ntohl(reply.weights[2].host_weight),
           "...load service weight matches first weight");
    is_int(ntohl(reply.weights[0].host_incr),
           ntohl(reply.weights[2].host_incr),
           "...load service increment matches first increment");
    is_int(1, ntohl(reply.weights[3].host_weight),
           "...rr service weight is 1");
    is_int(1, ntohl(reply.weights[3].host_incr),
           "...rr service increment is 1");

    /* All done.  Clean up and return. */
    close(fd);
    return 0;
}
Example #26
0
int
main(void)
{
    pam_handle_t *pamh;
    struct pam_conv conv = { NULL, NULL };
    char **env;
    size_t i;

    /*
     * Skip this test if the native PAM library doesn't support a PAM
     * environment, since we "break" pam_putenv to mirror the native behavior
     * in that case.
     */
#ifndef HAVE_PAM_GETENV
    skip_all("system doesn't support PAM environment");
#endif

    plan(33);

    /* Basic environment manipulation. */
    if (pam_start("test", NULL, &conv, &pamh) != PAM_SUCCESS)
        sysbail("Fake PAM initialization failed");
    is_int(PAM_BAD_ITEM, pam_putenv(pamh, "TEST"), "delete when NULL");
    ok(pam_getenv(pamh, "TEST") == NULL, "getenv when NULL");
    env = pam_getenvlist(pamh);
    ok(env != NULL, "getenvlist when NULL returns non-NULL");
    is_string(NULL, env[0], "...but first element is NULL");
    for (i = 0; env[i] != NULL; i++)
        free(env[i]);
    free(env);

    /* putenv and getenv. */
    is_int(PAM_SUCCESS, pam_putenv(pamh, "TEST=foo"), "putenv TEST");
    is_string("foo", pam_getenv(pamh, "TEST"), "getenv TEST");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=bar"), "putenv FOO");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "BAR=baz"), "putenv BAR");
    is_string("foo", pam_getenv(pamh, "TEST"), "getenv TEST");
    is_string("bar", pam_getenv(pamh, "FOO"), "getenv FOO");
    is_string("baz", pam_getenv(pamh, "BAR"), "getenv BAR");
    ok(pam_getenv(pamh, "BAZ") == NULL, "getenv BAZ is NULL");

    /* Replacing and deleting environment variables. */
    is_int(PAM_BAD_ITEM, pam_putenv(pamh, "BAZ"), "putenv nonexistent delete");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=foo"), "putenv replace");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOON=bar=n"), "putenv prefix");
    is_string("foo", pam_getenv(pamh, "FOO"), "getenv FOO");
    is_string("bar=n", pam_getenv(pamh, "FOON"), "getenv FOON");
    is_int(PAM_BAD_ITEM, pam_putenv(pamh, "FO"), "putenv delete FO");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO"), "putenv delete FOO");
    ok(pam_getenv(pamh, "FOO") == NULL, "getenv FOO is NULL");
    is_string("bar=n", pam_getenv(pamh, "FOON"), "getenv FOON");
    is_string("baz", pam_getenv(pamh, "BAR"), "getenv BAR");

    /* pam_getenvlist. */
    env = pam_getenvlist(pamh);
    ok(env != NULL, "getenvlist not NULL");
    is_string("TEST=foo", env[0], "getenvlist TEST");
    is_string("BAR=baz", env[1], "getenvlist BAR");
    is_string("FOON=bar=n", env[2], "getenvlist FOON");
    ok(env[3] == NULL, "getenvlist length");
    for (i = 0; env[i] != NULL; i++)
        free(env[i]);
    free(env);
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=foo"), "putenv FOO");
    is_string("TEST=foo", pamh->environ[0], "pamh environ TEST");
    is_string("BAR=baz", pamh->environ[1], "pamh environ BAR");
    is_string("FOON=bar=n", pamh->environ[2], "pamh environ FOON");
    is_string("FOO=foo", pamh->environ[3], "pamh environ FOO");
    ok(pamh->environ[4] == NULL, "pamh environ length");

    pam_end(pamh, 0);

    return 0;
}
Example #27
0
int
main(void)
{
    pam_handle_t *pamh;
    struct pam_args *args;
    struct pam_conv conv = { NULL, NULL };
    bool status;
    struct vector *cells;
    char *program;
    struct output *seen;
    const char *argv_bool[2] = { NULL, NULL };
    const char *argv_err[2] = { NULL, NULL };
    const char *argv_empty[] = { NULL };
#ifdef HAVE_KRB5
    const char *argv_all[] = {
        "cells=stanford.edu,ir.stanford.edu", "debug", "expires=1d",
        "ignore_root", "minimum_uid=1000", "program=/bin/true"
    };
    char *krb5conf;
#else
    const char *argv_all[] = {
        "cells=stanford.edu,ir.stanford.edu", "debug", "expires=86400",
        "ignore_root", "minimum_uid=1000", "program=/bin/true"
    };
#endif

    if (pam_start("test", NULL, &conv, &pamh) != PAM_SUCCESS)
        sysbail("cannot create pam_handle_t");
    args = putil_args_new(pamh, 0);
    if (args == NULL)
        bail("cannot create PAM argument struct");

    plan(161);

    /* First, check just the defaults. */
    args->config = config_new();
    status = putil_args_defaults(args, options, optlen);
    ok(status, "Setting the defaults");
    ok(args->config->cells == NULL, "...cells default");
    is_int(false, args->config->debug, "...debug default");
    is_int(10, args->config->expires, "...expires default");
    is_int(true, args->config->ignore_root, "...ignore_root default");
    is_int(0, args->config->minimum_uid, "...minimum_uid default");
    ok(args->config->program == NULL, "...program default");

    /* Now parse an empty set of PAM arguments.  Nothing should change. */
    status = putil_args_parse(args, 0, argv_empty, options, optlen);
    ok(status, "Parse of empty argv");
    ok(args->config->cells == NULL, "...cells still default");
    is_int(false, args->config->debug, "...debug still default");
    is_int(10, args->config->expires, "...expires default");
    is_int(true, args->config->ignore_root, "...ignore_root still default");
    is_int(0, args->config->minimum_uid, "...minimum_uid still default");
    ok(args->config->program == NULL, "...program still default");

    /* Now, check setting everything. */
    status = putil_args_parse(args, 6, argv_all, options, optlen);
    ok(status, "Parse of full argv");
    if (args->config->cells == NULL)
        ok_block(4, false, "...cells is set");
    else {
        ok(args->config->cells != NULL, "...cells is set");
        is_int(2, args->config->cells->count, "...with two cells");
        is_string("stanford.edu", args->config->cells->strings[0],
                  "...first is stanford.edu");
        is_string("ir.stanford.edu", args->config->cells->strings[1],
                  "...second is ir.stanford.edu");
    }
    is_int(true, args->config->debug, "...debug is set");
    is_int(86400, args->config->expires, "...expires is set");
    is_int(true, args->config->ignore_root, "...ignore_root is set");
    is_int(1000, args->config->minimum_uid, "...minimum_uid is set");
    is_string("/bin/true", args->config->program, "...program is set");
    config_free(args->config);
    args->config = NULL;

    /* Test deep copying of defaults. */
    cells = vector_new();
    if (cells == NULL)
        sysbail("cannot allocate memory");
    vector_add(cells, "foo.com");
    vector_add(cells, "bar.com");
    options[0].defaults.list = cells;
    program = strdup("/bin/false");
    if (program == NULL)
        sysbail("cannot allocate memory");
    options[5].defaults.string = program;
    args->config = config_new();
    status = putil_args_defaults(args, options, optlen);
    ok(status, "Setting defaults with new defaults");
    if (args->config->cells == NULL)
        ok_block(4, false, "...cells is set");
    else {
        ok(args->config->cells != NULL, "...cells is set");
        is_int(2, args->config->cells->count, "...with two cells");
        is_string("foo.com", args->config->cells->strings[0],
                  "...first is foo.com");
        is_string("bar.com", args->config->cells->strings[1],
                  "...second is bar.com");
    }
    is_string("/bin/false", args->config->program,
              "...program is /bin/false");
    status = putil_args_parse(args, 6, argv_all, options, optlen);
    ok(status, "Parse of full argv after defaults");
    if (args->config->cells == NULL)
        ok_block(4, false, "...cells is set");
    else {
        ok(args->config->cells != NULL, "...cells is set");
        is_int(2, args->config->cells->count, "...with two cells");
        is_string("stanford.edu", args->config->cells->strings[0],
                  "...first is stanford.edu");
        is_string("ir.stanford.edu", args->config->cells->strings[1],
                  "...second is ir.stanford.edu");
    }
    is_int(true, args->config->debug, "...debug is set");
    is_int(86400, args->config->expires, "...expires is set");
    is_int(true, args->config->ignore_root, "...ignore_root is set");
    is_int(1000, args->config->minimum_uid, "...minimum_uid is set");
    is_string("/bin/true", args->config->program, "...program is set");
    is_string("foo.com", cells->strings[0], "...first cell after parse");
    is_string("bar.com", cells->strings[1], "...second cell after parse");
    is_string("/bin/false", program, "...string after parse");
    config_free(args->config);
    args->config = NULL;
    is_string("foo.com", cells->strings[0], "...first cell after free");
    is_string("bar.com", cells->strings[1], "...second cell after free");
    is_string("/bin/false", program, "...string after free");
    options[0].defaults.list = NULL;
    options[5].defaults.string = NULL;
    vector_free(cells);
    free(program);

    /* Test specifying the default for a vector parameter as a string. */
    options[0].type = TYPE_STRLIST;
    options[0].defaults.string = "foo.com,bar.com";
    args->config = config_new();
    status = putil_args_defaults(args, options, optlen);
    ok(status, "Setting defaults with string default for vector");
    if (args->config->cells == NULL)
        ok_block(4, false, "...cells is set");
    else {
        ok(args->config->cells != NULL, "...cells is set");
        is_int(2, args->config->cells->count, "...with two cells");
        is_string("foo.com", args->config->cells->strings[0],
                  "...first is foo.com");
        is_string("bar.com", args->config->cells->strings[1],
                  "...second is bar.com");
    }
    config_free(args->config);
    args->config = NULL;
    options[0].type = TYPE_LIST;
    options[0].defaults.string = NULL;

    /* Should be no errors so far. */
    ok(pam_output() == NULL, "No errors so far");

    /* Test various ways of spelling booleans. */
    args->config = config_new();
    TEST_BOOL("debug", args->config->debug, true);
    TEST_BOOL("debug=false", args->config->debug, false);
    TEST_BOOL("debug=true", args->config->debug, true);
    TEST_BOOL("debug=no", args->config->debug, false);
    TEST_BOOL("debug=yes", args->config->debug, true);
    TEST_BOOL("debug=off", args->config->debug, false);
    TEST_BOOL("debug=on", args->config->debug, true);
    TEST_BOOL("debug=0", args->config->debug, false);
    TEST_BOOL("debug=1", args->config->debug, true);
    TEST_BOOL("debug=False", args->config->debug, false);
    TEST_BOOL("debug=trUe", args->config->debug, true);
    TEST_BOOL("debug=No", args->config->debug, false);
    TEST_BOOL("debug=Yes", args->config->debug, true);
    TEST_BOOL("debug=OFF", args->config->debug, false);
    TEST_BOOL("debug=ON", args->config->debug, true);
    config_free(args->config);
    args->config = NULL;

    /* Test for various parsing errors. */
    args->config = config_new();
    TEST_ERROR("debug=", LOG_ERR,
               "invalid boolean in setting: debug=");
    TEST_ERROR("debug=truth", LOG_ERR,
               "invalid boolean in setting: debug=truth");
    TEST_ERROR("minimum_uid", LOG_ERR,
               "value missing for option minimum_uid");
    TEST_ERROR("minimum_uid=", LOG_ERR,
               "value missing for option minimum_uid=");
    TEST_ERROR("minimum_uid=foo", LOG_ERR,
               "invalid number in setting: minimum_uid=foo");
    TEST_ERROR("minimum_uid=1000foo", LOG_ERR,
               "invalid number in setting: minimum_uid=1000foo");
    TEST_ERROR("program", LOG_ERR, "value missing for option program");
    TEST_ERROR("cells", LOG_ERR, "value missing for option cells");
    config_free(args->config);
    args->config = NULL;

#ifdef HAVE_KRB5

    /* Test for Kerberos krb5.conf option parsing. */
    krb5conf = test_file_path("data/krb5-pam.conf");
    if (krb5conf == NULL)
        bail("cannot find data/krb5-pam.conf");
    if (setenv("KRB5_CONFIG", krb5conf, 1) < 0)
        sysbail("cannot set KRB5_CONFIG");
    krb5_free_context(args->ctx);
    status = krb5_init_context(&args->ctx);
    if (status != 0)
        bail("cannot parse test krb5.conf file");
    args->config = config_new();
    status = putil_args_defaults(args, options, optlen);
    ok(status, "Setting the defaults");
    status = putil_args_krb5(args, "testing", options, optlen);
    ok(status, "Options from krb5.conf");
    ok(args->config->cells == NULL, "...cells default");
    is_int(true, args->config->debug, "...debug set from krb5.conf");
    is_int(1800, args->config->expires, "...expires set from krb5.conf");
    is_int(true, args->config->ignore_root, "...ignore_root default");
    is_int(1000, args->config->minimum_uid,
           "...minimum_uid set from krb5.conf");
    ok(args->config->program == NULL, "...program default");
    status = putil_args_krb5(args, "other-test", options, optlen);
    ok(status, "Options from krb5.conf (other-test)");
    is_int(-1000, args->config->minimum_uid,
           "...minimum_uid set from krb5.conf other-test");

    /* Test with a realm set, which should expose more settings. */
    krb5_free_context(args->ctx);
    status = krb5_init_context(&args->ctx);
    if (status != 0)
        bail("cannot parse test krb5.conf file");
    args->realm = strdup("FOO.COM");
    if (args->realm == NULL)
        sysbail("cannot allocate memory");
    status = putil_args_krb5(args, "testing", options, optlen);
    ok(status, "Options from krb5.conf with FOO.COM");
    is_int(2, args->config->cells->count, "...cells count from krb5.conf");
    is_string("foo.com", args->config->cells->strings[0],
              "...first cell from krb5.conf");
    is_string("bar.com", args->config->cells->strings[1],
              "...second cell from krb5.conf");
    is_int(true, args->config->debug, "...debug set from krb5.conf");
    is_int(1800, args->config->expires, "...expires set from krb5.conf");
    is_int(true, args->config->ignore_root, "...ignore_root default");
    is_int(1000, args->config->minimum_uid,
           "...minimum_uid set from krb5.conf");
    is_string("/bin/false", args->config->program,
              "...program from krb5.conf");

    /* Test with a different realm. */
    free(args->realm);
    args->realm = strdup("BAR.COM");
    if (args->realm == NULL)
        sysbail("cannot allocate memory");
    status = putil_args_krb5(args, "testing", options, optlen);
    ok(status, "Options from krb5.conf with BAR.COM");
    is_int(2, args->config->cells->count, "...cells count from krb5.conf");
    is_string("bar.com", args->config->cells->strings[0],
              "...first cell from krb5.conf");
    is_string("foo.com", args->config->cells->strings[1],
              "...second cell from krb5.conf");
    is_int(true, args->config->debug, "...debug set from krb5.conf");
    is_int(1800, args->config->expires, "...expires set from krb5.conf");
    is_int(true, args->config->ignore_root, "...ignore_root default");
    is_int(1000, args->config->minimum_uid,
           "...minimum_uid set from krb5.conf");
    is_string("echo /bin/true", args->config->program,
              "...program from krb5.conf");
    config_free(args->config);
    args->config = config_new();
    status = putil_args_krb5(args, "other-test", options, optlen);
    ok(status, "Options from krb5.conf (other-test with realm)");
    ok(args->config->cells == NULL, "...cells is NULL");
    is_string("echo /bin/true", args->config->program,
              "...program from krb5.conf");
    config_free(args->config);
    args->config = NULL;

    /* Test for time parsing errors. */
    args->config = config_new();
    TEST_ERROR("expires=ft87", LOG_ERR,
               "bad time value in setting: expires=ft87");
    config_free(args->config);

    /* Test error reporting from the krb5.conf parser. */
    args->config = config_new();
    status = putil_args_krb5(args, "bad-number", options, optlen);
    ok(status, "Options from krb5.conf (bad-number)");
    seen = pam_output();
    is_string("invalid number in krb5.conf setting for minimum_uid: 1000foo",
              seen->lines[0].line, "...and correct error reported");
    is_int(LOG_ERR, seen->lines[0].priority, "...with correct priority");
    pam_output_free(seen);
    config_free(args->config);
    args->config = NULL;

    /* Test error reporting on times from the krb5.conf parser. */
    args->config = config_new();
    status = putil_args_krb5(args, "bad-time", options, optlen);
    ok(status, "Options from krb5.conf (bad-time)");
    seen = pam_output();
    if (seen == NULL)
        ok_block(2, false, "...no error output");
    else {
        is_string("invalid time in krb5.conf setting for expires: ft87",
                  seen->lines[0].line, "...and correct error reported");
        is_int(LOG_ERR, seen->lines[0].priority, "...with correct priority");
    }
    pam_output_free(seen);
    config_free(args->config);
    args->config = NULL;

    test_file_path_free(krb5conf);

#else /* !HAVE_KRB5 */

    skip_block(37, "Kerberos support not configured");

#endif

    putil_args_free(args);
    pam_end(pamh, 0);
    return 0;
}
Example #28
0
int
main(void)
{
    struct rule rule = {
        NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0, 0, NULL,
        NULL, NULL
    };
    const char *acls[5];

    plan(78);
    if (chdir(getenv("C_TAP_SOURCE")) < 0)
        sysbail("can't chdir to C_TAP_SOURCE");

    rule.file = (char *) "TEST";
    rule.acls = (char **) acls;
    acls[0] = "data/acl-simple";
    acls[1] = NULL;
    acls[2] = NULL;
    acls[3] = NULL;
    acls[4] = NULL;

    ok(acl_permit(&rule, "*****@*****.**"), "simple 1");
    ok(acl_permit(&rule, "*****@*****.**"), "simple 2");
    ok(acl_permit(&rule, "*****@*****.**"), "simple 3");
    ok(acl_permit(&rule, "*****@*****.**"), "simple 4");
    ok(acl_permit(&rule, "*****@*****.**"), "simple 5");

    ok(!acl_permit(&rule, "*****@*****.**"), "no 1");
    ok(!acl_permit(&rule, "*****@*****.**"), "no 2");
    ok(!acl_permit(&rule, "*****@*****.**"), "no 3");
    ok(!acl_permit(&rule, "*****@*****.**"), "no 4");

    /* Okay, now capture and check the errors. */
    acls[0] = "data/acl-bad-include";
    acls[1] = "data/acls/valid";
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "included file not found");
    is_string("data/acl-bad-include:1: included file data/acl-nosuchfile"
              " not found\n", errors, "...and correct error message");
    acls[0] = "data/acl-recursive";
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "recursive ACL inclusion");
    is_string("data/acl-recursive:3: data/acl-recursive recursively"
              " included\n", errors, "...and correct error message");
    acls[0] = "data/acls/valid-2";
    acls[1] = "data/acl-too-long";
    errors_capture();
    ok(acl_permit(&rule, "*****@*****.**"),
       "granted access based on first ACL file");
    ok(errors == NULL, "...with no errors");
    ok(!acl_permit(&rule, "*****@*****.**"),
       "...but failed when we hit second file with long line");
    is_string("data/acl-too-long:1: ACL file line too long\n", errors,
              "...with correct error message");
    acls[0] = "data/acl-no-such-file";
    acls[1] = "data/acls/valid";
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "no such ACL file");
    is_string("TEST:0: included file data/acl-no-such-file not found\n",
              errors, "...with correct error message");
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"),
       "...even with a principal in an ACL file");
    is_string("TEST:0: included file data/acl-no-such-file not found\n",
              errors, "...still with right error message");
    acls[0] = "data/acl-bad-syntax";
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "incorrect syntax");
    is_string("data/acl-bad-syntax:2: parse error\n", errors,
              "...with correct error message");
    errors_uncapture();

    /* Check that file: works at the top level. */
    acls[0] = "file:data/acl-simple";
    acls[1] = NULL;
    ok(acl_permit(&rule, "*****@*****.**"), "file: success");
    ok(!acl_permit(&rule, "*****@*****.**"), "file: failure");

    /* Check that include syntax works. */
    ok(acl_permit(&rule, "*****@*****.**"), "include 1");
    ok(acl_permit(&rule, "*****@*****.**"), "include 2");
    ok(acl_permit(&rule, "*****@*****.**"), "include 3");
    ok(acl_permit(&rule, "*****@*****.**"), "include 4");
    ok(acl_permit(&rule, "*****@*****.**"), "include 5");
    ok(!acl_permit(&rule, "*****@*****.**"), "include failure");

    /* Check that princ: works at the top level. */
    acls[0] = "princ:[email protected]";
    ok(acl_permit(&rule, "*****@*****.**"), "princ: success");
    ok(!acl_permit(&rule, "*****@*****.**"), "princ: failure");

    /* Check that deny: works at the top level. */
    acls[0] = "deny:princ:[email protected]";
    acls[1] = "princ:[email protected]";
    acls[2] = "princ:[email protected]";
    acls[3] = NULL;
    ok(acl_permit(&rule, "*****@*****.**"), "deny: success");
    ok(!acl_permit(&rule, "*****@*****.**"), "deny: failure");

    /* And make sure deny interacts correctly with files. */
    acls[0] = "data/acl-simple";
    acls[1] = "princ:[email protected]";
    acls[2] = NULL;
    ok(!acl_permit(&rule, "*****@*****.**"),
       "deny in file beats later princ");
    acls[0] = "deny:princ:[email protected]";
    acls[1] = "data/acl-simple";
    ok(!acl_permit(&rule, "*****@*****.**"), "deny overrides later file");

    /*
     * Ensure deny never affirmatively grants access, so deny:deny: matches
     * nothing.
     */
    acls[0] = "deny:deny:princ:[email protected]";
    acls[1] = "data/acl-simple";
    ok(acl_permit(&rule, "*****@*****.**"), "deny:deny does nothing");
    ok(acl_permit(&rule, "*****@*****.**"),
       "deny:deny doesn't break anything");

    /*
     * Denying a file denies anything that would match the file, and nothing
     * that wouldn't, including due to an embedded deny.
     */
    acls[0] = "deny:file:data/acl-simple";
    acls[1] = "princ:[email protected]";
    acls[2] = "princ:[email protected]";
    acls[3] = "princ:[email protected]";
    acls[4] = NULL;
    ok(!acl_permit(&rule, "*****@*****.**"), "deny of a file works");
    ok(acl_permit(&rule, "*****@*****.**"),
       "...and doesn't break anything");
    ok(acl_permit(&rule, "*****@*****.**"),
       "...and deny inside a denied file is ignored");

    /* Check for an invalid ACL scheme. */
    acls[0] = "ihateyou:verymuch";
    acls[1] = "data/acls/valid";
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "invalid ACL scheme");
    is_string("TEST:0: invalid ACL scheme 'ihateyou'\n", errors,
              "...with correct error");
    errors_uncapture();

    /*
     * Check GPUT ACLs, or make sure they behave sanely when GPUT support is
     * not compiled.
     */
    server_config_set_gput_file((char *) "data/gput");
    acls[0] = "gput:test";
    acls[1] = NULL;
#ifdef HAVE_GPUT
    ok(acl_permit(&rule, "*****@*****.**"), "GPUT 1");
    ok(!acl_permit(&rule, "*****@*****.**"), "GPUT 2");
    ok(!acl_permit(&rule, "*****@*****.**"), "GPUT 3");
    acls[0] = "gput:test[%@EXAMPLE.NET]";
    ok(acl_permit(&rule, "*****@*****.**"), "GPUT with transform 1");
    ok(!acl_permit(&rule, "*****@*****.**"), "GPUT with transform 2");
    ok(!acl_permit(&rule, "*****@*****.**"), "GPUT with transform 3");
#else
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "GPUT");
    is_string("TEST:0: ACL scheme 'gput' is not supported\n", errors,
              "...with not supported error");
    errors_uncapture();
    skip_block(4, "GPUT support not configured");
#endif

    /*
     * Check PCRE ACLs, or make sure they behave as they should when not
     * supported.
     */
    acls[0] = "deny:pcre:host/foo.+\\.org@EXAMPLE\\.ORG";
    acls[1] = "pcre:host/.+\\.org@EXAMPLE\\.ORG";
    acls[2] = NULL;
#ifdef HAVE_PCRE
    ok(acl_permit(&rule, "host/[email protected]"), "PCRE 1");
    ok(!acl_permit(&rule, "host/[email protected]"), "PCRE 2");
    ok(!acl_permit(&rule, "host/[email protected]"), "PCRE 3");
    ok(!acl_permit(&rule, "host/[email protected]"), "PCRE 4 (plus operator)");
    ok(!acl_permit(&rule, "host/[email protected]"),
       "PCRE 5 (escaped period)");
    acls[1] = "pcre:+host/.*";
    errors_capture();
    ok(!acl_permit(&rule, "host/[email protected]"), "PCRE invalid regex");
    is_string("TEST:0: compilation of regex '+host/.*' failed around 0\n",
              errors, "...with invalid regex error");
    errors_uncapture();
#else
    errors_capture();
    ok(!acl_permit(&rule, "host/[email protected]"), "PCRE");
    is_string("TEST:0: ACL scheme 'pcre' is not supported\n", errors,
              "...with not supported error");
    errors_uncapture();
    skip_block(5, "PCRE support not configured");
#endif

    /*
     * Check POSIX regex ACLs, or make sure they behave as they should when
     * not supported.
     */
    acls[0] = "deny:regex:host/foo.*\\.org@EXAMPLE\\.ORG";
    acls[1] = "regex:host/.*\\.org@EXAMPLE\\.ORG";
    acls[2] = NULL;
#ifdef HAVE_REGCOMP
    ok(acl_permit(&rule, "host/[email protected]"), "regex 1");
    ok(!acl_permit(&rule, "host/[email protected]"), "regex 2");
    ok(!acl_permit(&rule, "host/[email protected]"), "regex 3");
    ok(acl_permit(&rule, "host/[email protected]"), "regex 4");
    ok(!acl_permit(&rule, "host/[email protected]"),
       "regex 5 (escaped period)");
    acls[1] = "regex:*host/.*";
    errors_capture();
    ok(!acl_permit(&rule, "host/[email protected]"), "regex invalid regex");
    ok(strncmp(errors, "TEST:0: compilation of regex '*host/.*' failed:",
               strlen("TEST:0: compilation of regex '*host/.*' failed:")) == 0,
       "...with invalid regex error");
    errors_uncapture();
    free(errors);
    errors = NULL;
#else
    errors_capture();
    ok(!acl_permit(&rule, "host/[email protected]"), "regex");
    is_string("TEST:0: ACL scheme 'regex' is not supported\n", errors,
              "...with not supported error");
    errors_uncapture();
    skip_block(5, "regex support not available");
    free(errors);
    errors = NULL;
#endif

    /* Test for valid characters in ACL files. */
    acls[0] = "file:data/acls";
    acls[1] = NULL;
    ok(acl_permit(&rule, "*****@*****.**"), "valid chars 1");
    ok(acl_permit(&rule, "*****@*****.**"), "valid chars 2");
    ok(acl_permit(&rule, "*****@*****.**"), "valid chars 3");
    ok(!acl_permit(&rule, "*****@*****.**"), "invalid chars 1");
    ok(!acl_permit(&rule, "*****@*****.**"), "invalid chars 2");
    ok(!acl_permit(&rule, "*****@*****.**"), "invalid chars 3");

    /* Check anyuser:*. */
    acls[0] = "anyuser:auth";
    acls[1] = NULL;
    ok(acl_permit(&rule, "*****@*****.**"), "anyuser:auth");
    acls[0] = "anyuser:anonymous";
    ok(acl_permit(&rule, "*****@*****.**"), "anyuser:anonymous");
    acls[0] = "ANYUSER";
    ok(acl_permit(&rule, "*****@*****.**"), "ANYUSER");

    /*
     * Ensure that anyuser:auth and ANYUSER don't allow the anonymous
     * identity, but anyuser:anonymous does.
     */
    acls[0] = "anyuser:auth";
    acls[1] = NULL;
    ok(!acl_permit_anonymous(&rule), "anyuser:auth disallows anonymous");
    acls[0] = "ANYUSER";
    ok(!acl_permit_anonymous(&rule), "ANYUSER disallows anonymous");
    acls[0] = "anyuser:anonymous";
    ok(acl_permit_anonymous(&rule), "anyuser:anonymous allows anonymous");

    /* Check error handling of unknown anyuser ACLs. */
    acls[0] = "anyuser:foo";
    acls[1] = NULL;
    errors_capture();
    ok(!acl_permit(&rule, "*****@*****.**"), "invalid anyuser ACL");
    is_string("TEST:0: invalid ACL value 'anyuser:foo'\n", errors,
              "...with correct error.");
    errors_uncapture();
    free(errors);
    errors = NULL;

    return 0;
}
Example #29
0
int
main(void)
{
    struct script_config config;
    struct kerberos_password *password;
    DIR *tmpdir;
    struct dirent *file;
    char *tmppath, *path;

    /* Load the Kerberos principal and password from a file. */
    password = kerberos_config_password();
    if (password == NULL)
        skip_all("Kerberos tests not configured");
    memset(&config, 0, sizeof(config));
    config.user = password->username;
    config.password = password->password;
    config.extra[0] = password->principal;

    /* Generate a testing krb5.conf file. */
    kerberos_generate_conf(password->realm);

    /* Get the temporary directory and store that as the %1 substitution. */
    tmppath = test_tmpdir();
    config.extra[1] = tmppath;

    plan_lazy();

    /*
     * We need to ensure that the only thing in the test temporary directory
     * is the krb5.conf file that we generated, since we're going to check for
     * cleanup by looking for any out-of-place files.
     */
    tmpdir = opendir(tmppath);
    if (tmpdir == NULL)
        sysbail("cannot open directory %s", tmppath);
    while ((file = readdir(tmpdir)) != NULL) {
        if (strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)
            continue;
        if (strcmp(file->d_name, "krb5.conf") == 0)
            continue;
        basprintf(&path, "%s/%s", tmppath, file->d_name);
        if (unlink(path) < 0)
            sysbail("cannot delete temporary file %s", path);
        free(path);
    }
    closedir(tmpdir);

    /*
     * Authenticate only, call pam_end, and be sure the ticket cache is
     * gone.  The auth-only script sets ccache_dir to the temporary directory,
     * so the module will create a temporary ticket cache there and then
     * should clean it up.
     */
    run_script("data/scripts/cache-cleanup/auth-only", &config);
    path = NULL;
    tmpdir = opendir(tmppath);
    if (tmpdir == NULL)
        sysbail("cannot open directory %s", tmppath);
    while ((file = readdir(tmpdir)) != NULL) {
        if (strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)
            continue;
        if (strcmp(file->d_name, "krb5.conf") == 0)
            continue;
        if (path == NULL)
            basprintf(&path, "%s/%s", tmppath, file->d_name);
    }
    closedir(tmpdir);
    if (path != NULL)
        diag("found stray temporary file %s", path);
    ok(path == NULL, "ticket cache cleaned up");
    if (path != NULL)
        free(path);

    test_tmpdir_free(tmppath);
    kerberos_config_password_free(password);
    return 0;
}
Example #30
0
/*
 * We found a section delimiter while parsing another section.  Rewind our
 * input file back before the section delimiter so that we'll read it again.
 * Takes the length of the line we read, which is used to determine how far to
 * rewind.
 */
static void
rewind_section(FILE *script, size_t length)
{
    if (fseek(script, -length - 1, SEEK_CUR) != 0)
        sysbail("cannot rewind file");
}