-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
*/
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <sys/wait.h>
#define DEBUG 0
-void Usage_and_abort(void)
-{
- fprintf(stderr, "Usage: runas -u user_id [ -g grp_id ]"
- " command_to_be_run \n");
- exit(-1);
-}
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 32
+#endif
-// Usage: runas -u user_id [ -g grp_id ] [--] command_to_be_run
-// return: the return value of "command_to_be_run"
-// NOTE: returning -1 might be the return code of this program itself or
-// the "command_to_be_run"
+static const char usage[] =
+"Usage: %s -u user_id [-g grp_id] [-v euid] [-j egid] [-G[gid0,gid1,...]] command\n"
+" -u user_id switch to UID user_id\n"
+" -g grp_id switch to GID grp_id\n"
+" -v euid switch euid to UID\n"
+" -j egid switch egid to GID\n"
+" -G[gid0,gid1,...] set supplementary groups\n";
-// ROOT runs "runas" for free
-// Other users run "runas" requires chmod 6755 "command_to_be_run"
+void Usage_and_abort(const char *name)
+{
+ fprintf(stderr, usage, name);
+ exit(-1);
+}
int main(int argc, char **argv)
{
- char **my_argv;
- int status;
- int c,i;
- int gid_is_set = 0;
- int uid_is_set = 0;
- uid_t user_id;
- gid_t grp_id;
-
- if (argc == 1)
- Usage_and_abort();
+ char **my_argv, *name = argv[0], *grp;
+ int status, c, i;
+ int gid_is_set = 0, uid_is_set = 0, num_supp = -1;
+ uid_t user_id = 0;
+ gid_t grp_id = 0, supp_groups[NGROUPS_MAX] = { 0 };
+ int euid_is_set = 0, egid_is_set = 0;
+ uid_t euid = 0;
+ gid_t egid = 0;
+
+ if (argc == 1) {
+ fprintf(stderr, "No parameter count\n");
+ Usage_and_abort(name);
+ }
// get UID and GID
- while ((c = getopt (argc, argv, "+u:g:h")) != -1) {
+ while ((c = getopt(argc, argv, "+u:g:v:j:hG::")) != -1) {
switch (c) {
case 'u':
- user_id = (uid_t)atoi(optarg);
+ if (!isdigit(optarg[0])) {
+ struct passwd *pw = getpwnam(optarg);
+ if (pw == NULL) {
+ fprintf(stderr, "parameter '%s' bad\n",
+ optarg);
+ Usage_and_abort(name);
+ }
+ user_id = pw->pw_uid;
+ } else {
+ user_id = (uid_t)atoi(optarg);
+ }
uid_is_set = 1;
if (!gid_is_set)
grp_id = user_id;
break;
case 'g':
- grp_id = (gid_t)atoi(optarg);
+ if (!isdigit(optarg[0])) {
+ struct group *gr = getgrnam(optarg);
+ if (gr == NULL) {
+ fprintf(stderr, "getgrname %s failed\n",
+ optarg);
+ Usage_and_abort(name);
+ }
+ grp_id = gr->gr_gid;
+ } else {
+ grp_id = (gid_t)atoi(optarg);
+ }
gid_is_set = 1;
break;
- case 'h':
- Usage_and_abort();
+ case 'v':
+ if (!isdigit(optarg[0])) {
+ struct passwd *pw = getpwnam(optarg);
+ if (pw == NULL) {
+ fprintf(stderr, "parameter '%s' bad\n",
+ optarg);
+ Usage_and_abort(name);
+ }
+ euid = pw->pw_uid;
+ } else {
+ euid = (uid_t)atoi(optarg);
+ }
+ euid_is_set = 1;
+ break;
+
+ case 'j':
+ if (!isdigit(optarg[0])) {
+ struct group *gr = getgrnam(optarg);
+ if (gr == NULL) {
+ fprintf(stderr, "getgrname %s failed\n",
+ optarg);
+ Usage_and_abort(name);
+ }
+ egid = gr->gr_gid;
+ } else {
+ egid = (gid_t)atoi(optarg);
+ }
+ egid_is_set = 1;
+ break;
+
+ case 'G':
+ num_supp = 0;
+ if (optarg == NULL || !isdigit(optarg[0]))
+ break;
+ while ((grp = strsep(&optarg, ",")) != NULL) {
+ printf("adding supp group %d\n", atoi(grp));
+ supp_groups[num_supp++] = atoi(grp);
+ if (num_supp >= NGROUPS_MAX)
+ break;
+ }
break;
default:
- //fprintf(stderr, "Bad parameters.\n");
- //Usage_and_abort ();
+ case 'h':
+ Usage_and_abort(name);
break;
}
}
- if (!uid_is_set)
- Usage_and_abort();
+ if (!uid_is_set) {
+ fprintf(stderr, "Must specify uid to run.\n");
+ Usage_and_abort(name);
+ }
if (optind == argc) {
- fprintf(stderr, "Bad parameters.\n");
- Usage_and_abort();
+ fprintf(stderr, "Must specify command to run.\n");
+ Usage_and_abort(name);
}
// assemble the command
#endif
// set GID
- status = setregid(grp_id, grp_id);
+ if (!egid_is_set)
+ egid = grp_id;
+ status = setregid(grp_id, egid);
if (status == -1) {
- fprintf(stderr, "Cannot change grp_ID to %d, errno=%d (%s)\n",
- grp_id, errno, strerror(errno) );
+ fprintf(stderr, "Cannot change gid to %d/%d, errno=%d (%s)\n",
+ grp_id, egid, errno, strerror(errno) );
exit(-1);
}
+ if (num_supp >= 0) {
+ status = setgroups(num_supp, supp_groups);
+ if (status == -1) {
+ perror("setting supplementary groups");
+ exit(-1);
+ }
+ }
+
// set UID
- status = setreuid(user_id, user_id );
+ if (!euid_is_set)
+ euid = user_id;
+ status = setreuid(user_id, euid);
if(status == -1) {
- fprintf(stderr,"Cannot change user_ID to %d, errno=%d (%s)\n",
- user_id, errno, strerror(errno) );
+ fprintf(stderr,"Cannot change uid to %d/%d, errno=%d (%s)\n",
+ user_id, euid, errno, strerror(errno) );
exit(-1);
}
-
- fprintf(stderr, "running as USER(%d), Grp (%d): ", user_id, grp_id );
+ fprintf(stderr, "running as uid/gid/euid/egid %d/%d/%d/%d, groups:",
+ user_id, grp_id, euid, egid);
+ for (i = 0; i < num_supp; i++)
+ fprintf(stderr, " %d", supp_groups[i]);
+ fprintf(stderr, "\n");
for (i = 0; i < argc - optind; i++)
fprintf(stderr, " [%s]", my_argv[i]);
// The command to be run
execvp(my_argv[0], my_argv);
- fprintf(stderr, "execvp fails running %s\n", my_argv[0]);
+ fprintf(stderr, "execvp fails running %s (%d): %s\n", my_argv[0],
+ errno, strerror(errno));
exit(-1);
}
-