Browse Source

a simple implementation of the "-u" option with mostly trivial tests.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac268@2525 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 14 years ago
parent
commit
95316d81ac

+ 1 - 0
src/bin/auth/Makefile.am

@@ -46,6 +46,7 @@ libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
 BUILT_SOURCES = spec_config.h 
 pkglibexec_PROGRAMS = b10-auth
 b10_auth_SOURCES = auth_srv.cc auth_srv.h
+b10_auth_SOURCES += change_user.cc change_user.h
 b10_auth_SOURCES += common.h
 b10_auth_SOURCES += main.cc
 b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a

+ 54 - 0
src/bin/auth/change_user.cc

@@ -0,0 +1,54 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <errno.h>
+#include <string.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <auth/common.h>
+
+using namespace boost;
+
+void
+changeUser(const char* const username) {
+    const struct passwd *runas_pw = NULL;
+
+    runas_pw = getpwnam(username);
+    if (runas_pw == NULL) {
+        try {
+            runas_pw = getpwuid(lexical_cast<uid_t>(username));
+        } catch (const bad_lexical_cast& err) {
+            isc_throw(FatalError,
+                      "Failed to parse user name or UID:" << username);
+        }
+    }
+    if (runas_pw == NULL) {
+        isc_throw(FatalError, "Unknown user name or UID:" << username);
+    }
+
+    if (setgid(runas_pw->pw_gid) < 0) {
+        isc_throw(FatalError, "setgid() failed: " << strerror(errno));
+    }
+
+    if (setuid(runas_pw->pw_uid) < 0) {
+        isc_throw(FatalError, "setuid() failed: " << strerror(errno));
+    }
+}

+ 37 - 0
src/bin/auth/change_user.h

@@ -0,0 +1,37 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __CHANGE_USER_H
+#define __CHANGE_USER_H 1
+
+/// \brief Change the run time user.
+///
+/// This function changes the effective user of the authoritative server
+/// process.
+/// \c username can be either a textual user name or its numeric ID.
+/// If the specified user name (or ID) doesn't specify a local user ID
+/// or the user originally starting the process doesn't have a permission
+/// of changing the user to \c username, this function throws an exception
+/// of class \c FatalError.
+///
+/// \param username User name or ID of the new effective user.
+void changeUser(const char* const username);
+
+#endif // __CHANGE_USER_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 9 - 1
src/bin/auth/main.cc

@@ -96,9 +96,10 @@ main(int argc, char* argv[]) {
     int ch;
     const char* port = DNSPORT;
     const char* address = NULL;
+    const char* uid = NULL;
     bool use_ipv4 = true, use_ipv6 = true, cache = true;
 
-    while ((ch = getopt(argc, argv, "46a:np:v")) != -1) {
+    while ((ch = getopt(argc, argv, "46a:np:u:v")) != -1) {
         switch (ch) {
         case '4':
             // Note that -4 means "ipv4 only", we need to set "use_ipv6" here,
@@ -120,6 +121,9 @@ main(int argc, char* argv[]) {
         case 'p':
             port = optarg;
             break;
+        case 'u':
+            uid = optarg;
+            break;
         case 'v':
             verbose_mode = true;
             break;
@@ -165,6 +169,10 @@ main(int argc, char* argv[]) {
                                  my_command_handler);
         cout << "[b10-auth] Configuration channel established." << endl;
 
+        if (uid != NULL) {
+            changeUser(uid);
+        }
+
         auth_server->setConfigSession(cs);
         auth_server->updateConfig(ElementPtr());
 

+ 2 - 0
src/bin/auth/tests/Makefile.am

@@ -13,7 +13,9 @@ TESTS += run_unittests
 run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
 run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
 run_unittests_SOURCES += ../auth_srv.h ../auth_srv.cc
+run_unittests_SOURCES += ../change_user.h ../change_user.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
+run_unittests_SOURCES += change_user_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 59 - 0
src/bin/auth/tests/change_user_unittest.cc

@@ -0,0 +1,59 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdlib.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <auth/common.h>
+#include <auth/change_user.h>
+
+using namespace std;
+
+namespace {
+class ChangeUserTest : public ::testing::Test {
+protected:
+    // normally the USER environment variable should be set to the name
+    // of the local user running this test.  If we encounter a case where
+    // this doesn't hold, we'll need to add a prerequisite check in each
+    // test.  For now we assume this is valid for simplicity.
+    ChangeUserTest() : my_username(getenv("USER")) {}
+    const string my_username;
+};
+
+TEST_F(ChangeUserTest, changeToTheSameUser) {
+    // changing to the run time user should succeed.
+    EXPECT_NO_THROW(changeUser(my_username.c_str()));
+}
+
+TEST_F(ChangeUserTest, badUID) {
+    // -1 should be an invalid numeric UID, and (hopefully) shouldn't be
+    // a valid textual username.
+    EXPECT_THROW(changeUser("-1"), FatalError);
+}
+
+TEST_F(ChangeUserTest, promotionAttempt) {
+    // change to root should fail unless the running user is a super user.
+
+    if (my_username == "root") {
+        cerr << "Already a super user, skipping the test" << endl;
+        return;
+    }
+    EXPECT_THROW(changeUser("root"), FatalError);
+}
+}