Blame authfile.c

Packit 4e8bc4
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit 4e8bc4
#include <stdio.h>
Packit 4e8bc4
#include <stdlib.h>
Packit 4e8bc4
#include <stdbool.h>
Packit 4e8bc4
#include <string.h>
Packit 4e8bc4
#include <sys/types.h>
Packit 4e8bc4
#include <sys/stat.h>
Packit 4e8bc4
#include <unistd.h>
Packit 4e8bc4
#include <inttypes.h>
Packit 4e8bc4
Packit 4e8bc4
#include "authfile.h"
Packit 4e8bc4
#include "util.h"
Packit 4e8bc4
Packit 4e8bc4
// TODO: frontend needs a refactor so this can avoid global objects.
Packit 4e8bc4
Packit 4e8bc4
#define MAX_ENTRY_LEN 256
Packit 4e8bc4
// Not supposed to be a huge database!
Packit 4e8bc4
#define MAX_ENTRIES 8
Packit 4e8bc4
Packit 4e8bc4
typedef struct auth_entry {
Packit 4e8bc4
    char *user;
Packit 4e8bc4
    size_t ulen;
Packit 4e8bc4
    char *pass;
Packit 4e8bc4
    size_t plen;
Packit 4e8bc4
} auth_t;
Packit 4e8bc4
Packit 4e8bc4
auth_t main_auth_entries[MAX_ENTRIES];
Packit 4e8bc4
int entry_cnt = 0;
Packit 4e8bc4
char *main_auth_data = NULL;
Packit 4e8bc4
Packit 4e8bc4
enum authfile_ret authfile_load(const char *file) {
Packit 4e8bc4
    struct stat sb;
Packit 4e8bc4
    char *auth_data = NULL;
Packit 4e8bc4
    auth_t auth_entries[MAX_ENTRIES];
Packit 4e8bc4
Packit 4e8bc4
    if (stat(file, &sb) == -1) {
Packit 4e8bc4
        return AUTHFILE_MISSING;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    auth_data = calloc(1, sb.st_size);
Packit 4e8bc4
Packit 4e8bc4
    if (auth_data == NULL) {
Packit 4e8bc4
        return AUTHFILE_OOM;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    FILE *pwfile = fopen(file, "r");
Packit 4e8bc4
    if (pwfile == NULL) {
Packit 4e8bc4
        // not strictly necessary but to be safe.
Packit 4e8bc4
        free(auth_data);
Packit 4e8bc4
        return AUTHFILE_OPENFAIL;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    char *auth_cur = auth_data;
Packit 4e8bc4
    auth_t *entry_cur = auth_entries;
Packit 4e8bc4
    int used = 0;
Packit 4e8bc4
Packit 4e8bc4
    while ((fgets(auth_cur, MAX_ENTRY_LEN, pwfile)) != NULL) {
Packit 4e8bc4
        int x;
Packit 4e8bc4
        int found = 0;
Packit 4e8bc4
Packit 4e8bc4
        for (x = 0; x < MAX_ENTRY_LEN; x++) {
Packit 4e8bc4
            if (!found && auth_cur[x] == ':') {
Packit 4e8bc4
                entry_cur->user = auth_cur;
Packit 4e8bc4
                entry_cur->ulen = x;
Packit 4e8bc4
                entry_cur->pass = &auth_cur[x+1];
Packit 4e8bc4
                found = 1;
Packit 4e8bc4
            } else if (found) {
Packit 4e8bc4
                // Find end of password.
Packit 4e8bc4
                if (auth_cur[x] == '\n' ||
Packit 4e8bc4
                    auth_cur[x] == '\r' ||
Packit 4e8bc4
                    auth_cur[x] == '\0') {
Packit 4e8bc4
                    entry_cur->plen = x - (entry_cur->ulen + 1);
Packit 4e8bc4
                    break;
Packit 4e8bc4
                }
Packit 4e8bc4
            }
Packit 4e8bc4
        }
Packit 4e8bc4
Packit 4e8bc4
        // malformed line.
Packit 4e8bc4
        if (!found) {
Packit 4e8bc4
            (void)fclose(pwfile);
Packit 4e8bc4
            free(auth_data);
Packit 4e8bc4
            return AUTHFILE_MALFORMED;
Packit 4e8bc4
        }
Packit 4e8bc4
Packit 4e8bc4
        // FIXME: no silent truncation.
Packit 4e8bc4
        if (++used == MAX_ENTRIES) {
Packit 4e8bc4
            break;
Packit 4e8bc4
        }
Packit 4e8bc4
        // EOF
Packit 4e8bc4
        if (auth_cur[x] == '\0')
Packit 4e8bc4
            break;
Packit 4e8bc4
Packit 4e8bc4
        auth_cur += x;
Packit 4e8bc4
        entry_cur++;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    // swap the main pointer out now, so if there's an error reloading we
Packit 4e8bc4
    // don't break the existing authentication.
Packit 4e8bc4
    if (main_auth_data != NULL) {
Packit 4e8bc4
        free(main_auth_data);
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    entry_cnt = used;
Packit 4e8bc4
    main_auth_data = auth_data;
Packit 4e8bc4
    memcpy(main_auth_entries, auth_entries, sizeof(auth_entries));
Packit 4e8bc4
Packit 4e8bc4
    (void)fclose(pwfile);
Packit 4e8bc4
Packit 4e8bc4
    return AUTHFILE_OK;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
// if only loading the file could be this short...
Packit 4e8bc4
int authfile_check(const char *user, const char *pass) {
Packit 4e8bc4
    size_t ulen = strlen(user);
Packit 4e8bc4
    size_t plen = strlen(pass);
Packit 4e8bc4
Packit 4e8bc4
    for (int x = 0; x < entry_cnt; x++) {
Packit 4e8bc4
        auth_t *e = &main_auth_entries[x];
Packit 4e8bc4
        if (ulen == e->ulen && plen == e->plen &&
Packit 4e8bc4
            safe_memcmp(user, e->user, e->ulen) &&
Packit 4e8bc4
            safe_memcmp(pass, e->pass, e->plen)) {
Packit 4e8bc4
            return 1;
Packit 4e8bc4
        }
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    return 0;
Packit 4e8bc4
}