Example #1
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)
    {
        WARN3 ("seen non-UTF8 data (%s), probably incorrect metadata (%s, %s)",
                source?source:"global", name, value);
        return;
    }
    build_event (&event, source, name, (char *)value);
    process_event (&event);
}
Example #2
0
static void url_stream_end (auth_client *auth_user)
{
    char *mount, *server, *ipaddr = NULL, *agent = NULL;
    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)
    {
        if (client->connection.ip)
            ipaddr = util_url_escape (client->connection.ip);
        if (client->shared_data)
            agent = util_url_escape (client->shared_data);
    }
    if (ipaddr == NULL) ipaddr = strdup("");
    if (agent == NULL) agent = strdup("");

    snprintf (post, sizeof (post),
            "action=mount_remove&mount=%s&server=%.200s&port=%d&ip=%s&agent=%.200s", mount, server,
            auth_user->port, ipaddr, agent);
    free (ipaddr);
    free (agent);
    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);

    DEBUG2 ("handler %d (%s) sending request", auth_user->handler, auth_user->mount);
    if (curl_easy_perform (atd->curl))
        WARN3 ("auth to server %s (%s) failed with %s", url->stream_end, auth_user->mount, atd->errormsg);
    DEBUG2 ("handler %d (%s) request finished", auth_user->handler, auth_user->mount);
}
Example #3
0
int parse_xml_tags (xmlNodePtr parent, const struct cfg_tag *args)
{
    int ret = 0, seen_element = 0;
    xmlNodePtr node = parent->xmlChildrenNode;

    for (; node != NULL && ret == 0; node = node->next)
    {
        const struct cfg_tag *argp;

        if (xmlIsBlankNode (node) || node->type != XML_ELEMENT_NODE)
            continue;
        seen_element = 1;
        argp = args;
        while (argp->name)
        {
            if (strcmp ((const char*)node->name, argp->name) == 0)
            {
                ret = argp->retrieve (node, argp->storage);
                if (ret > 0)
                {
                    if (ret == 2)
                    {
                        argp++;
                        ret = 0;
                        continue;
                    }
                    xmlParserWarning (NULL, "skipping element \"%s\" parsing \"%s\" "
                            "at line %ld\n", node->name, parent->name, xmlGetLineNo(node));
                    ret = 0;
                }
                break;
            }
            argp++;
        }
        if (argp->name == NULL)
            WARN3 ("unknown element \"%s\" parsing \"%s\" at line %ld", node->name,
                    parent->name, xmlGetLineNo(node));
    }
    if (ret == 0 && seen_element == 0)
        return 2;
    return ret;
}
Example #4
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))
        WARN3 ("auth to server %s (%s) failed with %s", url->stream_auth, auth_user->mount, atd->errormsg);
}
Example #5
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;
}
int
RecvBytes(Socket sd,
          void *bytes,
          size_t byteSize,
          double timeOut) {

  double end;
  int isPipe;
  char *nextByte;
  fd_set readFds;
  int recvd;
  double start;
  int totalRecvd;
  struct timeval tout;
  void (*was)(int);

  isPipe = FD_ISSET(sd, &connectedPipes);
  FD_ZERO(&readFds);
  FD_SET(sd, &readFds);

  tout.tv_sec = (int)timeOut;
  tout.tv_usec = 0;

  start = CurrentTime();
  was = signal(SIGALRM, RecvTimeOut);
  nextByte = (char *)bytes;

  for(totalRecvd = 0; totalRecvd < byteSize; totalRecvd += recvd) {
    
    recvd = 0;
    switch (select(FD_SETSIZE, &readFds, NULL, NULL, &tout)) {

    case -1:
      if(errno == EINTR) {
        end = CurrentTime();
        if((int)(end - start) < timeOut) {
          tout.tv_sec = (int)(timeOut - (end - start));
          continue;
        }
      }
      signal(SIGALRM, was);
      FAIL2("RecvBytes: select %d failed %s\n", sd, strerror(errno));
      break;

    case 0:
      if(!isPipe) {
        end = CurrentTime();
        SetPktTimeOut(sd, end - start, 1);
      }
      signal(SIGALRM, was);
      FAIL3("RecvBytes: timed out socket %d after %d/%fs\n",
            sd, tout.tv_sec, timeOut);
      break;

    default:
      SetRealTimer((unsigned int)timeOut);

 	  recvd = read(sd, nextByte, (size_t)(byteSize - totalRecvd));

      RESETREALTIMER;

      if(recvd <= 0) {
		WARN3("RecvBytes: read() on descriptor %d returned %d (errno=%d).\n", sd, recvd, errno);
        if(!isPipe) {
          end = CurrentTime();
          SetPktTimeOut(sd, end - start, 0);
        }
        signal(SIGALRM, was);
        FAIL5("RecvBytes: sd %d (addr:%s) failed with %s after %d of %d\n",
              sd, PeerName(sd), strerror(errno), totalRecvd, byteSize);
      }
      break;

    }

    nextByte += recvd;

  }

  return(1);

}
Example #7
0
static auth_result url_add_listener (auth_client *auth_user)
{
    client_t *client = auth_user->client;
    auth_t *auth = auth_user->auth;
    auth_url *url = auth->state;
    auth_thread_data *atd = auth_user->thread_data;

    int res = 0, ret = AUTH_FAILED, poffset = 0;
    struct build_intro_contents *x;
    char *userpwd = NULL, post [8192];

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

    if (url->stop_req_until)
    {
        time_t now = time(NULL);
        if (url->stop_req_until <= now)
        {
            INFO1 ("restarting url after timeout on %s", auth_user->mount);
            url->stop_req_until = 0;
        }
        else
        {
            if (auth->flags & AUTH_SKIP_IF_SLOW)
            {
                client->flags |= CLIENT_AUTHENTICATED;
                return AUTH_OK;
            }
            return AUTH_FAILED;
        }
    }
    do
    {
        ice_config_t *config = config_get_config ();
        char *user_agent, *username, *password, *mount, *ipaddr, *referer, *current_listeners,
             *server = util_url_escape (config->hostname);
        int port = config->port;
        config_release_config ();

        const char *tmp = httpp_getvar (client->parser, "user-agent");

        if (tmp == NULL)
            tmp = "-";
        user_agent = util_url_escape (tmp);

        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) */
        tmp = httpp_getvar (client->parser, HTTPP_VAR_QUERYARGS);
        snprintf (post, sizeof post, "%s%s", auth_user->mount, tmp ? tmp : "");
        mount = util_url_escape (post);
        ipaddr = util_url_escape (client->connection.ip);
        tmp = httpp_getvar (client->parser, "referer");
        referer = tmp ? util_url_escape (tmp) : strdup ("");

        current_listeners = stats_get_value(auth->mount, "listeners");
        if (current_listeners == NULL)
            current_listeners = strdup("");

        poffset = snprintf (post, sizeof (post),
                "action=listener_add&server=%s&port=%d&client=%" PRIu64 "&mount=%s"
                "&user=%s&pass=%s&ip=%s&agent=%s&referer=%s&listeners=%s",
                server, port, client->connection.id, mount, username,
                password, ipaddr, user_agent, referer, current_listeners);
        free (current_listeners);
        free (server);
        free (mount);
        free (referer);
        free (user_agent);
        free (username);
        free (password);
        free (ipaddr);
        if (poffset < 0 || poffset >= sizeof (post))
        {
            WARN2 ("client from %s (on %s), rejected with headers problem", &client->connection.ip[0], auth_user->mount);
            return AUTH_FAILED;
        }
    } while (0);

    if (url->header_chk_list)
    {
        int c = url->header_chk_count, remaining = sizeof(post) - poffset;
        char *cur_header = url->header_chk_list;
        const char *prefix = (url->header_chk_prefix && isalnum (url->header_chk_prefix[0])) ? url->header_chk_prefix : "ClientHeader-";

        for (; c ; c--)
        {
            int len = strlen (cur_header);
            const char *val = httpp_getvar (client->parser, cur_header);
            if (val)
            {
                char *valesc = util_url_escape (val);
                int r = remaining > 0 ? snprintf (post+poffset, remaining, "&%s%s=%s", prefix, cur_header, valesc) : -1;
                free (valesc);
                if (r < 0 || r > remaining)
                {
                    WARN2 ("client from %s (on %s), rejected with too much in headers", &client->connection.ip[0], auth_user->mount);
                    return AUTH_FAILED;
                }
                poffset += r;
                remaining -= r;
            }
            cur_header += (len + 1); // get past next nul
        }
    }

    if (strchr (url->addurl, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (atd->curl, 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 = malloc (len);
                snprintf (userpwd, len, "%s:%s", client->username, client->password);
                curl_easy_setopt (atd->curl, CURLOPT_USERPWD, userpwd);
            }
            else
                curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
        }
    }
    else
    {
        /* url has user/pass but libcurl may need to clear any existing settings */
        curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
    }
    curl_easy_setopt (atd->curl, CURLOPT_URL, url->addurl);
    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);
    atd->errormsg[0] = '\0';
    free (atd->location);
    atd->location = NULL;
    /* setup in case intro data is returned */
    x = (void *)client->refbuf->data;
    x->type = 0;
    x->head = NULL;
    x->intro_len = 0;
    x->tailp = &x->head;

    DEBUG2 ("handler %d (%s) sending request", auth_user->handler, auth_user->mount);
    res = curl_easy_perform (atd->curl);
    DEBUG2 ("handler %d (%s) request finished", auth_user->handler, auth_user->mount);

    free (userpwd);

    if (client->flags & CLIENT_AUTHENTICATED)
    {
        if (client->flags & CLIENT_HAS_INTRO_CONTENT)
        {
            client->refbuf->next = x->head;
            DEBUG3 ("intro (%d) received %lu for %s", x->type, (unsigned long)x->intro_len, client->connection.ip);
        }
        if (x->head == NULL)
            client->flags &= ~CLIENT_HAS_INTRO_CONTENT;
        x->head = NULL;
        ret = AUTH_OK;
    }
    if (res)
    {
        url->stop_req_until = time (NULL) + url->stop_req_duration; /* prevent further attempts for a while */
        WARN3 ("auth to server %s (%s) failed with %s", url->addurl, auth_user->mount, atd->errormsg);
        INFO1 ("will not auth new listeners for %d seconds", url->stop_req_duration);
        if (auth->flags & AUTH_SKIP_IF_SLOW)
        {
            client->flags |= CLIENT_AUTHENTICATED;
            ret = AUTH_OK;
        }
    }
    /* better cleanup memory */
    while (x->head)
    {
        refbuf_t *n = x->head;
        x->head = n->next;
        n->next = NULL;
        refbuf_release (n);
    }
    if (x->type)
        mpeg_cleanup (&x->sync);
    if (atd->location)
    {
        client_send_302 (client, atd->location);
        auth_user->client = NULL;
        free (atd->location);
        atd->location = NULL;
    }
    else if (atd->errormsg[0])
    {
        INFO3 ("listener %s (%s) returned \"%s\"", client->connection.ip, url->addurl, atd->errormsg);
        if (atoi (atd->errormsg) == 403)
        {
            auth_user->client = NULL;
            client_send_403 (client, atd->errormsg+4);
        }
    }
    return ret;
}
Example #8
0
static auth_result url_remove_listener (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;
    time_t now = time(NULL), duration = now - client->connection.con_time;
    char *username, *password, *mount, *server, *ipaddr, *user_agent;
    const char *qargs, *tmp;
    char *userpwd = NULL, post [4096];

    if (url->removeurl == NULL || client == NULL)
        return AUTH_OK;
    if (url->stop_req_until)
    {
        if (url->stop_req_until >= now)
            return AUTH_FAILED;
        url->stop_req_until = 0;
    }
    server = util_url_escape (auth_user->hostname);

    if (client->username)
        username = util_url_escape (client->username);
    else
        username = strdup ("");

    if (client->password)
        password = util_url_escape (client->password);
    else
        password = strdup ("");

    tmp = httpp_getvar(client->parser, "user-agent");
    if (tmp == NULL)
        tmp = "-";
    user_agent = util_url_escape (tmp);

    /* get the full uri (with query params if available) */
    qargs = httpp_getvar (client->parser, HTTPP_VAR_QUERYARGS);
    snprintf (post, sizeof post, "%s%s", auth_user->mount, qargs ? qargs : "");
    mount = util_url_escape (post);
    ipaddr = util_url_escape (client->connection.ip);

    snprintf (post, sizeof (post),
            "action=listener_remove&server=%s&port=%d&client=%" PRIu64 "&mount=%s"
            "&user=%s&pass=%s&ip=%s&duration=%lu&agent=%s&sent=%" PRIu64,
            server, auth_user->port, client->connection.id, mount, username,
            password, ipaddr, (long unsigned)duration, user_agent, client->connection.sent_bytes);
    free (ipaddr);
    free (server);
    free (mount);
    free (username);
    free (password);
    free (user_agent);

    if (strchr (url->removeurl, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (atd->curl, 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 = malloc (len);
                snprintf (userpwd, len, "%s:%s", client->username, client->password);
                curl_easy_setopt (atd->curl, CURLOPT_USERPWD, userpwd);
            }
            else
                curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
        }
    }
    else
    {
        /* url has user/pass but libcurl may need to clear any existing settings */
        curl_easy_setopt (atd->curl, CURLOPT_USERPWD, "");
    }
    curl_easy_setopt (atd->curl, CURLOPT_URL, url->removeurl);
    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);

    DEBUG2 ("...handler %d (%s) sending request", auth_user->handler, auth_user->mount);
    if (curl_easy_perform (atd->curl))
    {
        WARN3 ("auth to server %s (%s) failed with \"%s\"", url->removeurl, auth_user->mount, atd->errormsg);
        url->stop_req_until = time (NULL) + url->stop_req_duration; /* prevent further attempts for a while */
    }
    else
        DEBUG2 ("...handler %d (%s) request complete", auth_user->handler, auth_user->mount);

    free (userpwd);

    return AUTH_OK;
}