Add passwd component
This commit is contained in:
parent
e00ffe6f70
commit
f43bb30065
|
@ -0,0 +1,245 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file passwd.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <cStuff/file.h>
|
||||||
|
#include "passwd.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_passwd_ctx {
|
||||||
|
struct ax_passwd *items;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_passwd_hex2bytes(const char *hex, char *out, int max_len)
|
||||||
|
{
|
||||||
|
char s_byte[] = {'\0', '\0', '\0'}, *e_ptr = NULL;
|
||||||
|
for (i = 0; i < max_len; i++) {
|
||||||
|
if (!(*ptr)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
memcpy(s_byte, hex, 2);
|
||||||
|
*out = strtol(s_byte, &e_ptr, 16) & 0xFF;
|
||||||
|
if (e_ptr != &s_byte[2]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (!(*ptr)) ? true : flase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_hash(struct ax_passwd *entry, char *hash, int length)
|
||||||
|
{
|
||||||
|
char *ptr, *saveptr = NULL, *out, c;
|
||||||
|
int token = 0, i, cnt;
|
||||||
|
|
||||||
|
while ((ptr = strtok(hash, "$", &saveptr)) != NULL) {
|
||||||
|
switch (token++) {
|
||||||
|
case 0:
|
||||||
|
if (!(*ptr)) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if (!(strcmp(ptr, "1"))) {
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if (ax_passwd_hex2bytes(ptr, entry->salt, sizeof (entry->salt))) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
if (ax_passwd_hex2bytes(ptr, entry->hash, sizeof (entry->hash))) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_line(char *line, ssize_t len, void *p_ctx)
|
||||||
|
{
|
||||||
|
int token = 0;
|
||||||
|
struct ax_passwd_ctx *ctx = (struct ax_passwd_ctx *)p_ctx;
|
||||||
|
struct ax_passwd entry = {0};
|
||||||
|
char *ptr, *saveptr = NULL;
|
||||||
|
|
||||||
|
while ((ptr = strtok(line, ":", &saveptr)) != NULL) {
|
||||||
|
switch (token++) {
|
||||||
|
case 0:
|
||||||
|
if (!cstuff_strncpy(&entry.name, ptr, (int)(saveptr - line))) {
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return CSTUFF_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
entry.uid = strtol(ptr, NULL, 10);
|
||||||
|
continue;
|
||||||
|
case 2:
|
||||||
|
entry.gid = strtol(ptr, NULL, 10);
|
||||||
|
continue;
|
||||||
|
case 3:
|
||||||
|
return ax_passwd_get_hash(&entry, ptr, (int)(saveptr - line));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_import(struct ax_passwd **p_out, const char *file)
|
||||||
|
{
|
||||||
|
struct ax_passwd_ctx ctx = {NULL, 0};
|
||||||
|
|
||||||
|
if (!cstuff_file_get_lines(file, ax_passwd_get_line, (void *)&ctx)) {
|
||||||
|
*p_out = ctx->items;
|
||||||
|
return ctx->count;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_export(const struct ax_passwd *in, int size, const char *file)
|
||||||
|
{
|
||||||
|
int result = -1, i, j = 0;
|
||||||
|
char *swap, hash[2 * (sizeof (in->salt) + sizeof (in->hash)) + 2];
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof (in->salt); i++) {
|
||||||
|
sprintf(&hash[j], "%02x", in->salt[i] & 0xFF);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
hash[j++] = '$';
|
||||||
|
for (i = 0; i < sizeof (in->hash); i++) {
|
||||||
|
sprintf(&hash[j], "%02x", in->hash[i] & 0xFF);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cstuff_printf(&swap, "%s.swap", file)) {
|
||||||
|
if ((f = fopen(swap, "w")) != NULL) {
|
||||||
|
result = 0;
|
||||||
|
while (size--) {
|
||||||
|
if (fprintf(f, "%s:%"PRIu32":%"PRIu32":$1$%s:\n", in->name, in->uid,
|
||||||
|
in->gid, hash) < 0) {
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
if (!result) {
|
||||||
|
if (cstuff_file_move(swap, file) != CSTUFF_SUCCESS)
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(swap);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_salted(unsigned char **out, const char *password,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
int l = strlen(password), result = l + AX_PASSWD_SALT_SIZE;
|
||||||
|
unsigned char *salted;
|
||||||
|
|
||||||
|
if ((salted = malloc(result)) != NULL) {
|
||||||
|
strcpy(salted, password);
|
||||||
|
memcpy(&salted[l], salt, AX_PASSWD_SALT_SIZE);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_verify(const struct ax_passwd *passwd, const char *password)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned char *sltpass, hash[AX_PASSWD_HASH_SIZE];
|
||||||
|
int l;
|
||||||
|
|
||||||
|
if ((l = ax_passwd_get_salted(&sltpass, password, passwd->salt)) != -1) {
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, sltpass, l);
|
||||||
|
SHA1_Final(hash, &ctx);
|
||||||
|
free(sltpass);
|
||||||
|
return (!memcmp(passwd->hash, hash, sizeof (hash))) ? 0 : 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_set_hash(struct ax_passwd *out, const char *password)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned char *sltpass;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
RAND_bytes(out->salt, (sizeof (out->salt)));
|
||||||
|
|
||||||
|
if ((l = ax_passwd_get_salted(&sltpass, password, out->salt)) != -1) {
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, sltpass, l);
|
||||||
|
SHA1_Final(out->hash, &ctx);
|
||||||
|
free(sltpass);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_free(struct ax_passwd **p_out, int size)
|
||||||
|
{
|
||||||
|
struct ax_passwd *p = *p_out;
|
||||||
|
|
||||||
|
while (size--) {
|
||||||
|
if (p->name)
|
||||||
|
free(p->name);
|
||||||
|
if (p->hash)
|
||||||
|
free(p->hash);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
free(*p_out);
|
||||||
|
*p_out = NULL;
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file passwd.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA
|
||||||
|
#define AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#define AX_PASSWD_TOKENS 4
|
||||||
|
#define AX_PASSWD_SALT_SIZE 16
|
||||||
|
#define AX_PASSWD_HASH_SIZE SHA1_DIGEST_LENGTH
|
||||||
|
|
||||||
|
struct ax_passwd {
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
char *name;
|
||||||
|
char salt[AX_PASSWD_SALT_SIZE];
|
||||||
|
char hash[AX_PASSWD_HASH_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_passwd * AxPasswd;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_import(struct ax_passwd **p_out, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_export(const struct ax_passwd *in, int size, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_verify(const struct ax_passwd *passwd, const char *password);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_set_hash(struct ax_passwd *out, const char *password);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_free(struct ax_passwd **p_out, int size);
|
||||||
|
|
||||||
|
#endif /* !AX_PASSWD_H */
|
Loading…
Reference in New Issue