11cb0ef41Sopenharmony_ci#include "env-inl.h"
21cb0ef41Sopenharmony_ci#include "node_external_reference.h"
31cb0ef41Sopenharmony_ci#include "node_internals.h"
41cb0ef41Sopenharmony_ci#include "util-inl.h"
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#ifdef NODE_IMPLEMENTS_POSIX_CREDENTIALS
71cb0ef41Sopenharmony_ci#include <grp.h>  // getgrnam()
81cb0ef41Sopenharmony_ci#include <pwd.h>  // getpwnam()
91cb0ef41Sopenharmony_ci#endif            // NODE_IMPLEMENTS_POSIX_CREDENTIALS
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#if !defined(_MSC_VER)
121cb0ef41Sopenharmony_ci#include <unistd.h>  // setuid, getuid
131cb0ef41Sopenharmony_ci#endif
141cb0ef41Sopenharmony_ci#ifdef __linux__
151cb0ef41Sopenharmony_ci#include <linux/capability.h>
161cb0ef41Sopenharmony_ci#include <sys/auxv.h>
171cb0ef41Sopenharmony_ci#include <sys/syscall.h>
181cb0ef41Sopenharmony_ci#endif  // __linux__
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cinamespace node {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciusing v8::Array;
231cb0ef41Sopenharmony_ciusing v8::Context;
241cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
251cb0ef41Sopenharmony_ciusing v8::HandleScope;
261cb0ef41Sopenharmony_ciusing v8::Isolate;
271cb0ef41Sopenharmony_ciusing v8::Local;
281cb0ef41Sopenharmony_ciusing v8::MaybeLocal;
291cb0ef41Sopenharmony_ciusing v8::Object;
301cb0ef41Sopenharmony_ciusing v8::String;
311cb0ef41Sopenharmony_ciusing v8::TryCatch;
321cb0ef41Sopenharmony_ciusing v8::Uint32;
331cb0ef41Sopenharmony_ciusing v8::Value;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_cibool linux_at_secure() {
361cb0ef41Sopenharmony_ci  // This could reasonably be a static variable, but this way
371cb0ef41Sopenharmony_ci  // we can guarantee that this function is always usable
381cb0ef41Sopenharmony_ci  // and returns the correct value,  e.g. even in static
391cb0ef41Sopenharmony_ci  // initialization code in other files.
401cb0ef41Sopenharmony_ci#ifdef __linux__
411cb0ef41Sopenharmony_ci  static const bool value = getauxval(AT_SECURE);
421cb0ef41Sopenharmony_ci  return value;
431cb0ef41Sopenharmony_ci#else
441cb0ef41Sopenharmony_ci  return false;
451cb0ef41Sopenharmony_ci#endif
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cinamespace credentials {
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci#if defined(__linux__)
511cb0ef41Sopenharmony_ci// Returns true if the current process only has the passed-in capability.
521cb0ef41Sopenharmony_cibool HasOnly(int capability) {
531cb0ef41Sopenharmony_ci  DCHECK(cap_valid(capability));
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3];
561cb0ef41Sopenharmony_ci  struct __user_cap_header_struct cap_header_data = {
571cb0ef41Sopenharmony_ci    _LINUX_CAPABILITY_VERSION_3,
581cb0ef41Sopenharmony_ci    getpid()};
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  if (syscall(SYS_capget, &cap_header_data, &cap_data) != 0) {
621cb0ef41Sopenharmony_ci    return false;
631cb0ef41Sopenharmony_ci  }
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  static_assert(arraysize(cap_data) == 2);
661cb0ef41Sopenharmony_ci  return cap_data[CAP_TO_INDEX(capability)].permitted ==
671cb0ef41Sopenharmony_ci             static_cast<unsigned int>(CAP_TO_MASK(capability)) &&
681cb0ef41Sopenharmony_ci         cap_data[1 - CAP_TO_INDEX(capability)].permitted == 0;
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci#endif
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci// Look up the environment variable and allow the lookup if the current
731cb0ef41Sopenharmony_ci// process only has the capability CAP_NET_BIND_SERVICE set. If the current
741cb0ef41Sopenharmony_ci// process does not have any capabilities set and the process is running as
751cb0ef41Sopenharmony_ci// setuid root then lookup will not be allowed.
761cb0ef41Sopenharmony_cibool SafeGetenv(const char* key,
771cb0ef41Sopenharmony_ci                std::string* text,
781cb0ef41Sopenharmony_ci                std::shared_ptr<KVStore> env_vars,
791cb0ef41Sopenharmony_ci                v8::Isolate* isolate) {
801cb0ef41Sopenharmony_ci#if !defined(__CloudABI__) && !defined(_WIN32)
811cb0ef41Sopenharmony_ci#if defined(__linux__)
821cb0ef41Sopenharmony_ci  if ((!HasOnly(CAP_NET_BIND_SERVICE) && linux_at_secure()) ||
831cb0ef41Sopenharmony_ci      getuid() != geteuid() || getgid() != getegid())
841cb0ef41Sopenharmony_ci#else
851cb0ef41Sopenharmony_ci  if (linux_at_secure() || getuid() != geteuid() || getgid() != getegid())
861cb0ef41Sopenharmony_ci#endif
871cb0ef41Sopenharmony_ci    goto fail;
881cb0ef41Sopenharmony_ci#endif
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  if (env_vars != nullptr) {
911cb0ef41Sopenharmony_ci    DCHECK_NOT_NULL(isolate);
921cb0ef41Sopenharmony_ci    HandleScope handle_scope(isolate);
931cb0ef41Sopenharmony_ci    TryCatch ignore_errors(isolate);
941cb0ef41Sopenharmony_ci    MaybeLocal<String> maybe_value = env_vars->Get(
951cb0ef41Sopenharmony_ci        isolate, String::NewFromUtf8(isolate, key).ToLocalChecked());
961cb0ef41Sopenharmony_ci    Local<String> value;
971cb0ef41Sopenharmony_ci    if (!maybe_value.ToLocal(&value)) goto fail;
981cb0ef41Sopenharmony_ci    String::Utf8Value utf8_value(isolate, value);
991cb0ef41Sopenharmony_ci    if (*utf8_value == nullptr) goto fail;
1001cb0ef41Sopenharmony_ci    *text = std::string(*utf8_value, utf8_value.length());
1011cb0ef41Sopenharmony_ci    return true;
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  {
1051cb0ef41Sopenharmony_ci    Mutex::ScopedLock lock(per_process::env_var_mutex);
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci    size_t init_sz = 256;
1081cb0ef41Sopenharmony_ci    MaybeStackBuffer<char, 256> val;
1091cb0ef41Sopenharmony_ci    int ret = uv_os_getenv(key, *val, &init_sz);
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci    if (ret == UV_ENOBUFS) {
1121cb0ef41Sopenharmony_ci      // Buffer is not large enough, reallocate to the updated init_sz
1131cb0ef41Sopenharmony_ci      // and fetch env value again.
1141cb0ef41Sopenharmony_ci      val.AllocateSufficientStorage(init_sz);
1151cb0ef41Sopenharmony_ci      ret = uv_os_getenv(key, *val, &init_sz);
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci    if (ret >= 0) {  // Env key value fetch success.
1191cb0ef41Sopenharmony_ci      *text = *val;
1201cb0ef41Sopenharmony_ci      return true;
1211cb0ef41Sopenharmony_ci    }
1221cb0ef41Sopenharmony_ci  }
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_cifail:
1251cb0ef41Sopenharmony_ci  text->clear();
1261cb0ef41Sopenharmony_ci  return false;
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_cistatic void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
1301cb0ef41Sopenharmony_ci  CHECK(args[0]->IsString());
1311cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1321cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
1331cb0ef41Sopenharmony_ci  Utf8Value strenvtag(isolate, args[0]);
1341cb0ef41Sopenharmony_ci  std::string text;
1351cb0ef41Sopenharmony_ci  if (!SafeGetenv(*strenvtag, &text, env->env_vars(), isolate)) return;
1361cb0ef41Sopenharmony_ci  Local<Value> result =
1371cb0ef41Sopenharmony_ci      ToV8Value(isolate->GetCurrentContext(), text).ToLocalChecked();
1381cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(result);
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci#ifdef NODE_IMPLEMENTS_POSIX_CREDENTIALS
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_cistatic const uid_t uid_not_found = static_cast<uid_t>(-1);
1441cb0ef41Sopenharmony_cistatic const gid_t gid_not_found = static_cast<gid_t>(-1);
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_cistatic uid_t uid_by_name(const char* name) {
1471cb0ef41Sopenharmony_ci  struct passwd pwd;
1481cb0ef41Sopenharmony_ci  struct passwd* pp;
1491cb0ef41Sopenharmony_ci  char buf[8192];
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  errno = 0;
1521cb0ef41Sopenharmony_ci  pp = nullptr;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  if (getpwnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr)
1551cb0ef41Sopenharmony_ci    return pp->pw_uid;
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  return uid_not_found;
1581cb0ef41Sopenharmony_ci}
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_cistatic char* name_by_uid(uid_t uid) {
1611cb0ef41Sopenharmony_ci  struct passwd pwd;
1621cb0ef41Sopenharmony_ci  struct passwd* pp;
1631cb0ef41Sopenharmony_ci  char buf[8192];
1641cb0ef41Sopenharmony_ci  int rc;
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  errno = 0;
1671cb0ef41Sopenharmony_ci  pp = nullptr;
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  if ((rc = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pp)) == 0 &&
1701cb0ef41Sopenharmony_ci      pp != nullptr) {
1711cb0ef41Sopenharmony_ci    return strdup(pp->pw_name);
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  if (rc == 0) errno = ENOENT;
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  return nullptr;
1771cb0ef41Sopenharmony_ci}
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_cistatic gid_t gid_by_name(const char* name) {
1801cb0ef41Sopenharmony_ci  struct group pwd;
1811cb0ef41Sopenharmony_ci  struct group* pp;
1821cb0ef41Sopenharmony_ci  char buf[8192];
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  errno = 0;
1851cb0ef41Sopenharmony_ci  pp = nullptr;
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  if (getgrnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr)
1881cb0ef41Sopenharmony_ci    return pp->gr_gid;
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  return gid_not_found;
1911cb0ef41Sopenharmony_ci}
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci#if 0  // For future use.
1941cb0ef41Sopenharmony_cistatic const char* name_by_gid(gid_t gid) {
1951cb0ef41Sopenharmony_ci  struct group pwd;
1961cb0ef41Sopenharmony_ci  struct group* pp;
1971cb0ef41Sopenharmony_ci  char buf[8192];
1981cb0ef41Sopenharmony_ci  int rc;
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  errno = 0;
2011cb0ef41Sopenharmony_ci  pp = nullptr;
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  if ((rc = getgrgid_r(gid, &pwd, buf, sizeof(buf), &pp)) == 0 &&
2041cb0ef41Sopenharmony_ci      pp != nullptr) {
2051cb0ef41Sopenharmony_ci    return strdup(pp->gr_name);
2061cb0ef41Sopenharmony_ci  }
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  if (rc == 0)
2091cb0ef41Sopenharmony_ci    errno = ENOENT;
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  return nullptr;
2121cb0ef41Sopenharmony_ci}
2131cb0ef41Sopenharmony_ci#endif
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_cistatic uid_t uid_by_name(Isolate* isolate, Local<Value> value) {
2161cb0ef41Sopenharmony_ci  if (value->IsUint32()) {
2171cb0ef41Sopenharmony_ci    static_assert(std::is_same<uid_t, uint32_t>::value);
2181cb0ef41Sopenharmony_ci    return value.As<Uint32>()->Value();
2191cb0ef41Sopenharmony_ci  } else {
2201cb0ef41Sopenharmony_ci    Utf8Value name(isolate, value);
2211cb0ef41Sopenharmony_ci    return uid_by_name(*name);
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci}
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_cistatic gid_t gid_by_name(Isolate* isolate, Local<Value> value) {
2261cb0ef41Sopenharmony_ci  if (value->IsUint32()) {
2271cb0ef41Sopenharmony_ci    static_assert(std::is_same<gid_t, uint32_t>::value);
2281cb0ef41Sopenharmony_ci    return value.As<Uint32>()->Value();
2291cb0ef41Sopenharmony_ci  } else {
2301cb0ef41Sopenharmony_ci    Utf8Value name(isolate, value);
2311cb0ef41Sopenharmony_ci    return gid_by_name(*name);
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci}
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_cistatic void GetUid(const FunctionCallbackInfo<Value>& args) {
2361cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2371cb0ef41Sopenharmony_ci  CHECK(env->has_run_bootstrapping_code());
2381cb0ef41Sopenharmony_ci  // uid_t is an uint32_t on all supported platforms.
2391cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(static_cast<uint32_t>(getuid()));
2401cb0ef41Sopenharmony_ci}
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_cistatic void GetGid(const FunctionCallbackInfo<Value>& args) {
2431cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2441cb0ef41Sopenharmony_ci  CHECK(env->has_run_bootstrapping_code());
2451cb0ef41Sopenharmony_ci  // gid_t is an uint32_t on all supported platforms.
2461cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(static_cast<uint32_t>(getgid()));
2471cb0ef41Sopenharmony_ci}
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_cistatic void GetEUid(const FunctionCallbackInfo<Value>& args) {
2501cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2511cb0ef41Sopenharmony_ci  CHECK(env->has_run_bootstrapping_code());
2521cb0ef41Sopenharmony_ci  // uid_t is an uint32_t on all supported platforms.
2531cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(static_cast<uint32_t>(geteuid()));
2541cb0ef41Sopenharmony_ci}
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_cistatic void GetEGid(const FunctionCallbackInfo<Value>& args) {
2571cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2581cb0ef41Sopenharmony_ci  CHECK(env->has_run_bootstrapping_code());
2591cb0ef41Sopenharmony_ci  // gid_t is an uint32_t on all supported platforms.
2601cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(static_cast<uint32_t>(getegid()));
2611cb0ef41Sopenharmony_ci}
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_cistatic void SetGid(const FunctionCallbackInfo<Value>& args) {
2641cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2651cb0ef41Sopenharmony_ci  CHECK(env->owns_process_state());
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci  CHECK_EQ(args.Length(), 1);
2681cb0ef41Sopenharmony_ci  CHECK(args[0]->IsUint32() || args[0]->IsString());
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  gid_t gid = gid_by_name(env->isolate(), args[0]);
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  if (gid == gid_not_found) {
2731cb0ef41Sopenharmony_ci    // Tells JS to throw ERR_INVALID_CREDENTIAL
2741cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(1);
2751cb0ef41Sopenharmony_ci  } else if (setgid(gid)) {
2761cb0ef41Sopenharmony_ci    env->ThrowErrnoException(errno, "setgid");
2771cb0ef41Sopenharmony_ci  } else {
2781cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(0);
2791cb0ef41Sopenharmony_ci  }
2801cb0ef41Sopenharmony_ci}
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_cistatic void SetEGid(const FunctionCallbackInfo<Value>& args) {
2831cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
2841cb0ef41Sopenharmony_ci  CHECK(env->owns_process_state());
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci  CHECK_EQ(args.Length(), 1);
2871cb0ef41Sopenharmony_ci  CHECK(args[0]->IsUint32() || args[0]->IsString());
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  gid_t gid = gid_by_name(env->isolate(), args[0]);
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  if (gid == gid_not_found) {
2921cb0ef41Sopenharmony_ci    // Tells JS to throw ERR_INVALID_CREDENTIAL
2931cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(1);
2941cb0ef41Sopenharmony_ci  } else if (setegid(gid)) {
2951cb0ef41Sopenharmony_ci    env->ThrowErrnoException(errno, "setegid");
2961cb0ef41Sopenharmony_ci  } else {
2971cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(0);
2981cb0ef41Sopenharmony_ci  }
2991cb0ef41Sopenharmony_ci}
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_cistatic void SetUid(const FunctionCallbackInfo<Value>& args) {
3021cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3031cb0ef41Sopenharmony_ci  CHECK(env->owns_process_state());
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci  CHECK_EQ(args.Length(), 1);
3061cb0ef41Sopenharmony_ci  CHECK(args[0]->IsUint32() || args[0]->IsString());
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  uid_t uid = uid_by_name(env->isolate(), args[0]);
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci  if (uid == uid_not_found) {
3111cb0ef41Sopenharmony_ci    // Tells JS to throw ERR_INVALID_CREDENTIAL
3121cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(1);
3131cb0ef41Sopenharmony_ci  } else if (setuid(uid)) {
3141cb0ef41Sopenharmony_ci    env->ThrowErrnoException(errno, "setuid");
3151cb0ef41Sopenharmony_ci  } else {
3161cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(0);
3171cb0ef41Sopenharmony_ci  }
3181cb0ef41Sopenharmony_ci}
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_cistatic void SetEUid(const FunctionCallbackInfo<Value>& args) {
3211cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3221cb0ef41Sopenharmony_ci  CHECK(env->owns_process_state());
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci  CHECK_EQ(args.Length(), 1);
3251cb0ef41Sopenharmony_ci  CHECK(args[0]->IsUint32() || args[0]->IsString());
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci  uid_t uid = uid_by_name(env->isolate(), args[0]);
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  if (uid == uid_not_found) {
3301cb0ef41Sopenharmony_ci    // Tells JS to throw ERR_INVALID_CREDENTIAL
3311cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(1);
3321cb0ef41Sopenharmony_ci  } else if (seteuid(uid)) {
3331cb0ef41Sopenharmony_ci    env->ThrowErrnoException(errno, "seteuid");
3341cb0ef41Sopenharmony_ci  } else {
3351cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(0);
3361cb0ef41Sopenharmony_ci  }
3371cb0ef41Sopenharmony_ci}
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_cistatic void GetGroups(const FunctionCallbackInfo<Value>& args) {
3401cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3411cb0ef41Sopenharmony_ci  CHECK(env->has_run_bootstrapping_code());
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci  int ngroups = getgroups(0, nullptr);
3441cb0ef41Sopenharmony_ci  if (ngroups == -1) return env->ThrowErrnoException(errno, "getgroups");
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_ci  std::vector<gid_t> groups(ngroups);
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  ngroups = getgroups(ngroups, groups.data());
3491cb0ef41Sopenharmony_ci  if (ngroups == -1)
3501cb0ef41Sopenharmony_ci    return env->ThrowErrnoException(errno, "getgroups");
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci  groups.resize(ngroups);
3531cb0ef41Sopenharmony_ci  gid_t egid = getegid();
3541cb0ef41Sopenharmony_ci  if (std::find(groups.begin(), groups.end(), egid) == groups.end())
3551cb0ef41Sopenharmony_ci    groups.push_back(egid);
3561cb0ef41Sopenharmony_ci  MaybeLocal<Value> array = ToV8Value(env->context(), groups);
3571cb0ef41Sopenharmony_ci  if (!array.IsEmpty())
3581cb0ef41Sopenharmony_ci    args.GetReturnValue().Set(array.ToLocalChecked());
3591cb0ef41Sopenharmony_ci}
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_cistatic void SetGroups(const FunctionCallbackInfo<Value>& args) {
3621cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  CHECK_EQ(args.Length(), 1);
3651cb0ef41Sopenharmony_ci  CHECK(args[0]->IsArray());
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_ci  Local<Array> groups_list = args[0].As<Array>();
3681cb0ef41Sopenharmony_ci  size_t size = groups_list->Length();
3691cb0ef41Sopenharmony_ci  MaybeStackBuffer<gid_t, 64> groups(size);
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  for (size_t i = 0; i < size; i++) {
3721cb0ef41Sopenharmony_ci    gid_t gid = gid_by_name(
3731cb0ef41Sopenharmony_ci        env->isolate(), groups_list->Get(env->context(), i).ToLocalChecked());
3741cb0ef41Sopenharmony_ci
3751cb0ef41Sopenharmony_ci    if (gid == gid_not_found) {
3761cb0ef41Sopenharmony_ci      // Tells JS to throw ERR_INVALID_CREDENTIAL
3771cb0ef41Sopenharmony_ci      args.GetReturnValue().Set(static_cast<uint32_t>(i + 1));
3781cb0ef41Sopenharmony_ci      return;
3791cb0ef41Sopenharmony_ci    }
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci    groups[i] = gid;
3821cb0ef41Sopenharmony_ci  }
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ci  int rc = setgroups(size, *groups);
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  if (rc == -1) return env->ThrowErrnoException(errno, "setgroups");
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(0);
3891cb0ef41Sopenharmony_ci}
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_cistatic void InitGroups(const FunctionCallbackInfo<Value>& args) {
3921cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci  CHECK_EQ(args.Length(), 2);
3951cb0ef41Sopenharmony_ci  CHECK(args[0]->IsUint32() || args[0]->IsString());
3961cb0ef41Sopenharmony_ci  CHECK(args[1]->IsUint32() || args[1]->IsString());
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  Utf8Value arg0(env->isolate(), args[0]);
3991cb0ef41Sopenharmony_ci  gid_t extra_group;
4001cb0ef41Sopenharmony_ci  bool must_free;
4011cb0ef41Sopenharmony_ci  char* user;
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  if (args[0]->IsUint32()) {
4041cb0ef41Sopenharmony_ci    user = name_by_uid(args[0].As<Uint32>()->Value());
4051cb0ef41Sopenharmony_ci    must_free = true;
4061cb0ef41Sopenharmony_ci  } else {
4071cb0ef41Sopenharmony_ci    user = *arg0;
4081cb0ef41Sopenharmony_ci    must_free = false;
4091cb0ef41Sopenharmony_ci  }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  if (user == nullptr) {
4121cb0ef41Sopenharmony_ci    // Tells JS to throw ERR_INVALID_CREDENTIAL
4131cb0ef41Sopenharmony_ci    return args.GetReturnValue().Set(1);
4141cb0ef41Sopenharmony_ci  }
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci  extra_group = gid_by_name(env->isolate(), args[1]);
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci  if (extra_group == gid_not_found) {
4191cb0ef41Sopenharmony_ci    if (must_free) free(user);
4201cb0ef41Sopenharmony_ci    // Tells JS to throw ERR_INVALID_CREDENTIAL
4211cb0ef41Sopenharmony_ci    return args.GetReturnValue().Set(2);
4221cb0ef41Sopenharmony_ci  }
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci  int rc = initgroups(user, extra_group);
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci  if (must_free) free(user);
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci  if (rc) return env->ThrowErrnoException(errno, "initgroups");
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(0);
4311cb0ef41Sopenharmony_ci}
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci#endif  // NODE_IMPLEMENTS_POSIX_CREDENTIALS
4341cb0ef41Sopenharmony_ci
4351cb0ef41Sopenharmony_civoid RegisterExternalReferences(ExternalReferenceRegistry* registry) {
4361cb0ef41Sopenharmony_ci  registry->Register(SafeGetenv);
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci#ifdef NODE_IMPLEMENTS_POSIX_CREDENTIALS
4391cb0ef41Sopenharmony_ci  registry->Register(GetUid);
4401cb0ef41Sopenharmony_ci  registry->Register(GetEUid);
4411cb0ef41Sopenharmony_ci  registry->Register(GetGid);
4421cb0ef41Sopenharmony_ci  registry->Register(GetEGid);
4431cb0ef41Sopenharmony_ci  registry->Register(GetGroups);
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci  registry->Register(InitGroups);
4461cb0ef41Sopenharmony_ci  registry->Register(SetEGid);
4471cb0ef41Sopenharmony_ci  registry->Register(SetEUid);
4481cb0ef41Sopenharmony_ci  registry->Register(SetGid);
4491cb0ef41Sopenharmony_ci  registry->Register(SetUid);
4501cb0ef41Sopenharmony_ci  registry->Register(SetGroups);
4511cb0ef41Sopenharmony_ci#endif  // NODE_IMPLEMENTS_POSIX_CREDENTIALS
4521cb0ef41Sopenharmony_ci}
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_cistatic void Initialize(Local<Object> target,
4551cb0ef41Sopenharmony_ci                       Local<Value> unused,
4561cb0ef41Sopenharmony_ci                       Local<Context> context,
4571cb0ef41Sopenharmony_ci                       void* priv) {
4581cb0ef41Sopenharmony_ci  SetMethod(context, target, "safeGetenv", SafeGetenv);
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci#ifdef NODE_IMPLEMENTS_POSIX_CREDENTIALS
4611cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(context);
4621cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  READONLY_TRUE_PROPERTY(target, "implementsPosixCredentials");
4651cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(context, target, "getuid", GetUid);
4661cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(context, target, "geteuid", GetEUid);
4671cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(context, target, "getgid", GetGid);
4681cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(context, target, "getegid", GetEGid);
4691cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(context, target, "getgroups", GetGroups);
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci  if (env->owns_process_state()) {
4721cb0ef41Sopenharmony_ci    SetMethod(context, target, "initgroups", InitGroups);
4731cb0ef41Sopenharmony_ci    SetMethod(context, target, "setegid", SetEGid);
4741cb0ef41Sopenharmony_ci    SetMethod(context, target, "seteuid", SetEUid);
4751cb0ef41Sopenharmony_ci    SetMethod(context, target, "setgid", SetGid);
4761cb0ef41Sopenharmony_ci    SetMethod(context, target, "setuid", SetUid);
4771cb0ef41Sopenharmony_ci    SetMethod(context, target, "setgroups", SetGroups);
4781cb0ef41Sopenharmony_ci  }
4791cb0ef41Sopenharmony_ci#endif  // NODE_IMPLEMENTS_POSIX_CREDENTIALS
4801cb0ef41Sopenharmony_ci}
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci}  // namespace credentials
4831cb0ef41Sopenharmony_ci}  // namespace node
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(credentials, node::credentials::Initialize)
4861cb0ef41Sopenharmony_ciNODE_BINDING_EXTERNAL_REFERENCE(credentials,
4871cb0ef41Sopenharmony_ci                                node::credentials::RegisterExternalReferences)
488