From f43bb30065682b2ea9eeb1395b640cd0abacb9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilja=20Karta=C5=A1ov?= Date: Wed, 17 Jul 2019 22:50:08 +0200 Subject: [PATCH] Add passwd component --- components/passwd.c | 245 ++++++++++++++++++++++++++++++++++++++++++++ components/passwd.h | 57 +++++++++++ 2 files changed, 302 insertions(+) create mode 100644 components/passwd.c create mode 100644 components/passwd.h diff --git a/components/passwd.c b/components/passwd.c new file mode 100644 index 0000000..3f023c9 --- /dev/null +++ b/components/passwd.c @@ -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 + * @brief + * + * @see https://lowenware.com/ + */ + +#include +#include +#include +#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; +} diff --git a/components/passwd.h b/components/passwd.h new file mode 100644 index 0000000..9f79566 --- /dev/null +++ b/components/passwd.h @@ -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 + * @brief + * + * @see https://lowenware.com/ + */ + +#ifndef AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA +#define AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA + +#include +#include +#include + +#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 */