summaryrefslogtreecommitdiffstats
path: root/helper
diff options
context:
space:
mode:
authorMatthew Booth <mbooth@redhat.com>2010-10-28 15:17:21 +0100
committerRichard W.M. Jones <rjones@redhat.com>2010-10-28 16:05:09 +0100
commit3b870aa9f9865754119e32cf3ff6beb154b4d9df (patch)
tree850cc2d9d4c3718dec2ea6f052f31924d3ea0283 /helper
parentf6e12eccb65bef3eb57631e54199d8b1610e7c5c (diff)
downloadfebootstrap-3b870aa9f9865754119e32cf3ff6beb154b4d9df.tar.gz
febootstrap-3b870aa9f9865754119e32cf3ff6beb154b4d9df.tar.xz
febootstrap-3b870aa9f9865754119e32cf3ff6beb154b4d9df.zip
Add -u and -g options to febootstrap-supermin-helper
Bash automatically resets euid to uid when it executes. This means that the effective user id of a program at the point it calls febootstrap-supermin-helper will be lost if any part of execution chain involved bash. This in turn can result in: * the generation of an incorrect checksum, which contains the uid. * the generation of supermin files with a mixture of owners The -u and -g options allow the caller to pass in an explicit user and group to run as. febootstrap-supermin-helper will set(u|g)id as appropriate.
Diffstat (limited to 'helper')
-rw-r--r--helper/febootstrap-supermin-helper.pod13
-rw-r--r--helper/main.c116
2 files changed, 126 insertions, 3 deletions
diff --git a/helper/febootstrap-supermin-helper.pod b/helper/febootstrap-supermin-helper.pod
index c6c551c..1ef960f 100644
--- a/helper/febootstrap-supermin-helper.pod
+++ b/helper/febootstrap-supermin-helper.pod
@@ -94,6 +94,19 @@ If this option is not specified, then every kernel module from the
host will be included. This is safer, but can produce rather large
appliances which need a lot more memory to boot.
+=item B<-u user> | B<--user user> | B<-g group> | B<--group group>
+
+Run febootstrap-supermin-helper as an alternate user and/or group.
+C<user> and C<group> can be specified as either a name, which will
+be resolved using the system name service, or a uid/gid. Use of these
+options requires root privileges.
+
+Use of these options is required if running febootstrap-supermin-helper
+as root with the effective uid/gid set to non-root. Bash will reset
+the effective uid/gid to the real uid/gid when invoked. As
+febootstrap-supermin-helper uses bash in parts, this will result in the
+creation of an appliance with a mixture of ownerships.
+
=back
=head1 SPEED
diff --git a/helper/main.c b/helper/main.c
index f194008..b769bc7 100644
--- a/helper/main.c
+++ b/helper/main.c
@@ -28,23 +28,26 @@
#include <sys/types.h>
#include <sys/time.h>
#include <assert.h>
+#include <grp.h>
+#include <pwd.h>
#include "error.h"
+#include "xstrtol.h"
#include "helper.h"
struct timeval start_t;
int verbose = 0;
-static const char *format = "cpio";
-
enum { HELP_OPTION = CHAR_MAX + 1 };
-static const char *options = "f:k:vV";
+static const char *options = "f:g:k:u:vV";
static const struct option long_options[] = {
{ "help", 0, 0, HELP_OPTION },
{ "format", required_argument, 0, 'f' },
+ { "group", 0, 0, 'g' },
{ "kmods", required_argument, 0, 'k' },
+ { "user", 0, 0, 'u' },
{ "verbose", 0, 0, 'v' },
{ "version", 0, 0, 'V' },
{ 0, 0, 0, 0 }
@@ -76,6 +79,12 @@ usage (FILE *f, const char *progname)
" Display this help text and exit.\n"
" -f cpio|ext2|checksum | --format cpio|ext2|checksum\n"
" Specify output format (default: cpio).\n"
+ " -u user\n"
+ " The user name or uid the appliance will run as. Use of this\n"
+ " option requires root privileges.\n"
+ " -g group\n"
+ " The group name or gid the appliance will run as. Use of\n"
+ " this option requires root privileges.\n"
" -k file | --kmods file\n"
" Specify kernel module whitelist.\n"
" --verbose | -v\n"
@@ -85,14 +94,76 @@ usage (FILE *f, const char *progname)
progname, progname, progname, progname, progname, progname);
}
+static uid_t
+parseuser (const char *id, const char *progname)
+{
+
+ struct passwd *pwd;
+
+ errno = 0;
+ pwd = getpwnam (id);
+
+ if (NULL == pwd) {
+ if (errno != 0) {
+ fprintf (stderr, "Error looking up user: %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ long val;
+ int err = xstrtol (id, NULL, 10, &val, "");
+ if (err != LONGINT_OK) {
+ fprintf (stderr, "%s is not a valid user name or uid\n", id);
+ usage (stderr, progname);
+ exit (EXIT_FAILURE);
+ }
+
+ return (uid_t) val;
+ }
+
+ return pwd->pw_uid;
+}
+
+static gid_t
+parsegroup (const char *id, const char *progname)
+{
+
+ struct group *grp;
+
+ errno = 0;
+ grp = getgrnam (id);
+
+ if (NULL == grp) {
+ if (errno != 0) {
+ fprintf (stderr, "Error looking up group: %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ long val;
+ int err = xstrtol (id, NULL, 10, &val, "");
+ if (err != LONGINT_OK) {
+ fprintf (stderr, "%s is not a valid group name or gid\n", id);
+ usage (stderr, progname);
+ exit (EXIT_FAILURE);
+ }
+
+ return (gid_t) val;
+ }
+
+ return grp->gr_gid;
+}
+
int
main (int argc, char *argv[])
{
/* First thing: start the clock. */
gettimeofday (&start_t, NULL);
+ const char *format = "cpio";
const char *whitelist = NULL;
+ uid_t euid = geteuid ();
+ gid_t egid = getegid ();
+
/* Command line arguments. */
for (;;) {
int c = getopt_long (argc, argv, options, long_options, NULL);
@@ -107,6 +178,14 @@ main (int argc, char *argv[])
format = optarg;
break;
+ case 'u':
+ euid = parseuser (optarg, argv[0]);
+ break;
+
+ case 'g':
+ egid = parsegroup (optarg, argv[0]);
+ break;
+
case 'k':
whitelist = optarg;
break;
@@ -125,6 +204,37 @@ main (int argc, char *argv[])
}
}
+ /* We need to set the real, not effective, uid here to work round a
+ * misfeature in bash. bash will automatically reset euid to uid when
+ * invoked. As shell is used in places by febootstrap-supermin-helper, this
+ * results in code running with varying privilege. */
+ uid_t uid = getuid ();
+ gid_t gid = getgid ();
+
+ if (uid != euid || gid != egid) {
+ if (uid != 0) {
+ fprintf (stderr, "The -u and -g options require root privileges.\n");
+ usage (stderr, argv[0]);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Need to become root first because setgid and setuid require it */
+ if (seteuid (0) == -1) {
+ perror ("seteuid");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Set gid and uid to command-line parameters */
+ if (setgid (egid) == -1) {
+ perror ("setgid");
+ exit (EXIT_FAILURE);
+ }
+ if (setuid (euid) == -1) {
+ perror ("setuid");
+ exit (EXIT_FAILURE);
+ }
+ }
+
/* Select the correct writer module. */
struct writer *writer;
int nr_outputs;