From 2420f07e9479b5c40140e01dca53db3512b2faf4 Mon Sep 17 00:00:00 2001 From: Peter Griess Date: Tue, 18 May 2010 17:40:44 -0700 Subject: [PATCH] Allow process.setuid() and process.setgid() to accept string names in lieu of numeric IDs --- src/node.cc | 54 +++++++++++++++++++++++++++++---- test/disabled/test-setuidgid.js | 23 ++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 test/disabled/test-setuidgid.js diff --git a/src/node.cc b/src/node.cc index 4cff11bd85..d1718cae83 100644 --- a/src/node.cc +++ b/src/node.cc @@ -14,6 +14,8 @@ #include /* dlopen(), dlsym() */ #include #include /* setuid, getuid */ +#include /* getpwnam() */ +#include /* getgrnam() */ #include #include @@ -90,6 +92,10 @@ static ev_async eio_want_poll_notifier; static ev_async eio_done_poll_notifier; static ev_idle eio_poller; +// Buffer for getpwnam_r(), getgrpam_r(); keep this scoped at file-level rather +// than method-level to avoid excess stack usage. +static char getbuf[1024]; + // We need to notify V8 when we're idle so that it can run the garbage // collector. The interface to this is V8::IdleNotification(). It returns // true if the heap hasn't be fully compacted, and needs to be run again. @@ -1152,11 +1158,29 @@ static Handle SetGid(const Arguments& args) { String::New("setgid requires 1 argument"))); } - Local given_gid = args[0]->ToInteger(); - int gid = given_gid->Int32Value(); + int gid; + + if (args[0]->IsNumber()) { + gid = args[0]->Int32Value(); + } else if (args[0]->IsString()) { + String::Utf8Value grpnam(args[0]->ToString()); + struct group grp, *grpp = NULL; + int err; + + if ((err = getgrnam_r(*grpnam, &grp, getbuf, sizeof(getbuf), &grpp)) || + grpp == NULL) { + return ThrowException(ErrnoException(errno, "getgrnam_r")); + } + + gid = grpp->gr_gid; + } else { + return ThrowException(Exception::Error( + String::New("setgid argument must be a number or a string"))); + } + int result; if ((result = setgid(gid)) != 0) { - return ThrowException(Exception::Error(String::New(strerror(errno)))); + return ThrowException(ErrnoException(errno, "setgid")); } return Undefined(); } @@ -1169,11 +1193,29 @@ static Handle SetUid(const Arguments& args) { String::New("setuid requires 1 argument"))); } - Local given_uid = args[0]->ToInteger(); - int uid = given_uid->Int32Value(); + int uid; + + if (args[0]->IsNumber()) { + uid = args[0]->Int32Value(); + } else if (args[0]->IsString()) { + String::Utf8Value pwnam(args[0]->ToString()); + struct passwd pwd, *pwdp = NULL; + int err; + + if ((err = getpwnam_r(*pwnam, &pwd, getbuf, sizeof(getbuf), &pwdp)) || + pwdp == NULL) { + return ThrowException(ErrnoException(errno, "getpwnam_r")); + } + + uid = pwdp->pw_uid; + } else { + return ThrowException(Exception::Error( + String::New("setuid argument must be a number or a string"))); + } + int result; if ((result = setuid(uid)) != 0) { - return ThrowException(Exception::Error(String::New(strerror(errno)))); + return ThrowException(ErrnoException(errno, "setuid")); } return Undefined(); } diff --git a/test/disabled/test-setuidgid.js b/test/disabled/test-setuidgid.js new file mode 100644 index 0000000000..c34864bf2b --- /dev/null +++ b/test/disabled/test-setuidgid.js @@ -0,0 +1,23 @@ +// Requires special privlages +require('../common'); +var assert = require('assert'); + +var oldgid = process.getgid(); +process.setgid('nobody'); +var newgid = process.getgid(); +assert.notEqual(newgid, oldgid, 'gids expected to be different'); + +var olduid = process.getuid(); +process.setuid('nobody'); +var newuid = process.getuid(); +assert.notEqual(newuid, olduid, 'uids expected to be different'); + +try { + process.setuid('nobody1234'); +} catch (e) { + assert.equal( + e.message, + 'failed to resolve group', + 'unexpected error message' + ); +}