#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#if defined(__sun) && defined(__SunOS_5_10)
#include <sha2.h>
#define SHA256_Init SHA256Init
#define SHA256_Update SHA256Update
#define SHA256_Final SHA256Final
#endif
#include "../util/atomic.h"
#include "../util/util.h"
#include <cx/hash_map.h>
#include "keyfile_auth.h"
Keyfile* keyfile_new(CxAllocator *a) {
Keyfile *keyfile = cxCalloc(a,
1,
sizeof(Keyfile));
if(!keyfile) {
return NULL;
}
keyfile->authdb.get_user = keyfile_get_user;
keyfile->authdb.use_cache =
0;
keyfile->users = cxHashMapCreate(a,
CX_STORE_POINTERS,
16);
return keyfile;
}
int keyfile_add_user(
Keyfile *keyfile,
cxmutstr name,
enum KeyfileHashType hash_type,
cxmutstr hash,
cxmutstr *groups,
size_t ngroups)
{
const CxAllocator *a = keyfile->users->allocator;
if(hash.length <
12) {
return -
1;
}
KeyfileUser *user = cxMalloc(a,
sizeof(KeyfileUser));
user->user.name = cx_strdup_a(a, cx_strcast(name)).ptr;
user->user.uid = -
1;
user->user.gid = -
1;
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 = cxMalloc(a, hash.length +
1);
if(!user->user.name || !user->hash) {
return -
1;
}
user->hashlen = util_base64decode(hash.ptr, hash.length, user->hash);
if(ngroups >
0) {
user->groups = cxCalloc(a, ngroups,
sizeof(cxmutstr));
if(!user->groups) {
return -
1;
}
for(
int i=
0;i<ngroups;i++) {
user->groups[i] = cx_strdup_a(a, cx_strcast(groups[i]));
}
}
else {
user->groups =
NULL;
}
return cxMapPut(keyfile->users, cx_hash_key(name.ptr, name.length), user);
}
User* keyfile_get_user(AuthDB *db, Session *sn, Request *rq,
const char *user) {
Keyfile *keyfile = (Keyfile*)db;
return cxMapGet(keyfile->users, cx_hash_key_str(user));
}
int keyfile_user_verify_password(User *user,
const char *password) {
KeyfileUser *usr = (KeyfileUser*)user;
return ssha_verify(usr, password);
}
int keyfile_user_check_group(User *user,
const char *group) {
KeyfileUser *usr = (KeyfileUser*)user;
cxstring grp = cx_str(group);
for(
int i=
0;i<usr->numgroups;i++) {
if(!cx_strcmp(cx_strcast(usr->groups[i]), grp)) {
return 1;
}
}
return 0;
}
void keyfile_user_free(User *user) {
}
int ssha_verify(KeyfileUser *user,
const char *password) {
size_t hlen;
switch(user->hash_type) {
case KEYFILE_SSHA: hlen =
20;
break;
case KEYFILE_SSHA256: hlen =
32;
break;
case KEYFILE_SSHA512: hlen =
64;
break;
}
char *salt = user->hash + hlen;
size_t saltlen = user->hashlen - hlen;
size_t pwlen = strlen(password);
unsigned char pwhash[
64];
switch(user->hash_type) {
case KEYFILE_SSHA: {
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, password, pwlen);
SHA1_Update(&ctx, salt, saltlen);
SHA1_Final(pwhash, &ctx);
break;
}
case KEYFILE_SSHA256: {
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, password, pwlen);
SHA256_Update(&ctx, salt, saltlen);
SHA256_Final(pwhash, &ctx);
break;
}
case KEYFILE_SSHA512: {
SHA512_CTX ctx;
SHA512_Init(&ctx);
SHA512_Update(&ctx, password, pwlen);
SHA512_Update(&ctx, salt, saltlen);
SHA512_Final(pwhash, &ctx);
break;
}
}
if(!memcmp(user->hash, pwhash, hlen)) {
return 1;
}
else {
return 0;
}
}