File: authfile.c

package info (click to toggle)
memcached 1.6.41-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,232 kB
  • sloc: ansic: 61,198; perl: 12,716; sh: 5,049; makefile: 471; python: 402; xml: 59
file content (131 lines) | stat: -rw-r--r-- 3,635 bytes parent folder | download
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;
}