[xiph-cvs] cvs commit: icecast/src auth.c auth.h md5.c md5.h Makefile.am admin.c cfgfile.c cfgfile.h client.c client.h compat.h connection.c connection.h format_vorbis.c slave.c source.c source.h util.c util.h

Michael Smith msmith at xiph.org
Wed Jan 14 17:01:10 PST 2004



msmith      04/01/14 20:01:10

  Modified:    src      Makefile.am admin.c cfgfile.c cfgfile.h client.c
                        client.h compat.h connection.c connection.h
                        format_vorbis.c slave.c source.c source.h util.c
                        util.h
  Added:       src      auth.c auth.h md5.c md5.h
  Log:
  Client authentication added.
  Melanie's multilevel fallbacks added (after major changes).

Revision  Changes    Path
1.21      +2 -2      icecast/src/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/Makefile.am,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- Makefile.am	27 Jul 2003 22:53:58 -0000	1.20
+++ Makefile.am	15 Jan 2004 01:01:09 -0000	1.21
@@ -8,10 +8,10 @@
 
 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 format.h format_vorbis.h\
-	 compat.h format_mp3.h fserve.h xslt.h geturl.h yp.h event.h
+	 compat.h format_mp3.h fserve.h xslt.h geturl.h yp.h event.h auth.h md5.h
 icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c\
          util.c slave.c source.c stats.c refbuf.c client.c format.c format_vorbis.c\
-	 format_mp3.c xslt.c fserve.c event.c admin.c
+	 format_mp3.c xslt.c fserve.c event.c admin.c auth.c md5.c
 EXTRA_icecast_SOURCES = geturl.c yp.c
     
 icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \

<p><p>1.16      +1 -1      icecast/src/admin.c

Index: admin.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/admin.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- admin.c	12 Dec 2003 23:06:44 -0000	1.15
+++ admin.c	15 Jan 2004 01:01:09 -0000	1.16
@@ -269,7 +269,7 @@
         }
         
         avl_tree_rlock(global.source_tree);
-        source = source_find_mount(mount);
+        source = source_find_mount_raw(mount);
         avl_tree_unlock(global.source_tree);
 
         if(source == NULL) {

<p><p>1.6       +51 -0     icecast/src/cfgfile.c

Index: cfgfile.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/cfgfile.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- cfgfile.c	12 Dec 2003 23:06:44 -0000	1.5
+++ cfgfile.c	15 Jan 2004 01:01:09 -0000	1.6
@@ -170,6 +170,17 @@
         xmlFree(mount->password);
         xmlFree(mount->dumpfile);
         xmlFree(mount->fallback_mount);
+
+        xmlFree(mount->auth_type);
+        config_options_t *option = mount->auth_options;
+        while(option) {
+            config_options_t *nextopt = option->next;
+            xmlFree(option->name);
+            xmlFree(option->value);
+            free(option);
+            option = nextopt;
+        }
+
         free(mount);
         mount = nextmount;
     }
@@ -483,6 +494,46 @@
             mount->max_listeners = atoi(tmp);
             if(tmp) xmlFree(tmp);
         }
+        else if (strcmp(node->name, "fallback-override") == 0) {
+            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+            mount->fallback_override = atoi(tmp);
+            if(tmp) xmlFree(tmp);
+        }
+        else if (strcmp(node->name, "no-mount") == 0) {
+            tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+            mount->no_mount = atoi(tmp);
+            if(tmp) xmlFree(tmp);
+        }
+        else if (strcmp(node->name, "authentication") == 0) {
+            mount->auth_type = xmlGetProp(node, "type");
+            xmlNodePtr option = node->xmlChildrenNode;
+            config_options_t *last = NULL;
+            while(option != NULL) {
+                if(strcmp(option->name, "option") == 0) {
+                    config_options_t *opt = malloc(sizeof(config_options_t));
+                    opt->name = xmlGetProp(option, "name");
+                    if(!opt->name) {
+                        free(opt);
+                        option = option->next;
+                        continue;
+                    }
+                    opt->value = xmlGetProp(option, "value");
+                    if(!opt->value) {
+                        free(opt->name);
+                        free(opt);
+                        option = option->next;
+                        continue;
+                    }
+
+                    if(last)
+                        last->next = opt;
+                    else
+                        mount->auth_options = opt;
+                    last = opt;
+                }
+                option = option->next;
+            }
+        }
     } while ((node = node->next));
 }
 

<p><p>1.5       +15 -1     icecast/src/cfgfile.h

Index: cfgfile.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/cfgfile.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- cfgfile.h	12 Dec 2003 23:06:44 -0000	1.4
+++ cfgfile.h	15 Jan 2004 01:01:09 -0000	1.5
@@ -29,6 +29,12 @@
     struct _relay_server *next;
 } relay_server;
 
+typedef struct _config_options {
+    char *name;
+    char *value;
+    struct _config_options *next;
+} config_options_t;
+
 typedef struct _mount_proxy {
     char *mountname; /* The mountpoint this proxy is used for */
 
@@ -39,7 +45,15 @@
                        to not dump. */
     int max_listeners; /* Max listeners for this mountpoint only. -1 to not 
                           limit here (i.e. only use the global limit) */
-    char *fallback_mount;
+    char *fallback_mount; /* Fallback mountname */
+
+    int fallback_override; /* When this source arrives, do we steal back
+                              clients from the fallback? */
+    int no_mount; /* Do we permit direct requests of this mountpoint? (or only
+                     indirect, through fallbacks) */
+
+    char *auth_type; /* Authentication type */
+    config_options_t *auth_options; /* Options for this type */
     struct _mount_proxy *next;
 } mount_proxy;
 

<p><p>1.11      +2 -0      icecast/src/client.c

Index: client.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/client.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- client.c	21 Jul 2003 01:58:54 -0000	1.10
+++ client.c	15 Jan 2004 01:01:09 -0000	1.11
@@ -49,6 +49,8 @@
     while ((refbuf = refbuf_queue_remove(&client->queue)))
         refbuf_release(refbuf);
 
+    free(client->username);
+
     free(client);
 }
 

<p><p>1.9       +7 -2      icecast/src/client.h

Index: client.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/client.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- client.h	15 Mar 2003 02:10:17 -0000	1.8
+++ client.h	15 Jan 2004 01:01:09 -0000	1.9
@@ -7,12 +7,14 @@
 #define __CLIENT_H__
 
 #include "connection.h"
+#include "refbuf.h"
+#include "httpp/httpp.h"
 
 typedef struct _client_tag
 {
-    /* the clients connection */
+    /* the client's connection */
     connection_t *con;
-    /* the clients http headers */
+    /* the client's http headers */
     http_parser_t *parser;
 
     /* http response code for this client */
@@ -23,6 +25,9 @@
     /* position in first buffer */
     unsigned long pos;
 
+    /* Client username, if authenticated */
+    char *username;
+
     /* Format-handler-specific data for this client */
     void *format_data;
 } client_t;

<p><p>1.2       +1 -0      icecast/src/compat.h

Index: compat.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/compat.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- compat.h	20 Oct 2001 21:28:09 -0000	1.1
+++ compat.h	15 Jan 2004 01:01:09 -0000	1.2
@@ -9,6 +9,7 @@
 #ifdef _WIN32
 #  define int64_t __int64
 #  define uint64_t unsigned __int64
+#  define uint32_t unsigned int
 #else
 #  ifdef HAVE_STDINT_H
 #    include <stdint.h>

<p><p>1.81      +34 -2     icecast/src/connection.c

Index: connection.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/connection.c,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -r1.80 -r1.81
--- connection.c	12 Dec 2003 23:06:44 -0000	1.80
+++ connection.c	15 Jan 2004 01:01:09 -0000	1.81
@@ -49,6 +49,7 @@
 #include "format_mp3.h"
 #include "event.h"
 #include "admin.h"
+#include "auth.h"
 
 #define CATMODULE "connection"
 
@@ -571,6 +572,7 @@
     config_release_config();
     return ret;
 }
+
 int connection_check_relay_pass(http_parser_t *parser)
 {
     int ret;
@@ -647,6 +649,10 @@
     stats_event_inc(NULL, "source_connections");
                 
     if (!connection_check_source_pass(parser, uri)) {
+        /* We commonly get this if the source client is using the wrong
+         * protocol: attempt to diagnose this and return an error
+         */
+        /* TODO: Do what the above comment says */
         INFO1("Source (%s) attempted to login with invalid or missing password", uri);
         client_send_401(client);
         return;
@@ -657,7 +663,7 @@
     */
 
     avl_tree_rlock(global.source_tree);
-    if (source_find_mount(uri) != NULL) {
+    if (source_find_mount_raw(uri) != NULL) {
         avl_tree_unlock(global.source_tree);
         INFO1("Source tried to log in as %s, but mountpoint is already used", uri);
         client_send_404(client, "Mountpoint in use");
@@ -854,7 +860,29 @@
     source = source_find_mount(uri);
     if (source) {
         DEBUG0("Source found for client");
-                        
+
+        /* The source may not be the requested source - it might have gone
+         * via one or more fallbacks. We only reject it for no-mount if it's
+         * the originally requested source
+         */
+        if(strcmp(uri, source->mount) == 0 && source->no_mount) {
+            client_send_404(client, "This mount is unavailable.");
+            avl_tree_unlock(global.source_tree);
+            return;
+        }
+
+        /* Check for any required authentication first */
+        if(source->authenticator != NULL) {
+            if(auth_check_client(source, client) != AUTH_OK) {
+                INFO1("Client attempted to log in to source (\"%s\")with "
+                        "incorrect or missing password", uri);
+                client_send_401(client);
+                avl_tree_unlock(global.source_tree);
+                return;
+            }
+        }
+
+        /* And then check that there's actually room in the server... */
         global_lock();
         if (global.clients >= client_limit) {
             client_send_504(client, 
@@ -863,6 +891,10 @@
             avl_tree_unlock(global.source_tree);
             return;
         }
+        /* Early-out for per-source max listeners. This gets checked again
+         * by the source itself, later. This route gives a useful message to
+         * the client, also.
+         */
         else if(source->max_listeners != -1 && 
                 source->listeners >= source->max_listeners) 
         {

<p><p>1.12      +2 -0      icecast/src/connection.h

Index: connection.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/connection.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- connection.h	16 Jul 2003 19:41:59 -0000	1.11
+++ connection.h	15 Jan 2004 01:01:09 -0000	1.12
@@ -2,6 +2,7 @@
 #define __CONNECTION_H__
 
 #include <sys/types.h>
+#include <time.h>
 #include "compat.h"
 #include "httpp/httpp.h"
 #include "thread/thread.h"
@@ -16,6 +17,7 @@
     time_t con_time;
     uint64_t sent_bytes;
 
+
     int sock;
     int serversock;
     int error;

<p><p>1.16      +1 -1      icecast/src/format_vorbis.c

Index: format_vorbis.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/format_vorbis.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- format_vorbis.c	21 Jul 2003 01:58:54 -0000	1.15
+++ format_vorbis.c	15 Jan 2004 01:01:09 -0000	1.16
@@ -177,7 +177,7 @@
                 /* If we get an update on the mountpoint, force a
                    yp touch */
                 avl_tree_rlock(global.source_tree);
-                source = source_find_mount(self->mount);
+                source = source_find_mount_raw(self->mount);
                 avl_tree_unlock(global.source_tree);
 
                 if (source) {

<p><p>1.30      +1 -1      icecast/src/slave.c

Index: slave.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/slave.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- slave.c	17 Dec 2003 23:03:38 -0000	1.29
+++ slave.c	15 Jan 2004 01:01:09 -0000	1.30
@@ -227,7 +227,7 @@
 
         while(relay) {
             avl_tree_rlock(global.source_tree);
-            if(!source_find_mount(relay->localmount)) {
+            if(!source_find_mount_raw(relay->localmount)) {
                 avl_tree_unlock(global.source_tree);
 
                 create_relay_stream(relay->server, relay->port, relay->mount,

<p><p>1.63      +147 -19   icecast/src/source.c

Index: source.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/source.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -r1.62 -r1.63
--- source.c	17 Dec 2003 22:54:43 -0000	1.62
+++ source.c	15 Jan 2004 01:01:09 -0000	1.63
@@ -37,10 +37,13 @@
 #endif
 #include "source.h"
 #include "format.h"
+#include "auth.h"
 
 #undef CATMODULE
 #define CATMODULE "source"
 
+#define MAX_FALLBACK_DEPTH 10
+
 /* avl tree helper */
 static int _compare_clients(void *compare_arg, void *a, void *b);
 static int _free_client(void *key);
@@ -70,6 +73,8 @@
     src->dumpfile = NULL;
     src->audio_info = util_dict_new();
     src->yp_public = 0;
+    src->fallback_override = 0;
+    src->no_mount = 0;
 
     if(mountinfo != NULL) {
         if (mountinfo->fallback_mount != NULL)
@@ -77,6 +82,11 @@
         src->max_listeners = mountinfo->max_listeners;
         if (mountinfo->dumpfile != NULL)
             src->dumpfilename = strdup (mountinfo->dumpfile);
+        if(mountinfo->auth_type != NULL)
+            src->authenticator = auth_get_authenticator(
+                    mountinfo->auth_type, mountinfo->auth_options);
+        src->fallback_override = mountinfo->fallback_override;
+        src->no_mount = mountinfo->no_mount;
     }
 
     if(src->dumpfilename != NULL) {
@@ -95,10 +105,10 @@
     return 1;
 }
 
-/* you must already have a read lock on the global source tree
-** to call this function
-*/
-source_t *source_find_mount(const char *mount)
+/* Find a mount with this raw name - ignoring fallbacks. You should have the
+ * global source tree locked to call this.
+ */
+source_t *source_find_mount_raw(const char *mount)
 {
     source_t *source;
     avl_node *node;
@@ -125,6 +135,56 @@
     return NULL;
 }
 
+static source_t *source_find_mount_recursive(const char *mount, int depth)
+{
+    source_t *source = source_find_mount_raw(mount);
+    mount_proxy *mountinfo;
+    ice_config_t *config;
+    char *fallback_mount;
+    
+    if(source == NULL) {
+        if(depth > MAX_FALLBACK_DEPTH)
+            return NULL;
+
+        /* Look for defined mounts to find a fallback source */
+
+        config = config_get_config();
+        mountinfo = config->mounts;
+        thread_mutex_lock(&(config_locks()->mounts_lock));
+        config_release_config();
+
+        while(mountinfo) {
+            if(!strcmp(mountinfo->mountname, mount))
+                break;
+            mountinfo = mountinfo->next;
+        }
+        
+        if(mountinfo)
+            fallback_mount = mountinfo->fallback_mount;
+        else
+            fallback_mount = NULL;
+
+        thread_mutex_unlock(&(config_locks()->mounts_lock));
+
+        if(fallback_mount != NULL) {
+            return source_find_mount_recursive(mount, depth+1);
+        }
+    }
+
+    return source;
+}
+
+/* you must already have a read lock on the global source tree
+** to call this function
+*/
+source_t *source_find_mount(const char *mount)
+{
+    if (!mount)
+        return NULL;
+
+    return source_find_mount_recursive(mount, 0);
+}
+
 int source_compare_sources(void *arg, void *a, void *b)
 {
     source_t *srca = (source_t *)a;
@@ -192,7 +252,6 @@
     refbuf_t *refbuf, *abuf;
     int data_done;
 
-    int listeners = 0;
 #ifdef USE_YP
     char *s;
     long current_time;
@@ -236,7 +295,7 @@
     /* Now, we must do a final check with write lock taken out that the
      * mountpoint is available..
      */
-    if (source_find_mount(source->mount) != NULL) {
+    if (source_find_mount_raw(source->mount) != NULL) {
         avl_tree_unlock(global.source_tree);
         if(source->send_return) {
             client_send_404(source->client, "Mountpoint in use");
@@ -353,6 +412,51 @@
 
     DEBUG0("Source creation complete");
 
+    /*
+    ** Now, if we have a fallback source and override is on, we want
+    ** to steal it's clients, because it means we've come back online
+    ** after a failure and they should be gotten back from the waiting
+    ** loop or jingle track or whatever the fallback is used for
+    */
+
+    if(source->fallback_override && source->fallback_mount) {
+        avl_tree_rlock(global.source_tree);
+        fallback_source = source_find_mount(source->fallback_mount);
+        avl_tree_unlock(global.source_tree);
+
+        if(fallback_source) {
+            /* we need to move the client and pending trees */
+            avl_tree_wlock(fallback_source->pending_tree);
+            while (avl_get_first(fallback_source->pending_tree)) {
+                client_t *client = (client_t *)avl_get_first(
+                        fallback_source->pending_tree)->key;
+                avl_delete(fallback_source->pending_tree, client, 
+                        source_remove_client);
+
+                /* TODO: reset client local format data?  */
+                avl_tree_wlock(source->pending_tree);
+                avl_insert(source->pending_tree, (void *)client);
+                avl_tree_unlock(source->pending_tree);
+            }
+            avl_tree_unlock(fallback_source->pending_tree);
+
+            avl_tree_wlock(fallback_source->client_tree);
+            while (avl_get_first(fallback_source->client_tree)) {
+                client_t *client = (client_t *)avl_get_first(
+                        fallback_source->client_tree)->key;
+
+                avl_delete(fallback_source->client_tree, client, 
+                        source_remove_client);
+
+                /* TODO: reset client local format data?  */
+                avl_tree_wlock(source->pending_tree);
+                avl_insert(source->pending_tree, (void *)client);
+                avl_tree_unlock(source->pending_tree);
+            }
+            avl_tree_unlock(fallback_source->client_tree);
+        }
+    }
+
     while (global.running == ICE_RUNNING && source->running) {
         ret = source->format->get_buffer(source->format, NULL, 0, &refbuf);
         if(ret < 0) {
@@ -375,7 +479,9 @@
                 }
 
                 bytes = sock_read_bytes(source->con->sock, buffer, 4096);
-                if (bytes == 0 || (bytes < 0 && !sock_recoverable(sock_error()))) {
+                if (bytes == 0 || 
+                        (bytes < 0 && !sock_recoverable(sock_error()))) 
+                {
                     DEBUG1("Disconnecting source due to socket read error: %s",
                             strerror(sock_error()));
                     break;
@@ -383,7 +489,8 @@
             }
             if (bytes <= 0) break;
             source->client->con->sent_bytes += bytes;
-            ret = source->format->get_buffer(source->format, buffer, bytes, &refbuf);
+            ret = source->format->get_buffer(source->format, buffer, bytes, 
+                    &refbuf);
             if(ret < 0) {
                 WARN0("Bad data from source");
                 goto done;
@@ -453,7 +560,8 @@
                     }
                 }
                 else {
-                    DEBUG0("Client has unrecoverable error catching up. Client has probably disconnected");
+                    DEBUG0("Client has unrecoverable error catching up. "
+                            "Client has probably disconnected");
                     client->con->error = 1;
                     data_done = 1;
                     refbuf_release(abuf);
@@ -483,7 +591,8 @@
                     }
                 }
                 else {
-                    DEBUG0("Client had unrecoverable error with new data, probably due to client disconnection");
+                    DEBUG0("Client had unrecoverable error with new data, "
+                            "probably due to client disconnection");
                     client->con->error = 1;
                 }
             }
@@ -518,9 +627,9 @@
             if (client->con->error) {
                 client_node = avl_get_next(client_node);
                 avl_delete(source->client_tree, (void *)client, _free_client);
-                listeners--;
-                stats_event_args(source->mount, "listeners", "%d", listeners);
-                source->listeners = listeners;
+                source->listeners--;
+                stats_event_args(source->mount, "listeners", "%d", 
+                        source->listeners);
                 DEBUG0("Client removed");
                 continue;
             }
@@ -533,15 +642,32 @@
         /** add pending clients **/
         client_node = avl_get_first(source->pending_tree);
         while (client_node) {
+            if(source->max_listeners != -1 && 
+                    source->listeners >= source->max_listeners) 
+            {
+                /* The common case is caught in the main connection handler,
+                 * this deals with rarer cases (mostly concerning fallbacks)
+                 * and doesn't give the listening client any information about
+                 * why they were disconnected
+                 */
+                client = (client_t *)client_node->key;
+                client_node = avl_get_next(client_node);
+                avl_delete(source->pending_tree, (void *)client, _free_client);
+
+                INFO0("Client deleted, exceeding maximum listeners for this "
+                        "mountpoint.");
+                continue;
+            }
+            
+            /* Otherwise, the client is accepted, add it */
             avl_insert(source->client_tree, client_node->key);
-            /* listener count may have changed */
-            listeners = source->listeners;
-            listeners++;
+
+            source->listeners++;
             DEBUG0("Client added");
             stats_event_inc(NULL, "clients");
             stats_event_inc(source->mount, "connections");
-            stats_event_args(source->mount, "listeners", "%d", listeners);
-            source->listeners = listeners;
+            stats_event_args(source->mount, "listeners", "%d", 
+                    source->listeners);
 
             /* we have to send cached headers for some data formats
             ** this is where we queue up the buffers to send
@@ -556,7 +682,9 @@
 
         /** clear pending tree **/
         while (avl_get_first(source->pending_tree)) {
-            avl_delete(source->pending_tree, avl_get_first(source->pending_tree)->key, source_remove_client);
+            avl_delete(source->pending_tree, 
+                    avl_get_first(source->pending_tree)->key, 
+                    source_remove_client);
         }
 
         /* release write lock on pending_tree */

<p><p>1.16      +6 -0      icecast/src/source.h

Index: source.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/source.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- source.h	21 Jul 2003 01:58:54 -0000	1.15
+++ source.h	15 Jan 2004 01:01:09 -0000	1.16
@@ -8,6 +8,8 @@
 
 #include <stdio.h>
 
+struct auth_tag;
+
 typedef struct source_tag
 {
     client_t *client;
@@ -40,12 +42,16 @@
     long max_listeners;
     int yp_public;
     int send_return;
+    struct auth_tag *authenticator;
+    int fallback_override;
+    int no_mount;
 } source_t;
 
 source_t *source_create(client_t *client, connection_t *con, 
         http_parser_t *parser, const char *mount, format_type_t type,
         mount_proxy *mountinfo);
 source_t *source_find_mount(const char *mount);
+source_t *source_find_mount_raw(const char *mount);
 client_t *source_find_client(source_t *source, int id);
 int source_compare_sources(void *arg, void *a, void *b);
 int source_free_source(void *key);

<p><p>1.26      +16 -1     icecast/src/util.c

Index: util.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/util.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- util.c	21 Jul 2003 01:58:54 -0000	1.25
+++ util.c	15 Jan 2004 01:01:09 -0000	1.26
@@ -220,7 +220,7 @@
 }
 
 static char hexchars[16] = {
-    '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+    '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
 };
 
 static char safechars[256] = {
@@ -368,6 +368,21 @@
      -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
 };
 
+char *util_bin_to_hex(unsigned char *data, int len)
+{
+    char *hex = malloc(len*2 + 1);
+    int i;
+
+    for(i = 0; i < len; i++) {
+        hex[i*2] = hexchars[(data[i]&0xf0) >> 4];
+        hex[i*2+1] = hexchars[data[i]&0x0f];
+    }
+
+    hex[len*2] = 0;
+
+    return hex;
+}
+
 /* This isn't efficient, but it doesn't need to be */
 char *util_base64_encode(char *data)
 {

<p><p>1.12      +1 -0      icecast/src/util.h

Index: util.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/util.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- util.h	6 Mar 2003 14:17:33 -0000	1.11
+++ util.h	15 Jan 2004 01:01:09 -0000	1.12
@@ -13,6 +13,7 @@
 char *util_normalise_uri(char *uri);
 char *util_base64_encode(char *data);
 char *util_base64_decode(unsigned char *input);
+char *util_bin_to_hex(unsigned char *data, int len);
 
 char *util_url_unescape(char *src);
 char *util_url_escape(char *src);

<p><p>1.1                  icecast/src/auth.c

Index: auth.c
===================================================================
/** 
 * 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"
#include "source.h"
#include "client.h"
#include "cfgfile.h"
#include "httpp/httpp.h"
#include "md5.h"

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

auth_result auth_check_client(source_t *source, client_t *client)
{
    auth_t *authenticator = source->authenticator;

    if(authenticator) {
        /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
        char *header = httpp_getvar(client->parser, "authorization");
        char *userpass, *tmp;
        char *username, *password;
    
        if(header == NULL)
            return AUTH_FAILED;
    
        if(strncmp(header, "Basic ", 6)) {
            INFO0("Authorization not using Basic");
            return 0;
        }
        
        userpass = util_base64_decode(header+6);
        if(userpass == NULL) {
            WARN1("Base64 decode of Authorization header \"%s\" failed",
                    header+6);
            return AUTH_FAILED;
        }
        
        tmp = strchr(userpass, ':');
        if(!tmp) { 
            free(userpass);
            return AUTH_FAILED;
        }

        *tmp = 0;
        username = userpass;
        password = tmp+1;

        auth_result result = authenticator->authenticate(
                authenticator, username, password);

        if(result == AUTH_OK)
            client->username = strdup(username);

        free(userpass);

        return result;
    }
    else
        return AUTH_FAILED;
}

tatic auth_t *auth_get_htpasswd_auth(config_options_t *options);

auth_t *auth_get_authenticator(char *type, config_options_t *options)
{
    auth_t *auth = NULL;
    if(!strcmp(type, "htpasswd")) {
        auth = auth_get_htpasswd_auth(options);
    }
    else {
        ERROR1("Unrecognised authenticator type: \"%s\"", type);
        return NULL;
    }

    if(!auth)
        ERROR1("Couldn't configure authenticator of type \"%s\"", type);
    
    return auth;
}

typedef struct {
    char *filename;
} htpasswd_auth_state;

tatic void htpasswd_clear(auth_t *self) {
    htpasswd_auth_state *state = self->state;
    free(state->filename);
    free(state);
    free(self);
}

tatic int get_line(FILE *file, char *buf, int len)
{
    if(fgets(buf, len, file)) {
        int len = strlen(buf);
        if(len > 0 && buf[len-1] == '\n') {
            buf[--len] = 0;
            if(len > 0 && buf[len-1] == '\r')
                buf[--len] = 0;
        }
        return 1;
    }
    return 0;
}

/* md5 hash */
static char *get_hash(char *data, int len)
{
    struct MD5Context context;

    MD5Init(&context);

    MD5Update(&context, data, len);

    unsigned char digest[16];
    MD5Final(digest, &context);

    return util_bin_to_hex(digest, 16);
}

#define MAX_LINE_LEN 512

/* Not efficient; opens and scans the entire file for every request */
static auth_result htpasswd_auth(auth_t *auth, char *username, char *password)
{
    htpasswd_auth_state *state = auth->state;
    FILE *passwdfile = fopen(state->filename, "rb");
    char line[MAX_LINE_LEN];
    char *sep;

    if(passwdfile == NULL) {
        WARN2("Failed to open authentication database \"%s\": %s", 
                state->filename, strerror(errno));
        return AUTH_FAILED;
    }

    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
        if(!line[0] || line[0] == '#')
            continue;

        sep = strchr(line, ':');
        if(sep == NULL) {
            DEBUG0("No seperator in line");
            continue;
        }

        *sep = 0;
        if(!strcmp(username, line)) {
            /* Found our user, now: does the hash of password match hash? */
            char *hash = sep+1;
            char *hashed_password = get_hash(password, strlen(password));
            if(!strcmp(hash, hashed_password)) {
                fclose(passwdfile);
                free(hashed_password);
                return AUTH_OK;
            }
            free(hashed_password);
            /* We don't keep searching through the file */
            break; 
        }
    }

    fclose(passwdfile);

    return AUTH_FAILED;
}

tatic auth_t *auth_get_htpasswd_auth(config_options_t *options)
{
    auth_t *authenticator = calloc(1, sizeof(auth_t));

    authenticator->authenticate = htpasswd_auth;
    authenticator->free = htpasswd_clear;

    htpasswd_auth_state *state = calloc(1, sizeof(htpasswd_auth_state));

    while(options) {
        if(!strcmp(options->name, "filename"))
            state->filename = strdup(options->value);
        options = options->next;
    }

    if(!state->filename) {
        free(state);
        free(authenticator);
        ERROR0("No filename given in options for authenticator.");
        return NULL;
    }

    authenticator->state = state;
    DEBUG1("Configured htpasswd authentication using password file %s", 
            state->filename);

    return authenticator;
}

<p><p><p>1.1                  icecast/src/auth.h

Index: auth.h
===================================================================
#ifndef __AUTH_H__
#define __AUTH_H__

#include "source.h"
#include "client.h"
#include "config.h"

typedef enum
{
    AUTH_OK,
    AUTH_FAILED,
} auth_result;

typedef struct auth_tag
{
    /* Authenticate using the given username and password */
    auth_result (*authenticate)(struct auth_tag *self, 
            char *username, char *password);
    void (*free)(struct auth_tag *self);
    void *state;
} auth_t;

auth_result auth_check_client(source_t *source, client_t *client);

auth_t *auth_get_authenticator(char *type, config_options_t *options);
void *auth_clear(auth_t *authenticator);

#endif

<p><p><p><p>1.1                  icecast/src/md5.c

Index: md5.c
===================================================================
/*
 * md5.c
 *
 * This code implements the MD5 message-digest algorithm.
 * The algorithm is due to Ron Rivest.  This code was
 * written by Colin Plumb in 1993, no copyright is claimed.
 * This code is in the public domain; do with it what you wish.
 *
 * Equivalent code is available from RSA Data Security, Inc.
 * This code has been tested against that, and is equivalent,
 * except that you don't need to include two pages of legalese
 * with every copy.
 *
 * To compute the message digest of a chunk of bytes, declare an
 * MD5Context structure, pass it to MD5Init, call MD5Update as
 * needed on buffers full of bytes, and then call MD5Final, which
 * will fill a supplied 16-byte array with the digest.
 */

/* Modified for icecast by Mike Smith <msmith at xiph.org>, mostly changing header
 * and type definitions
 */

#include "config.h"
#include "compat.h"
#include "md5.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>

tatic void MD5Transform(uint32_t buf[4], uint32_t const in[HASH_LEN]);

/*
 * Note: this code is harmless on little-endian machines.
 */
static void byteReverse(unsigned char *buf, unsigned longs)
{
    uint32_t t;
    do
        {
                t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
                        ((unsigned) buf[1] << 8 | buf[0]);
                *(uint32_t *) buf = t;
                buf += 4;
    }
        while (--longs);
}

/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
 */
void MD5Init(struct MD5Context *ctx)
{
    ctx->buf[0] = 0x67452301;
    ctx->buf[1] = 0xefcdab89;
    ctx->buf[2] = 0x98badcfe;
    ctx->buf[3] = 0x10325476;

    ctx->bits[0] = 0;
    ctx->bits[1] = 0;
}

/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, 
        unsigned len)
{
    uint32_t t;

    /* Update bitcount */

    t = ctx->bits[0];
    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
                ctx->bits[1]++;

        /* Carry from low to high */
    ctx->bits[1] += len >> 29;

    t = (t >> 3) & 0x3f;
        /* Bytes already in shsInfo->data */

    /* Handle any leading odd-sized chunks */
    if (t)
        {
                unsigned char *p = (unsigned char *) ctx->in + t;
                t = 64 - t;
                if (len < t)
                {
                        memcpy(p, buf, len);
                        return;
                }

                memcpy(p, buf, t);
                byteReverse(ctx->in, HASH_LEN);
                MD5Transform(ctx->buf, (uint32_t *) ctx->in);
                buf += t;
                len -= t;
    }
    /* Process data in 64-byte chunks */

    while (len >= 64)
        {
                memcpy(ctx->in, buf, 64);
                byteReverse(ctx->in, HASH_LEN);
                MD5Transform(ctx->buf, (uint32_t *) ctx->in);
                buf += 64;
                len -= 64;
    }

    /* Handle any remaining bytes of data. */
    memcpy(ctx->in, buf, len);
}

/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
void MD5Final(unsigned char digest[HASH_LEN], struct MD5Context *ctx)
{
    unsigned count;
    unsigned char *p;

    /* Compute number of bytes mod 64 */
    count = (ctx->bits[0] >> 3) & 0x3F;

    /* Set the first char of padding to 0x80.  This is safe since there is
         always at least one byte free */
    p = ctx->in + count;
    *p++ = 0x80;

    /* Bytes of padding needed to make 64 bytes */
    count = 64 - 1 - count;

    /* Pad out to 56 mod 64 */
    if (count < 8)
        {
                /* Two lots of padding:  Pad the first block to 64 bytes */
                memset(p, 0, count);
                byteReverse(ctx->in, HASH_LEN);
                MD5Transform(ctx->buf, (uint32_t *) ctx->in);

                /* Now fill the next block with 56 bytes */
                memset(ctx->in, 0, 56);
    }
        else
        {
                /* Pad block to 56 bytes */
                memset(p, 0, count - 8);
    }
    byteReverse(ctx->in, 14);

    /* Append length in bits and transform */
    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
    ((uint32_t *) ctx->in)[15] = ctx->bits[1];

    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    byteReverse((unsigned char *) ctx->buf, 4);
    memcpy(digest, ctx->buf, HASH_LEN);
    memset(ctx, 0, sizeof(ctx));
        /* In case it's sensitive */
}

/* The four core functions - F1 is optimized somewhat */

/* #define F1(x, y, z) (x & y | ~x & z) */
# define F1(x, y, z) (z ^ (x & (y ^ z)))
# define F2(x, y, z) F1(z, x, y)
# define F3(x, y, z) (x ^ y ^ z)
# define F4(x, y, z) (y ^ (x | ~z))

/* This is the central step in the MD5 algorithm. */
# define MD5STEP(f, w, x, y, z, data, s) ( w += f(x, y, z) + data,  w = (w<<s) | (w>>(32-s)),  w += x )

/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
 */
static void MD5Transform(uint32_t buf[4], uint32_t const in[HASH_LEN])
{
    register uint32_t a, b, c, d;

    a = buf[0];
    b = buf[1];
    c = buf[2];
    d = buf[3];

    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);

    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);

    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);

    buf[0] += a;
    buf[1] += b;
    buf[2] += c;
    buf[3] += d;
}

<p><p><p>1.1                  icecast/src/md5.h

Index: md5.h
===================================================================
#ifndef __MD5_H__
#define __MD5_H__

#include "config.h"
#include "compat.h"

#define HASH_LEN     16

truct MD5Context
{       
    uint32_t     buf[4];
    uint32_t     bits[2];
    unsigned char in[64];
};

void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf, 
        unsigned len);
void MD5Final(unsigned char digest[HASH_LEN], struct MD5Context *context);

<p>#endif

<p><p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list