2004-01-28 20:02:12 -05:00
|
|
|
/* 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).
|
|
|
|
*/
|
|
|
|
|
2004-01-14 20:01:09 -05:00
|
|
|
/**
|
|
|
|
* Client authentication functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "auth.h"
|
2005-08-07 19:01:04 -04:00
|
|
|
#include "auth_htpasswd.h"
|
2005-08-07 19:29:12 -04:00
|
|
|
#include "auth_url.h"
|
2004-01-14 20:01:09 -05:00
|
|
|
#include "source.h"
|
|
|
|
#include "client.h"
|
|
|
|
#include "cfgfile.h"
|
2005-08-07 19:01:04 -04:00
|
|
|
#include "stats.h"
|
2004-01-14 20:01:09 -05:00
|
|
|
#include "httpp/httpp.h"
|
2005-08-08 14:39:34 -04:00
|
|
|
#include "fserve.h"
|
2004-01-14 20:01:09 -05:00
|
|
|
|
|
|
|
#include "logging.h"
|
|
|
|
#define CATMODULE "auth"
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
static mutex_t auth_lock;
|
|
|
|
|
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
static auth_client *auth_client_setup (const char *mount, client_t *client)
|
2004-05-17 00:33:46 -04:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
/* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
|
2007-08-16 18:49:13 -04:00
|
|
|
const char *header = httpp_getvar(client->parser, "authorization");
|
2005-08-07 19:01:04 -04:00
|
|
|
char *userpass, *tmp;
|
|
|
|
char *username, *password;
|
2007-11-08 14:52:51 -05:00
|
|
|
auth_client *auth_user;
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (header == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (strncmp(header, "Basic ", 6) == 0)
|
|
|
|
{
|
|
|
|
userpass = util_base64_decode (header+6);
|
|
|
|
if (userpass == NULL)
|
|
|
|
{
|
|
|
|
WARN1("Base64 decode of Authorization header \"%s\" failed",
|
|
|
|
header+6);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = strchr(userpass, ':');
|
|
|
|
if (tmp == NULL)
|
|
|
|
{
|
|
|
|
free (userpass);
|
|
|
|
break;
|
2004-05-17 00:33:46 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
*tmp = 0;
|
|
|
|
username = userpass;
|
|
|
|
password = tmp+1;
|
|
|
|
client->username = strdup (username);
|
|
|
|
client->password = strdup (password);
|
|
|
|
free (userpass);
|
|
|
|
break;
|
2004-05-17 00:33:46 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
INFO1 ("unhandled authorization header: %s", header);
|
2004-05-17 00:33:46 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
} while (0);
|
2004-05-17 00:33:46 -04:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
auth_user = calloc (1, sizeof(auth_client));
|
|
|
|
auth_user->mount = strdup (mount);
|
|
|
|
auth_user->client = client;
|
|
|
|
return auth_user;
|
2004-05-17 00:33:46 -04:00
|
|
|
}
|
|
|
|
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
static void queue_auth_client (auth_client *auth_user, mount_proxy *mountinfo)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
2007-08-21 18:30:30 -04:00
|
|
|
auth_t *auth;
|
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
if (auth_user == NULL || (mountinfo == NULL && auth_user->client
|
|
|
|
&& auth_user->client->auth == NULL))
|
2007-08-21 18:30:30 -04:00
|
|
|
return;
|
|
|
|
auth_user->next = NULL;
|
2007-11-08 14:52:51 -05:00
|
|
|
if (mountinfo)
|
|
|
|
{
|
|
|
|
auth = mountinfo->auth;
|
|
|
|
thread_mutex_lock (&auth->lock);
|
|
|
|
if (auth_user->client)
|
|
|
|
auth_user->client->auth = auth;
|
|
|
|
auth->refcount++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auth = auth_user->client->auth;
|
|
|
|
thread_mutex_lock (&auth->lock);
|
|
|
|
}
|
|
|
|
DEBUG2 ("...refcount on auth_t %s is now %d", auth->mount, auth->refcount);
|
2007-08-21 18:30:30 -04:00
|
|
|
*auth->tailp = auth_user;
|
|
|
|
auth->tailp = &auth_user->next;
|
|
|
|
auth->pending_count++;
|
|
|
|
INFO2 ("auth on %s has %d pending", auth->mount, auth->pending_count);
|
|
|
|
thread_mutex_unlock (&auth->lock);
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* release the auth. It is referred to by multiple structures so this is
|
|
|
|
* refcounted and only actual freed after the last use
|
|
|
|
*/
|
|
|
|
void auth_release (auth_t *authenticator)
|
|
|
|
{
|
|
|
|
if (authenticator == NULL)
|
|
|
|
return;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-09-01 12:11:07 -04:00
|
|
|
thread_mutex_lock (&authenticator->lock);
|
2005-08-07 19:01:04 -04:00
|
|
|
authenticator->refcount--;
|
2007-08-21 18:30:30 -04:00
|
|
|
DEBUG2 ("...refcount on auth_t %s is now %d", authenticator->mount, authenticator->refcount);
|
2005-08-07 19:01:04 -04:00
|
|
|
if (authenticator->refcount)
|
2005-09-01 12:11:07 -04:00
|
|
|
{
|
|
|
|
thread_mutex_unlock (&authenticator->lock);
|
2005-08-07 19:01:04 -04:00
|
|
|
return;
|
2005-09-01 12:11:07 -04:00
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
/* cleanup auth thread attached to this auth */
|
|
|
|
authenticator->running = 0;
|
|
|
|
thread_join (authenticator->thread);
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (authenticator->free)
|
|
|
|
authenticator->free (authenticator);
|
2005-08-11 18:56:51 -04:00
|
|
|
xmlFree (authenticator->type);
|
2005-09-01 12:11:07 -04:00
|
|
|
thread_mutex_unlock (&authenticator->lock);
|
|
|
|
thread_mutex_destroy (&authenticator->lock);
|
2007-08-21 18:30:30 -04:00
|
|
|
free (authenticator->mount);
|
2005-08-07 19:01:04 -04:00
|
|
|
free (authenticator);
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
static void auth_client_free (auth_client *auth_user)
|
2004-01-14 20:01:09 -05:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
if (auth_user == NULL)
|
|
|
|
return;
|
|
|
|
if (auth_user->client)
|
|
|
|
{
|
|
|
|
client_t *client = auth_user->client;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (client->respcode)
|
|
|
|
client_destroy (client);
|
|
|
|
else
|
|
|
|
client_send_401 (client);
|
|
|
|
auth_user->client = NULL;
|
|
|
|
}
|
|
|
|
free (auth_user->mount);
|
|
|
|
free (auth_user);
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
/* verify that the listener is still connected. */
|
|
|
|
static int is_listener_connected (client_t *client)
|
|
|
|
{
|
|
|
|
int ret = 1;
|
|
|
|
if (client)
|
|
|
|
{
|
|
|
|
if (sock_active (client->con->sock) == 0)
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* wrapper function for auth thread to authenticate new listener
|
|
|
|
* connection details
|
|
|
|
*/
|
2007-11-08 14:52:51 -05:00
|
|
|
static void auth_new_listener (auth_t *auth, auth_client *auth_user)
|
2004-01-14 20:01:09 -05:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
client_t *client = auth_user->client;
|
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
/* make sure there is still a client at this point, a slow backend request
|
|
|
|
* can be avoided if client has disconnected */
|
|
|
|
if (is_listener_connected (client) == 0)
|
|
|
|
{
|
|
|
|
DEBUG0 ("listener is no longer connected");
|
|
|
|
client->respcode = 400;
|
2008-04-22 22:48:53 -04:00
|
|
|
auth_release (client->auth);
|
|
|
|
client->auth = NULL;
|
2007-08-21 18:30:30 -04:00
|
|
|
return;
|
|
|
|
}
|
2007-11-08 14:52:51 -05:00
|
|
|
if (auth->authenticate)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
2007-11-08 14:52:51 -05:00
|
|
|
if (auth->authenticate (auth_user) != AUTH_OK)
|
2008-04-22 22:48:53 -04:00
|
|
|
{
|
|
|
|
auth_release (client->auth);
|
|
|
|
client->auth = NULL;
|
2005-08-07 19:01:04 -04:00
|
|
|
return;
|
2008-04-22 22:48:53 -04:00
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
2007-08-21 18:30:30 -04:00
|
|
|
if (auth_postprocess_listener (auth_user) < 0)
|
2008-04-22 22:48:53 -04:00
|
|
|
{
|
|
|
|
auth_release (client->auth);
|
|
|
|
client->auth = NULL;
|
2005-08-07 19:01:04 -04:00
|
|
|
INFO1 ("client %lu failed", client->con->id);
|
2008-04-22 22:48:53 -04:00
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
/* wrapper function for auth thread to drop listener connections
|
2005-08-07 19:01:04 -04:00
|
|
|
*/
|
2007-11-08 14:52:51 -05:00
|
|
|
static void auth_remove_listener (auth_t *auth, auth_client *auth_user)
|
2004-01-14 20:01:09 -05:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
client_t *client = auth_user->client;
|
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
if (client->auth->release_listener)
|
|
|
|
client->auth->release_listener (auth_user);
|
2005-08-07 19:01:04 -04:00
|
|
|
auth_release (client->auth);
|
|
|
|
client->auth = NULL;
|
2007-08-21 18:30:30 -04:00
|
|
|
/* client is going, so auth is not an issue at this point */
|
|
|
|
client->authenticated = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Callback from auth thread to handle a stream start event, this applies
|
|
|
|
* to both source clients and relays.
|
|
|
|
*/
|
2007-11-08 14:52:51 -05:00
|
|
|
static void stream_start_callback (auth_t *auth, auth_client *auth_user)
|
2007-08-21 18:30:30 -04:00
|
|
|
{
|
|
|
|
if (auth->stream_start)
|
|
|
|
auth->stream_start (auth_user);
|
2007-11-08 14:52:51 -05:00
|
|
|
auth_release (auth);
|
2007-08-21 18:30:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Callback from auth thread to handle a stream start event, this applies
|
|
|
|
* to both source clients and relays.
|
|
|
|
*/
|
2007-11-08 14:52:51 -05:00
|
|
|
static void stream_end_callback (auth_t *auth, auth_client *auth_user)
|
2007-08-21 18:30:30 -04:00
|
|
|
{
|
|
|
|
if (auth->stream_end)
|
|
|
|
auth->stream_end (auth_user);
|
2007-11-08 14:52:51 -05:00
|
|
|
auth_release (auth);
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* The auth thread main loop. */
|
|
|
|
static void *auth_run_thread (void *arg)
|
|
|
|
{
|
2007-08-21 18:30:30 -04:00
|
|
|
auth_t *auth = arg;
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
INFO0 ("Authentication thread started");
|
2007-08-21 18:30:30 -04:00
|
|
|
while (auth->running)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
2007-08-21 18:30:30 -04:00
|
|
|
/* usually no clients are waiting, so don't bother taking locks */
|
|
|
|
if (auth->head)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
auth_client *auth_user;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
/* may become NULL before lock taken */
|
|
|
|
thread_mutex_lock (&auth->lock);
|
|
|
|
auth_user = (auth_client*)auth->head;
|
|
|
|
if (auth_user == NULL)
|
|
|
|
{
|
|
|
|
thread_mutex_unlock (&auth->lock);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
DEBUG2 ("%d client(s) pending on %s", auth->pending_count, auth->mount);
|
|
|
|
auth->head = auth_user->next;
|
|
|
|
if (auth->head == NULL)
|
|
|
|
auth->tailp = &auth->head;
|
|
|
|
auth->pending_count--;
|
|
|
|
thread_mutex_unlock (&auth->lock);
|
2005-08-07 19:01:04 -04:00
|
|
|
auth_user->next = NULL;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (auth_user->process)
|
2007-11-08 14:52:51 -05:00
|
|
|
auth_user->process (auth, auth_user);
|
2005-08-07 19:01:04 -04:00
|
|
|
else
|
|
|
|
ERROR0 ("client auth process not set");
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
auth_client_free (auth_user);
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
continue;
|
2004-05-17 00:33:46 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
thread_sleep (150000);
|
2004-05-17 00:33:46 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
INFO0 ("Authenication thread shutting down");
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* Check whether this client is currently on this mount, the client may be
|
|
|
|
* on either the active or pending lists.
|
|
|
|
* return 1 if ok to add or 0 to prevent
|
|
|
|
*/
|
2007-11-08 14:52:51 -05:00
|
|
|
static int check_duplicate_logins (source_t *source, client_t *client, auth_t *auth)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
/* allow multiple authenticated relays */
|
|
|
|
if (client->username == NULL)
|
|
|
|
return 1;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (auth && auth->allow_duplicate_users == 0)
|
|
|
|
{
|
|
|
|
avl_node *node;
|
|
|
|
|
|
|
|
avl_tree_rlock (source->client_tree);
|
|
|
|
node = avl_get_first (source->client_tree);
|
|
|
|
while (node)
|
|
|
|
{
|
2005-09-10 12:56:04 -04:00
|
|
|
client_t *existing_client = (client_t *)node->key;
|
|
|
|
if (existing_client->username &&
|
|
|
|
strcmp (existing_client->username, client->username) == 0)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
avl_tree_unlock (source->client_tree);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
node = avl_get_next (node);
|
|
|
|
}
|
|
|
|
avl_tree_unlock (source->client_tree);
|
|
|
|
|
|
|
|
avl_tree_rlock (source->pending_tree);
|
|
|
|
node = avl_get_first (source->pending_tree);
|
|
|
|
while (node)
|
|
|
|
{
|
2005-09-10 12:56:04 -04:00
|
|
|
client_t *existing_client = (client_t *)node->key;
|
|
|
|
if (existing_client->username &&
|
|
|
|
strcmp (existing_client->username, client->username) == 0)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
avl_tree_unlock (source->pending_tree);
|
|
|
|
return 0;
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
node = avl_get_next (node);
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
avl_tree_unlock (source->pending_tree);
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
return 1;
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
/* if 0 is returned then the client should not be touched, however if -1
|
|
|
|
* is returned then the caller is responsible for handling the client
|
|
|
|
*/
|
2007-08-21 18:30:30 -04:00
|
|
|
static int add_listener_to_source (source_t *source, client_t *client)
|
2004-01-14 20:01:09 -05:00
|
|
|
{
|
2005-08-23 14:40:20 -04:00
|
|
|
int loop = 10;
|
2005-08-07 19:01:04 -04:00
|
|
|
do
|
|
|
|
{
|
|
|
|
DEBUG3 ("max on %s is %ld (cur %lu)", source->mount,
|
|
|
|
source->max_listeners, source->listeners);
|
|
|
|
if (source->max_listeners == -1)
|
|
|
|
break;
|
|
|
|
if (source->listeners < (unsigned long)source->max_listeners)
|
|
|
|
break;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-23 14:40:20 -04:00
|
|
|
if (loop && source->fallback_when_full && source->fallback_mount)
|
|
|
|
{
|
|
|
|
source_t *next = source_find_mount (source->fallback_mount);
|
2006-03-07 14:12:43 -05:00
|
|
|
if (!next) {
|
2006-03-07 14:27:54 -05:00
|
|
|
ERROR2("Fallback '%s' for full source '%s' not found",
|
2006-03-07 14:12:43 -05:00
|
|
|
source->mount, source->fallback_mount);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-08-23 14:40:20 -04:00
|
|
|
INFO1 ("stream full trying %s", next->mount);
|
|
|
|
source = next;
|
|
|
|
loop--;
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
/* now we fail the client */
|
|
|
|
return -1;
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
} while (1);
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
client->write_to_client = format_generic_write_to_client;
|
|
|
|
client->check_buffer = format_check_http_buffer;
|
|
|
|
client->refbuf->len = PER_CLIENT_REFBUF_SIZE;
|
|
|
|
memset (client->refbuf->data, 0, PER_CLIENT_REFBUF_SIZE);
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-09-16 12:53:33 -04:00
|
|
|
/* lets add the client to the active list */
|
|
|
|
avl_tree_wlock (source->pending_tree);
|
|
|
|
avl_insert (source->pending_tree, client);
|
|
|
|
avl_tree_unlock (source->pending_tree);
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (source->running == 0 && source->on_demand)
|
|
|
|
{
|
|
|
|
/* enable on-demand relay to start, wake up the slave thread */
|
|
|
|
DEBUG0("kicking off on-demand relay");
|
|
|
|
source->on_demand_req = 1;
|
2004-01-14 20:01:09 -05:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
DEBUG1 ("Added client to %s", source->mount);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-01-14 20:01:09 -05:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* Add listener to the pending lists of either the source or fserve thread.
|
|
|
|
* This can be run from the connection or auth thread context
|
|
|
|
*/
|
2007-08-21 18:30:30 -04:00
|
|
|
static int add_authenticated_listener (const char *mount, mount_proxy *mountinfo, client_t *client)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
source_t *source = NULL;
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
client->authenticated = 1;
|
|
|
|
|
2007-08-25 12:04:33 -04:00
|
|
|
/* Here we are parsing the URI request to see if the extension is .xsl, if
|
|
|
|
* so, then process this request as an XSLT request
|
|
|
|
*/
|
|
|
|
if (util_check_valid_extension (mount) == XSLT_CONTENT)
|
|
|
|
{
|
|
|
|
/* If the file exists, then transform it, otherwise, write a 404 */
|
|
|
|
DEBUG0("Stats request, sending XSL transformed stats");
|
|
|
|
stats_transform_xslt (client, mount);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
avl_tree_rlock (global.source_tree);
|
|
|
|
source = source_find_mount (mount);
|
2004-01-14 20:01:09 -05:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (source)
|
|
|
|
{
|
2005-08-24 20:07:17 -04:00
|
|
|
if (mountinfo)
|
|
|
|
{
|
2007-12-15 12:21:22 -05:00
|
|
|
if (check_duplicate_logins (source, client, mountinfo->auth) == 0)
|
|
|
|
{
|
|
|
|
avl_tree_unlock (global.source_tree);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-08-24 20:07:17 -04:00
|
|
|
/* set a per-mount disconnect time if auth hasn't set one already */
|
|
|
|
if (mountinfo->max_listener_duration && client->con->discon_time == 0)
|
|
|
|
client->con->discon_time = time(NULL) + mountinfo->max_listener_duration;
|
|
|
|
}
|
2005-08-23 15:00:15 -04:00
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
ret = add_listener_to_source (source, client);
|
2005-08-07 19:01:04 -04:00
|
|
|
avl_tree_unlock (global.source_tree);
|
|
|
|
if (ret == 0)
|
|
|
|
DEBUG0 ("client authenticated, passed to source");
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
2005-08-08 14:39:34 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
avl_tree_unlock (global.source_tree);
|
|
|
|
fserve_client_create (client, mount);
|
|
|
|
}
|
2004-04-30 10:36:07 -04:00
|
|
|
return ret;
|
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
int auth_postprocess_listener (auth_client *auth_user)
|
2004-04-30 10:36:07 -04:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
int ret;
|
2007-08-21 18:30:30 -04:00
|
|
|
client_t *client = auth_user->client;
|
2005-08-07 19:01:04 -04:00
|
|
|
ice_config_t *config = config_get_config();
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
mount_proxy *mountinfo = config_find_mount (config, auth_user->mount);
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
ret = add_authenticated_listener (auth_user->mount, mountinfo, client);
|
2005-08-07 19:01:04 -04:00
|
|
|
config_release_config();
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
if (ret < 0)
|
|
|
|
client_send_401 (auth_user->client);
|
|
|
|
auth_user->client = NULL;
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
return ret;
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
/* Add a listener. Check for any mount information that states any
|
|
|
|
* authentication to be used.
|
|
|
|
*/
|
2007-08-21 18:30:30 -04:00
|
|
|
void auth_add_listener (const char *mount, client_t *client)
|
2004-04-30 10:36:07 -04:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
mount_proxy *mountinfo;
|
|
|
|
ice_config_t *config = config_get_config();
|
|
|
|
|
|
|
|
mountinfo = config_find_mount (config, mount);
|
|
|
|
if (mountinfo && mountinfo->no_mount)
|
|
|
|
{
|
|
|
|
config_release_config ();
|
2005-11-16 19:54:28 -05:00
|
|
|
client_send_403 (client, "mountpoint unavailable");
|
2005-08-07 19:01:04 -04:00
|
|
|
return;
|
|
|
|
}
|
2008-09-07 20:40:25 -04:00
|
|
|
if (mountinfo && mountinfo->auth)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
auth_client *auth_user;
|
|
|
|
|
2007-08-21 18:30:30 -04:00
|
|
|
if (mountinfo->auth->pending_count > 100)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
config_release_config ();
|
|
|
|
WARN0 ("too many clients awaiting authentication");
|
2005-11-16 19:54:28 -05:00
|
|
|
client_send_403 (client, "busy, please try again later");
|
2005-08-07 19:01:04 -04:00
|
|
|
return;
|
|
|
|
}
|
2007-11-08 14:52:51 -05:00
|
|
|
auth_user = auth_client_setup (mount, client);
|
2005-08-07 19:01:04 -04:00
|
|
|
auth_user->process = auth_new_listener;
|
|
|
|
INFO0 ("adding client for authentication");
|
2007-11-08 14:52:51 -05:00
|
|
|
queue_auth_client (auth_user, mountinfo);
|
|
|
|
config_release_config ();
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-08-21 18:30:30 -04:00
|
|
|
int ret = add_authenticated_listener (mount, mountinfo, client);
|
2005-08-07 19:01:04 -04:00
|
|
|
config_release_config ();
|
|
|
|
if (ret < 0)
|
2005-11-16 19:54:28 -05:00
|
|
|
client_send_403 (client, "max listeners reached");
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
|
|
|
|
/* determine whether we need to process this client further. This
|
|
|
|
* involves any auth exit, typically for external auth servers.
|
|
|
|
*/
|
2007-08-21 18:30:30 -04:00
|
|
|
int auth_release_listener (client_t *client)
|
2004-04-30 10:36:07 -04:00
|
|
|
{
|
2007-11-08 14:52:51 -05:00
|
|
|
if (client->authenticated)
|
2005-06-08 22:21:03 -04:00
|
|
|
{
|
2007-11-08 14:52:51 -05:00
|
|
|
const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI);
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
/* drop any queue reference here, we do not want a race between the source thread
|
|
|
|
* and the auth/fserve thread */
|
|
|
|
client_set_queue (client, NULL);
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
if (mount && client->auth && client->auth->release_listener)
|
|
|
|
{
|
|
|
|
auth_client *auth_user = auth_client_setup (mount, client);
|
|
|
|
auth_user->process = auth_remove_listener;
|
|
|
|
queue_auth_client (auth_user, NULL);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
client->authenticated = 0;
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2004-04-30 10:36:07 -04:00
|
|
|
|
|
|
|
|
2007-08-23 12:58:18 -04:00
|
|
|
static int get_authenticator (auth_t *auth, config_options_t *options)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
2007-09-21 21:21:17 -04:00
|
|
|
if (auth->type == NULL)
|
|
|
|
{
|
|
|
|
WARN0 ("no authentication type defined");
|
|
|
|
return -1;
|
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
do
|
|
|
|
{
|
|
|
|
DEBUG1 ("type is %s", auth->type);
|
2007-08-21 18:30:30 -04:00
|
|
|
|
2005-08-07 19:29:12 -04:00
|
|
|
if (strcmp (auth->type, "url") == 0)
|
|
|
|
{
|
2007-08-21 18:30:30 -04:00
|
|
|
#ifdef HAVE_AUTH_URL
|
2007-08-23 12:58:18 -04:00
|
|
|
if (auth_get_url_auth (auth, options) < 0)
|
|
|
|
return -1;
|
2007-10-19 21:55:18 -04:00
|
|
|
break;
|
2007-08-21 18:30:30 -04:00
|
|
|
#else
|
|
|
|
ERROR0 ("Auth URL disabled");
|
2007-08-23 12:58:18 -04:00
|
|
|
return -1;
|
2007-08-21 18:30:30 -04:00
|
|
|
#endif
|
2005-08-07 19:29:12 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
if (strcmp (auth->type, "htpasswd") == 0)
|
|
|
|
{
|
2007-08-23 12:58:18 -04:00
|
|
|
if (auth_get_htpasswd_auth (auth, options) < 0)
|
|
|
|
return -1;
|
2005-08-07 19:01:04 -04:00
|
|
|
break;
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
2007-08-23 12:58:18 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
ERROR1("Unrecognised authenticator type: \"%s\"", auth->type);
|
2007-08-23 12:58:18 -04:00
|
|
|
return -1;
|
2005-08-07 19:01:04 -04:00
|
|
|
} while (0);
|
|
|
|
|
|
|
|
while (options)
|
|
|
|
{
|
2007-10-04 12:48:38 -04:00
|
|
|
if (strcmp (options->name, "allow_duplicate_users") == 0)
|
|
|
|
auth->allow_duplicate_users = atoi ((char*)options->value);
|
2005-08-07 19:01:04 -04:00
|
|
|
options = options->next;
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
2007-08-23 12:58:18 -04:00
|
|
|
return 0;
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
2004-04-30 10:36:07 -04:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
auth_t *auth_get_authenticator (xmlNodePtr node)
|
|
|
|
{
|
|
|
|
auth_t *auth = calloc (1, sizeof (auth_t));
|
|
|
|
config_options_t *options = NULL, **next_option = &options;
|
|
|
|
xmlNodePtr option;
|
|
|
|
|
|
|
|
if (auth == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
option = node->xmlChildrenNode;
|
|
|
|
while (option)
|
|
|
|
{
|
|
|
|
xmlNodePtr current = option;
|
|
|
|
option = option->next;
|
2007-10-04 12:48:38 -04:00
|
|
|
if (xmlStrcmp (current->name, XMLSTR("option")) == 0)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
config_options_t *opt = calloc (1, sizeof (config_options_t));
|
2007-10-04 12:48:38 -04:00
|
|
|
opt->name = (char *)xmlGetProp (current, XMLSTR("name"));
|
2005-08-07 19:01:04 -04:00
|
|
|
if (opt->name == NULL)
|
|
|
|
{
|
|
|
|
free(opt);
|
|
|
|
continue;
|
|
|
|
}
|
2007-10-04 12:48:38 -04:00
|
|
|
opt->value = (char *)xmlGetProp (current, XMLSTR("value"));
|
2005-08-07 19:01:04 -04:00
|
|
|
if (opt->value == NULL)
|
|
|
|
{
|
|
|
|
xmlFree (opt->name);
|
|
|
|
free (opt);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*next_option = opt;
|
|
|
|
next_option = &opt->next;
|
|
|
|
}
|
|
|
|
else
|
2007-10-04 12:48:38 -04:00
|
|
|
if (xmlStrcmp (current->name, XMLSTR("text")) != 0)
|
2005-08-07 19:01:04 -04:00
|
|
|
WARN1 ("unknown auth setting (%s)", current->name);
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
2007-10-04 12:48:38 -04:00
|
|
|
auth->type = (char*)xmlGetProp (node, XMLSTR("type"));
|
2007-08-23 12:58:18 -04:00
|
|
|
if (get_authenticator (auth, options) < 0)
|
|
|
|
{
|
|
|
|
xmlFree (auth->type);
|
|
|
|
free (auth);
|
|
|
|
auth = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auth->tailp = &auth->head;
|
|
|
|
thread_mutex_create (&auth->lock);
|
|
|
|
auth->refcount = 1;
|
|
|
|
auth->running = 1;
|
|
|
|
auth->thread = thread_create ("auth thread", auth_run_thread, auth, THREAD_ATTACHED);
|
|
|
|
}
|
2007-08-21 18:30:30 -04:00
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
while (options)
|
|
|
|
{
|
|
|
|
config_options_t *opt = options;
|
|
|
|
options = opt->next;
|
|
|
|
xmlFree (opt->name);
|
|
|
|
xmlFree (opt->value);
|
|
|
|
free (opt);
|
2004-05-03 10:59:40 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
return auth;
|
|
|
|
}
|
2004-04-30 10:36:07 -04:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* called when the stream starts, so that authentication engine can do any
|
|
|
|
* cleanup/initialisation.
|
|
|
|
*/
|
|
|
|
void auth_stream_start (mount_proxy *mountinfo, const char *mount)
|
2004-04-30 10:36:07 -04:00
|
|
|
{
|
2005-08-07 19:01:04 -04:00
|
|
|
if (mountinfo && mountinfo->auth && mountinfo->auth->stream_start)
|
|
|
|
{
|
|
|
|
auth_client *auth_user = calloc (1, sizeof (auth_client));
|
|
|
|
if (auth_user)
|
|
|
|
{
|
|
|
|
auth_user->mount = strdup (mount);
|
2007-08-21 18:30:30 -04:00
|
|
|
auth_user->process = stream_start_callback;
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
queue_auth_client (auth_user, mountinfo);
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* Called when the stream ends so that the authentication engine can do
|
|
|
|
* any authentication cleanup
|
|
|
|
*/
|
|
|
|
void auth_stream_end (mount_proxy *mountinfo, const char *mount)
|
|
|
|
{
|
|
|
|
if (mountinfo && mountinfo->auth && mountinfo->auth->stream_end)
|
|
|
|
{
|
|
|
|
auth_client *auth_user = calloc (1, sizeof (auth_client));
|
|
|
|
if (auth_user)
|
|
|
|
{
|
|
|
|
auth_user->mount = strdup (mount);
|
2007-08-21 18:30:30 -04:00
|
|
|
auth_user->process = stream_end_callback;
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2007-11-08 14:52:51 -05:00
|
|
|
queue_auth_client (auth_user, mountinfo);
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
2005-08-07 19:01:04 -04:00
|
|
|
}
|
2004-04-30 10:36:07 -04:00
|
|
|
|
|
|
|
|
2005-08-07 19:01:04 -04:00
|
|
|
/* these are called at server start and termination */
|
2004-04-30 10:36:07 -04:00
|
|
|
|
2005-12-17 07:23:09 -05:00
|
|
|
void auth_initialise (void)
|
2005-08-07 19:01:04 -04:00
|
|
|
{
|
|
|
|
thread_mutex_create (&auth_lock);
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
|
|
|
|
2005-12-17 07:23:09 -05:00
|
|
|
void auth_shutdown (void)
|
2004-04-30 10:36:07 -04:00
|
|
|
{
|
2007-08-21 18:30:30 -04:00
|
|
|
thread_mutex_destroy (&auth_lock);
|
|
|
|
INFO0 ("Auth shutdown");
|
2004-04-30 10:36:07 -04:00
|
|
|
}
|
2004-05-17 00:33:46 -04:00
|
|
|
|