#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 "keyfile_auth.h"
Keyfile* keyfile_new() {
Keyfile *keyfile = malloc(
sizeof(Keyfile));
keyfile->authdb.get_user = keyfile_get_user;
keyfile->authdb.use_cache =
0;
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(key, user, i) {
free(user->user.name);
free(user->hash);
for(
int n=
0;n<user->numgroups;n++) {
free(user->groups[n].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) {
return;
}
KeyfileUser *user = malloc(
sizeof(KeyfileUser));
user->user.name = sstrdup(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 = 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]);
}
ucx_map_sstr_put(keyfile->users, name, user);
}
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;
return ssha_verify(usr, password);
}
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) {
}
int ssha_verify(KeyfileUser *user,
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;
}
}