blob: b3d16f49893b5d1a67fe11eb3ff0cc00a8cd0302 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Declarations of helper functions and parser for pwd.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_PWD_PWD_UTILS_H
#define LLVM_LIBC_SRC_PWD_PWD_UTILS_H
#include "hdr/errno_macros.h"
#include "hdr/types/gid_t.h"
#include "hdr/types/size_t.h"
#include "hdr/types/struct_passwd.h"
#include "hdr/types/uid_t.h"
#include "src/__support/CPP/span.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/error_or.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/pwd/field_tokenizer.h"
#include "src/__support/pwd/flat_file_db.h"
#include "src/__support/str_to_integer.h"
#include "src/string/string_utils.h"
namespace LIBC_NAMESPACE_DECL {
namespace pwd {
// Parses a colon-separated line in-place into a struct passwd.
template <>
LIBC_INLINE ErrorOr<void> parse_line<struct passwd>(cpp::span<char> line,
cpp::span<char> /*scratch*/,
struct passwd *pwd) {
if (!pwd || line.empty() || line.back() != '\0')
return Error(EINVAL);
FieldTokenizer tokenizer(line);
auto name = tokenizer.next_field();
if (!name || name->empty() || name->front() == '\0')
return Error(EINVAL);
pwd->pw_name = name->data();
auto passwd = tokenizer.next_field();
if (!passwd)
return Error(EINVAL);
pwd->pw_passwd = passwd->data();
auto uid_str = tokenizer.next_field();
if (!uid_str || uid_str->empty() || !internal::isdigit(uid_str->front()))
return Error(EINVAL);
auto uid_res = internal::strtointeger<uid_t>(uid_str->data(), 10);
if (uid_res.has_error() || uid_res.parsed_len <= 0 ||
static_cast<size_t>(uid_res.parsed_len) + 1 != uid_str->size() ||
(*uid_str)[uid_res.parsed_len] != '\0')
return Error(EINVAL);
pwd->pw_uid = uid_res.value;
auto gid_str = tokenizer.next_field();
if (!gid_str || gid_str->empty() || !internal::isdigit(gid_str->front()))
return Error(EINVAL);
auto gid_res = internal::strtointeger<gid_t>(gid_str->data(), 10);
if (gid_res.has_error() || gid_res.parsed_len <= 0 ||
static_cast<size_t>(gid_res.parsed_len) + 1 != gid_str->size() ||
(*gid_str)[gid_res.parsed_len] != '\0')
return Error(EINVAL);
pwd->pw_gid = gid_res.value;
auto gecos = tokenizer.next_field();
if (!gecos)
return Error(EINVAL);
pwd->pw_gecos = gecos->data();
auto dir = tokenizer.next_field();
if (!dir)
return Error(EINVAL);
pwd->pw_dir = dir->data();
auto shell = tokenizer.next_field();
if (!shell)
return Error(EINVAL);
pwd->pw_shell = shell->data();
if (tokenizer.next_field())
return Error(EINVAL);
return {};
}
// Parses a colon-separated password database line into a struct passwd.
ErrorOr<struct passwd> parse_passwd_line(char *line);
// Overrides the default password file path for testing purposes.
void TESTONLY_set_passwd_path(const char *path);
// Resets the password file path back to the default.
void TESTONLY_reset_passwd_path();
// Opens or rewinds the password file.
ErrorOr<void> open();
// Closes the password file.
ErrorOr<void> close();
// Reads the next entry from the password database.
ErrorOr<struct passwd *> read_next();
// Searches for a password entry matching the given username using the
// static process-global buffer.
ErrorOr<struct passwd *> find_by_name(cpp::string_view name);
// Searches for a password entry matching the given user ID using the
// static process-global buffer.
ErrorOr<struct passwd *> find_by_uid(uid_t uid);
// Searches for a password entry matching the given username.
// The optional path parameter allows unit tests to direct lookups to hermetic
// test database files without mutating global state.
ErrorOr<bool> find_by_name(cpp::string_view name, struct passwd *pwd,
cpp::span<char> buffer, const char *path = nullptr);
// Searches for a password entry matching the given user ID.
// The optional path parameter allows unit tests to direct lookups to hermetic
// test database files without mutating global state.
ErrorOr<bool> find_by_uid(uid_t uid, struct passwd *pwd, cpp::span<char> buffer,
const char *path = nullptr);
} // namespace pwd
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_PWD_PWD_UTILS_H