added keyfile based authentication

Thu, 09 May 2013 19:41:11 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 09 May 2013 19:41:11 +0200
changeset 62
c47e081b6c0f
parent 61
c858850f3d3a
child 63
66442f81f823

added keyfile based authentication

configure file | annotate | diff | comparison | revisions
make/linux.mk file | annotate | diff | comparison | revisions
make/solaris.mk file | annotate | diff | comparison | revisions
make/suncc.mk file | annotate | diff | comparison | revisions
src/server/Makefile file | annotate | diff | comparison | revisions
src/server/config/acl.c file | annotate | diff | comparison | revisions
src/server/config/initconf.c file | annotate | diff | comparison | revisions
src/server/config/keyfile.c file | annotate | diff | comparison | revisions
src/server/config/keyfile.h file | annotate | diff | comparison | revisions
src/server/config/mimeconf.c file | annotate | diff | comparison | revisions
src/server/config/objconf.c file | annotate | diff | comparison | revisions
src/server/config/objs.mk file | annotate | diff | comparison | revisions
src/server/config/serverconf.c file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/configmanager.c file | annotate | diff | comparison | revisions
src/server/daemon/keyfile_auth.c file | annotate | diff | comparison | revisions
src/server/daemon/keyfile_auth.h file | annotate | diff | comparison | revisions
src/server/daemon/objs.mk file | annotate | diff | comparison | revisions
src/server/public/auth.h file | annotate | diff | comparison | revisions
src/server/safs/auth.c file | annotate | diff | comparison | revisions
src/server/ucx/Makefile file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
--- a/configure	Thu May 09 13:19:51 2013 +0200
+++ b/configure	Thu May 09 19:41:11 2013 +0200
@@ -35,6 +35,9 @@
 HOST=`uname -n`
 INSTALL_DIR=`pwd`/work
 
+OPENSSL_CFLAGS=`pkg-config --cflags openssl`
+OPENSSL_LDFLAGS=`pkg-config --libs openssl`
+
 # create config.mk
 echo "generate config.mk"
 
@@ -68,6 +71,10 @@
 echo "
 include \$(BUILD_ROOT)/make/$CCONF
 include \$(BUILD_ROOT)/make/$PLATFORM
+
+CFLAGS += $OPENSSL_CFLAGS
+LDFLAGS += $OPENSSL_LDFLAGS
+
 " >> config.mk
 
 
--- a/make/linux.mk	Thu May 09 13:19:51 2013 +0200
+++ b/make/linux.mk	Thu May 09 19:41:11 2013 +0200
@@ -28,9 +28,8 @@
 
 
 # compiler and linker flags
-
-LDFLAGS = 
-CFLAGS += -DLINUX
+CFLAGS += -DLINUX 
+LDFLAGS = -lpthread -ldl -lnsl -lm -lxerces-c -lldap
 
 
 # platform dependend source files
--- a/make/solaris.mk	Thu May 09 13:19:51 2013 +0200
+++ b/make/solaris.mk	Thu May 09 19:41:11 2013 +0200
@@ -29,7 +29,7 @@
 
 # compiler and linker flags
 
-LDFLAGS = -lsocket -lsendfile -lposix4
+LDFLAGS += -lsendfile -lposix4 -lpthread -ldl -lm -lxerces-c -lldap
 
 
 # platform dependend source files
--- a/make/suncc.mk	Thu May 09 13:19:51 2013 +0200
+++ b/make/suncc.mk	Thu May 09 19:41:11 2013 +0200
@@ -26,7 +26,8 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-CFLAGS = -xc99 -g -D_REENTRANT
+CFLAGS += -xc99 -g -D_REENTRANT
+LDFLAGS += -lpthread -ldl -lm -lxerces-c -lldap
 
 CC  = cc
 CXX = CC
--- a/src/server/Makefile	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/Makefile	Thu May 09 19:41:11 2013 +0200
@@ -29,7 +29,7 @@
 BUILD_ROOT = ../..
 include $(BUILD_ROOT)/config.mk
 
-LDFLAGS += -lpthread -ldl -lnsl -lm -lxerces-c -lldap
+# LDFLAGS += -lpthread -ldl -lnsl -lm -lxerces-c -lldap
 
 OBJ_DIR = $(BUILD_ROOT)/build/
 
--- a/src/server/config/acl.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/config/acl.c	Thu May 09 19:41:11 2013 +0200
@@ -49,6 +49,8 @@
         free_acl_file(conf);
         return NULL;
     }
+    
+    fclose(in);
 
     return conf;
 }
--- a/src/server/config/initconf.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/config/initconf.c	Thu May 09 19:41:11 2013 +0200
@@ -48,6 +48,8 @@
         // TODO: free
         return NULL;
     }
+    
+    fclose(in);
 
     return conf;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/keyfile.c	Thu May 09 19:41:11 2013 +0200
@@ -0,0 +1,137 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "keyfile.h"
+
+KeyfileConfig *load_keyfile_config(char *file) {
+    FILE *in = fopen(file, "r");
+    if(in == NULL) {
+        return NULL;
+    }
+    
+    KeyfileConfig *conf = malloc(sizeof(KeyfileConfig));
+    conf->parser.parse = keyfile_parse;
+    conf->file = file;
+    conf->users = NULL;
+
+    int r = cfg_parse_basic_file((ConfigParser*)conf, in);
+    if(r != 0) {
+        // TODO: free
+        return NULL;
+    }
+    
+    fclose(in);
+
+    return conf;
+}
+
+void free_keyfile_config(KeyfileConfig *conf) {
+    if(conf->users) {
+        ucx_list_free(conf->users);
+    }
+    ucx_mempool_free(conf->parser.mp);
+    free(conf);
+}
+
+int keyfile_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
+    KeyfileConfig *conf = p;
+    UcxMempool *mp = conf->parser.mp;
+    
+    size_t tkn = 0;
+    sstr_t *tk = sstrsplit(line, sstrn(";", 1), &tkn);
+    
+    if(tkn < 2) {
+        return 1;
+    }
+    
+    KeyfileEntry *entry = OBJ_NEW(mp, KeyfileEntry);
+    entry->groups = NULL;
+    entry->numgroups = 0;
+    
+    // get user name
+    entry->name = sstrdup_mp(mp, tk[0]);
+    
+    // get hash
+    sstr_t hash = sstrtrim(tk[1]);
+    if(hash.length < 4) {
+        // to short
+        return 1;
+    }
+    if(hash.ptr[0] != '{') {
+        // missing hash type specification
+        return 1;
+    }
+    
+    // get hash type and data
+    sstr_t hash_type;
+    sstr_t hash_data;
+    for(int i=1;i<hash.length;i++) {
+        if(hash.ptr[i] == '}') {
+            hash_type = sstrsubsl(hash, 1, i-1);
+            hash_data = sstrsubs(hash, i+1);
+        }
+    }
+    
+    if(!sstrcmp(hash_type, sstr("SSHA"))) {
+        entry->hashtype = KEYFILE_SSHA;
+    } else {
+        // unkown hash type
+        fprintf(stderr, "unknown hash type: %s\n", sstrdup(hash_type).ptr);
+        return 1;
+    }
+    
+    entry->hashdata = sstrdup_mp(mp, hash_data);
+    
+    // get groups
+    if(tkn == 3) {
+        sstr_t groups_str = sstrtrim(tk[2]);
+        size_t ngroups = 0;
+        sstr_t *groups = sstrsplit(groups_str, sstrn(",", 1), &ngroups);
+        entry->groups = calloc(ngroups, sizeof(sstr_t));
+        entry->numgroups = ngroups;
+        for(int i=0;i<ngroups;i++) {
+            entry->groups[i] = sstrdup_mp(mp, sstrtrim(groups[i]));
+            free(groups[i].ptr);
+        }
+        free(groups);
+    }
+    
+    // add user
+    conf->users = ucx_list_append(conf->users, entry);
+    
+    // free tokens
+    for(int i=0;i<tkn;i++) {
+        free(tk[i].ptr);
+    }
+    free(tk);
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/keyfile.h	Thu May 09 19:41:11 2013 +0200
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef KEYFILE_H
+#define	KEYFILE_H
+
+#include "conf.h"
+#include "../daemon/keyfile_auth.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct _keyfile_conf {
+    ConfigParser parser;
+    char         *file;
+    UcxList      *users; // KeyfileEntry list
+} KeyfileConfig;
+
+typedef struct _keyfile_entry {
+    sstr_t               name;
+    enum KeyfileHashType hashtype;
+    sstr_t               hashdata;
+    sstr_t               *groups;
+    size_t               numgroups;
+} KeyfileEntry;
+
+KeyfileConfig *load_keyfile_config(char *file);
+void free_keyfile_config(KeyfileConfig *conf);
+int keyfile_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* KEYFILE_H */
+
--- a/src/server/config/mimeconf.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/config/mimeconf.c	Thu May 09 19:41:11 2013 +0200
@@ -49,6 +49,8 @@
         // TODO: free
         return NULL;
     }
+    
+    fclose(in);
 
     return conf;
 }
--- a/src/server/config/objconf.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/config/objconf.c	Thu May 09 19:41:11 2013 +0200
@@ -57,6 +57,8 @@
         // TODO: free
         return NULL;
     }
+    
+    fclose(in);
 
     return conf;
 }
--- a/src/server/config/objs.mk	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/config/objs.mk	Thu May 09 19:41:11 2013 +0200
@@ -36,6 +36,7 @@
 CONFOBJ += serverconf.o
 CONFOBJ += mimeconf.o
 CONFOBJ += acl.o
+CONFOBJ += keyfile.o
 
 CONFOBJS = $(CONFOBJ:%=$(CONF_OBJPRE)%)
 CONFSOURCE = $(CONFOBJ:%.o=config/%.c)
--- a/src/server/config/serverconf.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/config/serverconf.c	Thu May 09 19:41:11 2013 +0200
@@ -50,6 +50,8 @@
         // TODO: free
         return NULL;
     }
+    
+    fclose(in);
 
     return conf;
 }
--- a/src/server/daemon/config.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/daemon/config.c	Thu May 09 19:41:11 2013 +0200
@@ -473,6 +473,39 @@
         free(name.ptr);
         */
         
+    } else if(!sstrcmp(type, sstr("keyfile"))) {
+        // we only need the file parameter
+        sstr_t file = cfg_directivelist_get_str(
+                obj->directives,
+                sstr("File"));
+        if(file.length == 0) {
+            log_ereport(
+                    LOG_MISCONFIG,
+                    "missing File parameter for keyfile authdb");
+            return 1;
+        }
+        
+        // load keyfile
+        ConfigFile *f = cfgmgr_get_file(file);
+        if(f == NULL) {
+            f = malloc(sizeof(ConfigFile));
+            f->data = NULL;
+            f->file = sstrdup(file);
+            f->reload = keyfile_reload;
+            //f->reload(f, cfg);
+            if(cfgmgr_reload_file(f, cfg, NULL)) {
+                free(f->file.ptr);
+                free(f);
+                return -1;
+            }
+            cfgmgr_attach_file(f);
+        }
+        
+        // add keyfile authdb
+        Keyfile *keyfile = f->data;
+        keyfile->authdb.name = sstrdup(name).ptr;
+        printf("authdb: %d\n", keyfile);
+        ucx_map_sstr_put(cfg->authdbs, name, keyfile);
     }
 
     return 0;
@@ -833,3 +866,33 @@
     
     return &acllist->acl;
 }
+
+int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg) {
+    KeyfileConfig *conf = load_keyfile_config(file->file.ptr);
+    if(!conf) {
+        return 1;
+    }
+    
+    Keyfile *keyfile = keyfile_new();
+    
+    UCX_FOREACH(UcxList*, conf->users, elm) {
+        KeyfileEntry *user = elm->data;
+        keyfile_add_user(
+                keyfile,
+                user->name,
+                user->hashtype,
+                user->hashdata,
+                user->groups,
+                user->numgroups);
+    }
+    
+    free_keyfile_config(conf);
+    
+    Keyfile *old_data = file->data;
+    file->data = keyfile;
+    if(old_data) {
+        keyfile_unref(old_data);
+    }
+    
+    return 0;
+}
--- a/src/server/daemon/config.h	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/daemon/config.h	Thu May 09 19:41:11 2013 +0200
@@ -38,8 +38,10 @@
 #include "../config/serverconf.h"
 #include "../config/mimeconf.h"
 #include "../config/acl.h"
+#include "../config/keyfile.h"
 
 #include "acldata.h"
+#include "keyfile_auth.h"
 
 #include "../ucx/list.h"
 #include "../ucx/dlist.h"
@@ -116,6 +118,7 @@
 void mime_conf_unref(MimeMap *conf);
 int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg);
 ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl);
+int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg);
 
 
 
--- a/src/server/daemon/configmanager.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/daemon/configmanager.c	Thu May 09 19:41:11 2013 +0200
@@ -140,7 +140,8 @@
     }
 
     ServerConfiguration *config;
-    if(sc_last_modified != s.st_mtim.tv_sec) {
+    //if(sc_last_modified != s.st_mtim.tv_sec) {
+    if(cfgreload || !current_config) {
         printf("cfgmgr load server.conf\n");
         config = load_server_conf(
             current_config,
@@ -152,7 +153,7 @@
         }
         
         sc_last_modified = s.st_mtim.tv_sec;
-    } else if(cfgreload) {
+    } else if(0) {
         /* copy configuration */
         printf("cfgmgr copy server.conf\n");
         
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/keyfile_auth.c	Thu May 09 19:41:11 2013 +0200
@@ -0,0 +1,158 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/sha.h>
+
+#include "../util/atomic.h"
+#include "../util/util.h"
+
+#include "keyfile_auth.h"
+
+Keyfile* keyfile_new() {
+    Keyfile *keyfile = malloc(sizeof(Keyfile));
+    keyfile->authdb.get_user = keyfile_get_user;
+    keyfile->users = ucx_map_new(16);
+    keyfile->ref = 1;
+    return keyfile;
+}
+
+void keyfile_ref(Keyfile *keyfile) {
+    ws_atomic_inc32(&keyfile->ref);
+}
+
+void keyfile_unref(Keyfile *keyfile) {
+    uint32_t ref = ws_atomic_dec32(&keyfile->ref);
+    if(ref == 0) { 
+        UcxMapIterator i = ucx_map_iterator(keyfile->users);
+        KeyfileUser *user;
+        UCX_MAP_FOREACH(user, i) {
+            free(user->user.name);
+            free(user->hash);
+            for(int i=0;i<user->numgroups;i++) {
+                free(user->groups[i].ptr);
+            }
+            free(user->groups);
+        }
+        ucx_map_free(keyfile->users);
+        
+        free(keyfile->authdb.name);
+        free(keyfile);
+    }
+}
+
+void keyfile_add_user(
+        Keyfile *keyfile,
+        sstr_t name,
+        enum KeyfileHashType hash_type,
+        sstr_t hash,
+        sstr_t *groups,
+        size_t ngroups)
+{
+    if(hash.length < 12) {
+        // hash too short
+        // TODO: log
+        return;
+    }
+    
+    KeyfileUser *user = malloc(sizeof(KeyfileUser));
+    user->user.name = sstrdup(name).ptr;
+    user->user.verify_password = keyfile_user_verify_password;
+    user->user.check_group = keyfile_user_check_group;
+    user->user.free = keyfile_user_free;
+    
+    user->hash_type = hash_type;
+    user->hash = malloc(hash.length + 1);
+    user->hashlen = util_base64decode(hash.ptr, hash.length, user->hash);
+    
+    user->groups = calloc(ngroups, sizeof(sstr_t));
+    for(int i=0;i<ngroups;i++) {
+        //user->groups[i] = sstrdup(groups[i]);
+        sstrdup(groups[i]);
+    }
+    
+    // add to keyfile
+    ucx_map_sstr_put(keyfile->users, name, user);
+}
+
+// authdb functions
+
+User* keyfile_get_user(AuthDB *db, char *user) {
+    Keyfile *keyfile = (Keyfile*)db;
+    return ucx_map_cstr_get(keyfile->users, user);
+}
+
+int keyfile_user_verify_password(User *user, char *password) {
+    KeyfileUser *usr = (KeyfileUser*)user;
+    switch(usr->hash_type) {
+        case KEYFILE_SSHA: return ssha_verify(usr, password);
+    }
+    return 0;
+}
+
+int keyfile_user_check_group(User *user, char *group) {
+    KeyfileUser *usr = (KeyfileUser*)user;
+    sstr_t grp = sstr(group);
+    for(int i=0;i<usr->numgroups;i++) {
+        if(!sstrcmp(usr->groups[i], grp)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+void keyfile_user_free(User *user) {
+    // don't free, it will be freed by keyfile_unref
+}
+
+
+int ssha_verify(KeyfileUser *user, char *password) {
+    /*
+     * SSHA: SHA1(pw + salt) + 8 bytes salt
+     * the SSHA hash is already base64 decoded
+     */
+    
+    char *salt = user->hash + user->hashlen - 8; // last 8 bytes are salt 
+    size_t pwlen = strlen(password);
+    
+    size_t saltpwlen = pwlen + 8;
+    char *saltpw = malloc(saltpwlen);
+    memcpy(saltpw, password, pwlen);
+    memcpy(saltpw + pwlen, salt, 8);
+    
+    unsigned char pwhash[20];
+    SHA1((const unsigned char*)saltpw, saltpwlen, pwhash);
+    
+    if(!memcmp(user->hash, pwhash, 20)) {
+        return 1;
+    }
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/keyfile_auth.h	Thu May 09 19:41:11 2013 +0200
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef KEYFILE_AUTH_H
+#define	KEYFILE_AUTH_H
+
+#include "../public/auth.h"
+#include "../ucx/map.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct keyfile        Keyfile;
+typedef struct keyfile_user   KeyfileUser;
+    
+enum KeyfileHashType {
+    KEYFILE_SSHA = 0
+};
+
+struct keyfile {
+    AuthDB   authdb;
+    UcxMap   *users;
+    uint32_t ref;
+};
+
+struct keyfile_user {
+    User                 user;
+    sstr_t               *groups;
+    size_t               numgroups; 
+    enum KeyfileHashType hash_type;
+    char                 *hash;
+    size_t               hashlen;
+};
+
+Keyfile* keyfile_new();
+void keyfile_ref(Keyfile *keyfile);
+void keyfile_unref(Keyfile *keyfile);
+
+void keyfile_add_user(
+        Keyfile *keyfile,
+        sstr_t user,
+        enum KeyfileHashType hash_type,
+        sstr_t hash,
+        sstr_t *groups,
+        size_t ngroups);
+
+User* keyfile_get_user(AuthDB *db, char *user);
+int keyfile_user_verify_password(User *user, char *password);
+int keyfile_user_check_group(User *user, char *group);
+void keyfile_user_free(User *user);
+
+// SSHA password compare
+int ssha_verify(KeyfileUser *user, char *password);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* KEYFILE_AUTH_H */
+
--- a/src/server/daemon/objs.mk	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/daemon/objs.mk	Thu May 09 19:41:11 2013 +0200
@@ -49,6 +49,7 @@
 DAEMONOBJ += threadpools.o
 DAEMONOBJ += authdb.o
 DAEMONOBJ += ldap_auth.o
+DAEMONOBJ += keyfile_auth.o
 DAEMONOBJ += error.o
 DAEMONOBJ += acl.o
 DAEMONOBJ += acldata.o
--- a/src/server/public/auth.h	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/public/auth.h	Thu May 09 19:41:11 2013 +0200
@@ -52,6 +52,7 @@
 
 /*
  * verify the users password
+ * returns 1 if the password is correct, otherwise 0
  * 
  * param1: user
  * param2: password
--- a/src/server/safs/auth.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/safs/auth.c	Thu May 09 19:41:11 2013 +0200
@@ -42,7 +42,7 @@
 
 /* ------------------------------ _uudecode ------------------------------- */
 
-const unsigned char pr2six[256] = {
+static const unsigned char pr2six[256] = {
     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
     52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
--- a/src/server/ucx/Makefile	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/ucx/Makefile	Thu May 09 19:41:11 2013 +0200
@@ -27,5 +27,5 @@
 #
 
 $(UCX_OBJPRE)%.o: ucx/%.c
-	$(CC) -o $@ -c -g $(CFLAGS) $<
+	$(CC) -o $@ -c $(CFLAGS) $<
 	
--- a/src/server/util/util.c	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/util/util.c	Thu May 09 19:41:11 2013 +0200
@@ -56,6 +56,58 @@
 
 #include "util.h"
 
+
+
+/* ------------------------------ _uudecode ------------------------------- */
+
+static const unsigned char pr2six[256] = {
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
+    52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
+    10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
+    28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64
+};
+
+/** you MUST reserve at least 2 additional bytes for bufout */
+size_t util_base64decode(char *bufcoded, size_t codedbytes, char *bufout) {
+    register char *bufin = bufcoded;
+    register int nprbytes;
+    size_t nbytesdecoded;
+
+    /* Find the length */
+    nprbytes = (int) codedbytes;
+    while(pr2six[(int)(bufin[nprbytes-1])] >= 64) {
+      nprbytes--;
+    }
+    nbytesdecoded = ((nprbytes+3)/4) * 3;
+
+    while (nprbytes > 0) {
+        *(bufout++) = (unsigned char)
+            (pr2six[(int)(*bufin)] << 2 | pr2six[(int)bufin[1]] >> 4);
+        *(bufout++) = (unsigned char)
+            (pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2);
+        *(bufout++) = (unsigned char)
+            (pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]);
+        bufin += 4;
+        nprbytes -= 4;
+    }
+
+    if(nprbytes & 03) {
+        if(pr2six[(int)bufin[-2]] > 63)
+            nbytesdecoded -= 2;
+        else
+            nbytesdecoded -= 1;
+    }
+
+    return nbytesdecoded;
+}
+
 /*
 NSAPI_PUBLIC int util_getboolean(const char *v, int def) {
     if(v[0] == 'T' || v[0] == 't') {
--- a/src/server/util/util.h	Thu May 09 13:19:51 2013 +0200
+++ b/src/server/util/util.h	Thu May 09 19:41:11 2013 +0200
@@ -77,6 +77,8 @@
 extern "C" {
 #endif
 
+size_t util_base64decode(char *bufcoded, size_t codedbytes, char *bufout); 
+
 NSAPI_PUBLIC
 int INTutil_init_PRNetAddr(PRNetAddr * naddr, char * ipstr, int iplen, int type);
 

mercurial