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_rubyfor example
gcc _ruby.c -o nobody_ruby
sudo su
chown root nobody_ruby
chgrp root nobody_ruby
chmod 6777 nobody_rubyobviously 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 <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
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
···
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?
====================================
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)’
====================================