From: ahoward Date: 2003-08-29T08:56:42+09:00 Subject: Re: setuid wrapper On Thu, 28 Aug 2003, ahoward wrote: > > i wrote a little setuid C wrapper which essentially does > > execvp (ruby, argv); > > and was suprised that ruby was still aware that it was being run setuid and > set $SAFE to 1. is there an easy away around this? perhpas embedding the > interpreter? hate to reply to my own message - but here is the program i'm using, posted to clr for posterity. no security flames please! ;-) ----CUT---- /* 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); (*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)) { 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); } ----CUT---- -a ==================================== | Ara Howard | NOAA Forecast Systems Laboratory | Information and Technology Services | Data Systems Group | R/FST 325 Broadway | Boulder, CO 80305-3328 | Email: ara.t.howard@noaa.gov | Phone: 303-497-7238 | Fax: 303-497-7259 | ~ > ruby -e 'p(%.\x2d\x29..intern)' ====================================