/* 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); }
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); }
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; }
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); }
/* 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); }
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; }
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; }