--- /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; +}