summaryrefslogtreecommitdiff
path: root/LibC/pwd.cpp
blob: d0280861e1d590473f795225599e03bf564062d0 (plain)
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
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <AK/AKString.h>

extern "C" {

#define PWDB_STR_MAX_LEN 256

struct passwd_with_strings : public passwd {
    char name_buffer[PWDB_STR_MAX_LEN];
    char passwd_buffer[PWDB_STR_MAX_LEN];
    char gecos_buffer[PWDB_STR_MAX_LEN];
    char dir_buffer[PWDB_STR_MAX_LEN];
    char shell_buffer[PWDB_STR_MAX_LEN];
};

static FILE* __pwdb_stream = nullptr;
static unsigned __pwdb_line_number = 0;
static struct passwd_with_strings* __pwdb_entry = nullptr;

void setpwent()
{
    __pwdb_line_number = 0;
    if (__pwdb_stream) {
        rewind(__pwdb_stream);
    } else {
        __pwdb_stream = fopen("/etc/passwd", "r");
        if (!__pwdb_stream) {
            perror("open /etc/passwd");
        }
        assert(__pwdb_stream);
        __pwdb_entry = (struct passwd_with_strings*)mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
        set_mmap_name(__pwdb_entry, getpagesize(), "setpwent");
    }
}

void endpwent()
{
    __pwdb_line_number = 0;
    if (__pwdb_stream) {
        fclose(__pwdb_stream);
        __pwdb_stream = nullptr;
    }
    if (__pwdb_entry) {
        munmap(__pwdb_entry, getpagesize());
        __pwdb_entry = nullptr;
    }
}

struct passwd* getpwuid(uid_t uid)
{
    setpwent();
    while (auto* pw = getpwent()) {
        if (pw->pw_uid == uid)
            return pw;
    }
    return nullptr;
}

struct passwd* getpwnam(const char* name)
{
    setpwent();
    while (auto* pw = getpwent()) {
        if (!strcmp(pw->pw_name, name))
            return pw;
    }
    return nullptr;
}

struct passwd* getpwent()
{
    if (!__pwdb_stream)
        setpwent();

    assert(__pwdb_stream);
    if (feof(__pwdb_stream))
        return nullptr;

next_entry:
    char buffer[1024];
    ++__pwdb_line_number;
    char* s = fgets(buffer, sizeof(buffer), __pwdb_stream);
    if (!s)
        return nullptr;
    assert(__pwdb_stream);
    if (feof(__pwdb_stream))
        return nullptr;
    String line(s, Chomp);
    auto parts = line.split(':');
    if (parts.size() != 7) {
        fprintf(stderr, "getpwent(): Malformed entry on line %u\n", __pwdb_line_number);
        goto next_entry;
    }
    auto& e_name = parts[0];
    auto& e_passwd = parts[1];
    auto& e_uid_string = parts[2];
    auto& e_gid_string = parts[3];
    auto& e_gecos = parts[4];
    auto& e_dir = parts[5];
    auto& e_shell = parts[6];
    bool ok;
    uid_t e_uid = e_uid_string.to_uint(ok);
    if (!ok) {
        fprintf(stderr, "getpwent(): Malformed UID on line %u\n", __pwdb_line_number);
        goto next_entry;
    }
    gid_t e_gid = e_gid_string.to_uint(ok);
    if (!ok) {
        fprintf(stderr, "getpwent(): Malformed GID on line %u\n", __pwdb_line_number);
        goto next_entry;
    }
    __pwdb_entry->pw_uid = e_uid;
    __pwdb_entry->pw_gid = e_gid;
    __pwdb_entry->pw_name = __pwdb_entry->name_buffer;
    __pwdb_entry->pw_passwd = __pwdb_entry->passwd_buffer;
    __pwdb_entry->pw_gecos = __pwdb_entry->gecos_buffer;
    __pwdb_entry->pw_dir = __pwdb_entry->dir_buffer;
    __pwdb_entry->pw_shell = __pwdb_entry->shell_buffer;
    strncpy(__pwdb_entry->name_buffer, e_name.characters(), PWDB_STR_MAX_LEN);
    strncpy(__pwdb_entry->passwd_buffer, e_passwd.characters(), PWDB_STR_MAX_LEN);
    strncpy(__pwdb_entry->gecos_buffer, e_gecos.characters(), PWDB_STR_MAX_LEN);
    strncpy(__pwdb_entry->dir_buffer, e_dir.characters(), PWDB_STR_MAX_LEN);
    strncpy(__pwdb_entry->shell_buffer, e_shell.characters(), PWDB_STR_MAX_LEN);
    return __pwdb_entry;
}

}