static int unix_server_start(server_generic_t *server)
{
        int ret;
        struct sockaddr_un *sa = (struct sockaddr_un *) server->sa;

        server->sock = socket(AF_UNIX, SOCK_STREAM, 0);
        if ( server->sock < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error creating UNIX socket: %s", strerror(errno));

        ret = is_unix_socket_already_used(server->sock, sa, server->slen);
        if ( ret < 0 ) {
                close(server->sock);
                return ret;
        }

        ret = generic_server(server->sock, server->sa, server->slen);
        if ( ret < 0 ) {
                close(server->sock);
                return ret;
        }

        /*
         * Everyone should be able to access the filesystem object
         * representing our socket.
         */
        ret = chmod(sa->sun_path, S_IRWXU|S_IRWXG|S_IRWXO);
        if ( ret < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "could not set permission on UNIX socket: %s", strerror(errno));

        return 0;
}
static int get_profile_analyzerid(prelude_client_profile_t *cp)
{
        int ret;
        FILE *fd;
        char *ptr, filename[256], buf[256];

        prelude_client_profile_get_profile_dirname(cp, filename, sizeof(filename));
        if ( access(filename, R_OK|X_OK) < 0 ) {
                if ( errno == ENOENT )
                        return prelude_error_verbose(PRELUDE_ERROR_PROFILE, "profile '%s' does not exist", cp->name);

                else if ( errno == EACCES )
                        return prelude_error_verbose(PRELUDE_ERROR_PROFILE, "could not open profile '%s': insufficient permission", cp->name);
        }

        prelude_client_profile_get_analyzerid_filename(cp, filename, sizeof(filename));

        fd = fopen(filename, "r");
        if ( ! fd )
                return prelude_error_verbose(PRELUDE_ERROR_PROFILE, "could not open '%s' for reading", filename);

        ptr = fgets(buf, sizeof(buf), fd);
        fclose(fd);

        if ( ! ptr )
                return prelude_error_verbose(PRELUDE_ERROR_PROFILE, "could not read analyzerID from '%s'", filename);

        ret = sscanf(buf, "%" PRELUDE_PRIu64, &cp->analyzerid);
        if ( ret != 1 )
                return prelude_error_verbose(PRELUDE_ERROR_PROFILE, "'%s' is not a valid analyzerID", buf);

        return 0;
}
/*
 * If the UNIX socket already exist, check if it is in use.
 * if it is not, delete it.
 *
 * FIXME: Using connect for this is dirty.
 *
 * return 1 if the socket is already in use.
 * return 0 if the socket is unused.
 * retuir -1 on error.
 */
static int is_unix_socket_already_used(int sock, struct sockaddr_un *sa, int addrlen)
{
        int ret;
        struct stat st;

        /*
         * Minor check for operating system where bind() will incorrectly follow symlink.
         * Note that there is a race condition between the stat() and the bind call.
         */
        ret = stat(sa->sun_path, &st);
        if ( ret < 0 )
                return 0;

        if ( ! S_ISSOCK(st.st_mode) )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "'%s' exist and is not an UNIX socket", sa->sun_path);

        ret = connect(sock, (struct sockaddr *) sa, addrlen);
        if ( ret == 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "UNIX socket '%s' already in use", sa->sun_path);

        /*
         * The unix socket exist on the file system,
         * but no one use it... Delete it.
         */
        ret = unlink(sa->sun_path);
        if ( ret < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "could not delete unused UNIX socket: %s", strerror(errno));

        return 0;
}
static int inet_server_start(server_generic_t *server, struct sockaddr *addr, socklen_t addrlen)
{
        int ret, on = 1;

        server->sock = socket(server->sa->sa_family, SOCK_STREAM, IPPROTO_TCP);
        if ( server->sock < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error creating socket: %s", strerror(errno));


#ifdef IPV6_V6ONLY
        /*
         * There is a problem on Linux system where getaddrinfo() return address in
         * the wrong sort order (IPv4 first, IPv6 next).
         *
         * As a result we first bind IPv4 addresses, but then we get an error for
         * dual-stacked addresses, when the IPv6 addresses come second. When an
         * address is dual-stacked, we thus end-up listening only to the IPv4
         * instance.
         *
         * The error happen on dual-stack Linux system, because mapping the IPv6
         * address will actually attempt to bind both the IPv4 and IPv6 address.
         *
         * In order to prevent this problem, we set the IPV6_V6ONLY option so that
         * only the IPv6 address is bound.
         */
        if ( server->sa->sa_family == AF_INET6 ) {
                ret = setsockopt(server->sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &on, sizeof(int));
                if ( ret < 0 ) {
                        ret = prelude_error_verbose(PRELUDE_ERROR_GENERIC, "could not set IPV6_V6ONLY: %s.\n", strerror(errno));
                        goto err;
                }
        }
#endif

        ret = setsockopt(server->sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
        if ( ret < 0 ) {
                ret = prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error setting SO_REUSEADDR: %s", strerror(errno));
                goto err;
        }

        ret = generic_server(server->sock, addr, addrlen);
        if ( ret < 0 )
                goto err;

        return 0;

 err:
        close(server->sock);
        return ret;
}
static int generic_server(int sock, struct sockaddr *addr, size_t alen)
{
        int ret;

        ret = bind(sock, addr, alen);
        if ( ret < 0 )
                return prelude_error_verbose(prelude_error_code_from_errno(errno),
                                             "could not bind socket: %s", strerror(errno));

        ret = listen(sock, 10);
        if ( ret < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "listen error: %s", strerror(errno));

        return 0;
}
/*
 * put client socket in non blocking mode and
 * create a prelude_io object for IO abstraction.
 *
 * Tell server-logic to handle event on the newly accepted client.
 */
static int setup_client_socket(server_generic_t *server,
                               server_generic_client_t *cdata, int client)
{
        int ret;

#ifdef HAVE_TCP_WRAPPERS
        if ( server->sa->sa_family != AF_UNIX ) {
                ret = tcpd_auth(cdata, client);
                if ( ret < 0 )
                        return -1;
        }
#endif
        /*
         * set client socket non blocking.
         */
#if ! ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
        ret = fcntl(client, F_SETFL, O_NONBLOCK);
        if ( ret < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "could not set non blocking mode for client: %s", strerror(errno));

        fcntl(client, F_SETFD, fcntl(client, F_GETFD) | FD_CLOEXEC);
#endif

        ret = prelude_io_new(&cdata->fd);
        if ( ret < 0 )
                return ret;

        prelude_io_set_sys_io(cdata->fd, client);

        cdata->msg = NULL;
        cdata->state = 0;

        return 0;
}
Exemple #7
0
static int parse_time_hmsu(struct tm *tm, uint32_t *usec, char **buf)
{
        int fraction;
        char *eptr = NULL;

        *buf = strptime(*buf, "%H:%M:%S", tm);
        if ( ! *buf )
                goto fmterror;

        if ( **buf == '.' || **buf == ',' ) {
                (*buf)++;

                fraction = strtoul(*buf, &eptr, 10);
                if ( eptr == *buf )
                        goto fmterror;

                fraction = digit2usec(fraction, eptr - *buf);
                if ( fraction < 0 )
                        return fraction;

                *buf = eptr;
                *usec = fraction;
        }

        return 0;

    fmterror:
        return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error parsing time field, format should be: HH:MM:SS(.fraction)");
}
Exemple #8
0
/*
 * Only called if the memory dump of the file was modified,
 * will write the new content to filename 'filename'.
 */
static int sync_and_free_file_content(config_t *cfg)
{
        FILE *fd;
        unsigned int i;
        size_t ret, len;

        fd = fopen(cfg->filename, "w");
        if ( ! fd )
                return prelude_error_verbose(prelude_error_code_from_errno(errno), "could not open '%s' for writing: %s",
                                             cfg->filename, strerror(errno));

        for ( i = 0; i < cfg->elements; i++ ) {
                len = strlen(cfg->content[i]);

                ret = fwrite(cfg->content[i], 1, len, fd);
                if ( ret != len && ferror(fd) )
                        prelude_log(PRELUDE_LOG_ERR, "error writing content to '%s': %s", cfg->filename, strerror(errno));

                if ( i + 1 != cfg->elements ) {
                        ret = fwrite("\n", 1, 1, fd);
                        if ( ret != 1 && ferror(fd) )
                                prelude_log(PRELUDE_LOG_ERR, "error writing content to '%s': %s", cfg->filename, strerror(errno));
                }

                free(cfg->content[i]);
        }

        fclose(fd);
        free(cfg->content);

        return 0;
}
Exemple #9
0
/**
 * prelude_read_multiline:
 * @fd: File descriptor to read input from.
 * @line: Pointer to a line counter.
 * @buf: Pointer to a buffer where the line should be stored.
 * @size: Size of the @buf buffer.
 *
 * This function handles line reading separated by the '\' character.
 *
 * Returns: 0 on success, -1 if an error occured.
 */
int prelude_read_multiline(FILE *fd, unsigned int *line, char *buf, size_t size)
{
        size_t i, j, len;
        prelude_bool_t eol, has_data = FALSE, miss_eol=FALSE;

        while ( size > 1 ) {
                if ( ! fgets(buf, size, fd) )
                        return (has_data) ? 0 : prelude_error(PRELUDE_ERROR_EOF);

                len = strlen(buf);
                if ( ! len )
                        continue;

                eol = FALSE;
                for ( i = len - 1; isspace((int) buf[i]); i-- ) {

                        if ( buf[i] == '\n' || buf[i] == '\r' ) {
                                buf[i] = 0;
                                if ( ! eol ) {
                                        eol = TRUE;
                                        (*line)++;
                                }
                        }

                        if ( i == 0 )
                                break;
                }

                if ( miss_eol && eol && i == 0 )
                        continue;

                /*
                 * We don't want to handle multilines in case this is a comment.
                 */
                for ( j = 0; buf[j] != '\0' && isspace((int) buf[j]); j++ );
                if ( buf[j] == '#' )
                        continue;

                /*
                 * Multiline found, continue reading.
                 */
                if ( buf[i] != '\\' ) {
                        if ( eol )
                                return 0;

                        if ( len == size - 1 )
                                break;

                        has_data = TRUE;
                }

                if ( ! eol )
                        miss_eol = TRUE;

                buf += i;
                size -= i;
        }

        return prelude_error_verbose(PRELUDE_ERROR_EINVAL, "buffer is too small to store input line");
}
Exemple #10
0
/*
 * Loads filename into memory, we use append_line() for that.
 */
static int load_file_in_memory(config_t *cfg)
{
        int ret;
        FILE *fd;
        size_t len;
        prelude_string_t *out;
        char line[1024], *ptr, *tmp;

        ret = prelude_string_new(&out);
        if ( ret < 0 )
                return ret;

        fd = fopen(cfg->filename, "r");
        if ( ! fd ) {
                prelude_string_destroy(out);
                return prelude_error_verbose(prelude_error_code_from_errno(errno), "could not open '%s' for reading: %s",
                                             cfg->filename, strerror(errno));
        }

        do {
                len = 0;
                ptr = fgets(line, sizeof(line), fd);
                if ( ptr ) {
                        len = strlen(line);

                        if ( line[len - 1] == '\n' )
                                line[len - 1] = 0;

                        ret = prelude_string_cat(out, line);
                        if ( ret < 0 )
                                goto err;

                        if ( line[len - 1] != 0 )
                                continue;
                }

                ret = prelude_string_get_string_released(out, &tmp);
                if ( ret < 0 )
                        goto err;

                if ( ! tmp )
                        tmp = strdup("");

                ret = op_append_line(cfg, tmp);
                if ( ret < 0 ) {
                        free(tmp);
                        goto err;
                }

                prelude_string_clear(out);
        } while ( ptr );

 err:
        prelude_string_destroy(out);
        fclose(fd);

        return 0;
}
Exemple #11
0
/**
 * idmef_time_set_from_string:
 * @time: Pointer to an #idmef_time_t object.
 * @buf: Pointer to a string describing a time in an IDMEF conforming format.
 *
 * Fills @time object with information retrieved from the user provided
 * @buf, containing a string describing a time in a format conforming
 * to the IDMEF definition (v. 0.10, section 3.2.6).
 *
 * Additionally, the provided time might be separated with white spaces,
 * instead of the IDMEF defined 'T' character.
 *
 * If there is no UTC offset specified, we assume that the provided
 * time is local, and compute the GMT offset by ourselve.
 *
 * Returns: 0 on success, a negative value if an error occured.
 */
int idmef_time_set_from_string(idmef_time_t *time, const char *buf)
{
        int ret;
        char *ptr;
        struct tm tm;
        prelude_bool_t miss_gmt = FALSE;

        prelude_return_val_if_fail(time, prelude_error(PRELUDE_ERROR_ASSERTION));
        prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));

        memset(&tm, 0, sizeof(tm));
        tm.tm_isdst = -1;

        ptr = parse_time_ymd(&tm, buf);
        if ( ! ptr )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error parsing date field, format should be: YY-MM-DD");

        time->usec = 0;
        time->gmt_offset = 0;

        if ( *ptr ) {
                ret = parse_time_hmsu(&tm, &time->usec, &ptr);
                if ( ret < 0 )
                        return ret;

                miss_gmt = TRUE;
                if ( *ptr ) {
                        ret = parse_time_gmt(&tm, &time->gmt_offset, ptr);
                        if ( ret < 0 )
                                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error parsing GMT offset field (Z)?(+|-)?HH:MM");

                        miss_gmt = FALSE;
                }
        }

        if ( miss_gmt ) {
                long gmtoff;
                prelude_get_gmt_offset_from_tm(&tm, &gmtoff);
                time->gmt_offset = (int32_t) gmtoff;
        }

        time->sec = miss_gmt ? mktime(&tm) : prelude_timegm(&tm);
        return 0;
}
Exemple #12
0
static int digit2usec(uint32_t n, int digit_count)
{
        int i;
        const size_t max_digit = 6; /* 999999 */

        if ( digit_count > max_digit )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "Invalid number of digits for time fraction");

        for ( i = 0; i < (max_digit - digit_count); i++ )
                n *= 10;

        return n;
}
static int inet_server_start(server_generic_t *server, struct sockaddr *addr, socklen_t addrlen)
{
        int ret, on = 1;

        server->sock = socket(server->sa->sa_family, SOCK_STREAM, IPPROTO_TCP);
        if ( server->sock < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error creating socket: %s", strerror(errno));

        ret = setsockopt(server->sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
        if ( ret < 0 ) {
                ret = prelude_error_verbose(PRELUDE_ERROR_GENERIC, "error setting SO_REUSEADDR: %s", strerror(errno));
                goto err;
        }

        ret = generic_server(server->sock, addr, addrlen);
        if ( ret < 0 )
                goto err;

        return 0;

 err:
        close(server->sock);
        return ret;
}
static int do_getaddrinfo(struct addrinfo **ai, const char *addr, unsigned int port)
{
        int ret;
        struct addrinfo hints;
        char service[sizeof("00000")];

        memset(&hints, 0, sizeof(hints));
        snprintf(service, sizeof(service), "%u", port);

        hints.ai_family = PF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;

        ret = getaddrinfo(addr, service, &hints, ai);
        if ( ret != 0 )
                ret = prelude_error_verbose(PRELUDE_ERROR_GENERIC, "could not resolve '%s': %s",
                                            addr, (ret == EAI_SYSTEM) ? strerror(errno) : gai_strerror(ret));

        return ret;
}
Exemple #15
0
/**
 * prelude_parse_version:
 * @version: A version string.
 * @out: Where to store the parsed version
 *
 * Parse version to an integer, and return it in @out.
 * Accepted format are:
 *
 * major.minor.micro.patchlevel
 * the following special level string are supported : alpha, beta, rc
 *
 * For example: 1.1.1rc1
 *
 * Returns: The 0 on success, a negative value in case of error.
 */
int prelude_parse_version(const char *version, unsigned int *out)
{
        int ret;
        char levels[6] = { 0 };
        int major = 0, minor = 0, micro = 0, level = 0, patch = 0;

        ret = sscanf(version, "%d.%d.%d%5[^0-9]%d", &major, &minor, &micro, levels, &patch);
        if ( ret <= 0 )
                return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "version formatting error with '%s'", version);

        if ( *levels == 0 || *levels == '.' )
                level = LIBPRELUDE_RELEASE_LEVEL_FINAL;
        else {
                level = levelstr_to_int(levels);
                if ( level < 0 )
                        return level;
        }

        *out = (major << 24) | (minor << 16) | (micro << 8) | (level << 4) | (patch << 0);
        return 0;
}
Exemple #16
0
static int lockfile_get_exclusive(const char *lockfile)
{
        int fd;
#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
        int ret;
        struct flock lock;
#endif

        fd = open(lockfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
        if ( fd < 0 )
                return prelude_error_from_errno(errno);

#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
        fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);

        lock.l_type = F_WRLCK;    /* write lock */
        lock.l_start = 0;         /* from offset 0 */
        lock.l_whence = SEEK_SET; /* at the beginning of the file */
        lock.l_len = 0;           /* until EOF */

        ret = fcntl(fd, F_SETLK, &lock);
        if ( ret < 0 ) {
                if ( errno == EACCES || errno == EAGAIN )
                        return prelude_error_verbose(PRELUDE_ERROR_DAEMONIZE_LOCK_HELD,
                                                     "'%s' lock is held by another process", slockfile);

                close(fd);
                return prelude_error_from_errno(errno);
        }
#endif

        /*
         * lock is now held until program exits.
         */
        return fd;
}
Exemple #17
0
int _prelude_load_file(const char *filename, unsigned char **fdata, size_t *outsize)
{
        int ret, fd;
        struct stat st;
        unsigned char *dataptr;

        fd = open(filename, O_RDONLY);
        if ( fd < 0 )
                return prelude_error_from_errno(errno);

        ret = fstat(fd, &st);
        if ( ret < 0 ) {
                close(fd);
                return prelude_error_from_errno(errno);
        }

        if ( st.st_size == 0 ) {
                close(fd);
                return prelude_error_verbose(prelude_error_code_from_errno(EINVAL), "could not load '%s': empty file", filename);
        }

        *outsize = st.st_size;

#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
        dataptr = *fdata = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
        if ( dataptr == MAP_FAILED ) {
                close(fd);
                return prelude_error_from_errno(errno);
        }
#else
        dataptr = *fdata = malloc(st.st_size);
        if ( ! dataptr ) {
                close(fd);
                return prelude_error_from_errno(errno);
        }

        _setmode(fd, O_BINARY);

        do {
                ssize_t len;

                len = read(fd, dataptr, st.st_size);
                if ( len < 0 ) {
                        if ( errno == EINTR )
                                continue;

                        close(fd);
                        free(*fdata);

                        return prelude_error_from_errno(errno);
                }

                dataptr += len;
                st.st_size -= len;
        } while ( st.st_size > 0 );

#endif
        close(fd);

        return 0;
}
Exemple #18
0
/**
 * prelude_init:
 * @argc: Address of the argc parameter of your main() function.
 * @argv: Address of the argv parameter of your main() function.
 *
 * Call this function before using any other Prelude functions in your applications.
 * It will initialize everything needed to operate the library and parses some standard
 * command line options. @argc and @argv are adjusted accordingly so your own code will
 * never see those standard arguments.
 *
 * Returns: 0 on success, a negative value if an error occured.
 */
int prelude_init(int *argc, char **argv)
{
        int ret;
        const char *env;

        if ( libprelude_refcount++ > 0 )
                return 0;

        env = getenv("LIBPRELUDE_DEBUG");
        if ( env )
                prelude_log_set_debug_level(atoi(env));

        env = getenv("LIBPRELUDE_TLS_DEBUG");
        if ( env ) {
                gnutls_global_set_log_level(atoi(env));
                gnutls_global_set_log_function(tls_log_func);
        }

        env = getenv("LIBPRELUDE_LOGFILE");
        if ( env )
                prelude_log_set_logfile(env);

        env = getenv("LIBPRELUDE_PREFIX");
        if ( env )
                _prelude_prefix = strdup(env);

        env = getenv("LIBPRELUDE_ABORT");
        if ( env ) {
                if ( *env )
                        _prelude_log_set_abort_level_from_string(env);
                else
                        _prelude_log_set_abort_level(PRELUDE_LOG_CRIT);
        }

        prelude_thread_init(NULL);

        if ( ! getcwd(_prelude_init_cwd, sizeof(_prelude_init_cwd)) )
                _prelude_init_cwd[0] = 0;

        ret = _prelude_timer_init();
        if ( ret < 0 )
                return ret;

        ret = glthread_atfork(prelude_fork_prepare, prelude_fork_parent, prelude_fork_child);
        if ( ret != 0 )
                return prelude_error_from_errno(ret);

        slice_arguments(argc, argv);

        ret = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_prelude);
        if ( ret < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_TLS,
                                             "gcrypt initialization failed: %s", gcry_strerror(ret));

        ret = gnutls_global_init();
        if ( ret < 0 )
                return prelude_error_verbose(PRELUDE_ERROR_TLS,
                                             "TLS initialization failed: %s", gnutls_strerror(ret));

        return 0;
}