auth_url.c 16.2 KB
Newer Older
Karl Heyes's avatar
Karl Heyes committed
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>,
Karl Heyes's avatar
Karl Heyes committed
7 8 9 10
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
 *                      Karl Heyes <karl@xiph.org>
 *                      and others (see AUTHORS for details).
Philipp Schafft's avatar
Philipp Schafft committed
11
 * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
Karl Heyes's avatar
Karl Heyes committed
12 13
 */

14
/*
Karl Heyes's avatar
Karl Heyes committed
15 16 17 18 19 20
 * Client authentication via URL functions
 *
 * authenticate user via a URL, this is done via libcurl so https can also
 * be handled. The request will have POST information about the request in
 * the form of
 *
21
 * action=listener_add&client=1&server=host&port=8000&mount=/live&user=fred&pass=mypass&ip=127.0.0.1&agent=""
Karl Heyes's avatar
Karl Heyes committed
22 23 24 25 26 27
 *
 * For a user to be accecpted the following HTTP header needs
 * to be returned (the actual string can be specified in the xml file)
 *
 * icecast-auth-user: 1
 *
28 29 30 31 32 33
 * A listening client may also be configured as only to stay connected for a
 * certain length of time. eg The auth server may only allow a 15 minute
 * playback by sending back.
 *
 * icecast-auth-timelimit: 900
 *
Karl Heyes's avatar
Karl Heyes committed
34 35 36
 * On client disconnection another request can be sent to a URL with the POST
 * information of
 *
37
 * action=listener_remove&server=host&port=8000&client=1&mount=/live&user=fred&pass=mypass&duration=3600
Karl Heyes's avatar
Karl Heyes committed
38 39 40 41 42 43
 *
 * client refers to the icecast client identification number. mount refers
 * to the mountpoint (beginning with / and may contain query parameters eg ?&
 * encoded) and duration is the amount of time in seconds. user and pass
 * setting can be blank
 *
44 45 46 47 48 49 50 51
 * On source client connection, a request can be made to trigger a URL request
 * to verify the details externally. Post info is
 *
 * action=stream_auth&mount=/stream&ip=IP&server=SERVER&port=8000&user=fred&pass=pass
 *
 * As admin requests can come in for a stream (eg metadata update) these requests
 * can be issued while stream is active. For these &admin=1 is added to the POST
 * details.
Karl Heyes's avatar
Karl Heyes committed
52 53 54 55 56 57 58 59 60 61 62
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#ifndef _WIN32
63 64
#   include <sys/wait.h>
#   include <strings.h>
Karl Heyes's avatar
Karl Heyes committed
65
#else
66 67
#   define snprintf _snprintf
#   define strncasecmp strnicmp
Karl Heyes's avatar
Karl Heyes committed
68 69
#endif

70
#include "util.h"
71
#include "curl.h"
Karl Heyes's avatar
Karl Heyes committed
72 73 74 75
#include "auth.h"
#include "source.h"
#include "client.h"
#include "cfgfile.h"
76
#include "connection.h"
Marvin Scholz's avatar
Marvin Scholz committed
77
#include "common/httpp/httpp.h"
Karl Heyes's avatar
Karl Heyes committed
78 79 80 81 82

#include "logging.h"
#define CATMODULE "auth_url"

typedef struct {
Marvin Scholz's avatar
Marvin Scholz committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    char       *pass_headers; // headers passed from client to addurl.
    char       *prefix_headers; // prefix for passed headers.
    char       *addurl;
    char       *removeurl;
    char       *addaction;
    char       *removeaction;
    char       *username;
    char       *password;
    char       *auth_header;
    int         auth_header_len;
    char       *timelimit_header;
    int         timelimit_header_len;
    char       *userpwd;
    CURL       *handle;
    char        errormsg[CURL_ERROR_SIZE];
Philipp Schafft's avatar
Philipp Schafft committed
98
    auth_result result;
Karl Heyes's avatar
Karl Heyes committed
99 100 101 102
} auth_url;


static void auth_url_clear(auth_t *self)
103 104
{
    auth_url *url;
105

106
    ICECAST_LOG_INFO("Doing auth URL cleanup");
107
    url = self->state;
108
    self->state = NULL;
109
    icecast_curl_free(url->handle);
Philipp Schafft's avatar
Philipp Schafft committed
110 111 112 113 114 115 116 117 118 119 120 121
    free(url->username);
    free(url->password);
    free(url->pass_headers);
    free(url->prefix_headers);
    free(url->removeurl);
    free(url->addurl);
    free(url->addaction);
    free(url->removeaction);
    free(url->auth_header);
    free(url->timelimit_header);
    free(url->userpwd);
    free(url);
Karl Heyes's avatar
Karl Heyes committed
122 123
}

Marvin Scholz's avatar
Marvin Scholz committed
124 125 126 127
static size_t handle_returned_header(void      *ptr,
                                     size_t    size,
                                     size_t    nmemb,
                                     void      *stream)
Karl Heyes's avatar
Karl Heyes committed
128 129 130 131 132
{
    auth_client *auth_user = stream;
    unsigned bytes = size * nmemb;
    client_t *client = auth_user->client;

Marvin Scholz's avatar
Marvin Scholz committed
133
    if (client) {
Karl Heyes's avatar
Karl Heyes committed
134 135
        auth_t *auth = client->auth;
        auth_url *url = auth->state;
Marvin Scholz's avatar
Marvin Scholz committed
136
        if (strncasecmp(ptr, url->auth_header, url->auth_header_len) == 0)
Philipp Schafft's avatar
Philipp Schafft committed
137
            url->result = AUTH_OK;
Marvin Scholz's avatar
Marvin Scholz committed
138 139
        if (strncasecmp(ptr, url->timelimit_header,
                url->timelimit_header_len) == 0) {
140 141 142 143
            unsigned int limit = 0;
            sscanf ((char *)ptr+url->timelimit_header_len, "%u\r\n", &limit);
            client->con->discon_time = time(NULL) + limit;
        }
Marvin Scholz's avatar
Marvin Scholz committed
144
        if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0) {
Karl Heyes's avatar
Karl Heyes committed
145
            char *eol;
Marvin Scholz's avatar
Marvin Scholz committed
146 147
            snprintf(url->errormsg, sizeof(url->errormsg), "%s", (char*)ptr+22);
            eol = strchr(url->errormsg, '\r');
Karl Heyes's avatar
Karl Heyes committed
148
            if (eol == NULL)
Marvin Scholz's avatar
Marvin Scholz committed
149
                eol = strchr(url->errormsg, '\n');
Karl Heyes's avatar
Karl Heyes committed
150 151 152 153 154 155 156 157
            if (eol)
                *eol = '\0';
        }
    }

    return (int)bytes;
}

Marvin Scholz's avatar
Marvin Scholz committed
158
static auth_result url_remove_client(auth_client *auth_user)
Karl Heyes's avatar
Karl Heyes committed
159
{
Marvin Scholz's avatar
Marvin Scholz committed
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    client_t       *client      = auth_user->client;
    auth_t         *auth        = client->auth;
    auth_url       *url         = auth->state;
    time_t          duration    = time(NULL) - client->con->con_time;
    char           *username,
                   *password,
                   *mount,
                   *server;
    const char     *mountreq;
    ice_config_t   *config;
    int             port;
    char           *userpwd     = NULL,
                    post[4096];
    const char     *agent;
    char           *user_agent,
                   *ipaddr;
Karl Heyes's avatar
Karl Heyes committed
176

177 178
    if (url->removeurl == NULL)
        return AUTH_OK;
179

Marvin Scholz's avatar
Marvin Scholz committed
180 181
    config = config_get_config();
    server = util_url_escape(config->hostname);
Karl Heyes's avatar
Karl Heyes committed
182
    port = config->port;
Marvin Scholz's avatar
Marvin Scholz committed
183
    config_release_config();
Karl Heyes's avatar
Karl Heyes committed
184

Marvin Scholz's avatar
Marvin Scholz committed
185 186 187 188 189 190
    agent = httpp_getvar(client->parser, "user-agent");
    if (agent) {
        user_agent = util_url_escape(agent);
    } else {
        user_agent = strdup("-");
    }
191

Marvin Scholz's avatar
Marvin Scholz committed
192 193 194 195 196
    if (client->username) {
        username = util_url_escape(client->username);
    } else {
        username = strdup("");
    }
Karl Heyes's avatar
Karl Heyes committed
197

Marvin Scholz's avatar
Marvin Scholz committed
198 199 200 201 202
    if (client->password) {
        password = util_url_escape(client->password);
    } else {
        password = strdup("");
    }
Karl Heyes's avatar
Karl Heyes committed
203 204

    /* get the full uri (with query params if available) */
Marvin Scholz's avatar
Marvin Scholz committed
205
    mountreq = httpp_getvar(client->parser, HTTPP_VAR_RAWURI);
206
    if (mountreq == NULL)
Marvin Scholz's avatar
Marvin Scholz committed
207 208 209
        mountreq = httpp_getvar(client->parser, HTTPP_VAR_URI);
    mount = util_url_escape(mountreq);
    ipaddr = util_url_escape(client->con->ip);
Karl Heyes's avatar
Karl Heyes committed
210

Marvin Scholz's avatar
Marvin Scholz committed
211
    snprintf(post, sizeof (post),
Philipp Schafft's avatar
Philipp Schafft committed
212
            "action=%s&server=%s&port=%d&client=%lu&mount=%s"
213
            "&user=%s&pass=%s&duration=%lu&ip=%s&agent=%s",
Philipp Schafft's avatar
Philipp Schafft committed
214
            url->removeaction, /* already escaped */
Karl Heyes's avatar
Karl Heyes committed
215
            server, port, client->con->id, mount, username,
216
            password, (long unsigned)duration, ipaddr, user_agent);
Marvin Scholz's avatar
Marvin Scholz committed
217 218 219 220 221 222 223 224 225 226 227 228

    free(server);
    free(mount);
    free(username);
    free(password);
    free(ipaddr);
    free(user_agent);

    if (strchr (url->removeurl, '@') == NULL) {
        if (url->userpwd) {
            curl_easy_setopt(url->handle, CURLOPT_USERPWD, url->userpwd);
        } else {
229
            /* auth'd requests may not have a user/pass, but may use query args */
Marvin Scholz's avatar
Marvin Scholz committed
230 231 232 233 234 235 236 237 238
            if (client->username && client->password) {
                size_t len = strlen(client->username) +
                    strlen(client->password) + 2;
                userpwd = malloc(len);
                snprintf(userpwd, len, "%s:%s",
                    client->username, client->password);
                curl_easy_setopt(url->handle, CURLOPT_USERPWD, userpwd);
            } else {
                curl_easy_setopt(url->handle, CURLOPT_USERPWD, "");
239 240
            }
        }
Marvin Scholz's avatar
Marvin Scholz committed
241
    } else {
242
        /* url has user/pass but libcurl may need to clear any existing settings */
Marvin Scholz's avatar
Marvin Scholz committed
243
        curl_easy_setopt(url->handle, CURLOPT_USERPWD, "");
244
    }
Marvin Scholz's avatar
Marvin Scholz committed
245 246 247
    curl_easy_setopt(url->handle, CURLOPT_URL, url->removeurl);
    curl_easy_setopt(url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt(url->handle, CURLOPT_WRITEHEADER, auth_user);
Karl Heyes's avatar
Karl Heyes committed
248 249

    if (curl_easy_perform (url->handle))
Marvin Scholz's avatar
Marvin Scholz committed
250 251
        ICECAST_LOG_WARN("auth to server %s failed with %s",
            url->removeurl, url->errormsg);
Karl Heyes's avatar
Karl Heyes committed
252

Marvin Scholz's avatar
Marvin Scholz committed
253
    free(userpwd);
254

Karl Heyes's avatar
Karl Heyes committed
255 256 257 258
    return AUTH_OK;
}


Marvin Scholz's avatar
Marvin Scholz committed
259
static auth_result url_add_client(auth_client *auth_user)
Karl Heyes's avatar
Karl Heyes committed
260
{
Marvin Scholz's avatar
Marvin Scholz committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
    client_t       *client      = auth_user->client;
    auth_t         *auth        = client->auth;
    auth_url       *url         = auth->state;
    int             res         = 0,
                    port;
    const char     *agent;
    char           *user_agent,
                   *username,
                   *password;
    const char     *mountreq;
    char           *mount,
                   *ipaddr,
                   *server;
    ice_config_t   *config;
    char           *userpwd    = NULL, post [4096];
    ssize_t         post_offset;
    char           *pass_headers,
                   *cur_header,
                   *next_header;
    const char     *header_val;
    char           *header_valesc;
Karl Heyes's avatar
Karl Heyes committed
282 283 284 285

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

Marvin Scholz's avatar
Marvin Scholz committed
286 287
    config = config_get_config();
    server = util_url_escape(config->hostname);
Karl Heyes's avatar
Karl Heyes committed
288
    port = config->port;
Marvin Scholz's avatar
Marvin Scholz committed
289
    config_release_config();
290

Marvin Scholz's avatar
Marvin Scholz committed
291 292 293 294 295 296
    agent = httpp_getvar(client->parser, "user-agent");
    if (agent) {
        user_agent = util_url_escape(agent);
    } else {
        user_agent = strdup("-");
    }
297

Marvin Scholz's avatar
Marvin Scholz committed
298 299 300 301 302
    if (client->username) {
        username = util_url_escape(client->username);
    } else {
        username = strdup("");
    }
303

Marvin Scholz's avatar
Marvin Scholz committed
304 305 306 307 308
    if (client->password) {
        password = util_url_escape(client->password);
    } else {
        password = strdup("");
    }
Karl Heyes's avatar
Karl Heyes committed
309 310

    /* get the full uri (with query params if available) */
Marvin Scholz's avatar
Marvin Scholz committed
311
    mountreq = httpp_getvar(client->parser, HTTPP_VAR_RAWURI);
312
    if (mountreq == NULL)
Marvin Scholz's avatar
Marvin Scholz committed
313 314 315
        mountreq = httpp_getvar(client->parser, HTTPP_VAR_URI);
    mount = util_url_escape(mountreq);
    ipaddr = util_url_escape(client->con->ip);
Karl Heyes's avatar
Karl Heyes committed
316

Marvin Scholz's avatar
Marvin Scholz committed
317
    post_offset = snprintf(post, sizeof (post),
Philipp Schafft's avatar
Philipp Schafft committed
318
            "action=%s&server=%s&port=%d&client=%lu&mount=%s"
Karl Heyes's avatar
Karl Heyes committed
319
            "&user=%s&pass=%s&ip=%s&agent=%s",
Philipp Schafft's avatar
Philipp Schafft committed
320
            url->addaction, /* already escaped */
Karl Heyes's avatar
Karl Heyes committed
321 322
            server, port, client->con->id, mount, username,
            password, ipaddr, user_agent);
Marvin Scholz's avatar
Marvin Scholz committed
323 324 325 326 327 328 329

    free(server);
    free(mount);
    free(user_agent);
    free(username);
    free(password);
    free(ipaddr);
Karl Heyes's avatar
Karl Heyes committed
330

331 332
    pass_headers = NULL;
    if (url->pass_headers)
Marvin Scholz's avatar
Marvin Scholz committed
333 334
        pass_headers = strdup(url->pass_headers);
    if (pass_headers) {
335
        cur_header = pass_headers;
Marvin Scholz's avatar
Marvin Scholz committed
336 337 338
        while (cur_header) {
            next_header = strstr(cur_header, ",");
            if (next_header) {
339
                *next_header=0;
340
                next_header++;
341
            }
342 343

            header_val = httpp_getvar (client->parser, cur_header);
Marvin Scholz's avatar
Marvin Scholz committed
344
            if (header_val) {
345
                header_valesc = util_url_escape (header_val);
Marvin Scholz's avatar
Marvin Scholz committed
346 347 348 349 350 351
                post_offset += snprintf(post + post_offset,
                                        sizeof(post) - post_offset,
                                        "&%s%s=%s",
                                        url->prefix_headers ? url->prefix_headers : "",
                                        cur_header, header_valesc);
                free(header_valesc);
352 353
            }

354
            cur_header = next_header;
355 356 357
        }
    }

Marvin Scholz's avatar
Marvin Scholz committed
358 359 360 361
    if (strchr(url->addurl, '@') == NULL) {
        if (url->userpwd) {
            curl_easy_setopt(url->handle, CURLOPT_USERPWD, url->userpwd);
        } else {
362
            /* auth'd requests may not have a user/pass, but may use query args */
Marvin Scholz's avatar
Marvin Scholz committed
363 364
            if (client->username && client->password) {
                size_t len = strlen(client->username) + strlen(client->password) + 2;
365
                userpwd = malloc (len);
Marvin Scholz's avatar
Marvin Scholz committed
366 367 368 369
                snprintf(userpwd, len, "%s:%s",
                    client->username, client->password);
                curl_easy_setopt(url->handle, CURLOPT_USERPWD, userpwd);
            } else {
370
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
Marvin Scholz's avatar
Marvin Scholz committed
371
            }
372
        }
Marvin Scholz's avatar
Marvin Scholz committed
373
    } else {
374
        /* url has user/pass but libcurl may need to clear any existing settings */
Marvin Scholz's avatar
Marvin Scholz committed
375
        curl_easy_setopt(url->handle, CURLOPT_USERPWD, "");
376
    }
Marvin Scholz's avatar
Marvin Scholz committed
377 378 379
    curl_easy_setopt(url->handle, CURLOPT_URL, url->addurl);
    curl_easy_setopt(url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt(url->handle, CURLOPT_WRITEHEADER, auth_user);
Karl Heyes's avatar
Karl Heyes committed
380 381
    url->errormsg[0] = '\0';

Philipp Schafft's avatar
Philipp Schafft committed
382
    url->result = AUTH_FAILED;
Marvin Scholz's avatar
Marvin Scholz committed
383
    res = curl_easy_perform(url->handle);
Karl Heyes's avatar
Karl Heyes committed
384

Marvin Scholz's avatar
Marvin Scholz committed
385
    free(userpwd);
386

Marvin Scholz's avatar
Marvin Scholz committed
387 388 389
    if (res) {
        ICECAST_LOG_WARN("auth to server %s failed with %s",
            url->addurl, url->errormsg);
Karl Heyes's avatar
Karl Heyes committed
390 391 392
        return AUTH_FAILED;
    }
    /* we received a response, lets see what it is */
Philipp Schafft's avatar
Philipp Schafft committed
393
    if (url->result == AUTH_FAILED) {
Marvin Scholz's avatar
Marvin Scholz committed
394 395
        ICECAST_LOG_INFO("client auth (%s) failed with \"%s\"",
            url->addurl, url->errormsg);
396
    }
Philipp Schafft's avatar
Philipp Schafft committed
397
    return url->result;
398 399
}

Marvin Scholz's avatar
Marvin Scholz committed
400 401 402
static auth_result auth_url_adduser(auth_t      *auth,
                                    const char  *username,
                                    const char  *password)
Karl Heyes's avatar
Karl Heyes committed
403 404 405 406
{
    return AUTH_FAILED;
}

Marvin Scholz's avatar
Marvin Scholz committed
407
static auth_result auth_url_deleteuser(auth_t *auth, const char *username)
Karl Heyes's avatar
Karl Heyes committed
408 409 410 411
{
    return AUTH_FAILED;
}

Marvin Scholz's avatar
Marvin Scholz committed
412
static auth_result auth_url_listuser(auth_t *auth, xmlNodePtr srcnode)
Karl Heyes's avatar
Karl Heyes committed
413 414 415 416
{
    return AUTH_FAILED;
}

417
int auth_get_url_auth(auth_t *authenticator, config_options_t *options)
Karl Heyes's avatar
Karl Heyes committed
418
{
Marvin Scholz's avatar
Marvin Scholz committed
419 420 421
    auth_url    *url_info;
    const char  *addaction      = "listener_add";
    const char  *removeaction   = "listener_remove";
Karl Heyes's avatar
Karl Heyes committed
422

Marvin Scholz's avatar
Marvin Scholz committed
423 424 425 426
    authenticator->free         = auth_url_clear;
    authenticator->adduser      = auth_url_adduser;
    authenticator->deleteuser   = auth_url_deleteuser;
    authenticator->listuser     = auth_url_listuser;
Karl Heyes's avatar
Karl Heyes committed
427

Marvin Scholz's avatar
Marvin Scholz committed
428 429
    url_info                    = calloc(1, sizeof(auth_url));
    authenticator->state        = url_info;
430

431
    /* force auth thread to call function. this makes sure the auth_t is attached to client */
Philipp Schafft's avatar
Philipp Schafft committed
432
    authenticator->authenticate_client = url_add_client;
433

Karl Heyes's avatar
Karl Heyes committed
434
    while(options) {
Philipp Schafft's avatar
Philipp Schafft committed
435
        if(strcmp(options->name, "username") == 0) {
436
            replace_string(&(url_info->username), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
437
        } else if(strcmp(options->name, "password") == 0) {
438
            replace_string(&(url_info->password), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
439
        } else if(strcmp(options->name, "headers") == 0) {
440
            replace_string(&(url_info->pass_headers), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
441
        } else if(strcmp(options->name, "header_prefix") == 0) {
442
            replace_string(&(url_info->prefix_headers), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
443
        } else if(strcmp(options->name, "client_add") == 0) {
444
            replace_string(&(url_info->addurl), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
445 446
        } else if(strcmp(options->name, "client_remove") == 0) {
            authenticator->release_client = url_remove_client;
447
            replace_string(&(url_info->removeurl), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
448 449 450 451 452
        } else if(strcmp(options->name, "action_add") == 0) {
            addaction = options->value;
        } else if(strcmp(options->name, "action_remove") == 0) {
            removeaction = options->value;
        } else if(strcmp(options->name, "auth_header") == 0) {
453
            replace_string(&(url_info->auth_header), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
454
        } else if (strcmp(options->name, "timelimit_header") == 0) {
455
            replace_string(&(url_info->timelimit_header), options->value);
Philipp Schafft's avatar
Philipp Schafft committed
456 457
        } else {
            ICECAST_LOG_ERROR("Unknown option: %s", options->name);
458
        }
Karl Heyes's avatar
Karl Heyes committed
459 460
        options = options->next;
    }
Philipp Schafft's avatar
Philipp Schafft committed
461 462 463 464

    url_info->addaction = util_url_escape(addaction);
    url_info->removeaction = util_url_escape(removeaction);

465
    url_info->handle = icecast_curl_new(NULL, &url_info->errormsg[0]);
Marvin Scholz's avatar
Marvin Scholz committed
466 467
    if (url_info->handle == NULL) {
        auth_url_clear(authenticator);
Karl Heyes's avatar
Karl Heyes committed
468 469
        return -1;
    }
Philipp Schafft's avatar
Philipp Schafft committed
470

471 472 473 474 475 476
    /* default headers */
    if (!url_info->auth_header)
        url_info->auth_header = strdup("icecast-auth-user: 1\r\n");
    if (!url_info->timelimit_header)
        url_info->timelimit_header = strdup("icecast-auth-timelimit:");

Karl Heyes's avatar
Karl Heyes committed
477 478
    if (url_info->auth_header)
        url_info->auth_header_len = strlen (url_info->auth_header);
479 480
    if (url_info->timelimit_header)
        url_info->timelimit_header_len = strlen (url_info->timelimit_header);
Karl Heyes's avatar
Karl Heyes committed
481

Marvin Scholz's avatar
Marvin Scholz committed
482
    curl_easy_setopt(url_info->handle, CURLOPT_HEADERFUNCTION, handle_returned_header);
Karl Heyes's avatar
Karl Heyes committed
483

Marvin Scholz's avatar
Marvin Scholz committed
484 485 486 487 488
    if (url_info->username && url_info->password) {
        int len = strlen(url_info->username) + strlen(url_info->password) + 2;
        url_info->userpwd = malloc(len);
        snprintf(url_info->userpwd, len, "%s:%s",
            url_info->username, url_info->password);
489 490
    }

491
    ICECAST_LOG_INFO("URL based authentication setup");
Karl Heyes's avatar
Karl Heyes committed
492 493
    return 0;
}