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