1 /* Icecast
2  *
3  * This program is distributed under the GNU General Public License, version 2.
4  * A copy of this license is included with this source.
5  *
6  * Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
7  *                      Michael Smith <msmith@xiph.org>,
8  *                      oddsock <oddsock@xiph.org>,
9  *                      Karl Heyes <karl@xiph.org>
10  *                      and others (see AUTHORS for details).
11  * Copyright 2011,      Dave 'justdave' Miller <justdave@mozilla.com>.
12  * Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker <thomas@ruecker.fi>,
13  * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
14  */
15 
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #ifndef _WIN32
24 #include <fnmatch.h>
25 #endif
26 #include <libxml/xmlmemory.h>
27 #include <libxml/parser.h>
28 
29 #include "thread/thread.h"
30 #include "cfgfile.h"
31 #include "refbuf.h"
32 #include "client.h"
33 #include "logging.h"
34 
35 #define CATMODULE "CONFIG"
36 #define CONFIG_DEFAULT_LOCATION "Earth"
37 #define CONFIG_DEFAULT_ADMIN "icemaster@localhost"
38 #define CONFIG_DEFAULT_CLIENT_LIMIT 256
39 #define CONFIG_DEFAULT_SOURCE_LIMIT 16
40 #define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024)
41 #define CONFIG_DEFAULT_BURST_SIZE (64*1024)
42 #define CONFIG_DEFAULT_THREADPOOL_SIZE 4
43 #define CONFIG_DEFAULT_CLIENT_TIMEOUT 30
44 #define CONFIG_DEFAULT_HEADER_TIMEOUT 15
45 #define CONFIG_DEFAULT_SOURCE_TIMEOUT 10
46 #define CONFIG_DEFAULT_MASTER_USERNAME "relay"
47 #define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream"
48 #define CONFIG_DEFAULT_ICE_LOGIN 0
49 #define CONFIG_DEFAULT_FILESERVE 1
50 #define CONFIG_DEFAULT_TOUCH_FREQ 5
51 #define CONFIG_DEFAULT_HOSTNAME "localhost"
52 #define CONFIG_DEFAULT_PLAYLIST_LOG NULL
53 #define CONFIG_DEFAULT_ACCESS_LOG "access.log"
54 #define CONFIG_DEFAULT_ERROR_LOG "error.log"
55 #define CONFIG_DEFAULT_LOG_LEVEL 3
56 #define CONFIG_DEFAULT_CHROOT 0
57 #define CONFIG_DEFAULT_CHUID 0
58 #define CONFIG_DEFAULT_USER NULL
59 #define CONFIG_DEFAULT_GROUP NULL
60 #define CONFIG_MASTER_UPDATE_INTERVAL 120
61 #define CONFIG_YP_URL_TIMEOUT 10
62 #define CONFIG_DEFAULT_CIPHER_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
63 
64 #ifndef _WIN32
65 #define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast"
66 #define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs"
67 #define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot"
68 #define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin"
69 #define MIMETYPESFILE "/etc/mime.types"
70 #else
71 #define CONFIG_DEFAULT_BASE_DIR ".\\"
72 #define CONFIG_DEFAULT_LOG_DIR ".\\logs"
73 #define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot"
74 #define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin"
75 #define MIMETYPESFILE ".\\mime.types"
76 #endif
77 
78 static ice_config_t _current_configuration;
79 static ice_config_locks _locks;
80 
81 static void _set_defaults(ice_config_t *c);
82 static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
83 static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
84 static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
85 static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
86 static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
87 static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
88 static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
89         ice_config_t *c);
90 static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node,
91         ice_config_http_header_t **http_headers);
92 static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
93 static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
94 static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
95         ice_config_t *c);
96 static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
97 
98 static void merge_mounts(mount_proxy * dst, mount_proxy * src);
99 static inline void _merge_mounts_all(ice_config_t *c);
100 
create_locks(void)101 static void create_locks(void) {
102     thread_mutex_create(&_locks.relay_lock);
103     thread_rwlock_create(&_locks.config_lock);
104 }
105 
release_locks(void)106 static void release_locks(void) {
107     thread_mutex_destroy(&_locks.relay_lock);
108     thread_rwlock_destroy(&_locks.config_lock);
109 }
110 
config_initialize(void)111 void config_initialize(void) {
112     create_locks();
113 }
114 
config_shutdown(void)115 void config_shutdown(void) {
116     config_get_config();
117     config_clear(&_current_configuration);
118     config_release_config();
119     release_locks();
120 }
121 
config_init_configuration(ice_config_t * configuration)122 void config_init_configuration(ice_config_t *configuration)
123 {
124     memset(configuration, 0, sizeof(ice_config_t));
125     _set_defaults(configuration);
126 }
127 
config_clear_http_header(ice_config_http_header_t * header)128 static void config_clear_http_header(ice_config_http_header_t *header) {
129  ice_config_http_header_t *old;
130 
131  while (header) {
132   xmlFree(header->name);
133   xmlFree(header->value);
134   old = header;
135   header = header->next;
136   free(old);
137  }
138 }
139 
config_copy_http_header(ice_config_http_header_t * header)140 static inline ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
141     ice_config_http_header_t *ret = NULL;
142     ice_config_http_header_t *cur = NULL;
143     ice_config_http_header_t *old = NULL;
144 
145     while (header) {
146         if (cur) {
147             cur->next = calloc(1, sizeof(ice_config_http_header_t));
148             old = cur;
149             cur = cur->next;
150         } else {
151             ret = calloc(1, sizeof(ice_config_http_header_t));
152             cur = ret;
153         }
154 
155         if (!cur) return ret; /* TODO: do better error handling */
156 
157         cur->type   = header->type;
158         cur->name   = (char *)xmlCharStrdup(header->name);
159         cur->value  = (char *)xmlCharStrdup(header->value);
160         cur->status = header->status;
161 
162         if (!cur->name || !cur->value) {
163             if (cur->name) xmlFree(cur->name);
164             if (cur->value) xmlFree(cur->value);
165             if (old) {
166                 old->next = NULL;
167             } else {
168                 ret = NULL;
169             }
170             free(cur);
171             return ret;
172         }
173 
174         header = header->next;
175     }
176 
177     return ret;
178 }
179 
config_clear_mount(mount_proxy * mount)180 static void config_clear_mount (mount_proxy *mount)
181 {
182     config_options_t *option;
183 
184     if (mount->mountname)       xmlFree (mount->mountname);
185     if (mount->username)        xmlFree (mount->username);
186     if (mount->password)        xmlFree (mount->password);
187     if (mount->dumpfile)        xmlFree (mount->dumpfile);
188     if (mount->intro_filename)  xmlFree (mount->intro_filename);
189     if (mount->on_connect)      xmlFree (mount->on_connect);
190     if (mount->on_disconnect)   xmlFree (mount->on_disconnect);
191     if (mount->fallback_mount)  xmlFree (mount->fallback_mount);
192     if (mount->stream_name)     xmlFree (mount->stream_name);
193     if (mount->stream_description)  xmlFree (mount->stream_description);
194     if (mount->stream_url)      xmlFree (mount->stream_url);
195     if (mount->stream_genre)    xmlFree (mount->stream_genre);
196     if (mount->bitrate)         xmlFree (mount->bitrate);
197     if (mount->type)            xmlFree (mount->type);
198     if (mount->charset)         xmlFree (mount->charset);
199     if (mount->cluster_password)    xmlFree (mount->cluster_password);
200 
201     if (mount->auth_type)       xmlFree (mount->auth_type);
202     option = mount->auth_options;
203     while (option)
204     {
205         config_options_t *nextopt = option->next;
206         if (option->name)   xmlFree (option->name);
207         if (option->value)  xmlFree (option->value);
208         free (option);
209         option = nextopt;
210     }
211     auth_release (mount->auth);
212     config_clear_http_header(mount->http_headers);
213     free (mount);
214 }
215 
config_clear_listener(listener_t * listener)216 listener_t *config_clear_listener (listener_t *listener)
217 {
218     listener_t *next = NULL;
219     if (listener)
220     {
221         next = listener->next;
222         if (listener->bind_address)     xmlFree (listener->bind_address);
223         if (listener->shoutcast_mount)  xmlFree (listener->shoutcast_mount);
224         free (listener);
225     }
226     return next;
227 }
228 
config_clear(ice_config_t * c)229 void config_clear(ice_config_t *c)
230 {
231     ice_config_dir_t *dirnode, *nextdirnode;
232     relay_server *relay, *nextrelay;
233     mount_proxy *mount, *nextmount;
234     aliases *alias, *nextalias;
235 #ifdef USE_YP
236     int i;
237 #endif
238 
239     free(c->config_filename);
240 
241     xmlFree (c->server_id);
242     if (c->location) xmlFree(c->location);
243     if (c->admin) xmlFree(c->admin);
244     if (c->source_password) xmlFree(c->source_password);
245     if (c->admin_username)
246         xmlFree(c->admin_username);
247     if (c->admin_password)
248         xmlFree(c->admin_password);
249     if (c->relay_username)
250         xmlFree(c->relay_username);
251     if (c->relay_password)
252         xmlFree(c->relay_password);
253     if (c->hostname) xmlFree(c->hostname);
254     if (c->base_dir) xmlFree(c->base_dir);
255     if (c->log_dir) xmlFree(c->log_dir);
256     if (c->webroot_dir) xmlFree(c->webroot_dir);
257     if (c->adminroot_dir) xmlFree(c->adminroot_dir);
258     if (c->cert_file) xmlFree(c->cert_file);
259     if (c->cipher_list) xmlFree(c->cipher_list);
260     if (c->pidfile)
261         xmlFree(c->pidfile);
262     if (c->banfile) xmlFree(c->banfile);
263     if (c->allowfile) xmlFree(c->allowfile);
264     if (c->playlist_log) xmlFree(c->playlist_log);
265     if (c->access_log) xmlFree(c->access_log);
266     if (c->error_log) xmlFree(c->error_log);
267     if (c->shoutcast_mount) xmlFree(c->shoutcast_mount);
268     if (c->master_server) xmlFree(c->master_server);
269     if (c->master_username) xmlFree(c->master_username);
270     if (c->master_password) xmlFree(c->master_password);
271     if (c->user) xmlFree(c->user);
272     if (c->group) xmlFree(c->group);
273     if (c->mimetypes_fn) xmlFree (c->mimetypes_fn);
274 
275     while ((c->listen_sock = config_clear_listener (c->listen_sock)))
276         ;
277 
278     thread_mutex_lock(&(_locks.relay_lock));
279     relay = c->relay;
280     while(relay) {
281         nextrelay = relay->next;
282         xmlFree(relay->server);
283         xmlFree(relay->mount);
284         xmlFree(relay->localmount);
285         free(relay);
286         relay = nextrelay;
287     }
288     thread_mutex_unlock(&(_locks.relay_lock));
289 
290     mount = c->mounts;
291     while(mount) {
292         nextmount = mount->next;
293         config_clear_mount (mount);
294         mount = nextmount;
295     }
296 
297     alias = c->aliases;
298     while(alias) {
299         nextalias = alias->next;
300         xmlFree(alias->source);
301         xmlFree(alias->destination);
302         xmlFree(alias->bind_address);
303         free(alias);
304         alias = nextalias;
305     }
306 
307     dirnode = c->dir_list;
308     while(dirnode) {
309         nextdirnode = dirnode->next;
310         xmlFree(dirnode->host);
311         free(dirnode);
312         dirnode = nextdirnode;
313     }
314 #ifdef USE_YP
315     i = 0;
316     while (i < c->num_yp_directories)
317     {
318         xmlFree (c->yp_url[i]);
319         i++;
320     }
321 #endif
322 
323     config_clear_http_header(c->http_headers);
324 
325     memset(c, 0, sizeof(ice_config_t));
326 }
327 
config_initial_parse_file(const char * filename)328 int config_initial_parse_file(const char *filename)
329 {
330     /* Since we're already pointing at it, we don't need to copy it in place */
331     return config_parse_file(filename, &_current_configuration);
332 }
333 
config_parse_file(const char * filename,ice_config_t * configuration)334 int config_parse_file(const char *filename, ice_config_t *configuration)
335 {
336     xmlDocPtr doc;
337     xmlNodePtr node;
338 
339     if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE;
340 
341     doc = xmlParseFile(filename);
342     if (doc == NULL) {
343         return CONFIG_EPARSE;
344     }
345 
346     node = xmlDocGetRootElement(doc);
347     if (node == NULL) {
348         xmlFreeDoc(doc);
349         return CONFIG_ENOROOT;
350     }
351 
352     if (xmlStrcmp (node->name, XMLSTR("icecast")) != 0) {
353         xmlFreeDoc(doc);
354         return CONFIG_EBADROOT;
355     }
356 
357     config_init_configuration(configuration);
358 
359     configuration->config_filename = strdup (filename);
360 
361     _parse_root(doc, node->xmlChildrenNode, configuration);
362 
363     xmlFreeDoc(doc);
364 
365     _merge_mounts_all(configuration);
366 
367     return 0;
368 }
369 
config_parse_cmdline(int arg,char ** argv)370 int config_parse_cmdline(int arg, char **argv)
371 {
372     return 0;
373 }
374 
config_locks(void)375 ice_config_locks *config_locks(void)
376 {
377     return &_locks;
378 }
379 
config_release_config(void)380 void config_release_config(void)
381 {
382     thread_rwlock_unlock(&(_locks.config_lock));
383 }
384 
config_get_config(void)385 ice_config_t *config_get_config(void)
386 {
387     thread_rwlock_rlock(&(_locks.config_lock));
388     return &_current_configuration;
389 }
390 
config_grab_config(void)391 ice_config_t *config_grab_config(void)
392 {
393     thread_rwlock_wlock(&(_locks.config_lock));
394     return &_current_configuration;
395 }
396 
397 /* MUST be called with the lock held! */
config_set_config(ice_config_t * config)398 void config_set_config(ice_config_t *config) {
399     memcpy(&_current_configuration, config, sizeof(ice_config_t));
400 }
401 
config_get_config_unlocked(void)402 ice_config_t *config_get_config_unlocked(void)
403 {
404     return &_current_configuration;
405 }
406 
_set_defaults(ice_config_t * configuration)407 static void _set_defaults(ice_config_t *configuration)
408 {
409     configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
410     configuration->server_id = (char *)xmlCharStrdup (ICECAST_VERSION_STRING);
411     configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
412     configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT;
413     configuration->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT;
414     configuration->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT;
415     configuration->threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE;
416     configuration->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT;
417     configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
418     configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
419     configuration->source_password = NULL;
420     configuration->shoutcast_mount = (char *)xmlCharStrdup (CONFIG_DEFAULT_SHOUTCAST_MOUNT);
421     configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
422     configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
423     configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
424     configuration->on_demand = 0;
425     configuration->dir_list = NULL;
426     configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
427     configuration->mimetypes_fn = (char *)xmlCharStrdup (MIMETYPESFILE);
428     configuration->master_server = NULL;
429     configuration->master_server_port = 0;
430     configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
431     configuration->master_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
432     configuration->master_password = NULL;
433     configuration->base_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_BASE_DIR);
434     configuration->log_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOG_DIR);
435     configuration->cipher_list = (char *)xmlCharStrdup (CONFIG_DEFAULT_CIPHER_LIST);
436     configuration->webroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_WEBROOT_DIR);
437     configuration->adminroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMINROOT_DIR);
438     configuration->playlist_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_PLAYLIST_LOG);
439     configuration->access_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ACCESS_LOG);
440     configuration->error_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ERROR_LOG);
441     configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
442     configuration->chroot = CONFIG_DEFAULT_CHROOT;
443     configuration->chuid = CONFIG_DEFAULT_CHUID;
444     configuration->user = NULL;
445     configuration->group = NULL;
446     configuration->num_yp_directories = 0;
447     configuration->relay_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME);
448     configuration->relay_password = NULL;
449     /* default to a typical prebuffer size used by clients */
450     configuration->burst_size = CONFIG_DEFAULT_BURST_SIZE;
451 }
452 
_parse_root(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)453 static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
454         ice_config_t *configuration)
455 {
456     char *tmp;
457 
458     configuration->listen_sock = calloc (1, sizeof (*configuration->listen_sock));
459     configuration->listen_sock->port = 8000;
460     configuration->listen_sock_count = 1;
461 
462     do {
463         if (node == NULL) break;
464         if (xmlIsBlankNode(node)) continue;
465 
466         if (xmlStrcmp (node->name, XMLSTR("location")) == 0) {
467             if (configuration->location) xmlFree(configuration->location);
468             configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
469         } else if (xmlStrcmp (node->name, XMLSTR("admin")) == 0) {
470             if (configuration->admin) xmlFree(configuration->admin);
471             configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
472         } else if (xmlStrcmp (node->name, XMLSTR("server-id")) == 0) {
473             xmlFree (configuration->server_id);
474             configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
475             ICECAST_LOG_WARN("Warning, server version string override detected. This may lead to unexpected client software behavior.");
476         } else if(xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
477             _parse_authentication(doc, node->xmlChildrenNode, configuration);
478         } else if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
479             /* TODO: This is the backwards-compatibility location */
480             ICECAST_LOG_WARN("<source-password> defined outside <authentication>. This is deprecated.");
481             if (configuration->source_password) xmlFree(configuration->source_password);
482             configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
483         } else if (xmlStrcmp (node->name, XMLSTR("icelogin")) == 0) {
484             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
485             configuration->ice_login = atoi(tmp);
486             if (tmp) xmlFree(tmp);
487         } else if (xmlStrcmp (node->name, XMLSTR("fileserve")) == 0) {
488             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
489             configuration->fileserve = atoi(tmp);
490             if (tmp) xmlFree(tmp);
491         } else if (xmlStrcmp (node->name, XMLSTR("relays-on-demand")) == 0) {
492             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
493             configuration->on_demand = atoi(tmp);
494             if (tmp) xmlFree(tmp);
495         } else if (xmlStrcmp (node->name, XMLSTR("hostname")) == 0) {
496             if (configuration->hostname) xmlFree(configuration->hostname);
497             configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
498         } else if (xmlStrcmp (node->name, XMLSTR("mime-types")) == 0) {
499             if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn);
500             configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
501         } else if (xmlStrcmp (node->name, XMLSTR("listen-socket")) == 0) {
502             _parse_listen_socket(doc, node->xmlChildrenNode, configuration);
503         } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
504             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
505             if (tmp) {
506                 configuration->port = atoi(tmp);
507                 configuration->listen_sock->port = atoi(tmp);
508                 xmlFree(tmp);
509             } else {
510                 ICECAST_LOG_WARN("<port> must not be empty.");
511             }
512         } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
513             if (configuration->listen_sock->bind_address)
514                 xmlFree(configuration->listen_sock->bind_address);
515             configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
516         } else if (xmlStrcmp (node->name, XMLSTR("master-server")) == 0) {
517             if (configuration->master_server) xmlFree(configuration->master_server);
518             configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
519         } else if (xmlStrcmp (node->name, XMLSTR("master-username")) == 0) {
520             if (configuration->master_username) xmlFree(configuration->master_username);
521             configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
522         } else if (xmlStrcmp (node->name, XMLSTR("master-password")) == 0) {
523             if (configuration->master_password) xmlFree(configuration->master_password);
524             configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
525         } else if (xmlStrcmp (node->name, XMLSTR("master-server-port")) == 0) {
526             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
527             configuration->master_server_port = atoi(tmp);
528             xmlFree (tmp);
529         } else if (xmlStrcmp (node->name, XMLSTR("master-update-interval")) == 0) {
530             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
531             configuration->master_update_interval = atoi(tmp);
532             xmlFree (tmp);
533         } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
534             if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount);
535             configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
536         } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
537             _parse_limits(doc, node->xmlChildrenNode, configuration);
538         } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
539             _parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
540         } else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
541             _parse_relay(doc, node->xmlChildrenNode, configuration);
542         } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
543             _parse_mount(doc, node, configuration);
544         } else if (xmlStrcmp (node->name, XMLSTR("directory")) == 0) {
545             _parse_directory(doc, node->xmlChildrenNode, configuration);
546         } else if (xmlStrcmp (node->name, XMLSTR("paths")) == 0) {
547             _parse_paths(doc, node->xmlChildrenNode, configuration);
548         } else if (xmlStrcmp (node->name, XMLSTR("logging")) == 0) {
549             _parse_logging(doc, node->xmlChildrenNode, configuration);
550         } else if (xmlStrcmp (node->name, XMLSTR("security")) == 0) {
551             _parse_security(doc, node->xmlChildrenNode, configuration);
552         }
553     } while ((node = node->next));
554 
555     /* drop the first listening socket details if more than one is defined, as we only
556      * have port or listen-socket not both */
557     if (configuration->listen_sock_count > 1)
558     {
559         configuration->listen_sock = config_clear_listener (configuration->listen_sock);
560         configuration->listen_sock_count--;
561     }
562     if (configuration->port == 0)
563         configuration->port = 8000;
564 
565    /* issue some warnings on bad configurations */
566    if (!configuration->fileserve)
567        ICECAST_LOG_WARN("Warning, serving of static files has been disabled in the config, this will also affect files used by the web interface (stylesheets, images).");
568 
569   if (!configuration->hostname || strcmp(configuration->hostname, CONFIG_DEFAULT_HOSTNAME) == 0) {
570       ICECAST_LOG_WARN("Warning, <hostname> not configured, using default value \"%s\". This will cause problems, e.g. with YP directory listings.", CONFIG_DEFAULT_HOSTNAME);
571       if (!configuration->hostname)
572           configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME);
573   }
574 
575   if (!configuration->location || strcmp(configuration->location, CONFIG_DEFAULT_LOCATION) == 0) {
576       ICECAST_LOG_WARN("Warning, <location> not configured, using default value \"%s\".", CONFIG_DEFAULT_LOCATION);
577       if (!configuration->location)
578           configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION);
579   }
580 
581   if (!configuration->admin || strcmp(configuration->admin, CONFIG_DEFAULT_ADMIN) == 0) {
582       ICECAST_LOG_WARN("Warning, <admin> contact not configured, using default value \"%s\".", CONFIG_DEFAULT_ADMIN);
583       if (!configuration->admin)
584           configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN);
585   }
586 }
587 
_parse_limits(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)588 static void _parse_limits(xmlDocPtr doc, xmlNodePtr node,
589         ice_config_t *configuration)
590 {
591     char *tmp;
592 
593     do {
594         if (node == NULL) break;
595         if (xmlIsBlankNode(node)) continue;
596 
597         if (xmlStrcmp (node->name, XMLSTR("clients")) == 0) {
598             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
599             configuration->client_limit = atoi(tmp);
600             if (tmp) xmlFree(tmp);
601         } else if (xmlStrcmp (node->name, XMLSTR("sources")) == 0) {
602             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
603             configuration->source_limit = atoi(tmp);
604             if (tmp) xmlFree(tmp);
605         } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
606             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
607             configuration->queue_size_limit = atoi(tmp);
608             if (tmp) xmlFree(tmp);
609         } else if (xmlStrcmp (node->name, XMLSTR("threadpool")) == 0) {
610             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
611             configuration->threadpool_size = atoi(tmp);
612             if (tmp) xmlFree(tmp);
613         } else if (xmlStrcmp (node->name, XMLSTR("client-timeout")) == 0) {
614             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
615             configuration->client_timeout = atoi(tmp);
616             if (tmp) xmlFree(tmp);
617         } else if (xmlStrcmp (node->name, XMLSTR("header-timeout")) == 0) {
618             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
619             configuration->header_timeout = atoi(tmp);
620             if (tmp) xmlFree(tmp);
621         } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
622             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
623             configuration->source_timeout = atoi(tmp);
624             if (tmp) xmlFree(tmp);
625         } else if (xmlStrcmp (node->name, XMLSTR("burst-on-connect")) == 0) {
626             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
627             if (atoi(tmp) == 0)
628                 configuration->burst_size = 0;
629             if (tmp) xmlFree(tmp);
630         } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
631             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
632             configuration->burst_size = atoi(tmp);
633             if (tmp) xmlFree(tmp);
634         }
635     } while ((node = node->next));
636 }
637 
_parse_mount(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)638 static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
639         ice_config_t *configuration)
640 {
641     char *tmp;
642     mount_proxy *mount = calloc(1, sizeof(mount_proxy));
643     mount_proxy *current = configuration->mounts;
644     mount_proxy *last=NULL;
645 
646     /* default <mount> settings */
647     mount->mounttype = MOUNT_TYPE_NORMAL;
648     mount->max_listeners = -1;
649     mount->burst_size = -1;
650     mount->mp3_meta_interval = -1;
651     mount->yp_public = -1;
652     mount->next = NULL;
653 
654     tmp = (char *)xmlGetProp(node, XMLSTR("type"));
655     if (tmp) {
656         if (strcmp(tmp, "normal") == 0) {
657 	    mount->mounttype = MOUNT_TYPE_NORMAL;
658 	}
659 	else if (strcmp(tmp, "default") == 0) {
660 	    mount->mounttype = MOUNT_TYPE_DEFAULT;
661 	}
662 	else {
663 	    ICECAST_LOG_WARN("Unknown mountpoint type: %s", tmp);
664             config_clear_mount (mount);
665             return;
666 	}
667 	xmlFree(tmp);
668     }
669 
670     node = node->xmlChildrenNode;
671 
672     do {
673         if (node == NULL) break;
674         if (xmlIsBlankNode(node)) continue;
675 
676         if (xmlStrcmp (node->name, XMLSTR("mount-name")) == 0) {
677             mount->mountname = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
678         }
679         else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
680             mount->username = (char *)xmlNodeListGetString(
681                     doc, node->xmlChildrenNode, 1);
682         }
683         else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
684             mount->password = (char *)xmlNodeListGetString(
685                     doc, node->xmlChildrenNode, 1);
686         }
687         else if (xmlStrcmp (node->name, XMLSTR("dump-file")) == 0) {
688             mount->dumpfile = (char *)xmlNodeListGetString(
689                     doc, node->xmlChildrenNode, 1);
690         }
691         else if (xmlStrcmp (node->name, XMLSTR("intro")) == 0) {
692             mount->intro_filename = (char *)xmlNodeListGetString(
693                     doc, node->xmlChildrenNode, 1);
694         }
695         else if (xmlStrcmp (node->name, XMLSTR("fallback-mount")) == 0) {
696             mount->fallback_mount = (char *)xmlNodeListGetString(
697                     doc, node->xmlChildrenNode, 1);
698         }
699         else if (xmlStrcmp (node->name, XMLSTR("fallback-when-full")) == 0) {
700             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
701             mount->fallback_when_full = atoi(tmp);
702             if(tmp) xmlFree(tmp);
703         }
704         else if (xmlStrcmp (node->name, XMLSTR("max-listeners")) == 0) {
705             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
706             mount->max_listeners = atoi(tmp);
707             if(tmp) xmlFree(tmp);
708         }
709         else if (xmlStrcmp (node->name, XMLSTR("charset")) == 0) {
710             mount->charset = (char *)xmlNodeListGetString(doc,
711                     node->xmlChildrenNode, 1);
712         }
713         else if (xmlStrcmp (node->name, XMLSTR("mp3-metadata-interval")) == 0) {
714             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
715             mount->mp3_meta_interval = atoi(tmp);
716             if(tmp) xmlFree(tmp);
717         }
718         else if (xmlStrcmp (node->name, XMLSTR("fallback-override")) == 0) {
719             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
720             mount->fallback_override = atoi(tmp);
721             if(tmp) xmlFree(tmp);
722         }
723         else if (xmlStrcmp (node->name, XMLSTR("no-mount")) == 0) {
724             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
725             mount->no_mount = atoi(tmp);
726             if(tmp) xmlFree(tmp);
727         }
728         else if (xmlStrcmp (node->name, XMLSTR("no-yp")) == 0) {
729             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
730             mount->yp_public = atoi(tmp) == 0 ? -1 : 0;
731             if(tmp) xmlFree(tmp);
732         }
733         else if (xmlStrcmp (node->name, XMLSTR("hidden")) == 0) {
734             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
735             mount->hidden = atoi(tmp);
736             if(tmp) xmlFree(tmp);
737         }
738         else if (xmlStrcmp (node->name, XMLSTR("authentication")) == 0) {
739             mount->auth = auth_get_authenticator (node);
740         }
741         else if (xmlStrcmp (node->name, XMLSTR("on-connect")) == 0) {
742             mount->on_connect = (char *)xmlNodeListGetString(
743                     doc, node->xmlChildrenNode, 1);
744         }
745         else if (xmlStrcmp (node->name, XMLSTR("on-disconnect")) == 0) {
746             mount->on_disconnect = (char *)xmlNodeListGetString(
747                     doc, node->xmlChildrenNode, 1);
748         }
749         else if (xmlStrcmp (node->name, XMLSTR("max-listener-duration")) == 0) {
750             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
751             mount->max_listener_duration = atoi(tmp);
752             if(tmp) xmlFree(tmp);
753         }
754         else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) {
755             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
756             mount->queue_size_limit = atoi (tmp);
757             if(tmp) xmlFree(tmp);
758         }
759         else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) {
760             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
761             if (tmp)
762             {
763                 mount->source_timeout = atoi (tmp);
764                 xmlFree(tmp);
765             }
766         } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) {
767             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
768             mount->burst_size = atoi(tmp);
769             if (tmp) xmlFree(tmp);
770         } else if (xmlStrcmp (node->name, XMLSTR("cluster-password")) == 0) {
771             mount->cluster_password = (char *)xmlNodeListGetString(
772                     doc, node->xmlChildrenNode, 1);
773         } else if (xmlStrcmp (node->name, XMLSTR("stream-name")) == 0) {
774             mount->stream_name = (char *)xmlNodeListGetString(
775                     doc, node->xmlChildrenNode, 1);
776         } else if (xmlStrcmp (node->name, XMLSTR("stream-description")) == 0) {
777             mount->stream_description = (char *)xmlNodeListGetString(
778                     doc, node->xmlChildrenNode, 1);
779         } else if (xmlStrcmp (node->name, XMLSTR("stream-url")) == 0) {
780             mount->stream_url = (char *)xmlNodeListGetString(
781                     doc, node->xmlChildrenNode, 1);
782         } else if (xmlStrcmp (node->name, XMLSTR("genre")) == 0) {
783             mount->stream_genre = (char *)xmlNodeListGetString(
784                     doc, node->xmlChildrenNode, 1);
785         } else if (xmlStrcmp (node->name, XMLSTR("bitrate")) == 0) {
786             mount->bitrate = (char *)xmlNodeListGetString(
787                     doc, node->xmlChildrenNode, 1);
788         } else if (xmlStrcmp (node->name, XMLSTR("public")) == 0) {
789             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
790             mount->yp_public = atoi (tmp);
791             if(tmp) xmlFree(tmp);
792         } else if (xmlStrcmp (node->name, XMLSTR("type")) == 0) {
793             mount->type = (char *)xmlNodeListGetString(
794                     doc, node->xmlChildrenNode, 1);
795         } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
796             mount->subtype = (char *)xmlNodeListGetString(
797                     doc, node->xmlChildrenNode, 1);
798         } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
799             _parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
800         }
801     } while ((node = node->next));
802 
803     /* make sure we have at least the mountpoint name */
804     if (mount->mountname == NULL && mount->mounttype != MOUNT_TYPE_DEFAULT)
805     {
806         config_clear_mount (mount);
807         return;
808     }
809     else if (mount->mountname != NULL && mount->mounttype == MOUNT_TYPE_DEFAULT)
810     {
811     	ICECAST_LOG_WARN("Default mount %s has mount-name set. This is not supported. Behavior may not be consistent.", mount->mountname);
812     }
813     if (mount->auth && mount->mountname) {
814         mount->auth->mount = strdup ((char *)mount->mountname);
815     } else if (mount->auth && mount->mounttype == MOUNT_TYPE_DEFAULT ) {
816         mount->auth->mount = strdup ("(default mount)");
817     }
818     while(current) {
819         last = current;
820         current = current->next;
821     }
822 
823     if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override))
824     {
825         ICECAST_LOG_WARN("Config for mount %s contains fallback options but no fallback mount.", mount->mountname);
826     }
827 
828     if(last)
829         last->next = mount;
830     else
831         configuration->mounts = mount;
832 }
833 
_parse_http_headers(xmlDocPtr doc,xmlNodePtr node,ice_config_http_header_t ** http_headers)834 static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) {
835     ice_config_http_header_t *header;
836     ice_config_http_header_t *next;
837     char *name = NULL;
838     char *value = NULL;
839     char *tmp;
840     int status;
841     http_header_type type;
842 
843     do {
844         if (node == NULL) break;
845         if (xmlIsBlankNode(node)) continue;
846         if (xmlStrcmp (node->name, XMLSTR("header")) != 0) break;
847         if (!(name = (char *)xmlGetProp(node, XMLSTR("name")))) break;
848         if (!(value = (char *)xmlGetProp(node, XMLSTR("value")))) break;
849 
850         type = HTTP_HEADER_TYPE_STATIC; /* default */
851         if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
852             if (strcmp(tmp, "static") == 0) {
853                 type = HTTP_HEADER_TYPE_STATIC;
854             } else {
855                 ICECAST_LOG_WARN("Unknown type %s for HTTP Header %s", tmp, name);
856                 xmlFree(tmp);
857                 break;
858             }
859             xmlFree(tmp);
860         }
861 
862         status = 0; /* default: any */
863         if ((tmp = (char *)xmlGetProp(node, XMLSTR("status")))) {
864             status = atoi(tmp);
865             xmlFree(tmp);
866         }
867 
868         header = calloc(1, sizeof(ice_config_http_header_t));
869         if (!header) break;
870         header->type = type;
871         header->name = name;
872         header->value = value;
873         header->status = status;
874         name = NULL;
875         value = NULL;
876 
877         if (!*http_headers) {
878             *http_headers = header;
879             continue;
880         }
881         next = *http_headers;
882         while (next->next) next = next->next;
883         next->next = header;
884     } while ((node = node->next));
885     /* in case we used break we may need to clean those up */
886     if (name)
887 	xmlFree(name);
888     if (value)
889 	xmlFree(value);
890 }
891 
_parse_relay(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)892 static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
893         ice_config_t *configuration)
894 {
895     char *tmp;
896     relay_server *relay = calloc(1, sizeof(relay_server));
897     relay_server *current = configuration->relay;
898     relay_server *last=NULL;
899 
900     while(current) {
901         last = current;
902         current = current->next;
903     }
904 
905     if(last)
906         last->next = relay;
907     else
908         configuration->relay = relay;
909 
910     relay->next = NULL;
911     relay->mp3metadata = 1;
912     relay->on_demand = configuration->on_demand;
913     relay->server = (char *)xmlCharStrdup ("127.0.0.1");
914     relay->mount = (char *)xmlCharStrdup ("/");
915 
916     do {
917         if (node == NULL) break;
918         if (xmlIsBlankNode(node)) continue;
919 
920         if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
921             if (relay->server) xmlFree (relay->server);
922             relay->server = (char *)xmlNodeListGetString(
923                     doc, node->xmlChildrenNode, 1);
924         }
925         else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
926             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
927             if (tmp) {
928                 relay->port = atoi(tmp);
929                 xmlFree(tmp);
930             } else {
931                 ICECAST_LOG_WARN("<port> must not be empty.");
932             }
933         }
934         else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
935             if (relay->mount) xmlFree (relay->mount);
936             relay->mount = (char *)xmlNodeListGetString(
937                     doc, node->xmlChildrenNode, 1);
938         }
939         else if (xmlStrcmp (node->name, XMLSTR("local-mount")) == 0) {
940             if (relay->localmount) xmlFree (relay->localmount);
941             relay->localmount = (char *)xmlNodeListGetString(
942                     doc, node->xmlChildrenNode, 1);
943         }
944         else if (xmlStrcmp (node->name, XMLSTR("relay-shoutcast-metadata")) == 0) {
945             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
946             relay->mp3metadata = atoi(tmp);
947             if(tmp) xmlFree(tmp);
948         }
949         else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) {
950             if (relay->username) xmlFree (relay->username);
951             relay->username = (char *)xmlNodeListGetString(doc,
952                     node->xmlChildrenNode, 1);
953         }
954         else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) {
955             if (relay->password) xmlFree (relay->password);
956             relay->password = (char *)xmlNodeListGetString(doc,
957                     node->xmlChildrenNode, 1);
958         }
959         else if (xmlStrcmp (node->name, XMLSTR("on-demand")) == 0) {
960             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
961             relay->on_demand = atoi(tmp);
962             if (tmp) xmlFree(tmp);
963         }
964         else if (xmlStrcmp (node->name, XMLSTR("bind")) == 0) {
965             if (relay->bind) xmlFree (relay->bind);
966             relay->bind = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
967         }
968     } while ((node = node->next));
969     if (relay->localmount == NULL)
970         relay->localmount = (char *)xmlStrdup (XMLSTR(relay->mount));
971 }
972 
_parse_listen_socket(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)973 static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
974         ice_config_t *configuration)
975 {
976     char *tmp;
977     listener_t *listener = calloc (1, sizeof(listener_t));
978 
979     if (listener == NULL)
980         return;
981     listener->port = 8000;
982 
983     do {
984         if (node == NULL) break;
985         if (xmlIsBlankNode(node)) continue;
986 
987         if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
988             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
989             if (tmp) {
990                 if(configuration->port == 0)
991                     configuration->port = atoi(tmp);
992                 listener->port = atoi(tmp);
993                 xmlFree(tmp);
994             } else {
995                 ICECAST_LOG_WARN("<port> must not be empty.");
996             }
997         }
998         else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) {
999             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1000             listener->ssl = atoi(tmp);
1001             if(tmp) xmlFree(tmp);
1002         }
1003         else if (xmlStrcmp (node->name, XMLSTR("shoutcast-compat")) == 0) {
1004             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1005             listener->shoutcast_compat = atoi(tmp);
1006             if(tmp) xmlFree(tmp);
1007         }
1008         else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) {
1009             if (listener->shoutcast_mount) xmlFree (listener->shoutcast_mount);
1010             listener->shoutcast_mount = (char *)xmlNodeListGetString(doc,
1011                     node->xmlChildrenNode, 1);
1012         }
1013         else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
1014             if (listener->bind_address) xmlFree (listener->bind_address);
1015             listener->bind_address = (char *)xmlNodeListGetString(doc,
1016                     node->xmlChildrenNode, 1);
1017         }
1018         else if (xmlStrcmp (node->name, XMLSTR("so-sndbuf")) == 0) {
1019             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1020             listener->so_sndbuf = atoi(tmp);
1021             if(tmp) xmlFree(tmp);
1022         }
1023     } while ((node = node->next));
1024 
1025     /* we know there's at least one of these, so add this new one after the first
1026      * that way it can be removed easily later on */
1027     listener->next = configuration->listen_sock->next;
1028     configuration->listen_sock->next = listener;
1029     configuration->listen_sock_count++;
1030     if (listener->shoutcast_mount)
1031     {
1032         listener_t *sc_port = calloc (1, sizeof (listener_t));
1033         sc_port->port = listener->port+1;
1034         sc_port->shoutcast_compat = 1;
1035         sc_port->shoutcast_mount = (char*)xmlStrdup (XMLSTR(listener->shoutcast_mount));
1036         if (listener->bind_address)
1037             sc_port->bind_address = (char*)xmlStrdup (XMLSTR(listener->bind_address));
1038 
1039         sc_port->next = listener->next;
1040         listener->next = sc_port;
1041         configuration->listen_sock_count++;
1042     }
1043 }
1044 
_parse_authentication(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1045 static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
1046         ice_config_t *configuration)
1047 {
1048     do {
1049         if (node == NULL) break;
1050         if (xmlIsBlankNode(node)) continue;
1051 
1052         if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) {
1053             if (xmlGetProp(node, XMLSTR("mount"))) {
1054                 ICECAST_LOG_ERROR("Mount level source password defined within global <authentication> section.");
1055             }
1056             else {
1057                 if (configuration->source_password)
1058                     xmlFree(configuration->source_password);
1059                 configuration->source_password =
1060                     (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1061             }
1062         } else if (xmlStrcmp (node->name, XMLSTR("admin-password")) == 0) {
1063             if(configuration->admin_password)
1064                 xmlFree(configuration->admin_password);
1065             configuration->admin_password =
1066                 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1067         } else if (xmlStrcmp (node->name, XMLSTR("admin-user")) == 0) {
1068             if(configuration->admin_username)
1069                 xmlFree(configuration->admin_username);
1070             configuration->admin_username =
1071                 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1072         } else if (xmlStrcmp (node->name, XMLSTR("relay-password")) == 0) {
1073             if(configuration->relay_password)
1074                 xmlFree(configuration->relay_password);
1075             configuration->relay_password =
1076                 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1077         } else if (xmlStrcmp (node->name, XMLSTR("relay-user")) == 0) {
1078             if(configuration->relay_username)
1079                 xmlFree(configuration->relay_username);
1080             configuration->relay_username =
1081                 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1082         }
1083     } while ((node = node->next));
1084 }
1085 
_parse_directory(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1086 static void _parse_directory(xmlDocPtr doc, xmlNodePtr node,
1087         ice_config_t *configuration)
1088 {
1089     char *tmp;
1090 
1091     if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
1092         ICECAST_LOG_ERROR("Maximum number of yp directories exceeded!");
1093         return;
1094     }
1095     do {
1096         if (node == NULL) break;
1097         if (xmlIsBlankNode(node)) continue;
1098 
1099         if (xmlStrcmp (node->name, XMLSTR("yp-url")) == 0) {
1100             if (configuration->yp_url[configuration->num_yp_directories])
1101                 xmlFree(configuration->yp_url[configuration->num_yp_directories]);
1102             configuration->yp_url[configuration->num_yp_directories] =
1103                 (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1104         } else if (xmlStrcmp (node->name, XMLSTR("yp-url-timeout")) == 0) {
1105             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1106             configuration->yp_url_timeout[configuration->num_yp_directories] =
1107                 atoi(tmp);
1108             if (tmp) xmlFree(tmp);
1109         } else if (xmlStrcmp (node->name, XMLSTR("server")) == 0) {
1110             _add_server(doc, node->xmlChildrenNode, configuration);
1111         } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) {
1112             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1113             configuration->yp_touch_interval[configuration->num_yp_directories] =
1114                 atoi(tmp);
1115             if (tmp) xmlFree(tmp);
1116         }
1117     } while ((node = node->next));
1118     if (configuration->yp_url [configuration->num_yp_directories] == NULL)
1119         return;
1120     configuration->num_yp_directories++;
1121 }
1122 
_parse_paths(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1123 static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
1124         ice_config_t *configuration)
1125 {
1126     char *temp;
1127     aliases *alias, *current, *last;
1128 
1129     do {
1130         if (node == NULL) break;
1131         if (xmlIsBlankNode(node)) continue;
1132 
1133         if (xmlStrcmp (node->name, XMLSTR("basedir")) == 0) {
1134             if (configuration->base_dir) xmlFree(configuration->base_dir);
1135             configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1136         } else if (xmlStrcmp (node->name, XMLSTR("logdir")) == 0) {
1137             if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1138                 ICECAST_LOG_WARN("<logdir> must not be empty.");
1139                 continue;
1140             }
1141             if (configuration->log_dir) xmlFree(configuration->log_dir);
1142             configuration->log_dir = temp;
1143         } else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
1144             if (configuration->pidfile) xmlFree(configuration->pidfile);
1145             configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1146         } else if (xmlStrcmp (node->name, XMLSTR("deny-ip")) == 0) {
1147             if (configuration->banfile) xmlFree(configuration->banfile);
1148             configuration->banfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1149         } else if (xmlStrcmp (node->name, XMLSTR("allow-ip")) == 0) {
1150             if (configuration->allowfile) xmlFree(configuration->allowfile);
1151             configuration->allowfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1152         } else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) {
1153             if (configuration->cert_file) xmlFree(configuration->cert_file);
1154             configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1155         } else if (xmlStrcmp (node->name, XMLSTR("ssl-allowed-ciphers")) == 0) {
1156             if (configuration->cipher_list) xmlFree(configuration->cipher_list);
1157             configuration->cipher_list = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1158         } else if (xmlStrcmp (node->name, XMLSTR("webroot")) == 0) {
1159             if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1160                 ICECAST_LOG_WARN("<webroot> must not be empty.");
1161                 continue;
1162             }
1163             if (configuration->webroot_dir) xmlFree(configuration->webroot_dir);
1164             configuration->webroot_dir = temp;
1165             if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
1166                 configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
1167         } else if (xmlStrcmp (node->name, XMLSTR("adminroot")) == 0) {
1168             if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1169                 ICECAST_LOG_WARN("<adminroot> must not be empty.");
1170                 continue;
1171             }
1172             if (configuration->adminroot_dir)
1173                 xmlFree(configuration->adminroot_dir);
1174             configuration->adminroot_dir = (char *)temp;
1175             if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
1176                 configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
1177         } else if (xmlStrcmp (node->name, XMLSTR("alias")) == 0) {
1178             alias = malloc(sizeof(aliases));
1179             alias->next = NULL;
1180             alias->source = (char *)xmlGetProp(node, XMLSTR("source"));
1181             if(alias->source == NULL) {
1182                 free(alias);
1183                 continue;
1184             }
1185             alias->destination = (char *)xmlGetProp(node, XMLSTR("destination"));
1186             if (!alias->destination)
1187                 alias->destination = (char *)xmlGetProp(node, XMLSTR("dest"));
1188             if(alias->destination == NULL) {
1189                 xmlFree(alias->source);
1190                 free(alias);
1191                 continue;
1192             }
1193             temp = NULL;
1194             temp = (char *)xmlGetProp(node, XMLSTR("port"));
1195             if(temp != NULL) {
1196                 alias->port = atoi(temp);
1197                 xmlFree(temp);
1198             }
1199             else
1200                 alias->port = -1;
1201             alias->bind_address = (char *)xmlGetProp(node, XMLSTR("bind-address"));
1202             current = configuration->aliases;
1203             last = NULL;
1204             while(current) {
1205                 last = current;
1206                 current = current->next;
1207             }
1208             if(last)
1209                 last->next = alias;
1210             else
1211                 configuration->aliases = alias;
1212         }
1213     } while ((node = node->next));
1214 }
1215 
_parse_logging(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1216 static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
1217         ice_config_t *configuration)
1218 {
1219     char *tmp;
1220     do {
1221         if (node == NULL) break;
1222         if (xmlIsBlankNode(node)) continue;
1223 
1224         if (xmlStrcmp (node->name, XMLSTR("accesslog")) == 0) {
1225             if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1226                 ICECAST_LOG_WARN("<accesslog> must not be empty.");
1227                 continue;
1228             }
1229             if (configuration->access_log) xmlFree(configuration->access_log);
1230             configuration->access_log = tmp;
1231         } else if (xmlStrcmp (node->name, XMLSTR("errorlog")) == 0) {
1232             if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
1233                 ICECAST_LOG_WARN("<errorlog> must not be empty.");
1234                 continue;
1235             }
1236             if (configuration->error_log) xmlFree(configuration->error_log);
1237             configuration->error_log = tmp;
1238         } else if (xmlStrcmp (node->name, XMLSTR("playlistlog")) == 0) {
1239             if (configuration->playlist_log) xmlFree(configuration->playlist_log);
1240             configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1241         } else if (xmlStrcmp (node->name, XMLSTR("logsize")) == 0) {
1242             char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1243             configuration->logsize = atoi(tmp);
1244             if (tmp) xmlFree(tmp);
1245         } else if (xmlStrcmp (node->name, XMLSTR("loglevel")) == 0) {
1246            char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1247            configuration->loglevel = atoi(tmp);
1248            if (tmp) xmlFree(tmp);
1249         } else if (xmlStrcmp (node->name, XMLSTR("logarchive")) == 0) {
1250             char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1251             configuration->logarchive = atoi(tmp);
1252             if (tmp) xmlFree(tmp);
1253         }
1254     } while ((node = node->next));
1255 }
1256 
_parse_security(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1257 static void _parse_security(xmlDocPtr doc, xmlNodePtr node,
1258         ice_config_t *configuration)
1259 {
1260    char *tmp;
1261    xmlNodePtr oldnode;
1262 
1263    do {
1264        if (node == NULL) break;
1265        if (xmlIsBlankNode(node)) continue;
1266 
1267        if (xmlStrcmp (node->name, XMLSTR("chroot")) == 0) {
1268            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1269            configuration->chroot = atoi(tmp);
1270            if (tmp) xmlFree(tmp);
1271        } else if (xmlStrcmp (node->name, XMLSTR("changeowner")) == 0) {
1272            configuration->chuid = 1;
1273            oldnode = node;
1274            node = node->xmlChildrenNode;
1275            do {
1276                if(node == NULL) break;
1277                if(xmlIsBlankNode(node)) continue;
1278                if(xmlStrcmp (node->name, XMLSTR("user")) == 0) {
1279                    if(configuration->user) xmlFree(configuration->user);
1280                    configuration->user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1281                } else if(xmlStrcmp (node->name, XMLSTR("group")) == 0) {
1282                    if(configuration->group) xmlFree(configuration->group);
1283                    configuration->group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1284                }
1285            } while((node = node->next));
1286            node = oldnode;
1287        }
1288    } while ((node = node->next));
1289 }
1290 
_add_server(xmlDocPtr doc,xmlNodePtr node,ice_config_t * configuration)1291 static void _add_server(xmlDocPtr doc, xmlNodePtr node,
1292         ice_config_t *configuration)
1293 {
1294     ice_config_dir_t *dirnode, *server;
1295     int addnode;
1296     char *tmp;
1297 
1298     server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t));
1299     server->touch_interval = configuration->touch_interval;
1300     server->host = NULL;
1301     addnode = 0;
1302 
1303     do {
1304         if (node == NULL) break;
1305         if (xmlIsBlankNode(node)) continue;
1306 
1307         if (xmlStrcmp (node->name, XMLSTR("host")) == 0) {
1308             server->host = (char *)xmlNodeListGetString(doc,
1309                     node->xmlChildrenNode, 1);
1310             addnode = 1;
1311         } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) {
1312             tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1313             server->touch_interval = atoi(tmp);
1314             if (tmp) xmlFree(tmp);
1315         }
1316         server->next = NULL;
1317     } while ((node = node->next));
1318 
1319     if (addnode) {
1320         dirnode = configuration->dir_list;
1321         if (dirnode == NULL) {
1322             configuration->dir_list = server;
1323         } else {
1324             while (dirnode->next) dirnode = dirnode->next;
1325 
1326             dirnode->next = server;
1327         }
1328 
1329         server = NULL;
1330         addnode = 0;
1331     }
1332     else {
1333         free (server);
1334     }
1335 }
1336 
merge_mounts(mount_proxy * dst,mount_proxy * src)1337 static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
1338     ice_config_http_header_t *http_header_next;
1339     ice_config_http_header_t **http_header_tail;
1340 
1341     if (!dst || !src)
1342     	return;
1343 
1344     if (!dst->username)
1345     	dst->username = (char*)xmlStrdup((xmlChar*)src->username);
1346     if (!dst->password)
1347     	dst->password = (char*)xmlStrdup((xmlChar*)src->password);
1348     if (!dst->dumpfile)
1349     	dst->dumpfile = (char*)xmlStrdup((xmlChar*)src->dumpfile);
1350     if (!dst->intro_filename)
1351     	dst->intro_filename = (char*)xmlStrdup((xmlChar*)src->intro_filename);
1352     if (!dst->fallback_when_full)
1353     	dst->fallback_when_full = src->fallback_when_full;
1354     if (dst->max_listeners == -1)
1355     	dst->max_listeners = src->max_listeners;
1356     if (!dst->fallback_mount)
1357     	dst->fallback_mount = (char*)xmlStrdup((xmlChar*)src->fallback_mount);
1358     if (!dst->fallback_override)
1359     	dst->fallback_override = src->fallback_override;
1360     if (!dst->no_mount)
1361     	dst->no_mount = src->no_mount;
1362     if (dst->burst_size == -1)
1363     	dst->burst_size = src->burst_size;
1364     if (!dst->queue_size_limit)
1365     	dst->queue_size_limit = src->queue_size_limit;
1366     if (!dst->hidden)
1367     	dst->hidden = src->hidden;
1368     if (!dst->source_timeout)
1369     	dst->source_timeout = src->source_timeout;
1370     if (!dst->charset)
1371     	dst->charset = (char*)xmlStrdup((xmlChar*)src->charset);
1372     if (dst->mp3_meta_interval == -1)
1373     	dst->mp3_meta_interval = src->mp3_meta_interval;
1374     if (!dst->auth_type)
1375     	dst->auth_type = (char*)xmlStrdup((xmlChar*)src->auth_type);
1376     // TODO: dst->auth
1377     if (!dst->cluster_password)
1378     	dst->cluster_password = (char*)xmlStrdup((xmlChar*)src->cluster_password);
1379     // TODO: dst->auth_options
1380     if (!dst->on_connect)
1381     	dst->on_connect = (char*)xmlStrdup((xmlChar*)src->on_connect);
1382     if (!dst->on_disconnect)
1383     	dst->on_disconnect = (char*)xmlStrdup((xmlChar*)src->on_disconnect);
1384     if (!dst->max_listener_duration)
1385     	dst->max_listener_duration = src->max_listener_duration;
1386     if (!dst->stream_name)
1387     	dst->stream_name = (char*)xmlStrdup((xmlChar*)src->stream_name);
1388     if (!dst->stream_description)
1389     	dst->stream_description = (char*)xmlStrdup((xmlChar*)src->stream_description);
1390     if (!dst->stream_url)
1391     	dst->stream_url = (char*)xmlStrdup((xmlChar*)src->stream_url);
1392     if (!dst->stream_genre)
1393     	dst->stream_genre = (char*)xmlStrdup((xmlChar*)src->stream_genre);
1394     if (!dst->bitrate)
1395     	dst->bitrate = (char*)xmlStrdup((xmlChar*)src->bitrate);
1396     if (!dst->type)
1397     	dst->type = (char*)xmlStrdup((xmlChar*)src->type);
1398     if (!dst->subtype)
1399     	dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype);
1400     if (dst->yp_public == -1)
1401     	dst->yp_public = src->yp_public;
1402 
1403     if (dst->http_headers) {
1404         http_header_next = dst->http_headers;
1405         while (http_header_next->next) http_header_next = http_header_next->next;
1406         http_header_tail = &(http_header_next->next);
1407     } else {
1408         http_header_tail = &(dst->http_headers);
1409     }
1410     *http_header_tail = config_copy_http_header(src->http_headers);
1411 }
1412 
_merge_mounts_all(ice_config_t * c)1413 static inline void _merge_mounts_all(ice_config_t *c) {
1414     mount_proxy *mountinfo = c->mounts;
1415     mount_proxy *default_mount;
1416 
1417     for (; mountinfo; mountinfo = mountinfo->next)
1418     {
1419     	if (mountinfo->mounttype != MOUNT_TYPE_NORMAL)
1420 	    continue;
1421 
1422         default_mount = config_find_mount(c, mountinfo->mountname, MOUNT_TYPE_DEFAULT);
1423 
1424 	merge_mounts(mountinfo, default_mount);
1425     }
1426 }
1427 
1428 /* return the mount details that match the supplied mountpoint */
config_find_mount(ice_config_t * config,const char * mount,mount_type type)1429 mount_proxy *config_find_mount (ice_config_t *config, const char *mount, mount_type type)
1430 {
1431     mount_proxy *mountinfo = config->mounts;
1432 
1433     for (; mountinfo; mountinfo = mountinfo->next)
1434     {
1435         if (mountinfo->mounttype != type)
1436 	    continue;
1437 
1438 	if (mount == NULL || mountinfo->mountname == NULL)
1439             break;
1440 
1441 	if (mountinfo->mounttype == MOUNT_TYPE_NORMAL && strcmp (mountinfo->mountname, mount) == 0)
1442             break;
1443 
1444 #ifndef _WIN32
1445         if (fnmatch(mountinfo->mountname, mount, FNM_PATHNAME) == 0)
1446             break;
1447 #else
1448         if (strcmp(mountinfo->mountname, mount) == 0)
1449             break;
1450 #endif
1451     }
1452 
1453     /* retry with default mount */
1454     if (!mountinfo && type == MOUNT_TYPE_NORMAL)
1455             mountinfo = config_find_mount(config, mount, MOUNT_TYPE_DEFAULT);
1456 
1457     return mountinfo;
1458 }
1459 
1460 /* Helper function to locate the configuration details of the listening
1461  * socket
1462  */
config_get_listen_sock(ice_config_t * config,connection_t * con)1463 listener_t *config_get_listen_sock (ice_config_t *config, connection_t *con)
1464 {
1465     listener_t *listener;
1466     int i = 0;
1467 
1468     listener = config->listen_sock;
1469     while (listener)
1470     {
1471         if (i >= global.server_sockets)
1472             listener = NULL;
1473         else
1474         {
1475             if (global.serversock[i] == con->serversock)
1476                 break;
1477             listener = listener->next;
1478             i++;
1479         }
1480     }
1481     return listener;
1482 }
1483 
1484