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