cfgfile.c 102 KB
Newer Older
1 2 3 4 5
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
6
 * Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
7 8 9 10
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
 *                      Karl Heyes <karl@xiph.org>
 *                      and others (see AUTHORS for details).
11 12
 * Copyright 2011,      Dave 'justdave' Miller <justdave@mozilla.com>.
 * Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker <thomas@ruecker.fi>,
Philipp Schafft's avatar
Philipp Schafft committed
13
 * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
14 15
 */

16 17 18 19 20 21 22
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
23
#ifndef _WIN32
24
#include <fnmatch.h>
25
#endif
26 27 28
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

29
#include <igloo/thread.h>
30

31
#include "cfgfile.h"
32
#include "global.h"
33 34 35 36
#include "logging.h"
#include "util.h"
#include "auth.h"
#include "event.h"
37
#include <igloo/ro.h>
38
#include "reportxml.h"
39

40 41 42 43
/* for config_reread_config() */
#include "yp.h"
#include "fserve.h"
#include "stats.h"
44
#include "connection.h"
45
#include "main.h"
46
#include "slave.h"
47
#include "xslt.h"
48

Marvin Scholz's avatar
Marvin Scholz committed
49 50 51 52 53
#define CATMODULE                       "CONFIG"
#define CONFIG_DEFAULT_LOCATION         "Earth"
#define CONFIG_DEFAULT_ADMIN            "icemaster@localhost"
#define CONFIG_DEFAULT_CLIENT_LIMIT     256
#define CONFIG_DEFAULT_SOURCE_LIMIT     16
54
#define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024)
55
#define CONFIG_DEFAULT_BODY_SIZE_LIMIT  (4*1024)
Marvin Scholz's avatar
Marvin Scholz committed
56 57 58 59 60
#define CONFIG_DEFAULT_BURST_SIZE       (64*1024)
#define CONFIG_DEFAULT_THREADPOOL_SIZE  4
#define CONFIG_DEFAULT_CLIENT_TIMEOUT   30
#define CONFIG_DEFAULT_HEADER_TIMEOUT   15
#define CONFIG_DEFAULT_SOURCE_TIMEOUT   10
61
#define CONFIG_DEFAULT_BODY_TIMEOUT     (10 + CONFIG_DEFAULT_HEADER_TIMEOUT)
Marvin Scholz's avatar
Marvin Scholz committed
62 63
#define CONFIG_DEFAULT_MASTER_USERNAME  "relay"
#define CONFIG_DEFAULT_SHOUTCAST_MOUNT  "/stream"
64
#define CONFIG_DEFAULT_SHOUTCAST_USER   "source"
Marvin Scholz's avatar
Marvin Scholz committed
65 66 67 68 69 70 71 72 73 74 75 76 77
#define CONFIG_DEFAULT_FILESERVE        1
#define CONFIG_DEFAULT_TOUCH_FREQ       5
#define CONFIG_DEFAULT_HOSTNAME         "localhost"
#define CONFIG_DEFAULT_PLAYLIST_LOG     NULL
#define CONFIG_DEFAULT_ACCESS_LOG       "access.log"
#define CONFIG_DEFAULT_ERROR_LOG        "error.log"
#define CONFIG_DEFAULT_LOG_LEVEL        ICECAST_LOGLEVEL_INFO
#define CONFIG_DEFAULT_CHROOT           0
#define CONFIG_DEFAULT_CHUID            0
#define CONFIG_DEFAULT_USER             NULL
#define CONFIG_DEFAULT_GROUP            NULL
#define CONFIG_MASTER_UPDATE_INTERVAL   120
#define CONFIG_YP_URL_TIMEOUT           10
78 79 80
#define CONFIG_DEFAULT_RELAY_SERVER     "127.0.0.1"
#define CONFIG_DEFAULT_RELAY_PORT       80
#define CONFIG_DEFAULT_RELAY_MOUNT      "/"
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
#define CONFIG_DEFAULT_CIPHER_LIST      "ECDHE-ECDSA-CHACHA20-POLY1305:" \
                                        "ECDHE-RSA-CHACHA20-POLY1305:" \
                                        "ECDHE-ECDSA-AES128-GCM-SHA256:" \
                                        "ECDHE-RSA-AES128-GCM-SHA256:" \
                                        "ECDHE-ECDSA-AES256-GCM-SHA384:" \
                                        "ECDHE-RSA-AES256-GCM-SHA384:" \
                                        "DHE-RSA-AES128-GCM-SHA256:" \
                                        "DHE-RSA-AES256-GCM-SHA384:" \
                                        "ECDHE-ECDSA-AES128-SHA256:" \
                                        "ECDHE-RSA-AES128-SHA256:" \
                                        "ECDHE-ECDSA-AES128-SHA:" \
                                        "ECDHE-RSA-AES256-SHA384:" \
                                        "ECDHE-RSA-AES128-SHA:" \
                                        "ECDHE-ECDSA-AES256-SHA384:" \
                                        "ECDHE-ECDSA-AES256-SHA:" \
                                        "ECDHE-RSA-AES256-SHA:" \
                                        "DHE-RSA-AES128-SHA256:" \
                                        "DHE-RSA-AES128-SHA:" \
                                        "DHE-RSA-AES256-SHA256:" \
                                        "DHE-RSA-AES256-SHA:" \
                                        "ECDHE-ECDSA-DES-CBC3-SHA:" \
                                        "ECDHE-RSA-DES-CBC3-SHA:" \
                                        "EDH-RSA-DES-CBC3-SHA:" \
                                        "AES128-GCM-SHA256:" \
                                        "AES256-GCM-SHA384:" \
                                        "AES128-SHA256:" \
                                        "AES256-SHA256:" \
                                        "AES128-SHA:" \
                                        "AES256-SHA:" \
                                        "DES-CBC3-SHA:" \
                                        "!DSS:" \
                                        "!aNULL:!eNULL:" \
                                        "!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:" \
                                        "!EDH-DSS-DES-CBC3-SHA:" \
                                        "!EDH-RSA-DES-CBC3-SHA:" \
Marvin Scholz's avatar
Marvin Scholz committed
116
                                        "!KRB5-DES-CBC3-SHA"
117 118

#ifndef _WIN32
Marvin Scholz's avatar
Marvin Scholz committed
119 120 121 122 123 124
#define CONFIG_DEFAULT_BASE_DIR         "/usr/local/icecast"
#define CONFIG_DEFAULT_LOG_DIR          "/usr/local/icecast/logs"
#define CONFIG_DEFAULT_WEBROOT_DIR      "/usr/local/icecast/webroot"
#define CONFIG_DEFAULT_ADMINROOT_DIR    "/usr/local/icecast/admin"
#define CONFIG_DEFAULT_NULL_FILE        "/dev/null"
#define MIMETYPESFILE                   "/etc/mime.types"
125
#else
Marvin Scholz's avatar
Marvin Scholz committed
126 127 128 129 130 131
#define CONFIG_DEFAULT_BASE_DIR         ".\\"
#define CONFIG_DEFAULT_LOG_DIR          ".\\logs"
#define CONFIG_DEFAULT_WEBROOT_DIR      ".\\webroot"
#define CONFIG_DEFAULT_ADMINROOT_DIR    ".\\admin"
#define CONFIG_DEFAULT_NULL_FILE        "nul:"
#define MIMETYPESFILE                   ".\\mime.types"
132 133 134 135 136 137 138 139 140 141 142 143
#endif

static ice_config_t _current_configuration;
static ice_config_locks _locks;

static void _set_defaults(ice_config_t *c);
static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
Marvin Scholz's avatar
Marvin Scholz committed
144 145 146 147 148 149

static void _parse_authentication(xmlDocPtr                 doc,
                                  xmlNodePtr                node,
                                  ice_config_t             *c,
                                  char                    **source_password);

150 151
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c, const char *mount);
static void _parse_mount(xmlDocPtr doc, xmlNodePtr parentnode, ice_config_t *c);
Marvin Scholz's avatar
Marvin Scholz committed
152 153 154 155 156

static void _parse_listen_socket(xmlDocPtr                  doc,
                                 xmlNodePtr                 node,
                                 ice_config_t              *c);

157
static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
158
static void _parse_events(event_registration_t **events, xmlNodePtr node);
159

160 161 162
static void merge_mounts(mount_proxy * dst, mount_proxy * src);
static inline void _merge_mounts_all(ice_config_t *c);

Marvin Scholz's avatar
Marvin Scholz committed
163 164
operation_mode config_str_to_omode(const char *str)
{
165 166 167 168 169 170 171 172
    if (!str || !*str)
        return OMODE_DEFAULT;
    if (strcasecmp(str, "default") == 0) {
        return OMODE_DEFAULT;
    } else if (strcasecmp(str, "normal") == 0) {
        return OMODE_NORMAL;
    } else if (strcasecmp(str, "legacy-compat") == 0 || strcasecmp(str, "legacy") == 0) {
        return OMODE_LEGACY;
173 174
    } else if (strcasecmp(str, "strict") == 0) {
        return OMODE_STRICT;
175 176 177 178 179 180
    } else {
        ICECAST_LOG_ERROR("Unknown operation mode \"%s\", falling back to DEFAULT.", str);
        return OMODE_DEFAULT;
    }
}

181 182 183 184 185 186
static listener_type_t config_str_to_listener_type(const char *str)
{
    if (!str || !*str) {
        return LISTENER_TYPE_NORMAL;
    } else if (strcasecmp(str, "normal") == 0) {
        return LISTENER_TYPE_NORMAL;
187 188
    } else if (strcasecmp(str, "virtual") == 0) {
        return LISTENER_TYPE_VIRTUAL;
189 190 191 192 193 194
    } else {
        ICECAST_LOG_ERROR("Unknown listener type \"%s\", falling back to NORMAL.", str);
        return LISTENER_TYPE_NORMAL;
    }
}

195 196 197 198 199 200 201 202 203 204 205 206 207
char * config_href_to_id(const char *href)
{
    if (!href || !*href)
        return NULL;

    if (*href != '#') {
        ICECAST_LOG_ERROR("Can not convert string \"%H\" to ID.", href);
        return NULL;
    }

    return strdup(href+1);
}

Marvin Scholz's avatar
Marvin Scholz committed
208 209
static void create_locks(void)
{
210 211
    igloo_thread_mutex_create(&_locks.relay_lock);
    igloo_thread_rwlock_create(&_locks.config_lock);
212 213
}

Marvin Scholz's avatar
Marvin Scholz committed
214 215
static void release_locks(void)
{
216 217
    igloo_thread_mutex_destroy(&_locks.relay_lock);
    igloo_thread_rwlock_destroy(&_locks.config_lock);
218 219
}

Marvin Scholz's avatar
Marvin Scholz committed
220 221
void config_initialize(void)
{
222 223 224
    create_locks();
}

Marvin Scholz's avatar
Marvin Scholz committed
225 226
void config_shutdown(void)
{
227 228 229 230 231 232 233 234 235 236
    config_get_config();
    config_clear(&_current_configuration);
    config_release_config();
    release_locks();
}

void config_init_configuration(ice_config_t *configuration)
{
    memset(configuration, 0, sizeof(ice_config_t));
    _set_defaults(configuration);
237
    configuration->reportxml_db = igloo_ro_new(reportxml_database_t);
238 239
}

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning)
{
    char *str = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
    if (!str || !*str) {
        ICECAST_LOG_WARN("%s", warning);
    } else {
        *val = util_str_to_int(str, *val);
    }
    if (str)
        xmlFree(str);
}

static inline void __read_unsigned_int(xmlDocPtr doc, xmlNodePtr node, unsigned int *val, const char *warning)
{
    char *str = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
    if (!str || !*str) {
        ICECAST_LOG_WARN("%s", warning);
    } else {
        *val = util_str_to_unsigned_int(str, *val);
    }
    if (str)
        xmlFree(str);
}         

Marvin Scholz's avatar
Marvin Scholz committed
264 265
static inline int __parse_public(const char *str)
{
266 267 268 269 270 271 272 273 274 275 276 277
    /* values that are not bool */
    if (strcasecmp(str, "client") == 0)
        return -1;

    /* old way of doing so */
    if (strcmp(str, "-1") == 0)
        return -1;

    /* ok, only normal bool left! */
    return util_str_to_bool(str);
}

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
/* This converts TLS mode strings to (tlsmode_t).
 * In older versions of Icecast2 this was just a bool.
 * So we need to handle boolean values as well.
 * See also: util_str_to_bool().
 */
static tlsmode_t str_to_tlsmode(const char *str) {
    /* consider NULL and empty strings as auto mode */
    if (!str || !*str)
        return ICECAST_TLSMODE_AUTO;

    if (strcasecmp(str, "disabled") == 0) {
        return ICECAST_TLSMODE_DISABLED;
    } else if (strcasecmp(str, "auto") == 0) {
        return ICECAST_TLSMODE_AUTO;
    } else if (strcasecmp(str, "auto_no_plain") == 0) {
        return ICECAST_TLSMODE_AUTO_NO_PLAIN;
    } else if (strcasecmp(str, "rfc2817") == 0) {
        return ICECAST_TLSMODE_RFC2817;
    } else if (strcasecmp(str, "rfc2818") == 0 ||
               /* boolean-style values */
               strcasecmp(str, "true") == 0 ||
               strcasecmp(str, "yes")  == 0 ||
               strcasecmp(str, "on")   == 0 ) {
        return ICECAST_TLSMODE_RFC2818;
    }

    /* old style numbers: consider everyting non-zero RFC2818 */
    if (atoi(str))
        return ICECAST_TLSMODE_RFC2818;

    /* we default to auto mode */
    return ICECAST_TLSMODE_AUTO;
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
/* This checks for the TLS implementation of a node */
static int __check_node_impl(xmlNodePtr node, const char *def)
{
    char *impl;
    int res;

    impl = (char *)xmlGetProp(node, XMLSTR("implementation"));
    if (!impl)
        impl = (char *)xmlGetProp(node, XMLSTR("impl"));
    if (!impl)
        impl = (char *)xmlStrdup(XMLSTR(def));

    res = tls_check_impl(impl);

    xmlFree(impl);

    return res;
}


Marvin Scholz's avatar
Marvin Scholz committed
332 333 334 335 336 337 338 339 340 341 342 343 344 345
static void __append_old_style_auth(auth_stack_t       **stack,
                                    const char          *name,
                                    const char          *type,
                                    const char          *username,
                                    const char          *password,
                                    const char          *method,
                                    const char          *allow_method,
                                    int                  allow_web,
                                    const char          *allow_admin)
{
    xmlNodePtr  role,
                user,
                pass;
    auth_t     *auth;
Philipp Schafft's avatar
Philipp Schafft committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

    if (!type)
        return;

    role = xmlNewNode(NULL, XMLSTR("role"));

    xmlSetProp(role, XMLSTR("type"), XMLSTR(type));
    xmlSetProp(role, XMLSTR("deny-method"), XMLSTR("*"));
    if (allow_method)
        xmlSetProp(role, XMLSTR("allow-method"), XMLSTR(allow_method));

    if (name)
        xmlSetProp(role, XMLSTR("name"), XMLSTR(name));

    if (method)
        xmlSetProp(role, XMLSTR("method"), XMLSTR(method));

    if (allow_web) {
        xmlSetProp(role, XMLSTR("allow-web"), XMLSTR("*"));
    } else {
        xmlSetProp(role, XMLSTR("deny-web"), XMLSTR("*"));
    }

    if (allow_admin && strcmp(allow_admin, "*") == 0) {
        xmlSetProp(role, XMLSTR("allow-admin"), XMLSTR("*"));
    } else {
        xmlSetProp(role, XMLSTR("deny-admin"), XMLSTR("*"));
        if (allow_admin)
            xmlSetProp(role, XMLSTR("allow-admin"), XMLSTR(allow_admin));
    }

    if (username) {
        user = xmlNewChild(role, NULL, XMLSTR("option"), NULL);
        xmlSetProp(user, XMLSTR("name"), XMLSTR("username"));
        xmlSetProp(user, XMLSTR("value"), XMLSTR(username));
    }
    if (password) {
        pass = xmlNewChild(role, NULL, XMLSTR("option"), NULL);
        xmlSetProp(pass, XMLSTR("name"), XMLSTR("password"));
        xmlSetProp(pass, XMLSTR("value"), XMLSTR(password));
    }

    auth = auth_get_authenticator(role);
    auth_stack_push(stack, auth);
    auth_release(auth);

    xmlFreeNode(role);
}

Marvin Scholz's avatar
Marvin Scholz committed
395 396 397 398
static void __append_option_tag(xmlNodePtr  parent,
                                const char *name,
                                const char *value)
{
Philipp Schafft's avatar
Philipp Schafft committed
399 400 401 402 403 404 405 406 407 408
    xmlNodePtr node;

    if (!name || !value)
        return;

    node = xmlNewChild(parent, NULL, XMLSTR("option"), NULL);
    xmlSetProp(node, XMLSTR("name"), XMLSTR(name));
    xmlSetProp(node, XMLSTR("value"), XMLSTR(value));
}

Marvin Scholz's avatar
Marvin Scholz committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
static void __append_old_style_urlauth(auth_stack_t **stack,
                                       const char    *client_add,
                                       const char    *client_remove,
                                       const char    *action_add,
                                       const char    *action_remove,
                                       const char    *username,
                                       const char    *password,
                                       int            is_source,
                                       const char    *auth_header,
                                       const char    *timelimit_header,
                                       const char    *headers,
                                       const char    *header_prefix)
{
    xmlNodePtr   role;
    auth_t      *auth;
Philipp Schafft's avatar
Philipp Schafft committed
424

425
    if (!stack || (!client_add && !client_remove))
Philipp Schafft's avatar
Philipp Schafft committed
426 427 428 429 430 431 432 433 434 435 436 437 438
        return;

    role = xmlNewNode(NULL, XMLSTR("role"));

    xmlSetProp(role, XMLSTR("type"), XMLSTR("url"));

    if (is_source) {
        xmlSetProp(role, XMLSTR("method"), XMLSTR("source,put"));
        xmlSetProp(role, XMLSTR("deny-method"), XMLSTR("*"));
        xmlSetProp(role, XMLSTR("allow-method"), XMLSTR("source,put"));
        xmlSetProp(role, XMLSTR("allow-web"), XMLSTR("*"));
        xmlSetProp(role, XMLSTR("allow-admin"), XMLSTR("*"));
    } else {
439
        xmlSetProp(role, XMLSTR("method"), XMLSTR("get,post,head,options"));
Philipp Schafft's avatar
Philipp Schafft committed
440
        xmlSetProp(role, XMLSTR("deny-method"), XMLSTR("*"));
441
        xmlSetProp(role, XMLSTR("allow-method"), XMLSTR("get,post,head,options"));
Philipp Schafft's avatar
Philipp Schafft committed
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
        xmlSetProp(role, XMLSTR("allow-web"), XMLSTR("*"));
        xmlSetProp(role, XMLSTR("deny-admin"), XMLSTR("*"));
    }

    __append_option_tag(role, "client_add", client_add);
    __append_option_tag(role, "client_remove", client_remove);
    __append_option_tag(role, "action_add", action_add);
    __append_option_tag(role, "action_remove", action_remove);
    __append_option_tag(role, "username", username);
    __append_option_tag(role, "password", password);
    __append_option_tag(role, "auth_header", auth_header);
    __append_option_tag(role, "timelimit_header", timelimit_header);
    __append_option_tag(role, "headers", headers);
    __append_option_tag(role, "header_prefix", header_prefix);

    auth = auth_get_authenticator(role);
458 459 460 461 462 463 464
    if (auth) {
        auth_stack_push(stack, auth);
        auth_release(auth);
        ICECAST_LOG_DEBUG("Pushed authenticator %p on stack %p.", auth, stack);
    } else {
        ICECAST_LOG_DEBUG("Failed to set up authenticator.");
    }
Philipp Schafft's avatar
Philipp Schafft committed
465 466 467 468

    xmlFreeNode(role);
}

Marvin Scholz's avatar
Marvin Scholz committed
469 470 471 472 473
static void __append_old_style_exec_event(event_registration_t **list,
                                          const char            *trigger,
                                          const char            *executable)
{
    xmlNodePtr            exec;
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
    event_registration_t *er;

    exec = xmlNewNode(NULL, XMLSTR("event"));

    xmlSetProp(exec, XMLSTR("type"), XMLSTR("exec"));
    xmlSetProp(exec, XMLSTR("trigger"), XMLSTR(trigger));

    __append_option_tag(exec, "executable", executable);

    er = event_new_from_xml_node(exec);
    event_registration_push(list, er);
    event_registration_release(er);

    xmlFreeNode(exec);
}

Marvin Scholz's avatar
Marvin Scholz committed
490 491 492 493 494 495 496 497
static void __append_old_style_url_event(event_registration_t   **list,
                                         const char              *trigger,
                                         const char              *url,
                                         const char              *action,
                                         const char              *username,
                                         const char              *password)
{
    xmlNodePtr            exec;
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
    event_registration_t *er;

    exec = xmlNewNode(NULL, XMLSTR("event"));

    xmlSetProp(exec, XMLSTR("type"), XMLSTR("url"));
    xmlSetProp(exec, XMLSTR("trigger"), XMLSTR(trigger));

    __append_option_tag(exec, "url", url);
    __append_option_tag(exec, "action", action);
    __append_option_tag(exec, "username", username);
    __append_option_tag(exec, "password", password);

    er = event_new_from_xml_node(exec);
    event_registration_push(list, er);
    event_registration_release(er);

    xmlFreeNode(exec);
}

517
void config_clear_http_header(ice_config_http_header_t *header)
Marvin Scholz's avatar
Marvin Scholz committed
518 519
{
    ice_config_http_header_t *old;
520

Marvin Scholz's avatar
Marvin Scholz committed
521 522
    while (header) {
        xmlFree(header->name);
523 524
        if (header->value)
            xmlFree(header->value);
Marvin Scholz's avatar
Marvin Scholz committed
525 526 527 528
        old = header;
        header = header->next;
        free(old);
    }
529 530
}

Marvin Scholz's avatar
Marvin Scholz committed
531 532
static inline ice_config_http_header_t *config_copy_http_header(ice_config_http_header_t *header)
{
533 534 535 536 537 538 539 540 541 542 543 544 545 546
    ice_config_http_header_t *ret = NULL;
    ice_config_http_header_t *cur = NULL;
    ice_config_http_header_t *old = NULL;

    while (header) {
        if (cur) {
            cur->next = calloc(1, sizeof(ice_config_http_header_t));
            old = cur;
            cur = cur->next;
        } else {
            ret = calloc(1, sizeof(ice_config_http_header_t));
            cur = ret;
        }

Marvin Scholz's avatar
Marvin Scholz committed
547 548
        if (!cur)
            return ret; /* TODO: do better error handling */
549

550 551 552 553
        cur->type   = header->type;
        cur->name   = (char *)xmlCharStrdup(header->name);
        cur->value  = (char *)xmlCharStrdup(header->value);
        cur->status = header->status;
554 555

        if (!cur->name || !cur->value) {
Marvin Scholz's avatar
Marvin Scholz committed
556 557 558 559
            if (cur->name)
                xmlFree(cur->name);
            if (cur->value)
                xmlFree(cur->value);
560 561 562 563 564 565 566 567 568 569 570 571 572
            if (old) {
                old->next = NULL;
            } else {
                ret = NULL;
            }
            free(cur);
            return ret;
        }
        header = header->next;
    }
    return ret;
}

573
static void config_clear_mount(mount_proxy *mount)
574
{
575 576 577 578 579 580 581 582 583 584 585 586
    if (mount->mountname)           xmlFree(mount->mountname);
    if (mount->dumpfile)            xmlFree(mount->dumpfile);
    if (mount->intro_filename)      xmlFree(mount->intro_filename);
    if (mount->fallback_mount)      xmlFree(mount->fallback_mount);
    if (mount->stream_name)         xmlFree(mount->stream_name);
    if (mount->stream_description)  xmlFree(mount->stream_description);
    if (mount->stream_url)          xmlFree(mount->stream_url);
    if (mount->stream_genre)        xmlFree(mount->stream_genre);
    if (mount->bitrate)             xmlFree(mount->bitrate);
    if (mount->type)                xmlFree(mount->type);
    if (mount->charset)             xmlFree(mount->charset);
    if (mount->cluster_password)    xmlFree(mount->cluster_password);
Marvin Scholz's avatar
Marvin Scholz committed
587
    if (mount->authstack)           auth_stack_release(mount->authstack);
588

589
    event_registration_release(mount->event);
590
    config_clear_http_header(mount->http_headers);
Marvin Scholz's avatar
Marvin Scholz committed
591
    free(mount);
592 593
}

594 595 596 597 598 599 600 601 602 603
static void config_clear_resource(resource_t *resource)
{
    resource_t *nextresource;

    while (resource) {
        nextresource = resource->next;
        xmlFree(resource->source);
        xmlFree(resource->destination);
        xmlFree(resource->bind_address);
        xmlFree(resource->vhost);
604 605
        xmlFree(resource->module);
        xmlFree(resource->handler);
606
        free(resource->listen_socket);
607 608 609 610 611
        free(resource);
        resource = nextresource;
    }
}

Marvin Scholz's avatar
Marvin Scholz committed
612
listener_t *config_clear_listener(listener_t *listener)
613 614 615 616 617
{
    listener_t *next = NULL;
    if (listener)
    {
        next = listener->next;
618
        if (listener->id)               xmlFree(listener->id);
619
        if (listener->on_behalf_of)     free(listener->on_behalf_of);
620 621
        if (listener->bind_address)     xmlFree(listener->bind_address);
        if (listener->shoutcast_mount)  xmlFree(listener->shoutcast_mount);
622
        if (listener->authstack)        auth_stack_release(listener->authstack);
623 624 625 626
        free (listener);
    }
    return next;
}
627

628 629
void config_clear(ice_config_t *c)
{
Marvin Scholz's avatar
Marvin Scholz committed
630 631 632 633
    ice_config_dir_t    *dirnode,
                        *nextdirnode;
    mount_proxy         *mount,
                        *nextmount;
634
    size_t              i;
635

636
    free(c->config_filename);
637

Marvin Scholz's avatar
Marvin Scholz committed
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
    xmlFree(c->server_id);
    if (c->location)        xmlFree(c->location);
    if (c->admin)           xmlFree(c->admin);
    if (c->hostname)        xmlFree(c->hostname);
    if (c->base_dir)        xmlFree(c->base_dir);
    if (c->log_dir)         xmlFree(c->log_dir);
    if (c->webroot_dir)     xmlFree(c->webroot_dir);
    if (c->adminroot_dir)   xmlFree(c->adminroot_dir);
    if (c->null_device)     xmlFree(c->null_device);
    if (c->pidfile)         xmlFree(c->pidfile);
    if (c->banfile)         xmlFree(c->banfile);
    if (c->allowfile)       xmlFree(c->allowfile);
    if (c->playlist_log)    xmlFree(c->playlist_log);
    if (c->access_log)      xmlFree(c->access_log);
    if (c->error_log)       xmlFree(c->error_log);
653
    if (c->shoutcast_mount) xmlFree(c->shoutcast_mount);
654
    if (c->shoutcast_user)  xmlFree(c->shoutcast_user);
Philipp Schafft's avatar
Philipp Schafft committed
655
    if (c->authstack)       auth_stack_release(c->authstack);
Marvin Scholz's avatar
Marvin Scholz committed
656
    if (c->master_server)   xmlFree(c->master_server);
657
    if (c->master_username) xmlFree(c->master_username);
658
    if (c->master_password) xmlFree(c->master_password);
Marvin Scholz's avatar
Marvin Scholz committed
659 660
    if (c->user)            xmlFree(c->user);
    if (c->group)           xmlFree(c->group);
Philipp Schafft's avatar
Philipp Schafft committed
661
    if (c->mimetypes_fn)    xmlFree(c->mimetypes_fn);
662

663 664 665 666
    if (c->tls_context.cert_file)       xmlFree(c->tls_context.cert_file);
    if (c->tls_context.key_file)        xmlFree(c->tls_context.key_file);
    if (c->tls_context.cipher_list)     xmlFree(c->tls_context.cipher_list);

667 668
    event_registration_release(c->event);

669
    while ((c->listen_sock = config_clear_listener(c->listen_sock)));
670

671
    igloo_thread_mutex_lock(&(_locks.relay_lock));
672 673
    for (i = 0; i < c->relay_length; i++) {
        relay_config_free(c->relay[i]);
674
    }
675
    free(c->relay);
676
    igloo_thread_mutex_unlock(&(_locks.relay_lock));
677 678

    mount = c->mounts;
679
    while (mount) {
680
        nextmount = mount->next;
681
        config_clear_mount(mount);
682 683 684
        mount = nextmount;
    }

685
    config_clear_resource(c->resources);
686 687

    dirnode = c->dir_list;
688
    while (dirnode) {
689 690 691 692 693
        nextdirnode = dirnode->next;
        xmlFree(dirnode->host);
        free(dirnode);
        dirnode = nextdirnode;
    }
694
#ifdef USE_YP
695
    for (i = 0; i < c->num_yp_directories; i++) {
696
        xmlFree(c->yp_url[i]);
Karl Heyes's avatar
Karl Heyes committed
697 698
    }
#endif
699

700
    config_clear_http_header(c->http_headers);
701

702
    igloo_ro_unref(c->reportxml_db);
703

704 705 706
    memset(c, 0, sizeof(ice_config_t));
}

Marvin Scholz's avatar
Marvin Scholz committed
707 708 709
void config_reread_config(void)
{
    int           ret;
710
    ice_config_t *config;
Marvin Scholz's avatar
Marvin Scholz committed
711
    ice_config_t  new_config;
712 713 714 715 716 717 718 719 720 721 722
    /* reread config file */

    config = config_grab_config(); /* Both to get the lock, and to be able
                                     to find out the config filename */
    xmlSetGenericErrorFunc("config", log_parse_failure);
    ret = config_parse_file(config->config_filename, &new_config);
    if(ret < 0) {
        ICECAST_LOG_ERROR("Error parsing config, not replacing existing config");
        switch (ret) {
            case CONFIG_EINSANE:
                ICECAST_LOG_ERROR("Config filename null or blank");
Marvin Scholz's avatar
Marvin Scholz committed
723
            break;
724 725
            case CONFIG_ENOROOT:
                ICECAST_LOG_ERROR("Root element not found in %s", config->config_filename);
Marvin Scholz's avatar
Marvin Scholz committed
726
            break;
727 728 729
            case CONFIG_EBADROOT:
                ICECAST_LOG_ERROR("Not an icecast2 config file: %s",
                        config->config_filename);
Marvin Scholz's avatar
Marvin Scholz committed
730
            break;
731 732
            default:
                ICECAST_LOG_ERROR("Parse error in reading %s", config->config_filename);
Marvin Scholz's avatar
Marvin Scholz committed
733
            break;
734 735 736 737 738 739
        }
        config_release_config();
    } else {
        config_clear(config);
        config_set_config(&new_config);
        config = config_get_config_unlocked();
Marvin Scholz's avatar
Marvin Scholz committed
740
        restart_logging(config);
741
        main_config_reload(config);
742
        connection_reread_config(config);
Marvin Scholz's avatar
Marvin Scholz committed
743 744 745
        yp_recheck_config(config);
        fserve_recheck_mime_types(config);
        stats_global(config);
746 747
        config_release_config();
        slave_update_all_mounts();
748
        xslt_clear_cache();
749 750 751
    }
}

752 753 754 755 756 757 758 759
int config_initial_parse_file(const char *filename)
{
    /* Since we're already pointing at it, we don't need to copy it in place */
    return config_parse_file(filename, &_current_configuration);
}

int config_parse_file(const char *filename, ice_config_t *configuration)
{
Marvin Scholz's avatar
Marvin Scholz committed
760
    xmlDocPtr  doc;
761 762
    xmlNodePtr node;

Marvin Scholz's avatar
Marvin Scholz committed
763 764
    if (filename == NULL || strcmp(filename, "") == 0)
        return CONFIG_EINSANE;
765

766
    doc = xmlParseFile(filename);
Marvin Scholz's avatar
Marvin Scholz committed
767
    if (doc == NULL)
768 769 770 771 772 773 774
        return CONFIG_EPARSE;
    node = xmlDocGetRootElement(doc);
    if (node == NULL) {
        xmlFreeDoc(doc);
        return CONFIG_ENOROOT;
    }

775
    if (xmlStrcmp(node->name, XMLSTR("icecast")) != 0) {
776 777 778 779 780
        xmlFreeDoc(doc);
        return CONFIG_EBADROOT;
    }

    config_init_configuration(configuration);
Marvin Scholz's avatar
Marvin Scholz committed
781
    configuration->config_filename = strdup(filename);
782 783
    _parse_root(doc, node->xmlChildrenNode, configuration);
    xmlFreeDoc(doc);
784
    _merge_mounts_all(configuration);
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
    return 0;
}

int config_parse_cmdline(int arg, char **argv)
{
    return 0;
}

ice_config_locks *config_locks(void)
{
    return &_locks;
}

void config_release_config(void)
{
800
    igloo_thread_rwlock_unlock(&(_locks.config_lock));
801 802 803 804
}

ice_config_t *config_get_config(void)
{
805
    igloo_thread_rwlock_rlock(&(_locks.config_lock));
806 807 808 809 810
    return &_current_configuration;
}

ice_config_t *config_grab_config(void)
{
811
    igloo_thread_rwlock_wlock(&(_locks.config_lock));
812 813 814 815
    return &_current_configuration;
}

/* MUST be called with the lock held! */
Marvin Scholz's avatar
Marvin Scholz committed
816 817
void config_set_config(ice_config_t *config)
{
818 819 820 821 822 823 824 825 826 827
    memcpy(&_current_configuration, config, sizeof(ice_config_t));
}

ice_config_t *config_get_config_unlocked(void)
{
    return &_current_configuration;
}

static void _set_defaults(ice_config_t *configuration)
{
Marvin Scholz's avatar
Marvin Scholz committed
828 829 830 831 832 833 834 835 836 837 838 839
    configuration
        ->location = (char *) xmlCharStrdup(CONFIG_DEFAULT_LOCATION);
    configuration
        ->server_id = (char *) xmlCharStrdup(ICECAST_VERSION_STRING);
    configuration
        ->admin = (char *) xmlCharStrdup(CONFIG_DEFAULT_ADMIN);
    configuration
        ->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT;
    configuration
        ->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT;
    configuration
        ->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT;
840 841
    configuration
        ->body_size_limit = CONFIG_DEFAULT_BODY_SIZE_LIMIT;
Marvin Scholz's avatar
Marvin Scholz committed
842 843 844 845 846 847
    configuration
        ->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT;
    configuration
        ->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
    configuration
        ->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
848
    configuration
849
        ->body_timeout = CONFIG_DEFAULT_BODY_TIMEOUT;
Marvin Scholz's avatar
Marvin Scholz committed
850 851
    configuration
        ->shoutcast_mount = (char *) xmlCharStrdup(CONFIG_DEFAULT_SHOUTCAST_MOUNT);
852 853
    configuration
        ->shoutcast_user = (char *) xmlCharStrdup(CONFIG_DEFAULT_SHOUTCAST_USER);
Marvin Scholz's avatar
Marvin Scholz committed
854 855 856 857 858 859 860 861 862
    configuration
        ->fileserve  = CONFIG_DEFAULT_FILESERVE;
    configuration
        ->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
    configuration
        ->on_demand = 0;
    configuration
        ->dir_list = NULL;
    configuration
863
        ->hostname = (char *) xmlCharStrdup(CONFIG_DEFAULT_HOSTNAME);
Marvin Scholz's avatar
Marvin Scholz committed
864
    configuration
865
        ->mimetypes_fn = (char *) xmlCharStrdup(MIMETYPESFILE);
Marvin Scholz's avatar
Marvin Scholz committed
866 867 868 869 870 871 872
    configuration
        ->master_server = NULL;
    configuration
        ->master_server_port = 0;
    configuration
        ->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
    configuration
873
        ->master_username = (char *) xmlCharStrdup(CONFIG_DEFAULT_MASTER_USERNAME);
Marvin Scholz's avatar
Marvin Scholz committed
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
    configuration
        ->master_password = NULL;
    configuration
        ->base_dir = (char *) xmlCharStrdup(CONFIG_DEFAULT_BASE_DIR);
    configuration
        ->log_dir = (char *) xmlCharStrdup(CONFIG_DEFAULT_LOG_DIR);
    configuration
        ->null_device = (char *) xmlCharStrdup(CONFIG_DEFAULT_NULL_FILE);
    configuration
        ->webroot_dir = (char *) xmlCharStrdup(CONFIG_DEFAULT_WEBROOT_DIR);
    configuration
        ->adminroot_dir = (char *) xmlCharStrdup(CONFIG_DEFAULT_ADMINROOT_DIR);
    configuration
        ->playlist_log = (char *) xmlCharStrdup(CONFIG_DEFAULT_PLAYLIST_LOG);
    configuration
        ->access_log = (char *) xmlCharStrdup(CONFIG_DEFAULT_ACCESS_LOG);
    configuration
        ->error_log = (char *) xmlCharStrdup(CONFIG_DEFAULT_ERROR_LOG);
    configuration
        ->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
    configuration
        ->chroot = CONFIG_DEFAULT_CHROOT;
    configuration
        ->chuid = CONFIG_DEFAULT_CHUID;
    configuration
        ->user = NULL;
    configuration
        ->group = NULL;
    configuration
        ->num_yp_directories = 0;
Karl Heyes's avatar
Karl Heyes committed
904
    /* default to a typical prebuffer size used by clients */
Marvin Scholz's avatar
Marvin Scholz committed
905 906
    configuration
        ->burst_size = CONFIG_DEFAULT_BURST_SIZE;
907 908
    configuration->tls_context
        .cipher_list = (char *) xmlCharStrdup(CONFIG_DEFAULT_CIPHER_LIST);
909 910
}

Marvin Scholz's avatar
Marvin Scholz committed
911 912
static inline void __check_hostname(ice_config_t *configuration)
{
913 914
    char *p;

915
    /* ensure we have a non-NULL buffer: */
916
    if (!configuration->hostname)
917
        configuration->hostname = (char *)xmlCharStrdup(CONFIG_DEFAULT_HOSTNAME);
918

919
    /* convert to lower case: */
Marvin Scholz's avatar
Marvin Scholz committed
920
    for (p = configuration->hostname; *p; p++) {
921 922
        if ( *p >= 'A' && *p <= 'Z' )
            *p += 'a' - 'A';
Marvin Scholz's avatar
Marvin Scholz committed
923
    }
924 925 926 927 928 929 930

    configuration->sane_hostname = 0;
    switch (util_hostcheck(configuration->hostname)) {
        case HOSTCHECK_SANE:
            configuration->sane_hostname = 1;
        break;
        case HOSTCHECK_ERROR:
Marvin Scholz's avatar
Marvin Scholz committed
931 932
            ICECAST_LOG_ERROR("Can not check hostname \"%s\".",
                configuration->hostname);
933 934
        break;
        case HOSTCHECK_NOT_FQDN:
Marvin Scholz's avatar
Marvin Scholz committed
935
            ICECAST_LOG_WARN("Warning, <hostname> seems not to be set to a "
936
                "fully qualified domain name (FQDN). This may cause problems, "
Marvin Scholz's avatar
Marvin Scholz committed
937
                "e.g. with YP directory listings.");
938 939
        break;
        case HOSTCHECK_IS_LOCALHOST:
Marvin Scholz's avatar
Marvin Scholz committed
940
            ICECAST_LOG_WARN("Warning, <hostname> not configured, using "
941 942 943 944
                "default value \"%s\". This will cause problems, e.g. "
                "this breaks YP directory listings. YP directory listing "
                "support will be disabled.", CONFIG_DEFAULT_HOSTNAME);
                /* FIXME actually disable YP */
945 946
        break;
        case HOSTCHECK_IS_IPV4:
Marvin Scholz's avatar
Marvin Scholz committed
947 948 949
            ICECAST_LOG_WARN("Warning, <hostname> seems to be set to an IPv4 "
                "address. This may cause problems, e.g. with YP directory "
                "listings.");
950 951
        break;
        case HOSTCHECK_IS_IPV6:
Marvin Scholz's avatar
Marvin Scholz committed
952 953 954
            ICECAST_LOG_WARN("Warning, <hostname> seems to be set to an IPv6 "
                "address. This may cause problems, e.g. with YP directory "
                "listings.");
955 956
        break;
        case HOSTCHECK_BADCHAR:
957
            ICECAST_LOG_WARN("Warning, <hostname> contains unusual "
Marvin Scholz's avatar
Marvin Scholz committed
958 959
                "characters. This may cause problems, e.g. with YP directory "
                "listings.");
960 961 962 963
        break;
    }
}

Marvin Scholz's avatar
Marvin Scholz committed
964 965 966
static void _parse_root(xmlDocPtr       doc,
                        xmlNodePtr      node,
                        ice_config_t   *configuration)
967 968
{
    char *tmp;
Philipp Schafft's avatar
Philipp Schafft committed
969
    char *source_password = NULL;
970

Marvin Scholz's avatar
Marvin Scholz committed
971
    configuration
972
        ->listen_sock       = calloc(1, sizeof(*configuration->listen_sock));
Marvin Scholz's avatar
Marvin Scholz committed
973 974 975 976
    configuration
        ->listen_sock->port = 8000;
    configuration
        ->listen_sock_count = 1;
977

978
    do {
Marvin Scholz's avatar
Marvin Scholz committed
979 980 981 982 983 984 985
        if (node == NULL)
            break;
        if (xmlIsBlankNode(node))
            continue;
        if (xmlStrcmp(node->name, XMLSTR("location")) == 0) {
            if (configuration->location)
                xmlFree(configuration->location);
986
            configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
987
        } else if (xmlStrcmp(node->name, XMLSTR("admin")) == 0) {
Marvin Scholz's avatar
Marvin Scholz committed
988 989
            if (configuration->admin)
                xmlFree(configuration->admin);
990
            configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
991
        } else if (xmlStrcmp(node->name, XMLSTR("server-id")) == 0) {
Marvin Scholz's avatar
Marvin Scholz committed
992
            xmlFree(configuration->server_id);
993
            configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
994 995 996 997
            ICECAST_LOG_WARN("Warning, server version string override "
                "detected. This may lead to unexpected client software "
                "behavior.");
        } else if (xmlStrcmp(node->name, XMLSTR("authentication")) == 0) {
Philipp Schafft's avatar
Philipp Schafft committed
998
            _parse_authentication(doc, node->xmlChildrenNode, configuration, &source_password);
Marvin Scholz's avatar
Marvin Scholz committed
999
        } else if (xmlStrcmp(node->name, XMLSTR("source-password")) == 0) {
1000
            /* TODO: This is the backwards-compatibility location */
Marvin Scholz's avatar
Marvin Scholz committed
1001 1002
            ICECAST_LOG_WARN("<source-password> defined outside "
                "<authentication>. This is deprecated and will be removed in "
1003 1004
                "version 2.X.0");
	    /* FIXME Settle target version for removal of this functionality! */
Philipp Schafft's avatar
Philipp Schafft committed
1005 1006 1007
            if (source_password)
                xmlFree(source_password);
            source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1008
        } else if (xmlStrcmp(node->name, XMLSTR("icelogin")) == 0) {
1009
            ICECAST_LOG_ERROR("<icelogin> support has been removed.");
Marvin Scholz's avatar
Marvin Scholz committed
1010
        } else if (xmlStrcmp(node->name, XMLSTR("fileserve")) == 0) {
1011
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1012
            configuration->fileserve = util_str_to_bool(tmp);
Marvin Scholz's avatar
Marvin Scholz committed
1013 1014 1015
            if (tmp)
                xmlFree(tmp);
        } else if (xmlStrcmp(node->name, XMLSTR("relays-on-demand")) == 0) {
1016
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1017
            configuration->on_demand = util_str_to_bool(tmp);
Marvin Scholz's avatar
Marvin Scholz committed
1018 1019 1020 1021 1022
            if (tmp)
                xmlFree(tmp);
        } else if (xmlStrcmp(node->name, XMLSTR("hostname")) == 0) {
            if (configuration->hostname)
                xmlFree(configuration->hostname);
1023
            configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1024
        } else if (xmlStrcmp(node->name, XMLSTR("mime-types")) == 0) {
1025
            ICECAST_LOG_WARN("<mime-types> has been moved into <paths>. Please update your configuration file.");
Marvin Scholz's avatar
Marvin Scholz committed
1026 1027
            if (configuration->mimetypes_fn)
                xmlFree(configuration->mimetypes_fn);
1028
            configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1029
        } else if (xmlStrcmp(node->name, XMLSTR("listen-socket")) == 0) {
1030
            _parse_listen_socket(doc, node, configuration);
Marvin Scholz's avatar
Marvin Scholz committed
1031
        } else if (xmlStrcmp(node->name, XMLSTR("port")) == 0) {
1032
            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
1033
            if (tmp && *tmp) {
1034 1035 1036 1037
                configuration->port = atoi(tmp);
                configuration->listen_sock->port = atoi(tmp);
                xmlFree(tmp);
            } else {
1038
                ICECAST_LOG_WARN("<port> setting must not be empty.");
1039
            }
Marvin Scholz's avatar
Marvin Scholz committed
1040
        } else if (xmlStrcmp(node->name, XMLSTR("bind-address")) == 0) {
1041
            if (configuration->listen_sock->bind_address)
1042 1043
                xmlFree(configuration->listen_sock->bind_address);
            configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1044 1045 1046
        } else if (xmlStrcmp(node->name, XMLSTR("master-server")) == 0) {
            if (configuration->master_server)
                xmlFree(configuration->master_server);
1047
            configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1048 1049 1050
        } else if (xmlStrcmp(node->name, XMLSTR("master-username")) == 0) {
            if (configuration->master_username)
                xmlFree(configuration->master_username);
1051
            configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1052 1053 1054
        } else if (xmlStrcmp(node->name, XMLSTR("master-password")) == 0) {
            if (configuration->master_password)
                xmlFree(configuration->master_password);
1055
            configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1056
        } else if (xmlStrcmp(node->name, XMLSTR("master-server-port")) == 0) {
1057
            __read_int(doc, node, &configuration->master_server_port, "<master-server-port> must not be empty.");
Marvin Scholz's avatar
Marvin Scholz committed
1058
        } else if (xmlStrcmp(node->name, XMLSTR("master-update-interval")) == 0) {
1059
            __read_int(doc, node, &configuration->master_update_interval, "<master-update-interval> must not be empty.");
Marvin Scholz's avatar
Marvin Scholz committed
1060 1061 1062
        } else if (xmlStrcmp(node->name, XMLSTR("shoutcast-mount")) == 0) {
            if (configuration->shoutcast_mount)
                xmlFree(configuration->shoutcast_mount);
1063
            configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
Marvin Scholz's avatar
Marvin Scholz committed
1064
        } else if (xmlStrcmp(node->name, XMLSTR("limits")) == 0) {
1065
            _parse_limits(doc, node->xmlChildrenNode, configuration);
Marvin Scholz's avatar
Marvin Scholz committed
1066
        } else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) {
1067
            config_parse_http_headers(node->xmlChildrenNode, &(configuration->http_headers));
Marvin Scholz's avatar
Marvin Scholz committed
1068
        } else if (xmlStrcmp(node->name, XMLSTR("relay")) == 0) {
1069
            _parse_relay(doc, node->xmlChildrenNode, configuration, NULL);
Marvin Scholz's avatar
Marvin Scholz committed
1070
        } else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) {
1071
            _parse_mount(doc, node, configuration);
Marvin Scholz's avatar
Marvin Scholz committed
1072
        } else if (xmlStrcmp(node->name, XMLSTR("directory")) == 0) {
1073
            _parse_directory(doc, node->xmlChildrenNode, configuration);
Marvin Scholz's avatar
Marvin Scholz committed
1074
        } else if (xmlStrcmp(node->name, XMLSTR("paths")) == 0) {
1075
            _parse_paths(doc, node->xmlChildrenNode, configuration);
Marvin Scholz's avatar
Marvin Scholz committed
1076
        } else if (xmlStrcmp(node->name, XMLSTR("logging")) == 0) {
1077
            _parse_logging(doc, node->xmlChildrenNode, configuration);
Marvin Scholz's avatar
Marvin Scholz committed
1078
        } else if (xmlStrcmp(node->name, XMLSTR("security")) == 0) {
1079
            _parse_security(doc, node->xmlChildrenNode, configuration);
1080 1081
        } else if (xmlStrcmp(node->name, XMLSTR("event-bindings")) == 0 ||
                   xmlStrcmp(node->name, XMLSTR("kartoffelsalat")) == 0) {
1082
            _parse_events(&configuration->event, node->xmlChildrenNode);
1083 1084
        }
    } while ((node = node->next));
1085

Philipp Schafft's avatar
Philipp Schafft committed
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
    /* global source password is set.
     * We need to set it on default mount.
     * If default mount has a authstack not NULL we don't need to do anything.
     */
    if (source_password) {
        mount_proxy *mount = config_find_mount(configuration, NULL, MOUNT_TYPE_DEFAULT);
        if (!mount) {
            /* create a default mount here */
            xmlNodePtr node;
            node = xmlNewNode(NULL, XMLSTR("mount"));
            xmlSetProp(node, XMLSTR("type"), XMLSTR("default"));
            _parse_mount(doc, node, configuration);
            xmlFreeNode(node);
            mount = config_find_mount(configuration, NULL, MOUNT_TYPE_DEFAULT);
        }
        if (mount) {
Marvin Scholz's avatar
Marvin Scholz committed
1102 1103 1104 1105 1106
            if (!mount->authstack) {
                __append_old_style_auth(&mount->authstack,
                                        "legacy-global-source",
                                        AUTH_TYPE_STATIC, "source",
                                        source_password, NULL,
1107
                                        "source,put,get,delete", 0, "*");
Marvin Scholz's avatar
Marvin Scholz committed
1108
            }
Philipp Schafft's avatar
Philipp Schafft committed
1109
        } else {
1110 1111
            ICECAST_LOG_ERROR("Can not find nor create default mount, but "
                "global legacy source password set. This is bad.");
Philipp Schafft's avatar
Philipp Schafft committed
1112
        }
1113
        xmlFree(source_password);
Philipp Schafft's avatar
Philipp Schafft committed
1114
    }
1115 1116
    /* drop the first listening socket details if more than one is defined, as we only
     * have port or listen-socket not both */