Index: configure.in
===================================================================
--- configure.in	(revision 107)
+++ configure.in	(working copy)
@@ -112,6 +112,20 @@
         ])
     ],[ AC_MSG_NOTICE([libcurl not found])
     ])
+
+dnl -- hash geoip auth support --
+AC_CHECK_LIB(GeoIP, GeoIP_new,[have_geoip=yes],[have_geoip=no], -lGeoIP)
+if test "x$have_geoip" == "xyes"
+then
+    GEOIP_LIBS="-lGeoIP"
+	XIPH_VAR_APPEND([XIPH_CFLAGS],[$GEOIP_CFLAGS])
+	XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$GEOIP_CPPFLAGS])
+    XIPH_VAR_PREPEND([XIPH_LIBS],[$GEOIP_LIBS])
+    AC_DEFINE([HAVE_AUTH_HASH_GEOIP],[1],[Define to compile in auth HASH support code with GeoIP database])
+else
+  	AC_MSG_NOTICE([HASH authentication support without GeoIP])
+fi
+
 dnl -- YP support --
 AC_ARG_ENABLE([yp],
         AC_HELP_STRING([--disable-yp],[disable YP directory support]),
Index: src/auth_hash.c
===================================================================
--- src/auth_hash.c	(revision 0)
+++ src/auth_hash.c	(revision 111)
@@ -0,0 +1,262 @@
+/* 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 HASH functions
+ *
+ * authenticate user via a HASH, 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=listener_add
+ * http://server:8000/live?hash=ef273fceb9fa7ec5bff70e6c0cc48d1b&time=126235678
+ *
+ * For a user to be accecpted the hash have to be generated by following rule
+ * hash = md5(TIME + CLIENT_IP + SECRET_WORD)
+ *
+ * where time got from GET variable 'time' and it must be no less, then current time
+ * minus some interval in minutes.
+ *
+ * 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
+ *
+ */
+
+#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
+
+#ifdef HAVE_AUTH_HASH_GEOIP
+#include <GeoIP.h>
+#endif
+
+#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_hash"
+
+typedef struct {
+    char *secret;
+    time_t  lifetime;
+#ifdef HAVE_AUTH_HASH_GEOIP
+    char *geoip_country;
+    GeoIP *gi_handler;
+#endif
+} auth_hash;
+
+
+
+/* md5 hash */
+static char *get_hash(const char *data, int len)
+{
+    struct MD5Context context;
+    unsigned char digest[16];
+
+    MD5Init(&context);
+    MD5Update(&context, (const unsigned char *)data, len);
+    MD5Final(digest, &context);
+
+    return util_bin_to_hex(digest, 16);
+}
+
+static void auth_hash_clear(auth_t *self)
+{
+    auth_hash *hash;
+
+    INFO0 ("Doing auth HASH cleanup");
+    hash = self->state;
+    self->state = NULL;
+    free (hash->secret);
+#ifdef HAVE_AUTH_HASH_GEOIP
+    free (hash->geoip_country);
+    if(hash->gi_handler)
+        GeoIP_delete(hash->gi_handler);
+#endif
+    free (hash);
+}
+
+static auth_result auth_hash_auth (auth_client *auth_user)
+{
+    client_t *client = auth_user->client;
+    auth_t *auth = client->auth;
+    auth_hash *hash = auth->state;
+    char rawuriparams[64];
+    char unhashed_phrase[128];
+    char *hashed_phrase;
+    time_t  gottime;
+    char gothash[64];
+    char *ipaddr = client->con->ip;
+    const char *cc = NULL;
+#ifdef HAVE_AUTH_HASH_GEOIP
+    int cid;
+#endif
+    char *pch;
+    const char *mountreq, *tmp;
+    int len;
+
+
+#ifdef HAVE_AUTH_HASH_GEOIP
+    if(hash->geoip_country) {
+        if(hash->gi_handler) {
+            cid = GeoIP_id_by_addr(hash->gi_handler, ipaddr);
+            cc = GeoIP_country_code[cid];
+            if(strcmp(hash->geoip_country, cc)) {
+                DEBUG3 ("geoip for address: %s, tells that it's: %s, but config needed: %s", ipaddr, cc, hash->geoip_country);
+                return AUTH_FAILED;
+            }
+        } else {
+            WARN0("GeoIP database not initialized");
+            return AUTH_FAILED;
+        }
+    }
+#endif
+
+    mountreq = httpp_getvar (client->parser, HTTPP_VAR_RAWURI);
+    if (mountreq == NULL || (tmp = strchr(mountreq, '?')) == NULL) {
+        return AUTH_FAILED;
+    }
+
+    tmp++;
+    strncpy(rawuriparams, tmp, 63);
+    rawuriparams[63] = '\0';
+
+    pch = strtok (rawuriparams,"&");
+    while (pch != NULL)
+    {
+        if ((tmp = strchr(pch, '=')) != NULL){
+            if(strncmp("time", pch, 4) == 0){
+                gottime = atol(tmp+1);
+            } else if(strncmp("hash", pch, 4) == 0){
+                strncpy(gothash, tmp+1, 32);
+                gothash[32] = '\0';
+            }
+        }
+        pch = strtok (NULL, "&");
+    }
+
+    if (hash->lifetime && (time(NULL) - gottime > hash->lifetime)) {
+        DEBUG3 ("lifetime expired, server time: %ld, got time: %ld, diff: %d", time(NULL), gottime, time(NULL) - gottime);
+        return AUTH_FAILED;
+    }
+
+    len = snprintf(unhashed_phrase, 127, "%ld%s%s", gottime, ipaddr, hash->secret);
+    unhashed_phrase[127] = '\0';
+    hashed_phrase = get_hash (unhashed_phrase, len);
+    if (strcmp (gothash, hashed_phrase) == 0) {
+        free (hashed_phrase);
+        return AUTH_OK;
+    }
+
+    free (hashed_phrase);
+    DEBUG0 ("incorrect hash for client");
+    return AUTH_FAILED;
+}
+
+
+static auth_result auth_hash_adduser(auth_t *auth, const char *username, const char *password)
+{
+    return AUTH_FAILED;
+}
+
+static auth_result auth_hash_deleteuser (auth_t *auth, const char *username)
+{
+    return AUTH_FAILED;
+}
+
+static auth_result auth_hash_userlist (auth_t *auth, xmlNodePtr srcnode)
+{
+    return AUTH_FAILED;
+}
+
+int auth_get_hash_auth (auth_t *authenticator, config_options_t *options)
+{
+    auth_hash *hash_info;
+#ifdef HAVE_AUTH_HASH_GEOIP
+    char * db_info;
+#endif
+    authenticator->authenticate = auth_hash_auth;
+    authenticator->free = auth_hash_clear;
+    authenticator->adduser = auth_hash_adduser;
+    authenticator->deleteuser = auth_hash_deleteuser;
+    authenticator->listuser = auth_hash_userlist;
+
+    hash_info = calloc(1, sizeof(auth_hash));
+    authenticator->state = hash_info;
+
+    while(options) {
+        if(!strcmp(options->name, "secret"))
+        {
+            free (hash_info->secret);
+            hash_info->secret = strdup (options->value);
+            if (strlen (hash_info->secret) > 64){
+                ERROR0 ("too long secret, it's no cence");
+                auth_hash_clear (authenticator);
+                return -1;
+            }
+        }
+        if(!strcmp(options->name, "lifetime"))
+        {
+            hash_info->lifetime = atoi (options->value);
+        }
+        if(!strcmp(options->name, "geoip_country"))
+        {
+#ifdef HAVE_AUTH_HASH_GEOIP
+            free (hash_info->geoip_country);
+            hash_info->geoip_country = strdup (options->value);
+#else
+            ERROR0("hash auth compiled without GeoIP!");
+#endif
+        }
+        options = options->next;
+    }
+    INFO0("HASH based authentication setup");
+
+#ifdef HAVE_AUTH_HASH_GEOIP
+    if(hash_info->geoip_country) {
+        hash_info->gi_handler = GeoIP_new(GEOIP_STANDARD);
+        if (hash_info->gi_handler == NULL) {
+            ERROR0("GeoIP database can't be opened");
+        } else {
+            if (!GeoIP_db_avail(GEOIP_COUNTRY_EDITION)){
+                ERROR0("GeoIP database not available\n");
+                GeoIP_delete(hash_info->gi_handler);
+                hash_info->gi_handler=NULL;
+            } else {
+                db_info = GeoIP_database_info(hash_info->gi_handler);
+                INFO1("GeoIP database: %s", db_info);
+                free(db_info);
+            }
+        }
+    }
+#endif
+    return 0;
+}
+

Property changes on: src/auth_hash.c
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Index: src/auth_hash.h
===================================================================
--- src/auth_hash.h	(revision 0)
+++ src/auth_hash.h	(revision 111)
@@ -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_HASH_H__
+#define __AUTH_HASH_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int auth_get_hash_auth (auth_t *authenticator, config_options_t *options);
+
+#endif
+
+

Property changes on: src/auth_hash.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Index: src/auth.c
===================================================================
--- src/auth.c	(revision 107)
+++ src/auth.c	(working copy)
@@ -26,6 +26,7 @@
 #include "auth.h"
 #include "auth_htpasswd.h"
 #include "auth_url.h"
+#include "auth_hash.h"
 #include "source.h"
 #include "client.h"
 #include "cfgfile.h"
@@ -570,6 +571,12 @@
                 return -1;
             break;
         }
+        if (strcmp (auth->type, "hash") == 0)
+        {
+            if (auth_get_hash_auth (auth, options) < 0)
+                return -1;
+            break;
+        }
 
         ERROR1("Unrecognised authenticator type: \"%s\"", auth->type);
         return -1;
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 107)
+++ src/Makefile.am	(working copy)
@@ -9,7 +9,7 @@
 noinst_HEADERS = admin.h cfgfile.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_url.h \
+    auth.h auth_htpasswd.h auth_url.h auth_hash.h \
     format.h format_ogg.h format_mp3.h \
     format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \
     format_kate.h format_skeleton.h
@@ -17,7 +17,7 @@
     util.c slave.c source.c stats.c refbuf.c client.c \
     xslt.c fserve.c event.c admin.c md5.c \
     format.c format_ogg.c format_mp3.c format_midi.c format_flac.c \
-    auth.c auth_htpasswd.c format_kate.c format_skeleton.c
+    auth.c auth_htpasswd.c auth_hash.c format_kate.c format_skeleton.c
 EXTRA_icecast_SOURCES = yp.c \
     auth_url.c \
     format_vorbis.c format_theora.c format_speex.c
