mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-30 00:09:01 +00:00
LibC: Implement support for getspnam() and friends
This commit is contained in:
parent
ce77caf479
commit
302f9798ee
Notes:
sideshowbarker
2024-07-18 18:49:54 +09:00
Author: https://github.com/gunnarbeutner
Commit: 302f9798ee
Pull-request: https://github.com/SerenityOS/serenity/pull/6777
Reviewed-by: https://github.com/awesomekling
7 changed files with 356 additions and 61 deletions
|
@ -1,2 +1,12 @@
|
||||||
root:
|
root::18727::::::
|
||||||
anon:$5$zFiQBeTD88m/mhbU$ecHDSdRd5yNV45BzIRXwtRpxJtMpVI5twjRRXO8X03Q=
|
anon:$5$zFiQBeTD88m/mhbU$ecHDSdRd5yNV45BzIRXwtRpxJtMpVI5twjRRXO8X03Q=:18727:0:99999::::
|
||||||
|
lookup:!*:18727::::::
|
||||||
|
request:!*:18727::::::
|
||||||
|
notify:!*:18727::::::
|
||||||
|
window:!*:18727::::::
|
||||||
|
clipboard:!*:18727::::::
|
||||||
|
webcontent:!*:18727::::::
|
||||||
|
image:!*:18727::::::
|
||||||
|
symbol:!*:18727::::::
|
||||||
|
websocket:!*:18727::::::
|
||||||
|
nona:!*:18727::::::
|
||||||
|
|
|
@ -29,6 +29,7 @@ set(LIBC_SOURCES
|
||||||
scanf.cpp
|
scanf.cpp
|
||||||
sched.cpp
|
sched.cpp
|
||||||
serenity.cpp
|
serenity.cpp
|
||||||
|
shadow.cpp
|
||||||
signal.cpp
|
signal.cpp
|
||||||
spawn.cpp
|
spawn.cpp
|
||||||
stat.cpp
|
stat.cpp
|
||||||
|
|
248
Userland/Libraries/LibC/shadow.cpp
Normal file
248
Userland/Libraries/LibC/shadow.cpp
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <AK/TemporaryChange.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <errno_numbers.h>
|
||||||
|
#include <shadow.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static FILE* s_stream = nullptr;
|
||||||
|
static unsigned s_line_number = 0;
|
||||||
|
static struct spwd s_shadow_entry;
|
||||||
|
|
||||||
|
static String s_name;
|
||||||
|
static String s_pwdp;
|
||||||
|
|
||||||
|
void setspent()
|
||||||
|
{
|
||||||
|
s_line_number = 0;
|
||||||
|
if (s_stream) {
|
||||||
|
rewind(s_stream);
|
||||||
|
} else {
|
||||||
|
s_stream = fopen("/etc/shadow", "r");
|
||||||
|
if (!s_stream) {
|
||||||
|
perror("open /etc/shadow");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void endspent()
|
||||||
|
{
|
||||||
|
s_line_number = 0;
|
||||||
|
if (s_stream) {
|
||||||
|
fclose(s_stream);
|
||||||
|
s_stream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&s_shadow_entry, 0, sizeof(s_shadow_entry));
|
||||||
|
|
||||||
|
s_name = {};
|
||||||
|
s_pwdp = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct spwd* getspnam(const char* name)
|
||||||
|
{
|
||||||
|
setspent();
|
||||||
|
while (auto* sp = getspent()) {
|
||||||
|
if (!strcmp(sp->sp_namp, name)) {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_shadow_entry(const String& line)
|
||||||
|
{
|
||||||
|
auto parts = line.split_view(':', true);
|
||||||
|
if (parts.size() != 9) {
|
||||||
|
dbgln("getspent(): Malformed entry on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_name = parts[0];
|
||||||
|
s_pwdp = parts[1];
|
||||||
|
auto& lstchg_string = parts[2];
|
||||||
|
auto& min_string = parts[3];
|
||||||
|
auto& max_string = parts[4];
|
||||||
|
auto& warn_string = parts[5];
|
||||||
|
auto& inact_string = parts[6];
|
||||||
|
auto& expire_string = parts[7];
|
||||||
|
auto& flag_string = parts[8];
|
||||||
|
|
||||||
|
auto lstchg = lstchg_string.to_int();
|
||||||
|
if (!lstchg.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed lstchg on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_string.is_empty())
|
||||||
|
min_string = "-1";
|
||||||
|
auto min_value = min_string.to_int();
|
||||||
|
if (!min_value.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed min value on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_string.is_empty())
|
||||||
|
max_string = "-1";
|
||||||
|
auto max_value = max_string.to_int();
|
||||||
|
if (!max_value.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed max value on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warn_string.is_empty())
|
||||||
|
warn_string = "-1";
|
||||||
|
auto warn = warn_string.to_int();
|
||||||
|
if (!warn.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed warn on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inact_string.is_empty())
|
||||||
|
inact_string = "-1";
|
||||||
|
auto inact = inact_string.to_int();
|
||||||
|
if (!inact.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed inact on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expire_string.is_empty())
|
||||||
|
expire_string = "-1";
|
||||||
|
auto expire = expire_string.to_int();
|
||||||
|
if (!expire.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed expire on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag_string.is_empty())
|
||||||
|
flag_string = "0";
|
||||||
|
auto flag = flag_string.to_int();
|
||||||
|
if (!flag.has_value()) {
|
||||||
|
dbgln("getspent(): Malformed flag on line {}", s_line_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_shadow_entry.sp_namp = const_cast<char*>(s_name.characters());
|
||||||
|
s_shadow_entry.sp_pwdp = const_cast<char*>(s_pwdp.characters());
|
||||||
|
s_shadow_entry.sp_lstchg = lstchg.value();
|
||||||
|
s_shadow_entry.sp_min = min_value.value();
|
||||||
|
s_shadow_entry.sp_max = max_value.value();
|
||||||
|
s_shadow_entry.sp_warn = warn.value();
|
||||||
|
s_shadow_entry.sp_inact = inact.value();
|
||||||
|
s_shadow_entry.sp_expire = expire.value();
|
||||||
|
s_shadow_entry.sp_flag = flag.value();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct spwd* getspent()
|
||||||
|
{
|
||||||
|
if (!s_stream)
|
||||||
|
setspent();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!s_stream || feof(s_stream))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (ferror(s_stream)) {
|
||||||
|
dbgln("getspent(): Read error: {}", strerror(ferror(s_stream)));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
++s_line_number;
|
||||||
|
char* s = fgets(buffer, sizeof(buffer), s_stream);
|
||||||
|
|
||||||
|
// Silently tolerate an empty line at the end.
|
||||||
|
if ((!s || !s[0]) && feof(s_stream))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
String line(s, Chomp);
|
||||||
|
if (parse_shadow_entry(line))
|
||||||
|
return &s_shadow_entry;
|
||||||
|
// Otherwise, proceed to the next line.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void construct_spwd(struct spwd* sp, char* buf, struct spwd** result)
|
||||||
|
{
|
||||||
|
auto* buf_name = &buf[0];
|
||||||
|
auto* buf_pwdp = &buf[s_name.length() + 1];
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
ok = ok && s_name.copy_characters_to_buffer(buf_name, s_name.length() + 1);
|
||||||
|
ok = ok && s_pwdp.copy_characters_to_buffer(buf_pwdp, s_pwdp.length() + 1);
|
||||||
|
|
||||||
|
VERIFY(ok);
|
||||||
|
|
||||||
|
*result = sp;
|
||||||
|
sp->sp_namp = buf_name;
|
||||||
|
sp->sp_pwdp = buf_pwdp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getspnam_r(const char* name, struct spwd* sp, char* buf, size_t buflen, struct spwd** result)
|
||||||
|
{
|
||||||
|
// FIXME: This is a HACK!
|
||||||
|
TemporaryChange name_change { s_name, {} };
|
||||||
|
TemporaryChange pwdp_change { s_pwdp, {} };
|
||||||
|
|
||||||
|
setspent();
|
||||||
|
bool found = false;
|
||||||
|
while (auto* sp = getspent()) {
|
||||||
|
if (!strcmp(sp->sp_namp, name)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
*result = nullptr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto total_buffer_length = s_name.length() + s_pwdp.length() + 8;
|
||||||
|
if (buflen < total_buffer_length)
|
||||||
|
return ERANGE;
|
||||||
|
|
||||||
|
construct_spwd(sp, buf, result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putspent(struct spwd* p, FILE* stream)
|
||||||
|
{
|
||||||
|
if (!p || !stream || !p->sp_namp || !p->sp_pwdp) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto is_valid_field = [](const char* str) {
|
||||||
|
return str && !strpbrk(str, ":\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!is_valid_field(p->sp_namp) || !is_valid_field(p->sp_pwdp)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nwritten = fprintf(stream, "%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%ld\n", p->sp_namp,
|
||||||
|
p->sp_pwdp, p->sp_lstchg, p->sp_min, p->sp_max, p->sp_warn, p->sp_inact, p->sp_expire, p->sp_flag);
|
||||||
|
if (!nwritten || nwritten < 0) {
|
||||||
|
errno = ferror(stream);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
39
Userland/Libraries/LibC/shadow.h
Normal file
39
Userland/Libraries/LibC/shadow.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <bits/FILE.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
struct spwd {
|
||||||
|
char* sp_namp;
|
||||||
|
char* sp_pwdp;
|
||||||
|
long int sp_lstchg;
|
||||||
|
long int sp_min;
|
||||||
|
long int sp_max;
|
||||||
|
long int sp_warn;
|
||||||
|
long int sp_inact;
|
||||||
|
long int sp_expire;
|
||||||
|
unsigned long int sp_flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spwd* getspent();
|
||||||
|
void setspent();
|
||||||
|
void endspent();
|
||||||
|
struct spwd* getspnam(const char* name);
|
||||||
|
int putspent(struct spwd* p, FILE* stream);
|
||||||
|
|
||||||
|
int getspent_r(struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
|
||||||
|
int getspnam_r(const char* name, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
|
||||||
|
|
||||||
|
int fgetspent_r(FILE* fp, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
|
||||||
|
int sgetspent_r(const char* s, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp);
|
||||||
|
|
||||||
|
__END_DECLS
|
|
@ -13,6 +13,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <shadow.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -47,39 +48,52 @@ static Vector<gid_t> get_gids(const StringView& username)
|
||||||
return extra_gids;
|
return extra_gids;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Account, String> Account::from_passwd(const passwd& pwd)
|
Result<Account, String> Account::from_passwd(const passwd& pwd, const spwd& spwd)
|
||||||
{
|
{
|
||||||
Account account(pwd, get_gids(pwd.pw_name));
|
Account account(pwd, spwd, get_gids(pwd.pw_name));
|
||||||
endpwent();
|
endpwent();
|
||||||
|
endspent();
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Account, String> Account::from_name(const char* username)
|
Result<Account, String> Account::from_name(const char* username)
|
||||||
{
|
{
|
||||||
struct passwd* pwd = nullptr;
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
pwd = getpwnam(username);
|
auto* pwd = getpwnam(username);
|
||||||
if (!pwd) {
|
if (!pwd) {
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
return String("No such user");
|
return String("No such user");
|
||||||
|
|
||||||
return String(strerror(errno));
|
return String(strerror(errno));
|
||||||
}
|
}
|
||||||
return from_passwd(*pwd);
|
auto* spwd = getspnam(username);
|
||||||
|
if (!spwd) {
|
||||||
|
if (errno == 0)
|
||||||
|
return String("No such user");
|
||||||
|
|
||||||
|
return String(strerror(errno));
|
||||||
|
}
|
||||||
|
return from_passwd(*pwd, *spwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Account, String> Account::from_uid(uid_t uid)
|
Result<Account, String> Account::from_uid(uid_t uid)
|
||||||
{
|
{
|
||||||
struct passwd* pwd = nullptr;
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
pwd = getpwuid(uid);
|
auto* pwd = getpwuid(uid);
|
||||||
if (!pwd) {
|
if (!pwd) {
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
return String("No such user");
|
return String("No such user");
|
||||||
|
|
||||||
return String(strerror(errno));
|
return String(strerror(errno));
|
||||||
}
|
}
|
||||||
return from_passwd(*pwd);
|
auto* spwd = getspnam(pwd->pw_name);
|
||||||
|
if (!spwd) {
|
||||||
|
if (errno == 0)
|
||||||
|
return String("No such user");
|
||||||
|
|
||||||
|
return String(strerror(errno));
|
||||||
|
}
|
||||||
|
return from_passwd(*pwd, *spwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Account::authenticate(const char* password) const
|
bool Account::authenticate(const char* password) const
|
||||||
|
@ -133,8 +147,9 @@ void Account::delete_password()
|
||||||
m_password_hash = "";
|
m_password_hash = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Account::Account(const passwd& pwd, Vector<gid_t> extra_gids)
|
Account::Account(const passwd& pwd, const spwd& spwd, Vector<gid_t> extra_gids)
|
||||||
: m_username(pwd.pw_name)
|
: m_username(pwd.pw_name)
|
||||||
|
, m_password_hash(spwd.sp_pwdp)
|
||||||
, m_uid(pwd.pw_uid)
|
, m_uid(pwd.pw_uid)
|
||||||
, m_gid(pwd.pw_gid)
|
, m_gid(pwd.pw_gid)
|
||||||
, m_gecos(pwd.pw_gecos)
|
, m_gecos(pwd.pw_gecos)
|
||||||
|
@ -142,7 +157,6 @@ Account::Account(const passwd& pwd, Vector<gid_t> extra_gids)
|
||||||
, m_shell(pwd.pw_shell)
|
, m_shell(pwd.pw_shell)
|
||||||
, m_extra_gids(extra_gids)
|
, m_extra_gids(extra_gids)
|
||||||
{
|
{
|
||||||
load_shadow_file();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String Account::generate_passwd_file() const
|
String Account::generate_passwd_file() const
|
||||||
|
@ -179,50 +193,39 @@ String Account::generate_passwd_file() const
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Account::load_shadow_file()
|
|
||||||
{
|
|
||||||
auto file_or_error = Core::File::open("/etc/shadow", Core::File::ReadOnly);
|
|
||||||
VERIFY(!file_or_error.is_error());
|
|
||||||
auto shadow_file = file_or_error.release_value();
|
|
||||||
VERIFY(shadow_file->is_open());
|
|
||||||
|
|
||||||
Vector<ShadowEntry> entries;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
auto line = shadow_file->read_line();
|
|
||||||
if (line.is_null())
|
|
||||||
break;
|
|
||||||
auto parts = line.split(':', true);
|
|
||||||
if (parts.size() != 2) {
|
|
||||||
dbgln("Malformed shadow entry, ignoring.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto& username = parts[0];
|
|
||||||
const auto& password_hash = parts[1];
|
|
||||||
entries.append({ username, password_hash });
|
|
||||||
|
|
||||||
if (username == m_username) {
|
|
||||||
m_password_hash = password_hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_shadow_entries = move(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
String Account::generate_shadow_file() const
|
String Account::generate_shadow_file() const
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
bool updated_entry_in_place = false;
|
|
||||||
for (auto& entry : m_shadow_entries) {
|
setspent();
|
||||||
if (entry.username == m_username) {
|
|
||||||
updated_entry_in_place = true;
|
struct spwd* p;
|
||||||
builder.appendff("{}:{}\n", m_username, m_password_hash);
|
errno = 0;
|
||||||
|
while ((p = getspent())) {
|
||||||
|
if (p->sp_namp == m_username) {
|
||||||
|
builder.appendff("{}:{}:{}:{}:{}:{}:{}:{}:{}\n",
|
||||||
|
m_username, m_password_hash,
|
||||||
|
p->sp_lstchg, p->sp_min,
|
||||||
|
p->sp_max, p->sp_warn,
|
||||||
|
p->sp_inact, p->sp_expire,
|
||||||
|
p->sp_flag);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
builder.appendff("{}:{}\n", entry.username, entry.password_hash);
|
builder.appendff("{}:{}:{}:{}:{}:{}:{}:{}:{}\n",
|
||||||
|
p->sp_namp, p->sp_pwdp,
|
||||||
|
p->sp_lstchg, p->sp_min,
|
||||||
|
p->sp_max, p->sp_warn,
|
||||||
|
p->sp_inact, p->sp_expire,
|
||||||
|
p->sp_flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!updated_entry_in_place)
|
endspent();
|
||||||
builder.appendff("{}:{}\n", m_username, m_password_hash);
|
|
||||||
|
if (errno) {
|
||||||
|
dbgln("errno was non-zero after generating new passwd file.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <shadow.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -46,10 +47,9 @@ public:
|
||||||
bool sync();
|
bool sync();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Result<Account, String> from_passwd(const passwd&);
|
static Result<Account, String> from_passwd(const passwd&, const spwd&);
|
||||||
|
|
||||||
Account(const passwd& pwd, Vector<gid_t> extra_gids);
|
Account(const passwd& pwd, const spwd& spwd, Vector<gid_t> extra_gids);
|
||||||
void load_shadow_file();
|
|
||||||
|
|
||||||
String generate_passwd_file() const;
|
String generate_passwd_file() const;
|
||||||
String generate_shadow_file() const;
|
String generate_shadow_file() const;
|
||||||
|
@ -63,12 +63,6 @@ private:
|
||||||
String m_home_directory;
|
String m_home_directory;
|
||||||
String m_shell;
|
String m_shell;
|
||||||
Vector<gid_t> m_extra_gids;
|
Vector<gid_t> m_extra_gids;
|
||||||
|
|
||||||
struct ShadowEntry {
|
|
||||||
String username;
|
|
||||||
String password_hash;
|
|
||||||
};
|
|
||||||
Vector<ShadowEntry> m_shadow_entries;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
setpwent();
|
setpwent();
|
||||||
|
|
||||||
if (pledge("stdio wpath cpath fattr tty", nullptr) < 0) {
|
if (pledge("stdio wpath rpath cpath fattr tty", nullptr) < 0) {
|
||||||
perror("pledge");
|
perror("pledge");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ int main(int argc, char** argv)
|
||||||
target_account.set_password(new_password.value().characters());
|
target_account.set_password(new_password.value().characters());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pledge("stdio wpath cpath fattr", nullptr) < 0) {
|
if (pledge("stdio wpath rpath cpath fattr", nullptr) < 0) {
|
||||||
perror("pledge");
|
perror("pledge");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue