/* FILE: _ruby.c - this program is a wrapper on ruby which will run ruby as another user (setuid ruby). - it MUST be named 'USERNAME_ruby', for example 'nobody_ruby', and must also be a root owned setuid binary - compile with gcc _ruby.c -o USERNAME_ruby sudo su chown root USERNAME_ruby chgrp root USERNAME_ruby chmod 6777 USERNAME_ruby for example gcc _ruby.c -o nobody_ruby sudo su chown root nobody_ruby chgrp root nobody_ruby chmod 6777 nobody_ruby obviously the user this ruby would execute as is user 'nobody' - this program is known to work with * Linux 2.4.18-27.8.0 i686 * ruby 1.6.7 (2002-03-19) [i386-linux] - this program could be VERY dangerous to your system's health: use wisely */ #define RUBY "ruby" #include #include #include #include #include #include #include int die (const char * const msg, int err, const char * const file, int lineno) { fprintf (stderr, "%s @ %s:%d\n", msg ? msg : strerror (err), file, lineno); exit (err); } #define DIE() (die(strerror(errno),errno,__FILE__,__LINE__)) #define unless(exp) if(!(exp)) int main (argc, argv, env) int argc; char **argv; char **env; { int n; char *ruby; char *cp; char *name; uid_t pw_uid; gid_t pw_gid; struct passwd *entry; /* find basename of executing program */ for (cp = (*argv + strlen (*argv) - 1); cp > *argv && *cp != '/'; --cp); /* align with basename if stopped on separator */ (*cp == '/') && cp++; /* make a copy because we will munge it later */ unless (name = strdup (cp)) { DIE (); } /* search for XXX component of XXX_ruby */ for (cp = name; *cp && *cp != '_'; cp++); unless (*cp && cp != name && *cp == '_' && (strcmp (cp + 1, "ruby") == 0)) { fprintf (stderr, "%s\n", name); die ("THIS PROGRAM MUST BE NAMED ${USER}_ruby", EXIT_FAILURE, __FILE__, __LINE__); } /* we take everything before the '_' as the username */ *cp = 0; unless (entry = getpwnam (name)) { die (name, errno, __FILE__, __LINE__); } pw_uid = entry->pw_uid; pw_gid = entry->pw_gid; free (name); setregid (pw_gid, pw_gid); /* setgid (pw_gid); */ setfsgid (pw_gid); setreuid (pw_uid, pw_uid); /* setuid (pw_uid); */ setfsuid (pw_uid); (ruby = getenv ("RUBY")) || (ruby = RUBY); execvp (ruby, argv); return (EXIT_FAILURE); }