mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
merge URL listener auth
svn path=/icecast/trunk/icecast/; revision=9714
This commit is contained in:
parent
15b3a5f853
commit
eebb340a1a
23
configure.in
23
configure.in
@ -106,24 +106,27 @@ XIPH_VAR_APPEND([XIPH_CFLAGS],[$PTHREAD_CFLAGS])
|
||||
XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$PTHREAD_CPPFLAGS])
|
||||
XIPH_VAR_PREPEND([XIPH_LIBS],[$PTHREAD_LIBS])
|
||||
|
||||
dnl -- YP support --
|
||||
AC_ARG_ENABLE([yp],
|
||||
AC_HELP_STRING([--disable-yp],[disable YP directory support]),
|
||||
enable_yp="$enableval",
|
||||
enable_yp="yes")
|
||||
if test "x$enable_yp" = "xyes"
|
||||
then
|
||||
XIPH_PATH_CURL([
|
||||
AC_CHECK_DECL([CURLOPT_NOSIGNAL],
|
||||
[ AC_DEFINE([USE_YP], 1, [Define to compile in YP support code])
|
||||
ICECAST_OPTIONAL="$ICECAST_OPTIONAL yp.o"
|
||||
[ AC_DEFINE([HAVE_AUTH_URL], 1, [Define to compile in auth URL support code])
|
||||
ICECAST_OPTIONAL="$ICECAST_OPTIONAL auth_url.o"
|
||||
enable_curl="yes"
|
||||
XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$CURL_CFLAGS])
|
||||
XIPH_VAR_PREPEND([XIPH_LIBS],[$CURL_LIBS])
|
||||
], [ AC_MSG_NOTICE([Your curl dev files are too old (7.10 or above required), YP disabled])
|
||||
], [#include <curl/curl.h>
|
||||
])
|
||||
],[ AC_MSG_NOTICE([libcurl not found, YP disabled])
|
||||
],[ AC_MSG_NOTICE([libcurl not found])
|
||||
])
|
||||
dnl -- YP support --
|
||||
AC_ARG_ENABLE([yp],
|
||||
AC_HELP_STRING([--disable-yp],[disable YP directory support]),
|
||||
enable_yp="$enableval",
|
||||
enable_yp="yes")
|
||||
if test "x$enable_yp" = "xyes" -a "x$enable_curl" = xyes
|
||||
then
|
||||
AC_DEFINE([USE_YP], 1, [Define to compile in YP support code])
|
||||
ICECAST_OPTIONAL="$ICECAST_OPTIONAL yp.o"
|
||||
else
|
||||
AC_MSG_NOTICE([YP support disabled])
|
||||
fi
|
||||
|
@ -9,7 +9,7 @@ bin_PROGRAMS = icecast
|
||||
noinst_HEADERS = admin.h cfgfile.h os.h logging.h sighandler.h connection.h \
|
||||
global.h util.h slave.h source.h stats.h refbuf.h client.h \
|
||||
compat.h fserve.h xslt.h yp.h event.h md5.h \
|
||||
auth.h auth_htpasswd.h \
|
||||
auth.h auth_htpasswd.h auth_url.h \
|
||||
format.h format_ogg.h format_mp3.h \
|
||||
format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h
|
||||
icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \
|
||||
@ -18,6 +18,7 @@ icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c
|
||||
format.c format_ogg.c format_mp3.c format_midi.c format_flac.c \
|
||||
auth.c auth_htpasswd.c
|
||||
EXTRA_icecast_SOURCES = yp.c \
|
||||
auth_url.c \
|
||||
format_vorbis.c format_theora.c format_speex.c
|
||||
|
||||
icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "auth.h"
|
||||
#include "auth_htpasswd.h"
|
||||
#include "auth_url.h"
|
||||
#include "source.h"
|
||||
#include "client.h"
|
||||
#include "cfgfile.h"
|
||||
@ -423,6 +424,13 @@ static void get_authenticator (auth_t *auth, config_options_t *options)
|
||||
do
|
||||
{
|
||||
DEBUG1 ("type is %s", auth->type);
|
||||
#ifdef HAVE_AUTH_URL
|
||||
if (strcmp (auth->type, "url") == 0)
|
||||
{
|
||||
auth_get_url_auth (auth, options);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (strcmp (auth->type, "htpasswd") == 0)
|
||||
{
|
||||
auth_get_htpasswd_auth (auth, options);
|
||||
|
421
src/auth_url.c
Normal file
421
src/auth_url.c
Normal file
@ -0,0 +1,421 @@
|
||||
/* Icecast
|
||||
*
|
||||
* This program is distributed under the GNU General Public License, version 2.
|
||||
* A copy of this license is included with this source.
|
||||
*
|
||||
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
|
||||
* Michael Smith <msmith@xiph.org>,
|
||||
* oddsock <oddsock@xiph.org>,
|
||||
* Karl Heyes <karl@xiph.org>
|
||||
* and others (see AUTHORS for details).
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* action=auth&client=1&server=host&port=8000&mount=/live&user=fred&pass=mypass&ip=127.0.0.1&agent=""
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* On client disconnection another request can be sent to a URL with the POST
|
||||
* information of
|
||||
*
|
||||
* action=remove&server=host&port=8000&client=1&mount=/live&user=fred&pass=mypass&duration=3600
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* On stream start and end, another url can be issued to help clear any user
|
||||
* info stored at the auth server. Useful for abnormal outage/termination
|
||||
* cases.
|
||||
*
|
||||
* action=start&mount=/live&server=myserver.com&port=8000
|
||||
* action=end&mount=/live&server=myserver.com&port=8000
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#include <strings.h>
|
||||
#else
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "auth.h"
|
||||
#include "source.h"
|
||||
#include "client.h"
|
||||
#include "cfgfile.h"
|
||||
#include "httpp/httpp.h"
|
||||
|
||||
#include "logging.h"
|
||||
#define CATMODULE "auth_url"
|
||||
|
||||
typedef struct {
|
||||
char *addurl;
|
||||
char *removeurl;
|
||||
char *stream_start;
|
||||
char *stream_end;
|
||||
char *username;
|
||||
char *password;
|
||||
char *auth_header;
|
||||
int auth_header_len;
|
||||
CURL *handle;
|
||||
char errormsg [CURL_ERROR_SIZE];
|
||||
} auth_url;
|
||||
|
||||
|
||||
static void auth_url_clear(auth_t *self)
|
||||
{
|
||||
auth_url *url = self->state;
|
||||
curl_easy_cleanup (url->handle);
|
||||
free (url->username);
|
||||
free (url->password);
|
||||
free (url->removeurl);
|
||||
free (url->addurl);
|
||||
free (url->stream_start);
|
||||
free (url->stream_end);
|
||||
free (url->auth_header);
|
||||
free (url);
|
||||
}
|
||||
|
||||
|
||||
static int handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
auth_client *auth_user = stream;
|
||||
unsigned bytes = size * nmemb;
|
||||
client_t *client = auth_user->client;
|
||||
|
||||
if (client)
|
||||
{
|
||||
auth_t *auth = client->auth;
|
||||
auth_url *url = auth->state;
|
||||
if (strncasecmp (ptr, url->auth_header, url->auth_header_len) == 0)
|
||||
client->authenticated = 1;
|
||||
if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0)
|
||||
{
|
||||
char *eol;
|
||||
snprintf (url->errormsg, sizeof (url->errormsg), "%s", (char*)ptr+22);
|
||||
eol = strchr (url->errormsg, '\r');
|
||||
if (eol == NULL)
|
||||
eol = strchr (url->errormsg, '\n');
|
||||
if (eol)
|
||||
*eol = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return (int)bytes;
|
||||
}
|
||||
|
||||
/* capture returned data, but don't do anything with it */
|
||||
static int handle_returned_data (void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
return (int)(size*nmemb);
|
||||
}
|
||||
|
||||
|
||||
static auth_result url_remove_client (auth_client *auth_user)
|
||||
{
|
||||
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;
|
||||
ice_config_t *config;
|
||||
int port;
|
||||
char post [4096];
|
||||
|
||||
config = config_get_config ();
|
||||
server = util_url_escape (config->hostname);
|
||||
port = config->port;
|
||||
config_release_config ();
|
||||
|
||||
if (client->username)
|
||||
username = util_url_escape (client->username);
|
||||
else
|
||||
username = strdup ("");
|
||||
|
||||
if (client->password)
|
||||
password = util_url_escape (client->password);
|
||||
else
|
||||
password = strdup ("");
|
||||
|
||||
/* get the full uri (with query params if available) */
|
||||
mount = httpp_getvar (client->parser, HTTPP_VAR_RAWURI);
|
||||
if (mount == NULL)
|
||||
mount = httpp_getvar (client->parser, HTTPP_VAR_URI);
|
||||
mount = util_url_escape (mount);
|
||||
|
||||
snprintf (post, sizeof (post),
|
||||
"action=remove&server=%s&port=%d&client=%lu&mount=%s"
|
||||
"&user=%s&pass=%s&duration=%lu",
|
||||
server, port, client->con->id, mount, username,
|
||||
password, (long unsigned)duration);
|
||||
free (server);
|
||||
free (mount);
|
||||
free (username);
|
||||
free (password);
|
||||
|
||||
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);
|
||||
|
||||
if (curl_easy_perform (url->handle))
|
||||
WARN2 ("auth to server %s failed with %s", url->removeurl, url->errormsg);
|
||||
|
||||
return AUTH_OK;
|
||||
}
|
||||
|
||||
|
||||
static auth_result url_add_client (auth_client *auth_user)
|
||||
{
|
||||
client_t *client = auth_user->client;
|
||||
auth_t *auth = client->auth;
|
||||
auth_url *url = auth->state;
|
||||
int res = 0, port;
|
||||
char *agent, *user_agent, *username, *password;
|
||||
char *mount, *ipaddr, *server;
|
||||
ice_config_t *config;
|
||||
char post [4096];
|
||||
|
||||
if (url->addurl == NULL)
|
||||
return AUTH_OK;
|
||||
|
||||
config = config_get_config ();
|
||||
server = util_url_escape (config->hostname);
|
||||
port = config->port;
|
||||
config_release_config ();
|
||||
agent = httpp_getvar (client->parser, "user-agent");
|
||||
if (agent == NULL)
|
||||
agent = "-";
|
||||
user_agent = util_url_escape (agent);
|
||||
if (client->username)
|
||||
username = util_url_escape (client->username);
|
||||
else
|
||||
username = strdup ("");
|
||||
if (client->password)
|
||||
password = util_url_escape (client->password);
|
||||
else
|
||||
password = strdup ("");
|
||||
|
||||
/* get the full uri (with query params if available) */
|
||||
mount = httpp_getvar (client->parser, HTTPP_VAR_RAWURI);
|
||||
if (mount == NULL)
|
||||
mount = httpp_getvar (client->parser, HTTPP_VAR_URI);
|
||||
mount = util_url_escape (mount);
|
||||
ipaddr = util_url_escape (client->con->ip);
|
||||
|
||||
snprintf (post, sizeof (post),
|
||||
"action=auth&server=%s&port=%d&client=%lu&mount=%s"
|
||||
"&user=%s&pass=%s&ip=%s&agent=%s",
|
||||
server, port, client->con->id, mount, username,
|
||||
password, ipaddr, user_agent);
|
||||
free (server);
|
||||
free (mount);
|
||||
free (user_agent);
|
||||
free (username);
|
||||
free (password);
|
||||
free (ipaddr);
|
||||
|
||||
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);
|
||||
url->errormsg[0] = '\0';
|
||||
|
||||
res = curl_easy_perform (url->handle);
|
||||
|
||||
if (res)
|
||||
{
|
||||
WARN2 ("auth to server %s failed with %s", url->addurl, url->errormsg);
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
/* we received a response, lets see what it is */
|
||||
if (client->authenticated)
|
||||
return AUTH_OK;
|
||||
INFO2 ("client auth (%s) failed with \"%s\"", url->addurl, url->errormsg);
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
|
||||
|
||||
/* called by auth thread when a source starts, there is no client_t in
|
||||
* this case
|
||||
*/
|
||||
static void url_stream_start (auth_client *auth_user)
|
||||
{
|
||||
char *mount, *server;
|
||||
ice_config_t *config = config_get_config ();
|
||||
mount_proxy *mountinfo = config_find_mount (config, auth_user->mount);
|
||||
auth_t *auth = mountinfo->auth;
|
||||
auth_url *url = auth->state;
|
||||
char *stream_start_url;
|
||||
int port;
|
||||
char post [4096];
|
||||
|
||||
if (url->stream_start == NULL)
|
||||
{
|
||||
config_release_config ();
|
||||
return;
|
||||
}
|
||||
server = util_url_escape (config->hostname);
|
||||
port = config->port;
|
||||
stream_start_url = strdup (url->stream_start);
|
||||
/* we don't want this auth disappearing from under us while
|
||||
* the connection is in progress */
|
||||
mountinfo->auth->refcount++;
|
||||
config_release_config ();
|
||||
mount = util_url_escape (auth_user->mount);
|
||||
|
||||
snprintf (post, sizeof (post),
|
||||
"action=start&mount=%s&server=%s&port=%d", mount, server, port);
|
||||
free (server);
|
||||
free (mount);
|
||||
|
||||
curl_easy_setopt (url->handle, CURLOPT_URL, stream_start_url);
|
||||
curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
|
||||
curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);
|
||||
|
||||
if (curl_easy_perform (url->handle))
|
||||
WARN2 ("auth to server %s failed with %s", stream_start_url, url->errormsg);
|
||||
|
||||
auth_release (auth);
|
||||
free (stream_start_url);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void url_stream_end (auth_client *auth_user)
|
||||
{
|
||||
char *mount, *server;
|
||||
ice_config_t *config = config_get_config ();
|
||||
mount_proxy *mountinfo = config_find_mount (config, auth_user->mount);
|
||||
auth_t *auth = mountinfo->auth;
|
||||
auth_url *url = auth->state;
|
||||
char *stream_end_url;
|
||||
int port;
|
||||
char post [4096];
|
||||
|
||||
if (url->stream_end == NULL)
|
||||
{
|
||||
config_release_config ();
|
||||
return;
|
||||
}
|
||||
server = util_url_escape (config->hostname);
|
||||
port = config->port;
|
||||
stream_end_url = strdup (url->stream_end);
|
||||
/* we don't want this auth disappearing from under us while
|
||||
* the connection is in progress */
|
||||
mountinfo->auth->refcount++;
|
||||
config_release_config ();
|
||||
mount = util_url_escape (auth_user->mount);
|
||||
|
||||
snprintf (post, sizeof (post),
|
||||
"action=end&mount=%s&server=%s&port=%d", mount, server, port);
|
||||
free (server);
|
||||
free (mount);
|
||||
|
||||
curl_easy_setopt (url->handle, CURLOPT_URL, stream_end_url);
|
||||
curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
|
||||
curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);
|
||||
|
||||
if (curl_easy_perform (url->handle))
|
||||
WARN2 ("auth to server %s failed with %s", stream_end_url, url->errormsg);
|
||||
|
||||
auth_release (auth);
|
||||
free (stream_end_url);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static auth_result auth_url_adduser(auth_t *auth, const char *username, const char *password)
|
||||
{
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
|
||||
static auth_result auth_url_deleteuser (auth_t *auth, const char *username)
|
||||
{
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
|
||||
static auth_result auth_url_listuser (auth_t *auth, xmlNodePtr srcnode)
|
||||
{
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
|
||||
int auth_get_url_auth (auth_t *authenticator, config_options_t *options)
|
||||
{
|
||||
auth_url *url_info;
|
||||
|
||||
authenticator->authenticate = url_add_client;
|
||||
authenticator->release_client = url_remove_client;
|
||||
|
||||
authenticator->free = auth_url_clear;
|
||||
authenticator->adduser = auth_url_adduser;
|
||||
authenticator->deleteuser = auth_url_deleteuser;
|
||||
authenticator->listuser = auth_url_listuser;
|
||||
|
||||
authenticator->stream_start = url_stream_start;
|
||||
authenticator->stream_end = url_stream_end;
|
||||
|
||||
url_info = calloc(1, sizeof(auth_url));
|
||||
url_info->auth_header = strdup ("icecast-auth-user: 1\r\n");
|
||||
|
||||
while(options) {
|
||||
if(!strcmp(options->name, "username"))
|
||||
url_info->username = strdup (options->value);
|
||||
if(!strcmp(options->name, "password"))
|
||||
url_info->password = strdup (options->value);
|
||||
if(!strcmp(options->name, "add"))
|
||||
url_info->addurl = strdup (options->value);
|
||||
if(!strcmp(options->name, "remove"))
|
||||
url_info->removeurl = strdup (options->value);
|
||||
if(!strcmp(options->name, "start"))
|
||||
url_info->stream_start = strdup (options->value);
|
||||
if(!strcmp(options->name, "end"))
|
||||
url_info->stream_end = strdup (options->value);
|
||||
if(!strcmp(options->name, "auth_header"))
|
||||
{
|
||||
free (url_info->auth_header);
|
||||
url_info->auth_header = strdup (options->value);
|
||||
}
|
||||
options = options->next;
|
||||
}
|
||||
url_info->handle = curl_easy_init ();
|
||||
if (url_info->handle == NULL)
|
||||
{
|
||||
free (url_info);
|
||||
return -1;
|
||||
}
|
||||
if (url_info->auth_header)
|
||||
url_info->auth_header_len = strlen (url_info->auth_header);
|
||||
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_USERAGENT, ICECAST_VERSION_STRING);
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_HEADERFUNCTION, handle_returned_header);
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_WRITEFUNCTION, handle_returned_data);
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_WRITEDATA, url_info->handle);
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_TIMEOUT, 15L);
|
||||
curl_easy_setopt (url_info->handle, CURLOPT_ERRORBUFFER, &url_info->errormsg[0]);
|
||||
|
||||
authenticator->state = url_info;
|
||||
INFO0("URL based authentication setup");
|
||||
return 0;
|
||||
}
|
||||
|
24
src/auth_url.h
Normal file
24
src/auth_url.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* Icecast
|
||||
*
|
||||
* This program is distributed under the GNU General Public License, version 2.
|
||||
* A copy of this license is included with this source.
|
||||
*
|
||||
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
|
||||
* Michael Smith <msmith@xiph.org>,
|
||||
* oddsock <oddsock@xiph.org>,
|
||||
* Karl Heyes <karl@xiph.org>
|
||||
* and others (see AUTHORS for details).
|
||||
*/
|
||||
|
||||
#ifndef __AUTH_URL_H__
|
||||
#define __AUTH_URL_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
int *auth_get_url_auth (auth_t *authenticator, config_options_t *options);
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user