1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inttypes.h>
#include "authfile.h"
#include "util.h"
// TODO: frontend needs a refactor so this can avoid global objects.
#define MAX_ENTRY_LEN 256
// Not supposed to be a huge database!
#define MAX_ENTRIES 8
typedef struct auth_entry {
char *user;
size_t ulen;
char *pass;
size_t plen;
} auth_t;
auth_t main_auth_entries[MAX_ENTRIES];
int entry_cnt = 0;
char *main_auth_data = NULL;
enum authfile_ret authfile_load(const char *file) {
struct stat sb;
char *auth_data = NULL;
auth_t auth_entries[MAX_ENTRIES];
if (!file || strlen(file) == 0) {
return AUTHFILE_OPENFAIL;
}
FILE *pwfile = fopen(file, "r");
if (pwfile == NULL) {
return AUTHFILE_OPENFAIL;
} else if (fstat(fileno(pwfile), &sb)) {
fclose(pwfile);
return AUTHFILE_STATFAIL;
}
auth_data = calloc(1, sb.st_size + 2);
char *auth_cur = auth_data;
// fgets will stop at EOF or a newline, reading at most one bytes less
// than the size limit. If a user supplies a file without an ending
// newline we will end up chopping the last character of the password.
char *auth_end = auth_data + sb.st_size + 1;
auth_t *entry_cur = auth_entries;
int used = 0;
while ((fgets(auth_cur, auth_end - auth_cur < MAX_ENTRY_LEN ? auth_end - auth_cur : MAX_ENTRY_LEN, pwfile)) != NULL) {
int x;
int found = 0;
for (x = 0; x < MAX_ENTRY_LEN; x++) {
if (!found) {
if (auth_cur[x] == '\0') {
// The username is malformed - this is either the end of the file or a null byte.
break;
} else if (auth_cur[x] == ':') {
entry_cur->user = auth_cur;
entry_cur->ulen = x;
entry_cur->pass = &auth_cur[x+1];
found = 1;
}
} else {
// Find end of password.
if (auth_cur[x] == '\n' ||
auth_cur[x] == '\r' ||
auth_cur[x] == '\0') {
entry_cur->plen = x - (entry_cur->ulen + 1);
break;
}
}
}
// malformed line.
if (!found) {
(void)fclose(pwfile);
free(auth_data);
return AUTHFILE_MALFORMED;
}
// FIXME: no silent truncation.
if (++used == MAX_ENTRIES) {
break;
}
// EOF
if (auth_cur[x] == '\0')
break;
auth_cur += x;
entry_cur++;
}
// swap the main pointer out now, so if there's an error reloading we
// don't break the existing authentication.
if (main_auth_data != NULL) {
free(main_auth_data);
}
entry_cnt = used;
main_auth_data = auth_data;
memcpy(main_auth_entries, auth_entries, sizeof(auth_entries));
(void)fclose(pwfile);
return AUTHFILE_OK;
}
// if only loading the file could be this short...
int authfile_check(const char *user, unsigned int ulen, const char *pass, unsigned int plen) {
for (int x = 0; x < entry_cnt; x++) {
auth_t *e = &main_auth_entries[x];
if (ulen == e->ulen && plen == e->plen &&
safe_memcmp(user, e->user, e->ulen) &&
safe_memcmp(pass, e->pass, e->plen)) {
return 1;
}
}
return 0;
}
|