The Pedigree Project 0.1
UserManager.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "UserManager.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/process/Process.h"
23#include "pedigree/kernel/process/Thread.h"
24#include "pedigree/kernel/processor/Processor.h"
25#include "pedigree/kernel/processor/ProcessorInformation.h"
26#include "pedigree/kernel/utilities/Iterator.h"
27#include "pedigree/kernel/utilities/utility.h"
28
29#include "Group.h"
30#include "User.h"
31#include "modules/Module.h"
32#include "modules/system/vfs/File.h"
33#include "modules/system/vfs/VFS.h"
34
35UserManager UserManager::m_Instance;
36
37UserManager::UserManager() : m_Users(), m_Groups() {}
38
39UserManager::~UserManager() {}
40
41static bool readAccountFile(const char* path, String& contents) {
42 Directory::ChildLease fileLease;
43 File* pFile = VFS::instance().findRetained(String(path), fileLease);
44 if (!pFile || pFile->isDirectory()) {
45 ERROR("USERS: Unable to read " << path);
46 return false;
47 }
48
49 size_t offset = 0;
50 char buffer[256];
51 while (offset < pFile->getSize()) {
52 size_t amount = pFile->getSize() - offset;
53 if (amount >= sizeof(buffer))
54 amount = sizeof(buffer) - 1;
55
56 uint64_t nRead = pFile->read(offset, amount, reinterpret_cast<uintptr_t>(buffer));
57 if (!nRead) {
58 ERROR("USERS: Unable to read " << path);
59 return false;
60 }
61
62 contents += String(buffer, nRead, true);
63 offset += nRead;
64 }
65
66 return true;
67}
68
69bool UserManager::initialiseGroups() {
70 String contents;
71 if (!readAccountFile("/etc/group", contents))
72 return false;
73
74 Vector<String> lines;
75 contents.tokenise('\n', lines);
76 for (auto& line : lines) {
77 line.strip();
78 if (!line.length() || line[0] == '#')
79 continue;
80
81 Vector<String> fields;
82 line.tokenise(':', fields);
83 if (fields.count() < 3) {
84 WARNING("USERS: Ignoring malformed /etc/group entry");
85 continue;
86 }
87
88 addGroup(StringToUnsignedLong(fields[2].cstr(), 0, 10), fields[0]);
89 }
90
91 return true;
92}
93
94bool UserManager::initialiseUsers() {
95 String contents;
96 if (!readAccountFile("/etc/passwd", contents))
97 return false;
98
99 Vector<String> lines;
100 contents.tokenise('\n', lines);
101 for (auto& line : lines) {
102 line.strip();
103 if (!line.length() || line[0] == '#')
104 continue;
105
106 Vector<String> fields;
107 line.tokenise(':', fields);
108 if (fields.count() < 7) {
109 WARNING("USERS: Ignoring malformed /etc/passwd entry");
110 continue;
111 }
112
113 addUser(StringToUnsignedLong(fields[2].cstr(), 0, 10), fields[0], fields[4],
114 StringToUnsignedLong(fields[3].cstr(), 0, 10), fields[5], fields[6]);
115 }
116
117 return true;
118}
119
120bool UserManager::initialiseMemberships() {
121 String contents;
122 if (!readAccountFile("/etc/group", contents))
123 return false;
124
125 Vector<String> lines;
126 contents.tokenise('\n', lines);
127 for (auto& line : lines) {
128 line.strip();
129 if (!line.length() || line[0] == '#')
130 continue;
131
132 Vector<String> fields;
133 line.tokenise(':', fields);
134 if (fields.count() < 4)
135 continue;
136
137 Group* pGroup = getGroup(StringToUnsignedLong(fields[2].cstr(), 0, 10));
138 if (!pGroup)
139 continue;
140
141 Vector<String> members;
142 fields[3].tokenise(',', members);
143 for (auto& member : members) {
144 User* pUser = getUser(member);
145 if (pUser)
146 pUser->join(pGroup);
147 }
148 }
149
150 return true;
151}
152
154 return m_Users.lookup(id);
155}
156
158 for (Tree<size_t, User*>::Iterator it = m_Users.begin(); it != m_Users.end(); it++) {
159 User* pU = it.value();
160 if (pU->getUsername() == name)
161 return pU;
162 }
163 return 0;
164}
165
167 return m_Groups.lookup(id);
168}
169
171 for (Tree<size_t, Group*>::Iterator it = m_Groups.begin(); it != m_Groups.end(); it++) {
172 Group* pG = it.value();
173 if (pG->getName() == name)
174 return pG;
175 }
176 return 0;
177}
178
179void UserManager::addUser(size_t uid, String username, String fullName, size_t group, String home,
180 String shell) {
181 // Check for duplicates.
182 if (getUser(uid)) {
183 WARNING("USERS: Not inserting user '" << username << "' with uid " << uid << ": duplicate.");
184 return;
185 }
186
187 // Check that the given group exists.
188 Group* pGroup = getGroup(group);
189 if (!pGroup) {
190 WARNING("USERS: Not inserting user '" << username << "': group " << group
191 << " does not exist.");
192 return;
193 }
194
195 NOTICE("USERS: Adding user {" << uid << ",'" << username << "','" << fullName << "'}");
196 User* pUser = new User(uid, username, fullName, pGroup, home, shell);
197 pGroup->join(pUser);
198 m_Users.insert(uid, pUser);
199}
200
201void UserManager::addGroup(size_t gid, String name) {
202 // Check for duplicates.
203 if (getGroup(gid)) {
204 WARNING("USERS: Not inserting group '" << name << "' with gid " << gid << ": duplicate.");
205 return;
206 }
207
208 NOTICE("USERS: Adding group {" << gid << ",'" << name << "'}");
209 Group* pGroup = new Group(gid, name);
210 m_Groups.insert(gid, pGroup);
211}
212
214 if (!initialiseGroups() || !initialiseUsers() || !initialiseMemberships()) {
215 FATAL("USERS: Unable to load /etc/passwd and /etc/group");
216 return;
217 }
218
219 User* pUser = getUser(0);
220 if (!pUser) {
221 FATAL("USERS: Unable to set default user (no such user for uid 0)");
222 return;
223 }
224 Process* pProcess = Processor::information().getCurrentThread()->getParent();
225
226 if (!pProcess->installUserIdentity(pUser, pUser->getDefaultGroup(), nullptr, 0))
227 FATAL("USERS: Unable to publish the initial identity");
228}
229
230static bool init() {
231 // Initialise user/group configuration.
233
234 return true;
235}
236
237static void destroy() {}
238
239MODULE_INFO("users", &init, &destroy, "mountroot");
Definition File.h:75
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:239
virtual bool isDirectory()
Definition File.cc:804
Definition Group.h:32
const String & getName() const
Definition Group.h:54
void join(User *pUser)
Definition Group.cc:28
Process * getParent()
Definition Process.h:620
static ProcessorInformation & information()
An iterator applicable for many data structures.
Definition Iterator.h:147
Iterator begin()
Definition Tree.h:402
E lookup(const K &key) const
Definition Tree.h:193
void insert(const K &key, const E &value)
Definition Tree.h:149
Iterator end()
Definition Tree.h:427
User * getUser(size_t id)
Tree< size_t, User * > m_Users
Definition UserManager.h:64
Tree< size_t, Group * > m_Groups
Definition UserManager.h:66
static UserManager & instance()
Definition UserManager.h:32
void initialise()
Group * getGroup(size_t id)
Definition User.h:32
void join(Group *pGroup)
Definition User.cc:42
const String & getUsername() const
Definition User.h:64
Group * getDefaultGroup()
Definition User.h:72
File * findRetained(const String &path, Directory::ChildLease &result, File *pStartNode=nullptr)
Definition VFS.cc:1042
static VFS & instance()
Definition VFS.cc:311
A vector / dynamic array.
Definition Vector.h:33
size_t count() const
Definition Vector.h:270