Beispiel #1
0
/* wrapper for starting the provided relay stream */
static void check_relay_stream (relay_server *relay)
{
    if (relay->source == NULL)
    {
        if (relay->localmount[0] != '/')
        {
            WARN1 ("relay mountpoint \"%s\" does not start with /, skipping",
                    relay->localmount);
            return;
        }
        /* new relay, reserve the name */
        relay->source = source_reserve (relay->localmount);
        if (relay->source)
            DEBUG1("Adding relay source at mountpoint \"%s\"", relay->localmount);
        else
            WARN1 ("new relay but source \"%s\" already exists", relay->localmount);
    }
    if (relay->source && !relay->running)
    {
        relay->thread = thread_create ("Relay Thread", start_relay_stream,
                relay, THREAD_ATTACHED);
        return;
    }
    /* the relay thread may of close down */
    if (relay->cleanup && relay->thread)
    {
        DEBUG1 ("waiting for relay thread for \"%s\"", relay->localmount);
        thread_join (relay->thread);
        relay->thread = NULL;
        relay->cleanup = 0;
        relay->running = 0;
    }
}
Beispiel #2
0
static void queue_auth_client (auth_client *auth_user, mount_proxy *mountinfo)
{
    auth_t *auth;

    if (auth_user == NULL)
        return;
    auth_user->next = NULL;
    if (mountinfo)
    {
        auth = mountinfo->auth;
        thread_mutex_lock (&auth->lock);
        if (auth_user->client)
            auth_user->client->auth = auth;
        auth->refcount++;
    }
    else
    {
        if (auth_user->client == NULL || auth_user->client->auth == NULL)
        {
            WARN1 ("internal state is incorrect for %p", auth_user->client);
            return;
        }
        auth = auth_user->client->auth;
        thread_mutex_lock (&auth->lock);
    }
    DEBUG2 ("...refcount on auth_t %s is now %d", auth->mount, auth->refcount);
    *auth->tailp = auth_user;
    auth->tailp = &auth_user->next;
    auth->pending_count++;
    INFO2 ("auth on %s has %d pending", auth->mount, auth->pending_count);
    thread_mutex_unlock (&auth->lock);
}
Beispiel #3
0
static void
setVerboseFlags(char *str)
{
    for (; *str; str++)
    {
        switch (*str)
        {
        case 'f':
            verboseLevel |= WantFullNames;
            break;
        case 'h':
            verboseLevel |= WantHiddenMaps;
            break;
        case 'l':
            verboseLevel |= WantLongListing;
            break;
        case 'p':
            verboseLevel |= WantPartialMaps;
            break;
        case 'R':
            verboseLevel |= ListRecursive;
            break;
        default:
            if (warningLevel > 4)
            {
                WARN1("Unknown verbose option \"%c\"\n", (unsigned int) *str);
                ACTION("Ignored\n");
            }
            break;
        }
    }
    return;
}
Beispiel #4
0
/* This does the actual connection for a relay. A thread is
 * started off if a connection can be acquired
 */
int open_relay (relay_server *relay)
{
    source_t *src = relay->source;
    relay_server_master *master = relay->masters;
    client_t *client = src->client;
    do
    {
        int ret;

        if (master->skip)
        {
            INFO3 ("skipping %s:%d for %s", master->ip, master->port, relay->localmount);
            continue;
        }
        thread_mutex_unlock (&src->lock);
        ret = open_relay_connection (client, relay, master);
        thread_mutex_lock (&src->lock);

        if (ret < 0)
            continue;

        if (connection_complete_source (src) < 0)
        {
            WARN1 ("Failed to complete initialisation on %s", relay->localmount);
            continue;
        }
        return 1;
    } while ((master = master->next) && global.running == ICE_RUNNING);
    return -1;
}
Beispiel #5
0
/* wrapper for stats_event, this takes a charset to convert from */
void stats_event_conv(const char *mount, const char *name, const char *value, const char *charset)
{
    const char *metadata = value;
    xmlBufferPtr conv = xmlBufferCreate ();

    if (charset && value)
    {
        xmlCharEncodingHandlerPtr handle = xmlFindCharEncodingHandler (charset);

        if (handle)
        {
            xmlBufferPtr raw = xmlBufferCreate ();
            xmlBufferAdd (raw, (const xmlChar *)value, strlen (value));
            if (xmlCharEncInFunc (handle, conv, raw) > 0)
                metadata = (char *)xmlBufferContent (conv);
            xmlBufferFree (raw);
            xmlCharEncCloseFunc (handle);
        }
        else
            WARN1 ("No charset found for \"%s\"", charset);
    }

    stats_event (mount, name, metadata);
    xmlBufferFree (conv);
}
Beispiel #6
0
static void _add_stats_to_stats_client (client_t *client, const char *fmt, va_list ap)
{
    event_listener_t *listener = client->shared_data;
    refbuf_t *r = listener->recent_block;

    if (r && (r->flags & STATS_BLOCK_CONNECTION) == 0)
    {
        /* lets see if we can append to an existing block */
        if (r->len < 1390)
        {
            int written = _append_to_bufferv (r, 1400, fmt, ap);
            if (written > 0)
            {
                listener->content_len += written;
                return;
            }
        }
    }
    r = refbuf_new (1400);
    r->len = 0;
    if (_append_to_bufferv (r, 1400, fmt, ap) < 0)
    {
        WARN1 ("stat details are too large \"%s\"", fmt);
        refbuf_release (r);
        return;
    }
    _add_node_to_stats_client (client, r);
    client->schedule_ms = 0;
}
Beispiel #7
0
static int fserve_move_listener (client_t *client)
{
    fh_node *fh = client->shared_data;
    int ret = 0;
    fbinfo f;

    memset (&f, 0, sizeof (f));
    if (client->refbuf && client->pos < client->refbuf->len)
        client->flags |= CLIENT_HAS_INTRO_CONTENT; // treat it as a partial write needing completion
    else
        client_set_queue (client, NULL);
    f.flags = fh->finfo.flags & (~FS_DELETE);
    f.limit = fh->finfo.limit;
    f.mount = fh->finfo.fallback;
    f.type = fh->finfo.type;
    if (move_listener (client, &f) < 0)
    {
        WARN1 ("moved failed, terminating listener on %s", fh->finfo.mount);
        ret = -1;
    }
    else
    {
        DEBUG3 ("moved %s from %s (%d)", client->connection.ip, fh->finfo.mount, fh->finfo.flags);
        ret = 0;
        remove_from_fh (fh, client);
    }
    return ret;
}
/*
** A "local" function of ProcessRequest().  Implements the MEMORY_CLEAN service
** by deleting all files in the memory directory that have not been accessed
** within the past #idle# seconds.  Returns 1 if successful, else 0.
*/
static int
DoClean(unsigned long idle) {

  struct dirent *entry;
  DIR *directory;
  time_t expiration;
  char filePath[255 + 1];
  struct stat fileStat;
  char *namePlace;

  directory = opendir(memoryDir);
  if(directory == NULL) {
    FAIL1("DoClean: unable to open directory %s\n", memoryDir);
  }

  expiration = (time_t)CurrentTime() - (time_t)idle;
  SAFESTRCPY(filePath, memoryDir);
  namePlace = filePath + strlen(filePath);

  while((entry = readdir(directory)) != NULL) {
    strcpy(namePlace, entry->d_name);
    if(stat(filePath, &fileStat) != 0) {
      WARN1("DoClean: unable to state file %s\n", filePath);
    }
    else if(fileStat.st_mtime < expiration) {
      LOG2("DoClean: deleting %s, last modified %d\n",
           filePath, fileStat.st_mtime);
      (void)unlink(filePath);
    }
  }

  (void)closedir(directory);
  return(1);

}
Beispiel #9
0
static int fserve_move_listener (client_t *client)
{
    fh_node *fh = client->shared_data;
    int ret = 0;
    fbinfo f;

    memset (&f, 0, sizeof (f));
    client_set_queue (client, NULL);
    f.flags = fh->finfo.flags & (~FS_DELETE);
    f.limit = fh->finfo.limit;
    f.mount = fh->finfo.fallback;
    f.type = fh->finfo.type;
    if (move_listener (client, &f) < 0)
    {
        WARN1 ("moved failed, terminating listener on %s", fh->finfo.mount);
        ret = -1;
    }
    else
    {
        DEBUG3 ("moved %s from %s (%d)", client->connection.ip, fh->finfo.mount, fh->finfo.flags);
        ret = 0;
        remove_from_fh (fh, client);
    }
    return ret;
}
Beispiel #10
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");
}
static void _handle_source_request (client_t *client, char *uri, int auth_style)
{
    source_t *source;

    INFO1("Source logging in at mountpoint \"%s\"", uri);

    if (uri[0] != '/')
    {
        WARN0 ("source mountpoint not starting with /");
        client_send_401 (client);
        return;
    }
    if (auth_style == ICECAST_SOURCE_AUTH) {
        if (connection_check_source_pass (client->parser, uri) == 0)
        {
            /* We commonly get this if the source client is using the wrong
             * protocol: attempt to diagnose this and return an error
             */
            /* TODO: Do what the above comment says */
            INFO1("Source (%s) attempted to login with invalid or missing password", uri);
            client_send_401(client);
            return;
        }
    }
    source = source_reserve (uri);
    if (source)
    {
        if (auth_style == SHOUTCAST_SOURCE_AUTH) {
            source->shoutcast_compat = 1;
        }
        source->client = client;
        source->parser = client->parser;
        source->con = client->con;
        if (connection_complete_source (source, 1) < 0)
        {
            source_clear_source (source);
            source_free_source (source);
        }
        else
        {
            refbuf_t *ok = refbuf_new (PER_CLIENT_REFBUF_SIZE);
            client->respcode = 200;
            snprintf (ok->data, PER_CLIENT_REFBUF_SIZE,
                    "HTTP/1.0 200 OK\r\n\r\n");
            ok->len = strlen (ok->data);
            /* we may have unprocessed data read in, so don't overwrite it */
            ok->associated = client->refbuf;
            client->refbuf = ok;
            fserve_add_client_callback (client, source_client_callback, source);
        }
    }
    else
    {
        client_send_404 (client, "Mountpoint in use");
        WARN1 ("Mountpoint %s in use", uri);
    }
}
Beispiel #12
0
static void get_ssl_certificate (ice_config_t *config)
{
    SSL_METHOD *method;
    long ssl_opts;
    ssl_ok = 0;

    SSL_load_error_strings();                /* readable error messages */
    SSL_library_init();                      /* initialize library */

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

    do
    {
        if (config->cert_file == NULL)
            break;
        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);
    INFO0 ("No SSL capability on any configured ports");
}
Beispiel #13
0
void source_startup (client_t *client, const char *uri, int auth_style)
{
    source_t *source;
    refbuf_t *ok;
    source = source_reserve (uri);

    if (!source) {
        client_send_403 (client, "Mountpoint in use");
        WARN1 ("Mountpoint %s in use", uri);
        return;
    }

    source->client = client;
    source->parser = client->parser;
    source->con = client->con;
    if (connection_complete_source (source, 1) < 0) {
        source_clear_source (source);
        source_free_source (source);
        return;
    }
    client->respcode = 200;
    switch (auth_style) {
    case SHOUTCAST_SOURCE_AUTH:
        source->shoutcast_compat = 1;
    case NOAUTH_SOURCE_AUTH:
        break;
    case ICECAST_SOURCE_AUTH:
        ok = refbuf_new (PER_CLIENT_REFBUF_SIZE);
        client->respcode = 200;
        snprintf (ok->data, PER_CLIENT_REFBUF_SIZE,
                  "HTTP/1.0 200 OK\r\n\r\n");
        ok->len = strlen (ok->data);
        /* we may have unprocessed data read in, so don't overwrite it */
        ok->associated = client->refbuf;
        client->refbuf = ok;
        break;
    default:
        WARN1("Got unkown source auth type: %d", auth_style);
        return;
    }
    fserve_add_client_callback (client, source_client_callback, source);
}
Beispiel #14
0
/* Called from auth thread to process any request for source client
 * authentication. Only applies to source clients, not relays.
 */
static void stream_auth_callback (auth_client *auth_user)
{
    client_t *client = auth_user->client;

    if (auth_user->auth->stream_auth)
        auth_user->auth->stream_auth (auth_user);

    if (client->flags & CLIENT_AUTHENTICATED)
        auth_postprocess_source (auth_user);
    else
        WARN1 ("Failed auth for source \"%s\"", auth_user->mount);
}
Beispiel #15
0
static int command_list_log (client_t *client, int response)
{
    refbuf_t *content;
    const char *logname = httpp_get_query_param (client->parser, "log");
    int log = -1;
    ice_config_t *config;

    if (logname == NULL)
        return client_send_400 (client, "No log specified");

    config = config_get_config ();
    if (strcmp (logname, "errorlog") == 0)
        log = config->error_log.logid;
    else if (strcmp (logname, "accesslog") == 0)
        log = config->access_log.logid;
    else if (strcmp (logname, "playlistlog") == 0)
        log = config->playlist_log.logid;

    if (log < 0)
    {
        config_release_config();
        WARN1 ("request to show unknown log \"%s\"", logname);
        return client_send_400 (client, "unknown");
    }
    content = refbuf_new (0);
    log_contents (log, &content->data, &content->len);
    config_release_config();

    if (response == XSLT)
    {
        xmlNodePtr xmlnode;
        xmlDocPtr doc;

        doc = xmlNewDoc(XMLSTR("1.0"));
        xmlnode = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
        xmlDocSetRootElement(doc, xmlnode);
        xmlNewTextChild (xmlnode, NULL, XMLSTR("log"), XMLSTR(content->data));
        refbuf_release (content);

        return admin_send_response (doc, client, XSLT, "showlog.xsl");
    }
    else
    {
        refbuf_t *http = refbuf_new (100);
        int len = snprintf (http->data, 100, "%s",
                "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n");
        http->len = len;
        http->next = content; 
        client->respcode = 200;
        client_set_queue (client, http);
        return fserve_setup_client (client);
    }
}
/* called from the source thread when the metadata has been updated.
 * The artist title are checked and made ready for clients to send
 */
static void mp3_set_title (source_t *source)
{
    const char meta[] = "StreamTitle='";
    int size;
    unsigned char len_byte;
    refbuf_t *p;
    unsigned int len = sizeof(meta) + 2; /* the StreamTitle, quotes, ; and null */
    mp3_state *source_mp3 = source->format->_state;

    /* make sure the url data does not disappear from under us */
    thread_mutex_lock (&source_mp3->url_lock);

    /* work out message length */
    if (source_mp3->url_artist)
        len += strlen (source_mp3->url_artist);
    if (source_mp3->url_title)
        len += strlen (source_mp3->url_title);
    if (source_mp3->url_artist && source_mp3->url_title)
        len += 3;
#define MAX_META_LEN 255*16
    if (len > MAX_META_LEN)
    {
        thread_mutex_unlock (&source_mp3->url_lock);
        WARN1 ("Metadata too long at %d chars", len);
        return;
    }
    /* work out the metadata len byte */
    len_byte = (len-1) / 16 + 1;

    /* now we know how much space to allocate, +1 for the len byte */
    size = len_byte * 16 + 1;

    p = refbuf_new (size);
    if (p)
    {
        mp3_state *source_mp3 = source->format->_state;

        memset (p->data, '\0', size);
        if (source_mp3->url_artist && source_mp3->url_title)
            snprintf (p->data, size, "%c%s%s - %s';", len_byte, meta,
                    source_mp3->url_artist, source_mp3->url_title);
        else
            snprintf (p->data, size, "%c%s%s';", len_byte, meta,
                    source_mp3->url_title);
        filter_shoutcast_metadata (source, p->data, size);

        refbuf_release (source_mp3->metadata);
        source_mp3->metadata = p;
    }
    thread_mutex_unlock (&source_mp3->url_lock);
}
Beispiel #17
0
void auth_check_http (client_t *client)
{
    const char *header;
    char *username, *password;

    /* process any auth headers if any available */
    header = httpp_getvar (client->parser, "authorization");
    if (header == NULL)
        return;

    if (strncmp(header, "Basic ", 6) == 0)
    {
        /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
        char *tmp, *userpass = util_base64_decode (header+6);
        if (userpass == NULL)
        {
            WARN1("Base64 decode of Authorization header \"%s\" failed",
                    header+6);
            return;
        }

        tmp = strchr(userpass, ':');
        if (tmp == NULL)
        {
            free (userpass);
            return;
        }

        *tmp = 0;
        username = userpass;
        password = tmp+1;
        client->username = strdup (username);
        client->password = strdup (password);
        free (userpass);
        return;
    }
    WARN1 ("unhandled authorization header: %s", header);
}
Beispiel #18
0
/* Called from auth thread to process any request for source client
 * authentication. Only applies to source clients, not relays.
 */
static void stream_auth_callback (auth_t *auth, auth_client *auth_user)
{
    client_t *client = auth_user->client;

    if (auth->stream_auth)
        auth->stream_auth (auth_user);

    auth_release (auth);
    client->auth = NULL;
    if (client->authenticated)
        auth_postprocess_source (auth_user);
    else
        WARN1 ("Failed auth for source \"%s\"", auth_user->mount);
}
Beispiel #19
0
auth_result auth_check_client(source_t *source, client_t *client)
{
    auth_t *authenticator = source->authenticator;
    auth_result result;

    if(authenticator) {
        /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
        char *header = httpp_getvar(client->parser, "authorization");
        char *userpass, *tmp;
        char *username, *password;
    
        if(header == NULL)
            return AUTH_FAILED;
    
        if(strncmp(header, "Basic ", 6)) {
            INFO0("Authorization not using Basic");
            return 0;
        }
        
        userpass = util_base64_decode(header+6);
        if(userpass == NULL) {
            WARN1("Base64 decode of Authorization header \"%s\" failed",
                    header+6);
            return AUTH_FAILED;
        }
        
        tmp = strchr(userpass, ':');
        if(!tmp) { 
            free(userpass);
            return AUTH_FAILED;
        }

        *tmp = 0;
        username = userpass;
        password = tmp+1;

        result = authenticator->authenticate(
                authenticator, source, username, password);

        if(result == AUTH_OK)
            client->username = strdup(username);

        free(userpass);

        return result;
    }
    else
        return AUTH_FAILED;
}
Beispiel #20
0
/* thread to read xsl file and add to the cache */
void *xslt_update (void *arg)
{
    xsl_req *x = arg;
    client_t *client = x->client;
    char *fn = x->cache.filename;
    xsltStylesheetPtr sheet;

    xmlSetStructuredErrorFunc ("xsl/file", config_xml_parse_failure);
    xsltSetGenericErrorFunc ("", log_parse_failure);

    sheet = x->cache.stylesheet = xsltParseStylesheetFile (XMLSTR(fn));
    if (sheet)
    {
        int i;

        INFO1 ("loaded stylesheet %s", x->cache.filename);
        if (sheet->mediaType && strcmp ((char*)sheet->mediaType, "text/html") != 0)
        {
            // avoid this lookup for html pages
            const char _hdr[] = "Content-Disposition: attachment; filename=\"file.";
            const size_t _hdrlen = sizeof (_hdr);
            size_t len = _hdrlen + 12;
            char *filename = malloc (len); // enough for name and extension
            strcpy (filename, _hdr);
            fserve_write_mime_ext ((char*)sheet->mediaType, filename + _hdrlen - 1, len - _hdrlen - 4);
            strcat (filename, "\"\r\n");
            x->cache.disposition = filename;
        }
        // we now have a sheet, find and update.
        thread_rwlock_wlock (&xslt_lock);
        i = xslt_cached (fn, &x->cache, time(NULL));
        xslt_send_sheet (client, x->doc, i);
    }
    else
    {
        WARN1 ("problem reading stylesheet \"%s\"", x->cache.filename);
        free (fn);
        xmlFreeDoc (x->doc);
        free (x->cache.disposition);
        client->shared_data = NULL;
        client_send_404 (client, "Could not parse XSLT file");
    }
    thread_spin_lock (&update_lock);
    xsl_updating--;
    thread_spin_unlock (&update_lock);
    free (x);
    return NULL;
}
Beispiel #21
0
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
{
    xmlDocPtr    res;
    xsltStylesheetPtr cur;
    xmlChar *string;
    int len, problem = 0;

    xmlSetGenericErrorFunc ("", log_parse_failure);
    xsltSetGenericErrorFunc ("", log_parse_failure);

    thread_mutex_lock(&xsltlock);
    cur = xslt_get_stylesheet(xslfilename);

    if (cur == NULL)
    {
        thread_mutex_unlock(&xsltlock);
        ERROR1 ("problem reading stylesheet \"%s\"", xslfilename);
        client_send_404 (client, "Could not parse XSLT file");
        return;
    }

    res = xsltApplyStylesheet(cur, doc, NULL);

    if (xsltSaveResultToString (&string, &len, res, cur) < 0)
        problem = 1;
    thread_mutex_unlock(&xsltlock);
    if (problem == 0)
    {
        const char *http = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: ";
        int buf_len = strlen (http) + 20 + len;

        if (string == NULL)
            string = xmlStrdup ("");
        client->respcode = 200;
        client_set_queue (client, NULL);
        client->refbuf = refbuf_new (buf_len);
        len = snprintf (client->refbuf->data, buf_len, "%s%d\r\n\r\n%s", http, len, string);
        client->refbuf->len = len;
        fserve_add_client (client, NULL);
        xmlFree (string);
    }
    else
    {
        WARN1 ("problem applying stylesheet \"%s\"", xslfilename);
        client_send_404 (client, "XSLT problem");
    }
    xmlFreeDoc(res);
}
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);

}
Beispiel #23
0
int admin_mount_request (client_t *client, const char *uri)
{
    source_t *source;
    const char *mount = httpp_get_query_param (client->parser, "mount");

    struct admin_command *cmd = find_admin_command (admin_mount, uri);

    if (cmd == NULL)
        return command_stats (client, uri);

    if (cmd == NULL || cmd->handle.source == NULL)
    {
        INFO0("mount request not recognised");
        return client_send_400 (client, "unknown request");
    }

    avl_tree_rlock(global.source_tree);
    source = source_find_mount_raw(mount);

    if (source == NULL)
    {
        avl_tree_unlock(global.source_tree);
        if (strncmp (cmd->request, "stats", 5) == 0)
            return command_stats (client, uri);
        if (strncmp (cmd->request, "listclients", 11) == 0)
            return fserve_list_clients (client, mount, cmd->response, 1);
        if (strncmp (cmd->request, "killclient", 10) == 0)
            return fserve_kill_client (client, mount, cmd->response);
        WARN1("Admin command on non-existent source %s", mount);
        return client_send_400 (client, "Source does not exist");
    }
    else
    {
        int ret = 0;
        thread_mutex_lock (&source->lock);
        if (source_available (source) == 0)
        {
            thread_mutex_unlock (&source->lock);
            avl_tree_unlock (global.source_tree);
            INFO1("Received admin command on unavailable mount \"%s\"", mount);
            return client_send_400 (client, "Source is not available");
        }
        ret = cmd->handle.source (client, source, cmd->response);
        avl_tree_unlock(global.source_tree);
        return ret;
    }
}
Beispiel #24
0
static void _handle_source_request(connection_t *con, 
        http_parser_t *parser, char *uri)
{
    client_t *client;
    source_t *source;

    client = client_create(con, parser);

    INFO1("Source logging in at mountpoint \"%s\"", uri);
                
    if (uri[0] != '/')
    {
        WARN0 ("source mountpoint not starting with /");
        client_send_401 (client);
        return;
    }

    if (!connection_check_source_pass(parser, uri)) {
        /* We commonly get this if the source client is using the wrong
         * protocol: attempt to diagnose this and return an error
         */
        /* TODO: Do what the above comment says */
        INFO1("Source (%s) attempted to login with invalid or missing password", uri);
        client_send_401(client);
        return;
    }
    source = source_reserve (uri);
    if (source)
    {
        source->client = client;
        source->parser = parser;
        source->con = con;
        if (connection_complete_source (source) < 0)
        {
            source->client = NULL;
            source_free_source (source);
        }
        else
            thread_create ("Source Thread", source_client_thread,
                    source, THREAD_DETACHED);
    }
    else
    {
        client_send_404 (client, "Mountpoint in use");
        WARN1 ("Mountpoint %s in use", uri);
    }
}
Beispiel #25
0
static auth_client *auth_client_setup (const char *mount, client_t *client)
{
    /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
    const char *header = httpp_getvar(client->parser, "authorization");
    char *userpass, *tmp;
    char *username, *password;
    auth_client *auth_user;

    do
    {
        if (header == NULL)
            break;

        if (strncmp(header, "Basic ", 6) == 0)
        {
            userpass = util_base64_decode (header+6);
            if (userpass == NULL)
            {
                WARN1("Base64 decode of Authorization header \"%s\" failed",
                        header+6);
                break;
            }

            tmp = strchr(userpass, ':');
            if (tmp == NULL)
            { 
                free (userpass);
                break;
            }

            *tmp = 0;
            username = userpass;
            password = tmp+1;
            client->username = strdup (username);
            client->password = strdup (password);
            free (userpass);
            break;
        }
        INFO1 ("unhandled authorization header: %s", header);

    } while (0);

    auth_user = calloc (1, sizeof(auth_client));
    auth_user->mount = strdup (mount);
    auth_user->client = client;
    return auth_user;
}
Beispiel #26
0
/* thread to read xsl file and add to the cache */
void *xslt_update (void *arg)
{
    xsl_req *x = arg;
    client_t *client = x->client;
    worker_t *worker = client ? client->worker : NULL;
    char *fn = x->cache.filename;

    x->cache.stylesheet = xsltParseStylesheetFile (XMLSTR(fn));
    if (x->cache.stylesheet)
    {
        int i = x->index;

        if (client) fn = strdup (fn); // need to copy the filename if another lookup is to do
        INFO1 ("loaded stylesheet %s", x->cache.filename);
        thread_rwlock_wlock (&xslt_lock);
        free (cache[i].filename);
        xsltFreeStylesheet (cache[i].stylesheet);
        memcpy (&cache[i], &x->cache, sizeof (stylesheet_cache_t));
        thread_rwlock_unlock (&xslt_lock);
        memset (&x->cache, 0, sizeof (stylesheet_cache_t));

        if (client)
        {
            x->cache.filename = fn;
            client->flags |= CLIENT_ACTIVE;
        }
    }
    else
    {
        WARN1 ("problem reading stylesheet \"%s\"", x->cache.filename);
        free (fn);
        if (client) client_send_404 (client, "Could not parse XSLT file");
    }
    thread_spin_lock (&update_lock);
    xsl_updating--;
    thread_spin_unlock (&update_lock);
    if (worker) worker_wakeup (worker); // wakeup after the decrease or it may delay
    if (client == NULL) free (x);
    return NULL;
}
Beispiel #27
0
static int _check_pass_http(http_parser_t *parser, 
        const char *correctuser, const char *correctpass)
{
    /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
    const char *header = httpp_getvar(parser, "authorization");
    char *userpass, *tmp;
    char *username, *password;

    if(header == NULL)
        return 0;

    if(strncmp(header, "Basic ", 6))
        return 0;

    userpass = util_base64_decode(header+6);
    if(userpass == NULL) {
        WARN1("Base64 decode of Authorization header \"%s\" failed",
                header+6);
        return 0;
    }

    tmp = strchr(userpass, ':');
    if(!tmp) {
        free(userpass);
        return 0;
    }
    *tmp = 0;
    username = userpass;
    password = tmp+1;

    if(strcmp(username, correctuser) || strcmp(password, correctpass)) {
        free(userpass);
        return 0;
    }
    free(userpass);

    return 1;
}
Beispiel #28
0
void stats_set_conv (long handle, const char *name, const char *value, const char *charset)
{
    if (charset)
    {
        xmlCharEncodingHandlerPtr encoding = xmlFindCharEncodingHandler (charset);

        if (encoding)
        {
            xmlBufferPtr in = xmlBufferCreate ();
            xmlBufferPtr conv = xmlBufferCreate ();

            xmlBufferCCat (in, value);
            if (xmlCharEncInFunc (encoding, conv, in) > 0)
                stats_set_entity_decode (handle, name, (void*)xmlBufferContent (conv));
            xmlBufferFree (in);
            xmlBufferFree (conv);
            xmlCharEncCloseFunc (encoding);
            return;
        }
        WARN1 ("No charset found for \"%s\"", charset);
        return;
    }
    stats_set_entity_decode (handle, name, value);
}
Beispiel #29
0
/* Allocate a new source with the stated mountpoint, if one already
 * exists with that mountpoint in the global source tree then return
 * NULL.
 */
source_t *source_reserve (const char *mount)
{
    source_t *src = NULL;

    if(mount[0] != '/')
        WARN1("Source at \"%s\" does not start with '/', clients will be "
                "unable to connect", mount);

    do
    {
        avl_tree_wlock (global.source_tree);
        src = source_find_mount_raw (mount);
        if (src)
        {
            src = NULL;
            break;
        }

        src = calloc (1, sizeof(source_t));
        if (src == NULL)
            break;

        src->client_tree = avl_tree_new(_compare_clients, NULL);
        src->pending_tree = avl_tree_new(_compare_clients, NULL);

        /* make duplicates for strings or similar */
        src->mount = strdup (mount);
        src->max_listeners = -1;

        avl_insert (global.source_tree, src);

    } while (0);

    avl_tree_unlock (global.source_tree);
    return src;
}
Beispiel #30
0
int xslt_transform (xmlDocPtr doc, const char *xslfilename, client_t *client)
{
    xmlDocPtr    res;
    xsltStylesheetPtr cur;
    int len;
    refbuf_t *content = NULL;
    char **params = NULL;

    xmlSetGenericErrorFunc ("", log_parse_failure);
    xsltSetGenericErrorFunc ("", log_parse_failure);

    thread_mutex_lock(&xsltlock);
    cur = xslt_get_stylesheet(xslfilename);

    if (cur == NULL)
    {
        thread_mutex_unlock(&xsltlock);
        ERROR1 ("problem reading stylesheet \"%s\"", xslfilename);
        return client_send_404 (client, "Could not parse XSLT file");
    }
    if (client->parser->queryvars)
    {
        // annoying but we need to surround the args with ' when passing them in
        int i, arg_count = client->parser->queryvars->length * 2;
        avl_node *node = avl_get_first (client->parser->queryvars);

        params = calloc (arg_count+1, sizeof (char *));
        for (i = 0; node && i < arg_count; node = avl_get_next (node))
        {
            http_var_t *param = (http_var_t *)node->key;
            char *tmp = util_url_escape (param->value);
            params[i++] = param->name;
            // use alloca for now, should really url esc into a supplied buffer
            params[i] = (char*)alloca (strlen (tmp) + 3);
            sprintf (params[i++], "\'%s\'", tmp);
            free (tmp);
        }
        params[i] = NULL;
    }

    res = xsltApplyStylesheet (cur, doc, (const char **)params);
    free (params);

    if (res == NULL || xslt_SaveResultToBuf (&content, &len, res, cur) < 0)
    {
        thread_mutex_unlock (&xsltlock);
        xmlFreeDoc (res);
        WARN1 ("problem applying stylesheet \"%s\"", xslfilename);
        return client_send_404 (client, "XSLT problem");
    }
    else
    {
        /* the 100 is to allow for the hardcoded headers */
        refbuf_t *refbuf = refbuf_new (100);
        const char *mediatype = NULL;

        /* lets find out the content type to use */
        if (cur->mediaType)
            mediatype = (char *)cur->mediaType;
        else
        {
            /* check method for the default, a missing method assumes xml */
            if (cur->method && xmlStrcmp (cur->method, XMLSTR("html")) == 0)
                mediatype = "text/html";
            else
                if (cur->method && xmlStrcmp (cur->method, XMLSTR("text")) == 0)
                    mediatype = "text/plain";
                else
                    mediatype = "text/xml";
        }
        snprintf (refbuf->data, 100,
                "HTTP/1.0 200 OK\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n",
                mediatype, len);

        thread_mutex_unlock (&xsltlock);
        client->respcode = 200;
        client_set_queue (client, NULL);
        client->refbuf = refbuf;
        refbuf->len = strlen (refbuf->data);
        refbuf->next = content;
    }
    xmlFreeDoc(res);
    return fserve_setup_client (client);
}