[xiph-commits] r9583 - icecast/branches/kh/icecast/src

karl at svn.xiph.org karl at svn.xiph.org
Mon Jul 18 07:27:43 PDT 2005


Author: karl
Date: 2005-07-18 07:27:39 -0700 (Mon, 18 Jul 2005)
New Revision: 9583

Modified:
   icecast/branches/kh/icecast/src/auth.c
   icecast/branches/kh/icecast/src/auth_htpasswd.c
   icecast/branches/kh/icecast/src/auth_url.c
Log:
auth update. make htpasswd use an in-memory avl tree with checks on the
file mtime to identify changes made externally.  Add useragent field to
auth url.


Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c	2005-07-18 00:36:00 UTC (rev 9582)
+++ icecast/branches/kh/icecast/src/auth.c	2005-07-18 14:27:39 UTC (rev 9583)
@@ -63,14 +63,14 @@
             {
                 WARN1("Base64 decode of Authorization header \"%s\" failed",
                         header+6);
-                return;
+                break;
             }
 
             tmp = strchr(userpass, ':');
             if (tmp == NULL)
             { 
                 free (userpass);
-                return;
+                break;
             }
 
             *tmp = 0;
@@ -401,7 +401,7 @@
  */
 int release_client (client_t *client)
 {
-    if (client->auth && client->auth->release_client)
+    if (client->auth)
     {
         auth_client *auth_user = calloc (1, sizeof (auth_client));
         if (auth_user == NULL)

Modified: icecast/branches/kh/icecast/src/auth_htpasswd.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_htpasswd.c	2005-07-18 00:36:00 UTC (rev 9582)
+++ icecast/branches/kh/icecast/src/auth_htpasswd.c	2005-07-18 14:27:39 UTC (rev 9583)
@@ -42,15 +42,26 @@
 static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password);
 static auth_result htpasswd_deleteuser(auth_t *auth, const char *username);
 static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode);
+static int _free_user (void *key);
 
+typedef struct
+{
+    char *name;
+    char *pass;
+} htpasswd_user;
+
 typedef struct {
     char *filename;
     rwlock_t file_rwlock;
+    avl_tree *users;
+    time_t mtime;
 } htpasswd_auth_state;
 
 static void htpasswd_clear(auth_t *self) {
     htpasswd_auth_state *state = self->state;
     free(state->filename);
+    if (state->users)
+        avl_tree_free (state->users, _free_user);
     thread_rwlock_destroy(&state->file_rwlock);
     free(state);
 }
@@ -86,61 +97,127 @@
 
 #define MAX_LINE_LEN 512
 
-/* Not efficient; opens and scans the entire file for every request */
-static auth_result htpasswd_auth (auth_client *auth_user)
+
+static int compare_users (void *arg, void *a, void *b)
 {
-    auth_t *auth = auth_user->client->auth;
-    htpasswd_auth_state *state = auth->state;
-    client_t *client = auth_user->client;
+    htpasswd_user *user1 = (htpasswd_user *)a;
+    htpasswd_user *user2 = (htpasswd_user *)b;
+
+    return strcmp (user1->name, user2->name);
+}
+
+
+static int _free_user (void *key)
+{
+    htpasswd_user *user = (htpasswd_user *)key;
+
+    free (user->name); /* ->pass is part of same buffer */
+    free (user);
+    return 1;
+}
+
+
+static void htpasswd_recheckfile (htpasswd_auth_state *htpasswd)
+{
     FILE *passwdfile;
-    char line[MAX_LINE_LEN];
+    avl_tree *new_users;
+    int num = 0;
+    struct stat file_stat;
     char *sep;
+    char line [MAX_LINE_LEN];
 
-    if (client->username == NULL || client->password == NULL)
-        return AUTH_FAILED;
-
-    passwdfile = fopen(state->filename, "rb");
-    thread_rwlock_rlock(&state->file_rwlock);
-    if(passwdfile == NULL) {
+    if (stat (htpasswd->filename, &file_stat) < 0)
+    {
+        WARN1 ("failed to check status of %s", htpasswd->filename);
+        return;
+    }
+    if (file_stat.st_mtime == htpasswd->mtime)
+    {
+        /* common case, no update to file */
+        return;
+    }
+    INFO1 ("re-reading htpasswd file \"%s\"", htpasswd->filename);
+    passwdfile = fopen (htpasswd->filename, "rb");
+    if (passwdfile == NULL)
+    {
         WARN2("Failed to open authentication database \"%s\": %s", 
-                state->filename, strerror(errno));
-        thread_rwlock_unlock(&state->file_rwlock);
-        return AUTH_FAILED;
+                htpasswd->filename, strerror(errno));
+        return;
     }
+    htpasswd->mtime = file_stat.st_mtime;
 
-    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+    new_users = avl_tree_new (compare_users, NULL);
+
+    while (get_line(passwdfile, line, MAX_LINE_LEN))
+    {
+        int len;
+        htpasswd_user *entry;
+
+        num++;
         if(!line[0] || line[0] == '#')
             continue;
 
-        sep = strchr(line, ':');
-        if(sep == NULL) {
-            DEBUG0("No separator in line");
+        sep = strrchr (line, ':');
+        if (sep == NULL)
+        {
+            WARN2("No separator on line %d (%s)", num, htpasswd->filename);
             continue;
         }
-
+        entry = calloc (1, sizeof (htpasswd_user));
+        len = strlen (line) + 1;
+        entry->name = malloc (len);
         *sep = 0;
-        if(!strcmp(client->username, line)) {
-            /* Found our user, now: does the hash of password match hash? */
-            char *hash = sep+1;
-            char *hashed_password = get_hash(client->password, strlen(client->password));
-            if(!strcmp(hash, hashed_password)) {
-                fclose(passwdfile);
-                free(hashed_password);
-                thread_rwlock_unlock(&state->file_rwlock);
-                return AUTH_OK;
-            }
-            free(hashed_password);
-            /* We don't keep searching through the file */
-            break; 
-        }
+        memcpy (entry->name, line, len);
+        entry->pass = entry->name + (sep-line) + 1;
+        avl_insert (new_users, entry);
     }
+    fclose (passwdfile);
 
-    fclose(passwdfile);
+    thread_rwlock_wlock (&htpasswd->file_rwlock);
+    if (htpasswd->users)
+        avl_tree_free (htpasswd->users, _free_user);
+    htpasswd->users = new_users;
+    thread_rwlock_unlock (&htpasswd->file_rwlock);
+}
 
-    thread_rwlock_unlock(&state->file_rwlock);
+
+static auth_result htpasswd_auth (auth_client *auth_user)
+{
+    auth_t *auth = auth_user->client->auth;
+    htpasswd_auth_state *htpasswd = auth->state;
+    client_t *client = auth_user->client;
+    htpasswd_user entry;
+    void *result;
+
+    if (client->username == NULL || client->password == NULL)
+        return AUTH_FAILED;
+
+    htpasswd_recheckfile (htpasswd);
+
+    thread_rwlock_rlock (&htpasswd->file_rwlock);
+    entry.name = client->username;
+    if (avl_get_by_key (htpasswd->users, &entry, &result) == 0)
+    {
+        htpasswd_user *found = result;
+        char *hashed_pw;
+
+        thread_rwlock_unlock (&htpasswd->file_rwlock);
+        hashed_pw = get_hash (client->password, strlen (client->password));
+        if (strcmp (found->pass, hashed_pw) == 0)
+        {
+            free (hashed_pw);
+            return AUTH_OK;
+        }
+        free (hashed_pw);
+        DEBUG0 ("incorrect password for client");
+        return AUTH_FAILED;
+    }
+    DEBUG1 ("no such username: %s", client->username);
+    thread_rwlock_unlock (&htpasswd->file_rwlock);
     return AUTH_FAILED;
 }
 
+
 int  auth_get_htpasswd_auth (auth_t *authenticator, config_options_t *options)
 {
     htpasswd_auth_state *state;
@@ -170,61 +247,36 @@
             state->filename);
 
     thread_rwlock_create(&state->file_rwlock);
+    htpasswd_recheckfile (state);
 
     return 0;
 }
 
-int auth_htpasswd_existing_user(auth_t *auth, const char *username)
+
+static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password)
 {
     FILE *passwdfile;
-    htpasswd_auth_state *state;
-    int ret = AUTH_OK;
-    char line[MAX_LINE_LEN];
-    char *sep;
+    char *hashed_password = NULL;
+    htpasswd_auth_state *state = auth->state;
+    htpasswd_user entry;
+    void *result;
 
-    state = auth->state;
-    passwdfile = fopen(state->filename, "rb");
+    htpasswd_recheckfile (state);
 
-    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 separator in line");
-            continue;
-        }
-        *sep = 0;
-        if (!strcmp(username, line)) {
-            /* We found the user, break out of the loop */
-            ret = AUTH_USEREXISTS;
-            break;
-        }
-    }
+    thread_rwlock_wlock (&state->file_rwlock);
 
-    fclose(passwdfile);
-    return ret;
-
-}
-
-
-static int _auth_htpasswd_adduser(auth_t *auth, const char *username, const char *password)
-{
-    FILE *passwdfile;
-    char *hashed_password = NULL;
-    htpasswd_auth_state *state;
-
-    if (auth_htpasswd_existing_user(auth, username) == AUTH_USEREXISTS) {
+    entry.name = (char*)username;
+    if (avl_get_by_key (state->users, &entry, &result) == 0)
+    {
+        thread_rwlock_unlock (&state->file_rwlock);
         return AUTH_USEREXISTS;
     }
-    state = auth->state;
+
     passwdfile = fopen(state->filename, "ab");
 
-    if(passwdfile == NULL) {
+    if (passwdfile == NULL)
+    {
+        thread_rwlock_unlock (&state->file_rwlock);
         WARN2("Failed to open authentication database \"%s\": %s", 
                 state->filename, strerror(errno));
         return AUTH_FAILED;
@@ -237,21 +289,9 @@
     }
 
     fclose(passwdfile);
-    return AUTH_USERADDED;
-}
-
-
-static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password)
-{
-    auth_result ret = 0;
-    htpasswd_auth_state *state;
-
-    state = auth->state;
-    thread_rwlock_wlock (&state->file_rwlock);
-    ret = _auth_htpasswd_adduser (auth, username, password);
     thread_rwlock_unlock (&state->file_rwlock);
 
-    return ret;
+    return AUTH_USERADDED;
 }
 
 
@@ -267,11 +307,13 @@
     struct stat file_info;
 
     state = auth->state;
+    thread_rwlock_wlock (&state->file_rwlock);
     passwdfile = fopen(state->filename, "rb");
 
     if(passwdfile == NULL) {
         WARN2("Failed to open authentication database \"%s\": %s", 
                 state->filename, strerror(errno));
+        thread_rwlock_unlock (&state->file_rwlock);
         return AUTH_FAILED;
     }
     tmpfile_len = strlen(state->filename) + 6;
@@ -282,6 +324,7 @@
         WARN1 ("temp file \"%s\" exists, rejecting operation", tmpfile);
         free (tmpfile);
         fclose (passwdfile);
+        thread_rwlock_unlock (&state->file_rwlock);
         return AUTH_FAILED;
     }
 
@@ -292,6 +335,7 @@
                 tmpfile, strerror(errno));
         fclose(passwdfile);
         free(tmpfile);
+        thread_rwlock_unlock (&state->file_rwlock);
         return AUTH_FAILED;
     }
 
@@ -332,6 +376,8 @@
         }
     }
     free(tmpfile);
+    thread_rwlock_unlock (&state->file_rwlock);
+    htpasswd_recheckfile (state);
 
     return AUTH_USERDELETED;
 }
@@ -340,40 +386,25 @@
 static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode)
 {
     htpasswd_auth_state *state;
-    FILE *passwdfile;
-    char line[MAX_LINE_LEN];
-    char *sep;
-    char *passwd;
     xmlNodePtr newnode;
+    avl_node *node;
 
     state = auth->state;
 
-    passwdfile = fopen(state->filename, "rb");
+    htpasswd_recheckfile (state);
 
-    if(passwdfile == NULL) {
-        WARN2("Failed to open authentication database \"%s\": %s", 
-                state->filename, strerror(errno));
-        return AUTH_FAILED;
+    thread_rwlock_rlock (&state->file_rwlock);
+    node = avl_get_first (state->users);
+    while (node)
+    {
+        htpasswd_user *user = (htpasswd_user *)node->key;
+        newnode = xmlNewChild (srcnode, NULL, "User", NULL);
+        xmlNewChild(newnode, NULL, "username", user->name);
+        xmlNewChild(newnode, NULL, "password", user->pass);
+        node = avl_get_next (node);
     }
+    thread_rwlock_unlock (&state->file_rwlock);
 
-    while(get_line(passwdfile, line, MAX_LINE_LEN)) {
-        if(!line[0] || line[0] == '#')
-            continue;
-
-        sep = strchr(line, ':');
-        if(sep == NULL) {
-            DEBUG0("No separator in line");
-            continue;
-        }
-
-        *sep = 0;
-        newnode = xmlNewChild(srcnode, NULL, "User", NULL);
-        xmlNewChild(newnode, NULL, "username", line);
-        passwd = sep+1;
-        xmlNewChild(newnode, NULL, "password", passwd);
-    }
-
-    fclose(passwdfile);
     return AUTH_OK;
 }
 

Modified: icecast/branches/kh/icecast/src/auth_url.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.c	2005-07-18 00:36:00 UTC (rev 9582)
+++ icecast/branches/kh/icecast/src/auth_url.c	2005-07-18 14:27:39 UTC (rev 9583)
@@ -58,8 +58,10 @@
 #include <stdio.h>
 #ifndef _WIN32
 #include <sys/wait.h>
+#include <strings.h>
 #else
 #define snprintf _snprintf
+#define strncasecmp strnicmp
 #endif
 
 #include <curl/curl.h>
@@ -415,6 +417,7 @@
     if (url_info->timelimit_header)
         url_info->timelimit_header_len = strlen (url_info->timelimit_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);



More information about the commits mailing list