Exemple #1
0
/* function to handle the re-populating of the avl tree containing IP addresses
 * for deciding whether a connection of an incoming request is to be dropped.
 */
static void recheck_ip_file (cache_file_contents *cache)
{
    time_t now = time(NULL);
    if (now >= cache->file_recheck)
    {
        struct stat file_stat;
        FILE *file = NULL;
        int count = 0;
        avl_tree *new_ips;
        char line [MAX_LINE_LEN];

        cache->file_recheck = now + 10;
        if (cache->filename == NULL)
        {
            if (cache->contents)
            {
                avl_tree_free (cache->contents, free_filtered_ip);
                cache->contents = NULL;
            }
            return;
        }
        if (stat (cache->filename, &file_stat) < 0)
        {
            WARN2 ("failed to check status of \"%s\": %s", cache->filename, strerror(errno));
            return;
        }
        if (file_stat.st_mtime == cache->file_mtime)
            return; /* common case, no update to file */

        cache->file_mtime = file_stat.st_mtime;

        file = fopen (cache->filename, "r");
        if (file == NULL)
        {
            WARN2("Failed to open file \"%s\": %s", cache->filename, strerror (errno));
            return;
        }

        new_ips = avl_tree_new (compare_ip, NULL);

        while (get_line (file, line, MAX_LINE_LEN))
        {
            char *str;
            if(!line[0] || line[0] == '#')
                continue;
            count++;
            str = strdup (line);
            if (str)
                avl_insert (new_ips, str);
        }
        fclose (file);
        INFO2 ("%d entries read from file \"%s\"", count, cache->filename);

        if (cache->contents) avl_tree_free (cache->contents, free_filtered_ip);
        cache->contents = new_ips;
    }
}
Exemple #2
0
static int _delete_fh (void *mapping)
{
    fh_node *fh = mapping;
    if (fh == &no_file)
    {
        ERROR0 ("no file handle free detected");
        return 0;
    }
    if (fh->refcount)
        WARN2 ("handle for %s has refcount %d", fh->finfo.mount, fh->refcount);
    else
        thread_mutex_destroy (&fh->lock);

    file_close (&fh->f);
    if (fh->format)
    {
        free (fh->format->mount);
        format_plugin_clear (fh->format, NULL);
        free (fh->format);
    }
    if (fh->clients)
        avl_tree_free (fh->clients, NULL);
    rate_free (fh->out_bitrate);
    free (fh->finfo.mount);
    free (fh->finfo.fallback);
    free (fh);

    return 1;
}
Exemple #3
0
/* create a client_t with the provided connection and parser details. Return
 * 0 on success, -1 if server limit has been reached.  In either case a
 * client_t is returned just in case a message needs to be returned. Should
 * be called with global lock held.
 */
int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser)
{
    ice_config_t *config;
    client_t *client = (client_t *)calloc(1, sizeof(client_t));
    int ret = -1;

    if (client == NULL)
        abort();

    config = config_get_config ();

    global.clients++;
    if (config->client_limit < global.clients)
        WARN2 ("server client limit reached (%d/%d)", config->client_limit, global.clients);
    else
        ret = 0;

    config_release_config ();

    stats_event_args (NULL, "clients", "%d", global.clients);
    client->con = con;
    client->parser = parser;
    client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE);
    client->refbuf->len = 0; /* force reader code to ignore buffer contents */
    client->pos = 0;
    client->write_to_client = format_generic_write_to_client;
    *c_ptr = client;

    return ret;
}
static connection_t *_accept_connection(void)
{
    int sock;
    connection_t *con;
    char *ip;
    int serversock; 

    serversock = wait_for_serversock(100);
    if(serversock < 0)
        return NULL;

    /* malloc enough room for a full IP address (including ipv6) */
    ip = (char *)malloc(MAX_ADDR_LEN);

    sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
    if (sock >= 0)
    {
        con = connection_create (sock, serversock, ip);
        if (con == NULL)
            free (ip);

        return con;
    }

    if (!sock_recoverable(sock_error()))
        WARN2("accept() failed with error %d: %s", sock_error(), strerror(sock_error()));
    
    free(ip);

    return NULL;
}
Exemple #5
0
static uint64_t worker_check_time_ms (worker_t *worker)
{
    uint64_t tm = timing_get_time();
    if (tm - worker->time_ms > 1000 && worker->time_ms)
        WARN2 ("worker %p has been stuck for %" PRIu64 " ms", worker, (tm - worker->time_ms));
    return tm;
}
Exemple #6
0
int auth_htpasswd_adduser(auth_t *auth, char *username, char *password)
{
    FILE *passwdfile;
    char *hashed_password = NULL;
    htpasswd_auth_state *state;

    if (auth_htpasswd_existing_user(auth, username) == AUTH_USEREXISTS) {
        return AUTH_USEREXISTS;
    }
    state = auth->state;
    passwdfile = fopen(state->filename, "ab");

    if(passwdfile == NULL) {
        WARN2("Failed to open authentication database \"%s\": %s", 
                state->filename, strerror(errno));
        return AUTH_FAILED;
    }

    hashed_password = get_hash(password, strlen(password));
    if (hashed_password) {
        fprintf(passwdfile, "%s:%s\n", username, hashed_password);
        free(hashed_password);
    }

    fclose(passwdfile);
    return AUTH_USERADDED;
}
Exemple #7
0
/* function to handle the re-populating of the avl tree containing IP addresses
 * for deciding whether a connection of an incoming request is to be dropped.
 */
static void recheck_cached_file (cache_file_contents *cache, time_t now)
{
    if (now >= cache->file_recheck)
    {
        struct stat file_stat;
        FILE *file = NULL;
        int count = 0;
        char line [MAX_LINE_LEN];

        cache->file_recheck = now + 10;
        if (cache->filename == NULL)
        {
            cache_prune (cache);
            return;
        }
        if (stat (cache->filename, &file_stat) < 0)
        {
            WARN2 ("failed to check status of \"%s\": %s", cache->filename, strerror(errno));
            return;
        }
        if (file_stat.st_mtime == cache->file_mtime)
            return; /* common case, no update to file */

        cache->file_mtime = file_stat.st_mtime;

        file = fopen (cache->filename, "r");
        if (file == NULL)
        {
            WARN2("Failed to open file \"%s\": %s", cache->filename, strerror (errno));
            return;
        }

        cache_prune (cache);

        cache->contents = avl_tree_new (cache->compare, &cache->file_recheck);
        while (get_line (file, line, MAX_LINE_LEN))
        {
            if(!line[0] || line[0] == '#')
                continue;
            count++;
            cache->add_new_entry (cache, line, 0);
        }
        fclose (file);
        INFO2 ("%d entries read from file \"%s\"", count, cache->filename);
    }
}
Exemple #8
0
/* Not efficient; opens and scans the entire file for every request */
static auth_result htpasswd_auth(auth_t *auth, source_t *source, char *username, char *password)
{
    htpasswd_auth_state *state = auth->state;
    FILE *passwdfile = NULL;
    char line[MAX_LINE_LEN];
    char *sep;

    thread_rwlock_rlock(&state->file_rwlock);
    if (!state->allow_duplicate_users) {
        if (auth_is_listener_connected(source, username)) {
            thread_rwlock_unlock(&state->file_rwlock);
            return AUTH_FORBIDDEN;
        }
    }
    passwdfile = fopen(state->filename, "rb");
    if(passwdfile == NULL) {
        WARN2("Failed to open authentication database \"%s\": %s", 
                state->filename, strerror(errno));
        thread_rwlock_unlock(&state->file_rwlock);
        return AUTH_FAILED;
    }

    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
        if(!line[0] || line[0] == '#')
            continue;

        sep = strchr(line, ':');
        if(sep == NULL) {
            DEBUG0("No seperator in line");
            continue;
        }

        *sep = 0;
        if(!strcmp(username, line)) {
            /* Found our user, now: does the hash of password match hash? */
            char *hash = sep+1;
            char *hashed_password = get_hash(password, strlen(password));
            if(!strcmp(hash, hashed_password)) {
                fclose(passwdfile);
                free(hashed_password);
                thread_rwlock_unlock(&state->file_rwlock);
                return AUTH_OK;
            }
            free(hashed_password);
            /* We don't keep searching through the file */
            break; 
        }
    }

    fclose(passwdfile);

    thread_rwlock_unlock(&state->file_rwlock);
    return AUTH_FAILED;
}
Exemple #9
0
/* simple name=tag stat create/update */
void stats_event(const char *source, const char *name, const char *value)
{
    stats_event_t *event;

    if (value && xmlCheckUTF8 ((unsigned char *)value) == 0)
    {
        WARN2 ("seen non-UTF8 data, probably incorrect metadata (%s, %s)", name, value);
        return;
    }
    event = build_event (source, name, value);
    if (event)
        queue_global_event (event);
}
Exemple #10
0
static void url_stream_end (auth_client *auth_user)
{
    char *mount, *server;
    ice_config_t *config = config_get_config ();
    mount_proxy *mountinfo = config_find_mount (config, auth_user->mount);
    auth_t *auth = mountinfo->auth;
    auth_url *url = auth->state;
    char *stream_end_url;
    int port;
    char post [4096];

    if (url->stream_end == NULL)
    {
        config_release_config ();
        return;
    }
    server = util_url_escape (config->hostname);
    port = config->port;
    stream_end_url = strdup (url->stream_end);
    /* we don't want this auth disappearing from under us while
     * the connection is in progress */
    mountinfo->auth->refcount++;
    config_release_config ();
    mount = util_url_escape (auth_user->mount);

    snprintf (post, sizeof (post),
            "action=mount_remove&mount=%s&server=%s&port=%d", mount, server, port);
    free (server);
    free (mount);

    if (strchr (url->stream_end, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd);
        else
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    }
    else
        curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    curl_easy_setopt (url->handle, CURLOPT_URL, url->stream_end);
    curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);

    if (curl_easy_perform (url->handle))
        WARN2 ("auth to server %s failed with %s", stream_end_url, url->errormsg);

    auth_release (auth);
    free (stream_end_url);
    return;
}
Exemple #11
0
int config_get_port (xmlNodePtr node, void *x)
{
    int val = 0, ret = config_get_int (node, &val);

    if (ret == 0)
    {
        if (val < 0 || val > 65535)
        {
            WARN2 ("port out of range \"%s\" at line %ld, assuming 8000", node->name, xmlGetLineNo(node));
            val = 8000;
        }
        *(int*)x = val;
    }
    return ret;
}
Exemple #12
0
/* helper to apply specialised changes to a stats node */
static void modify_node_event (stats_node_t *node, stats_event_t *event)
{
    char *str;

    if (event->action == STATS_EVENT_HIDDEN)
    {
        if (event->value)
            node->hidden = 1;
        else
            node->hidden = 0;
        return;
    }
    if (event->action != STATS_EVENT_SET)
    {
        int64_t value = 0;

        switch (event->action)
        {
            case STATS_EVENT_INC:
                value = atoi (node->value)+1;
                break;
            case STATS_EVENT_DEC:
                value = atoi (node->value)-1;
                break;
            case STATS_EVENT_ADD:
                value = atoi (node->value)+atoi (event->value);
                break;
            case STATS_EVENT_SUB:
                value = atoll (node->value) - atoll (event->value);
                break;
            default:
                WARN2 ("unhandled event (%d) for %s", event->action, event->source);
                break;
        }
        str = malloc (16);
        snprintf (str, 16, "%" PRId64, value);
        if (event->value == NULL)
            event->value = strdup (str);
    }
    else
        str = (char *)strdup (event->value);
    free (node->value);
    node->value = str;
    if (event->source)
        DEBUG3 ("update \"%s\" %s (%s)", event->source, node->name, node->value);
    else
        DEBUG2 ("update global %s (%s)", node->name, node->value);
}
Exemple #13
0
static void get_ssl_certificate (ice_config_t *config)
{
    ssl_ok = 0;
    do
    {
        long ssl_opts;

        ssl_ctx = NULL;
        if (config->cert_file == NULL)
            break;

        ssl_ctx = SSL_CTX_new (SSLv23_server_method());
        ssl_opts = SSL_CTX_get_options (ssl_ctx);
        SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2);

        if (SSL_CTX_use_certificate_chain_file (ssl_ctx, config->cert_file) <= 0)
        {
            WARN1 ("Invalid cert file %s", config->cert_file);
            break;
        }
        if (SSL_CTX_use_PrivateKey_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0)
        {
            WARN1 ("Invalid private key file %s", config->cert_file);
            break;
        }
        if (!SSL_CTX_check_private_key (ssl_ctx))
        {
            ERROR1 ("Invalid %s - Private key does not match cert public key", config->cert_file);
            break;
        }
        if (SSL_CTX_set_cipher_list(ssl_ctx, config->cipher_list) <= 0)
        {
            WARN1 ("Invalid cipher list: %s", config->cipher_list);
        }
        ssl_ok = 1;
        INFO1 ("SSL certificate found at %s", config->cert_file);
        INFO1 ("SSL using ciphers %s", config->cipher_list);
        return;
    } while (0);
    if (ssl_ctx)
    {
        WARN2 ("failed to load cert %s (%s)", config->cert_file, ERR_reason_error_string (ERR_peek_last_error()));
        SSL_CTX_free (ssl_ctx);
        ssl_ctx = NULL;
    }
    INFO0 ("No SSL capability on any configured ports");
}
int
CloseSocket(Socket *sock,
            int waitForPeer) {

  fd_set readFDs;
  Socket sd = *sock;
  struct timeval timeout;

  if (debug > 0) {
      DDEBUG1("CloseSocket: Closing connection %d\n", *sock);
  }

  if(*sock == NO_SOCKET) {
    return 1;  /* Already closed; nothing to do. */
  }

  if(waitForPeer > 0) {

    FD_ZERO(&readFDs);
    FD_SET(sd, &readFDs);
    timeout.tv_sec = waitForPeer;
    timeout.tv_usec = 0;

    if(select(FD_SETSIZE, &readFDs, NULL, NULL, &timeout) < 0) {
      FAIL2("CloseSocket: no response on select %d %d\n", sd, errno);
    }

  }

  if(!FD_ISSET(sd, &connectedPipes)) {
    if(shutdown(sd, 2) < 0) {
      /* The other side may have beaten us to the reset. */
      if ((errno != ENOTCONN) && (errno != ECONNRESET)) {
        WARN1("CloseSocket: shutdown error %d\n", errno);
      }
    }
  }

  if(close(sd) < 0) {
    WARN2("CloseSocket: close error %d (%s)\n", errno, strerror(errno));
  }
  ClearSocket(sd);
  DoDisconnectNotification(sd);
  *sock = NO_SOCKET;
  return(1);

}
Exemple #15
0
static xsltStylesheetPtr xslt_get_stylesheet(const char *fn) {
    int i;
    int empty = -1;
    struct stat file;

    if(stat(fn, &file)) {
        WARN2("Error checking for stylesheet file \"%s\": %s", fn, 
                strerror(errno));
        return NULL;
    }

    for(i=0; i < CACHESIZE; i++) {
        if(cache[i].filename)
        {
#ifdef _WIN32
            if(!stricmp(fn, cache[i].filename))
#else
            if(!strcmp(fn, cache[i].filename))
#endif
            {
                if(file.st_mtime > cache[i].last_modified)
                {
                    xsltFreeStylesheet(cache[i].stylesheet);

                    cache[i].last_modified = file.st_mtime;
                    cache[i].stylesheet = xsltParseStylesheetFile(XMLSTR(fn));
                    cache[i].cache_age = time(NULL);
                }
                DEBUG1("Using cached sheet %i", i);
                return cache[i].stylesheet;
            }
        }
        else
            empty = i;
    }

    if(empty>=0)
        i = empty;
    else
        i = evict_cache_entry();

    cache[i].last_modified = file.st_mtime;
    cache[i].filename = strdup(fn);
    cache[i].stylesheet = xsltParseStylesheetFile(XMLSTR(fn));
    cache[i].cache_age = time(NULL);
    return cache[i].stylesheet;
}
Exemple #16
0
static void url_stream_auth (auth_client *auth_user)
{
    ice_config_t *config;
    int port;
    client_t *client = auth_user->client;
    auth_url *url = client->auth->state;
    char *mount, *host, *user, *pass, *ipaddr, *admin="";
    char post [4096];

    if (strchr (url->stream_auth, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd);
        else
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    }
    else
        curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    curl_easy_setopt (url->handle, CURLOPT_URL, url->stream_auth);
    curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);
    if (strcmp (auth_user->mount, httpp_getvar (client->parser, HTTPP_VAR_URI)) != 0)
        admin = "&admin=1";
    mount = util_url_escape (auth_user->mount);
    config = config_get_config ();
    host = util_url_escape (config->hostname);
    port = config->port;
    config_release_config ();
    user = util_url_escape (client->username);
    pass = util_url_escape (client->password);
    ipaddr = util_url_escape (client->con->ip);

    snprintf (post, sizeof (post),
            "action=stream_auth&mount=%s&ip=%s&server=%s&port=%d&user=%s&pass=%s%s",
            mount, ipaddr, host, port, user, pass, admin);
    free (ipaddr);
    free (user);
    free (pass);
    free (mount);
    free (host);

    client->authenticated = 0;
    if (curl_easy_perform (url->handle))
        WARN2 ("auth to server %s failed with %s", url->stream_auth, url->errormsg);
}
Exemple #17
0
static void url_stream_auth (auth_client *auth_user)
{
    client_t *client = auth_user->client;
    auth_url *url = auth_user->auth->state;
    auth_thread_data *atd = auth_user->thread_data;
    char *mount, *host, *user, *pass, *ipaddr, *admin="";
    char post [4096];

    if (strchr (url->stream_auth, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (atd->curl, CURLOPT_USERPWD, url->userpwd);
        else
            curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
    }
    else
        curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
    curl_easy_setopt (atd->curl, CURLOPT_URL, url->stream_auth);
    curl_easy_setopt (atd->curl, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (atd->curl, CURLOPT_WRITEHEADER, auth_user);
    curl_easy_setopt (atd->curl, CURLOPT_WRITEDATA, auth_user);
    if (strcmp (auth_user->mount, httpp_getvar (client->parser, HTTPP_VAR_URI)) != 0)
        admin = "&admin=1";
    mount = util_url_escape (auth_user->mount);
    host = util_url_escape (auth_user->hostname);
    user = util_url_escape (client->username);
    pass = util_url_escape (client->password);
    ipaddr = util_url_escape (client->connection.ip);

    snprintf (post, sizeof (post),
            "action=stream_auth&mount=%s&ip=%s&server=%s&port=%d&user=%s&pass=%s%s",
            mount, ipaddr, host, auth_user->port, user, pass, admin);
    free (ipaddr);
    free (user);
    free (pass);
    free (mount);
    free (host);

    client->flags &= ~CLIENT_AUTHENTICATED;
    if (curl_easy_perform (atd->curl))
        WARN2 ("auth to server %s failed with %s", url->stream_auth, atd->errormsg);
}
Exemple #18
0
/* printf style formatting for stat create/update */
void stats_event_args(const char *source, char *name, char *format, ...)
{
    va_list val;
    int ret;
    char buf[1024];

    if (name == NULL)
        return;
    va_start(val, format);
    ret = vsnprintf(buf, sizeof (buf), format, val);
    va_end(val);

    if (ret < 0 || (unsigned int)ret >= sizeof (buf))
    {
        WARN2 ("problem with formatting %s stat %s",
                source==NULL ? "global" : source, name);
        return;
    }
    stats_event(source, name, buf);
}
void stats_set_args (long handle, const char *name, const char *format, ...)
{
    va_list val;
    int ret;
    stats_source_t *src_stats = (stats_source_t *)handle;
    char buf[1024];

    if (name == NULL)
        return;
    va_start (val, format);
    ret = vsnprintf (buf, sizeof (buf), format, val);
    va_end (val);

    if (ret < 0 || (unsigned int)ret >= sizeof (buf))
    {
        WARN2 ("problem with formatting %s stat %s",
                src_stats == NULL ? "global" : src_stats->source, name);
        return;
    }
    stats_set (handle, name, buf);
}
Exemple #20
0
static void url_stream_end (auth_client *auth_user)
{
    char *mount, *server, *ipaddr;
    client_t *client = auth_user->client;
    auth_url *url = auth_user->auth->state;
    auth_thread_data *atd = auth_user->thread_data;
    char post [4096];

    server = util_url_escape (auth_user->hostname);
    mount = util_url_escape (auth_user->mount);
    if (client && client->connection.ip)
        ipaddr = util_url_escape (client->connection.ip);
    else
        ipaddr = strdup("");

    snprintf (post, sizeof (post),
            "action=mount_remove&mount=%s&server=%s&port=%d&ip=%s", mount, server, auth_user->port, ipaddr);
    free (ipaddr);
    free (server);
    free (mount);

    if (strchr (url->stream_end, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (atd->curl, CURLOPT_USERPWD, url->userpwd);
        else
            curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
    }
    else
        curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
    curl_easy_setopt (atd->curl, CURLOPT_URL, url->stream_end);
    curl_easy_setopt (atd->curl, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (atd->curl, CURLOPT_WRITEHEADER, auth_user);
    curl_easy_setopt (atd->curl, CURLOPT_WRITEDATA, auth_user);

    DEBUG1 ("handler %d sending request", auth_user->handler);
    if (curl_easy_perform (atd->curl))
        WARN2 ("auth to server %s failed with %s", url->stream_end, atd->errormsg);
    DEBUG1 ("handler %d request finished", auth_user->handler);
}
static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password)
{
    FILE *passwdfile;
    char *hashed_password = NULL;
    htpasswd_auth_state *state = auth->state;
    htpasswd_user entry;
    void *result;

    htpasswd_recheckfile (state);

    thread_rwlock_wlock (&state->file_rwlock);

    entry.name = (char*)username;
    if (avl_get_by_key (state->users, &entry, &result) == 0)
    {
        thread_rwlock_unlock (&state->file_rwlock);
        return AUTH_USEREXISTS;
    }

    passwdfile = fopen(state->filename, "ab");

    if (passwdfile == NULL)
    {
        thread_rwlock_unlock (&state->file_rwlock);
        WARN2("Failed to open authentication database \"%s\": %s", 
                state->filename, strerror(errno));
        return AUTH_FAILED;
    }

    hashed_password = get_hash(password, strlen(password));
    if (hashed_password) {
        fprintf(passwdfile, "%s:%s\n", username, hashed_password);
        free(hashed_password);
    }

    fclose(passwdfile);
    thread_rwlock_unlock (&state->file_rwlock);

    return AUTH_USERADDED;
}
Exemple #22
0
int auth_get_htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode)
{
    htpasswd_auth_state *state;
    FILE *passwdfile;
    char line[MAX_LINE_LEN];
    char *sep;
    char *passwd;
    xmlNodePtr newnode;

    state = auth->state;

    passwdfile = fopen(state->filename, "rb");

    if(passwdfile == NULL) {
        WARN2("Failed to open authentication database \"%s\": %s", 
                state->filename, strerror(errno));
        return AUTH_FAILED;
    }

    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
        if(!line[0] || line[0] == '#')
            continue;

        sep = strchr(line, ':');
        if(sep == NULL) {
            DEBUG0("No seperator in line");
            continue;
        }

        *sep = 0;
        newnode = xmlNewChild(srcnode, NULL, "User", NULL);
        xmlNewChild(newnode, NULL, "username", line);
        passwd = sep+1;
        xmlNewChild(newnode, NULL, "password", passwd);
    }

    fclose(passwdfile);
    return AUTH_OK;
}
Exemple #23
0
static connection_t *_accept_connection(int duration)
{
    sock_t sock, serversock;
    char *ip;

    serversock = wait_for_serversock (duration);
    if (serversock == SOCK_ERROR)
        return NULL;

    /* malloc enough room for a full IP address (including ipv6) */
    ip = (char *)malloc(MAX_ADDR_LEN);

    sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
    if (sock != SOCK_ERROR)
    {
        connection_t *con = NULL;
        /* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */
        if (strncmp (ip, "::ffff:", 7) == 0)
            memmove (ip, ip+7, strlen (ip+7)+1);

        if (accept_ip_address (ip))
            con = connection_create (sock, serversock, ip);
        if (con)
            return con;
        sock_close (sock);
    }
    else
    {
        if (!sock_recoverable(sock_error()))
        {
            WARN2("accept() failed with error %d: %s", sock_error(), strerror(sock_error()));
            thread_sleep (500000);
        }
    }
    free(ip);
    return NULL;
}
Exemple #24
0
int auth_htpasswd_existing_user(auth_t *auth, char *username)
{
    FILE *passwdfile;
    htpasswd_auth_state *state;
    int ret = AUTH_OK;
    char line[MAX_LINE_LEN];
    char *sep;

    state = auth->state;
    passwdfile = fopen(state->filename, "rb");

    if(passwdfile == NULL) {
        WARN2("Failed to open authentication database \"%s\": %s", 
                state->filename, strerror(errno));
        return AUTH_FAILED;
    }
    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
        if(!line[0] || line[0] == '#')
            continue;
        sep = strchr(line, ':');
        if(sep == NULL) {
            DEBUG0("No seperator in line");
            continue;
        }
        *sep = 0;
        if (!strcmp(username, line)) {
            /* We found the user, break out of the loop */
            ret = AUTH_USEREXISTS;
            break;
        }
    }

    fclose(passwdfile);
    return ret;

}
Exemple #25
0
/* client has requested a file, so check for it and send the file.  Do not
 * refer to the client_t afterwards.  return 0 for success, -1 on error.
 */
int fserve_client_create (client_t *httpclient, const char *path)
{
    struct stat file_buf;
    char *fullpath;
    int m3u_requested = 0, m3u_file_available = 1;
    int xspf_requested = 0, xspf_file_available = 1;
    int ret = -1;
    ice_config_t *config;
    fbinfo finfo;
    char fsize[20];

    fullpath = util_get_path_from_normalised_uri (path, 0);
    DEBUG2 ("checking for file %s (%s)", path, fullpath);

    if (strcmp (util_get_extension (fullpath), "m3u") == 0)
        m3u_requested = 1;

    if (strcmp (util_get_extension (fullpath), "xspf") == 0)
        xspf_requested = 1;

    /* check for the actual file */
    if (stat (fullpath, &file_buf) != 0)
    {
        /* the m3u can be generated, but send an m3u file if available */
        if (m3u_requested == 0 && xspf_requested == 0)
        {
            if (redirect_client (path, httpclient) == 0)
            {
                if ((httpclient->flags & CLIENT_SKIP_ACCESSLOG) == 0)
                    WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
                ret = client_send_404 (httpclient, "The file you requested could not be found");
            }
            free (fullpath);
            return ret;
        }
        m3u_file_available = 0;
        xspf_file_available = 0;
    }

    client_set_queue (httpclient, NULL);
    httpclient->refbuf = refbuf_new (4096);

    if (m3u_requested && m3u_file_available == 0)
    {
        const char  *host = httpp_getvar (httpclient->parser, "host"),
                    *args = httpp_getvar (httpclient->parser, HTTPP_VAR_QUERYARGS),
                    *at = "", *user = "", *pass ="";
        char *sourceuri = strdup (path);
        char *dot = strrchr (sourceuri, '.');
        char *protocol = "http";
        const char *agent = httpp_getvar (httpclient->parser, "user-agent");
        int x;
        char scratch[1000];

        if (agent)
        {
            if (strstr (agent, "QTS") || strstr (agent, "QuickTime"))
                protocol = "icy";
        }
        /* at least a couple of players (fb2k/winamp) are reported to send a 
         * host header but without the port number. So if we are missing the
         * port then lets treat it as if no host line was sent */
        if (host && strchr (host, ':') == NULL)
            host = NULL;

        *dot = 0;
        if (httpclient->username && httpclient->password)
        {
            at = "@";
            user = httpclient->username;
            pass = httpclient->password;
        }
        httpclient->respcode = 200;
        if (host == NULL)
        {
            config = config_get_config();
            x = snprintf (scratch, sizeof scratch,
                    "%s://%s%s%s%s%s:%d%s%s\r\n",
                    protocol,
                    user, at[0]?":":"", pass, at,
                    config->hostname, config->port,
                    sourceuri,
                    args?args:"");
            config_release_config();
        }
        else
        {
            x = snprintf (scratch, sizeof scratch,
                    "%s://%s%s%s%s%s%s%s\r\n",
                    protocol,
                    user, at[0]?":":"", pass, at,
                    host,
                    sourceuri,
                    args?args:"");
        }
        snprintf (httpclient->refbuf->data, BUFSIZE,
                "HTTP/1.0 200 OK\r\n"
                "Content-Length: %d\r\n"
                "%s\r\n"
                "Content-Type: audio/x-mpegurl\r\n\r\n%s",
                x, client_keepalive_header (httpclient), scratch);
        httpclient->refbuf->len = strlen (httpclient->refbuf->data);
        free (sourceuri);
        free (fullpath);
        return fserve_setup_client_fb (httpclient, NULL);
    }
    if (xspf_requested && xspf_file_available == 0)
    {
        xmlDocPtr doc;
        char *reference = strdup (path);
        char *eol = strrchr (reference, '.');
        if (eol)
            *eol = '\0';
        doc = stats_get_xml (0, reference);
        free (reference);
        free (fullpath);
        return admin_send_response (doc, httpclient, XSLT, "xspf.xsl");
    }

    /* on demand file serving check */
    config = config_get_config();
    if (config->fileserve == 0)
    {
        config_release_config();
        DEBUG1 ("on demand file \"%s\" refused", fullpath);
        free (fullpath);
        return client_send_404 (httpclient, "The file you requested could not be found");
    }
    config_release_config();

    if (S_ISREG (file_buf.st_mode) == 0)
    {
        WARN1 ("found requested file but there is no handler for it: %s", fullpath);
        free (fullpath);
        return client_send_404 (httpclient, "The file you requested could not be found");
    }

    free (fullpath);
    finfo.flags = 0;
    finfo.mount = (char *)path;
    finfo.fallback = NULL;
    finfo.limit = 0;
    finfo.type = FORMAT_TYPE_UNDEFINED;
    snprintf (fsize, 20, "%" PRId64, (int64_t)file_buf.st_size);
    httpp_setvar (httpclient->parser, "__FILESIZE", fsize);
    stats_event_inc (NULL, "file_connections");

    return fserve_setup_client_fb (httpclient, &finfo);
}
Exemple #26
0
static void remove_fh_from_cache (fh_node *fh)
{
    if (fh->refcount)
        WARN2 ("removing %s with %d still on", fh->finfo.mount, fh->refcount);
    avl_delete (fh_cache, fh, NULL);
}
Exemple #27
0
static int xslt_cached (const char *fn, client_t *client)
{
    worker_t *worker = client->worker;
    time_t now = worker->current_time.tv_sec, oldest = now;
    int evict = 0, i;
    struct stat file;

    for(i=0; i < CACHESIZE; i++)
    {
        if(cache[i].filename)
        {
#ifdef _WIN32
            if (stricmp(fn, cache[i].filename) == 0)
#else
            if (strcmp(fn, cache[i].filename) == 0)
#endif
            {
                if (now - cache[i].last_checked > 10)
                {
                    cache[i].last_checked = now;
                    if (stat (fn, &file))
                    {
                        WARN2("Error checking for stylesheet file \"%s\": %s", fn, strerror(errno));
                        return i;
                    }
                    DEBUG1 ("rechecked file time on %s", fn);

                    thread_spin_lock (&update_lock);
                    if (file.st_mtime > cache[i].last_modified)
                    {
                        cache[i].last_modified = file.st_mtime;
                        thread_spin_unlock (&update_lock);
                        break;
                    }
                }
                thread_spin_unlock (&update_lock);
                cache[i].cache_age = now;
                return i;
            }
            if (oldest < cache[i].cache_age)
                continue;
        }
        evict = i;
    }
    xsl_req *x = calloc (1, sizeof (xsl_req));
    if (i < CACHESIZE)
    {
        x->index = i;
    }
    else
    {
        if (stat (fn, &file))
        {
            WARN2("Error checking for stylesheet file \"%s\": %s", fn, strerror(errno));
            free (x);
            return -2;
        }
        x->client = client;
        x->index = evict;
    }
    x->doc = client->shared_data;
    x->cache.filename = strdup (fn);
    x->cache.last_modified = file.st_mtime;
    x->cache.cache_age = now;
    x->cache.last_checked = now;
    client->shared_data = x;
    client->schedule_ms = worker->time_ms;
    client->ops = &xslt_ops;

    thread_spin_lock (&update_lock);
    if (xsl_updating < 3)
    {
        xsl_updating++;
        thread_spin_unlock (&update_lock);
        if (x->client)   client->flags &= ~CLIENT_ACTIVE;
        thread_create ("update xslt", xslt_update, x, THREAD_DETACHED);
        if (x->client == NULL)   return i;
    }
    else
    {
        thread_spin_unlock (&update_lock);
        x->client = client;
        client->schedule_ms += 10;
        if ((client->flags & CLIENT_ACTIVE) == 0)
        {
            client->flags |= CLIENT_ACTIVE;
            worker_wakeup (worker);
        }
    }
    return -1;
}
Exemple #28
0
/* Add a listener. Check for any mount information that states any
 * authentication to be used.
 */
int auth_add_listener (const char *mount, client_t *client)
{
    int ret = 0, need_auth = 1;
    ice_config_t *config = config_get_config();
    mount_proxy *mountinfo = config_find_mount (config, mount);

    if (client->flags & CLIENT_AUTHENTICATED)
        need_auth = 0;
    else
    {
        const char *range = httpp_getvar (client->parser, "range");
        if (range)
        {
            uint64_t pos1 = 0, pos2 = (uint64_t)-1;

            if (strncmp (range, "bytes=", 6) == 0)
            {
                if (sscanf (range+6, "-%" SCNuMAX, &pos2) < 1)
                    if (sscanf (range+6, "%" SCNuMAX "-%" SCNuMAX, &pos1, &pos2) < 1)
                        pos2 = 0;
            }
            else
                pos2 = 0;

            if (pos2 > 0 && pos1 < pos2)
            {
                client->intro_offset = pos1;
                client->connection.discon.offset = pos2;
                client->flags |= CLIENT_RANGE_END;
                if (pos2 - pos1 < 10)
                    need_auth = 0; // avoid auth check if range is very small, player hack
            }
            else
                WARN2 ("client range invalid (%" PRIu64 ", %" PRIu64 "), ignoring", pos1, pos2);
        }
    }
    if (client->parser->req_type == httpp_req_head)
    {
        client->flags &= ~CLIENT_AUTHENTICATED;
        need_auth = 0;
    }

    if (need_auth)
    {
        if (mountinfo)
        {
            auth_t *auth = mountinfo->auth;

            if (mountinfo->skip_accesslog)
                client->flags |= CLIENT_SKIP_ACCESSLOG;
            if (mountinfo->ban_client)
            {
                if (mountinfo->ban_client < 0)
                    client->flags |= CLIENT_IP_BAN_LIFT;
                connection_add_banned_ip (client->connection.ip, mountinfo->ban_client);
            }
            if (mountinfo->no_mount)
            {
                config_release_config ();
                return client_send_403 (client, "mountpoint unavailable");
            }
            if (mountinfo->redirect)
            {
                char buffer [4096] = "";
                unsigned int len = sizeof buffer;

                if (util_expand_pattern (mount, mountinfo->redirect, buffer, &len) == 0)
                {
                    config_release_config ();
                    return client_send_302 (client, buffer);
                }
                WARN3 ("failed to expand %s on %s for %s", mountinfo->redirect, mountinfo->mountname, mount);
                return client_send_501 (client);
            }
            do
            {
                if (auth == NULL) break;
                if ((auth->flags & AUTH_RUNNING) == 0) break;
                if (auth->pending_count > 400)
                {
                    if (auth->flags & AUTH_SKIP_IF_SLOW) break;
                    config_release_config ();
                    WARN0 ("too many clients awaiting authentication");
                    if (global.new_connections_slowdown < 10)
                        global.new_connections_slowdown++;
                    return client_send_403 (client, "busy, please try again later");
                }
                if (auth->authenticate)
                {
                    auth_client *auth_user = auth_client_setup (mount, client);
                    auth_user->process = auth_new_listener;
                    client->flags &= ~CLIENT_ACTIVE;
                    DEBUG0 ("adding client for authentication");
                    queue_auth_client (auth_user, mountinfo);
                    config_release_config ();
                    return 0;
                }
            } while (0);
        }
        else
        {
            if (strcmp (mount, "/admin/streams") == 0)
            {
                config_release_config ();
                return client_send_401 (client, NULL);
            }
        }
    }
    ret = add_authenticated_listener (mount, mountinfo, client);
    config_release_config ();
    return ret;
}
Exemple #29
0
static client_t *accept_client (void)
{
    client_t *client = NULL;
    sock_t sock, serversock = wait_for_serversock ();
    char addr [200];

    if (serversock == SOCK_ERROR)
        return NULL;

    sock = sock_accept (serversock, addr, 200);
    if (sock == SOCK_ERROR)
    {
        if (sock_recoverable (sock_error()))
            return NULL;
        WARN2 ("accept() failed with error %d: %s", sock_error(), strerror(sock_error()));
        thread_sleep (500000);
        return NULL;
    }
    do
    {
        int i, num;
        refbuf_t *r;

        if (sock_set_blocking (sock, 0) || sock_set_nodelay (sock))
        {
            WARN0 ("failed to set tcp options on client connection, dropping");
            break;
        }
        client = calloc (1, sizeof (client_t));
        if (client == NULL || connection_init (&client->connection, sock, addr) < 0)
            break;

        client->shared_data = r = refbuf_new (PER_CLIENT_REFBUF_SIZE);
        r->len = 0; // for building up the request coming in

        global_lock ();
        client_register (client);

        for (i=0; i < global.server_sockets; i++)
        {
            if (global.serversock[i] == serversock)
            {
                client->server_conn = global.server_conn[i];
                client->server_conn->refcount++;
                if (client->server_conn->ssl && ssl_ok)
                    connection_uses_ssl (&client->connection);
                if (client->server_conn->shoutcast_compat)
                    client->ops = &shoutcast_source_ops;
                else
                    client->ops = &http_request_ops;
                break;
            }
        }
        num = global.clients;
        global_unlock ();
        stats_event_args (NULL, "clients", "%d", num);
        client->flags |= CLIENT_ACTIVE;
        return client;
    } while (0);

    free (client);
    sock_close (sock);
    return NULL;
}
Exemple #30
0
static auth_result url_add_listener (auth_client *auth_user)
{
    client_t *client = auth_user->client;
    auth_t *auth = client->auth;
    auth_url *url = auth->state;
    int res = 0, port;
    const char *agent;
    char *user_agent, *username, *password;
    const char *mountreq;
    char *mount, *ipaddr, *server;
    ice_config_t *config;
    char *userpwd = NULL, post [4096];

    if (url->addurl == NULL)
        return AUTH_OK;

    config = config_get_config ();
    server = util_url_escape (config->hostname);
    port = config->port;
    config_release_config ();
    agent = httpp_getvar (client->parser, "user-agent");
    if (agent == NULL)
        agent = "-";
    user_agent = util_url_escape (agent);
    if (client->username)
        username  = util_url_escape (client->username);
    else
        username = strdup ("");
    if (client->password)
        password  = util_url_escape (client->password);
    else
        password = strdup ("");

    /* get the full uri (with query params if available) */
    mountreq = httpp_getvar (client->parser, HTTPP_VAR_RAWURI);
    if (mountreq == NULL)
        mountreq = httpp_getvar (client->parser, HTTPP_VAR_URI);
    mount = util_url_escape (mountreq);
    ipaddr = util_url_escape (client->con->ip);

    snprintf (post, sizeof (post),
            "action=listener_add&server=%s&port=%d&client=%lu&mount=%s"
            "&user=%s&pass=%s&ip=%s&agent=%s",
            server, port, client->con->id, mount, username,
            password, ipaddr, user_agent);
    free (server);
    free (mount);
    free (user_agent);
    free (username);
    free (password);
    free (ipaddr);

    if (strchr (url->addurl, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd);
        else
        {
            /* auth'd requests may not have a user/pass, but may use query args */
            if (client->username && client->password)
            {
                int len = strlen (client->username) + strlen (client->password) + 2;
                userpwd = amalloc (len);
                snprintf (userpwd, len, "%s:%s", client->username, client->password);
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, userpwd);
            }
            else
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
        }
    }
    else
    {
        /* url has user/pass but libcurl may need to clear any existing settings */
        curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    }
    curl_easy_setopt (url->handle, CURLOPT_URL, url->addurl);
    curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);
    url->errormsg[0] = '\0';

    res = curl_easy_perform (url->handle);

    free (userpwd);

    if (res)
    {
        WARN2 ("auth to server %s failed with %s", url->addurl, url->errormsg);
        return AUTH_FAILED;
    }
    /* we received a response, lets see what it is */
    if (client->authenticated)
        return AUTH_OK;
    INFO2 ("client auth (%s) failed with \"%s\"", url->addurl, url->errormsg);
    return AUTH_FAILED;
}