chiark / gitweb /
xacpi-simple close bug
[chiark-utils.git] / cprogs / really.c
index 39fe8dd..46db574 100644 (file)
@@ -1,4 +1,23 @@
-/**/
+/*
+ * really.c - program for gaining privilege
+ *
+ * Copyright (C) 1992-3 Ian Jackson <ian@davenant.greenend.org.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3,
+ * or (at your option) any later version.
+ *
+ * This 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, consult the Free Software
+ * Foundation's website at www.fsf.org, or the GNU Project website at
+ * www.gnu.org.
+ */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include "myopt.h"
 
 void usagemessage(void) {
-  if (fputs("usage: really [<user-option>] [<group-option> ...] [--]"
+  if (fputs("usage: really [<really-option> ...] [--]"
             " [<command> [<argument/option> ...]]\n"
-            "user-options:\n"
+            "really-options specifying the user:\n"
             " if no options given, set the uid to 0;\n"
             " -u|--user <username>     also sets their default group list\n"
             " -i|--useronly <username> } set the uid\n"
             " -I|--uidonly <uid>       }  but inherits the group list\n"
-            "group-options:\n"
+            "really-options specifying the group:\n"
             " -z|--groupsclear         only groups specified are to be used\n"
             " -g|--group <groupname>   } add this to\n"
-            " -G|--gid <gid>           }  the group list\n",
+            " -G|--gid <gid>           }  the group list\n"
+            "other really-options:\n"
+           " -h|--help                display this message\n"
+           " -R|--chroot <dir>        chroot (but *not* chdir)\n",
             stderr) == EOF) { perror("write usage"); exit(-1); }
 }
 
-static const char *opt_user, *opt_useronly;
+static const char *opt_user, *opt_useronly, *opt_chroot;
 static int opt_groupsclear= 0, opt_ngids= 0, opt_uidonly= -1;
 static int opt_gids[512];
 
+static void af_uidonly(const struct cmdinfo *cip, const char *value) {
+  unsigned long ul;
+  char *ep;
+
+  ul= strtoul(value,&ep,10);
+  if (*ep) { fprintf(stderr,"bad uid `%s'\n",value); exit(-1); }
+  opt_uidonly= ul;
+}
+
 static void af_group(const struct cmdinfo *cip, const char *value) {
   struct group *gr;
 
@@ -58,37 +89,40 @@ static void af_help(const struct cmdinfo *cip, const char *value) {
 static const struct cmdinfo cmdinfos[]= {
   { "user",         'u',  1,  0, &opt_user,          0,           },
   { "useronly",     'i',  1,  0, &opt_useronly,      0            },
-  { "uidonly",      'I',  1,  &opt_uidonly, 0,       0            },
+  { "uidonly",      'I',  1,  0, 0,                  af_uidonly   },
   { "groupsclear",  'z',  0,  &opt_groupsclear, 0,   0,        1  },
   { "group",        'g',  1,  0, 0,                  af_group     },
   { "gid",          'G',  1,  0, 0,                  af_gid       },
+  { "chroot",       'R',  1,  0, &opt_chroot,        0            },
   { "help",         'h',  0,  0, 0,                  af_help      },
   {  0,              0                                            }
 };
 
 #ifdef REALLY_CHECK_FILE
-static void checkroot(void) {
+static int checkroot(void) {
   int r;
   r= access(REALLY_CHECK_FILE,W_OK);
-  if (r) { perror("sorry"); exit(-1); }
+  if (r) return -1;
+  return 0;
 }
 #endif
 #ifdef REALLY_CHECK_GID
-static void checkroot(void) {
+static int checkroot(void) {
   gid_t groups[512];
-  int r;
+  int r, i;
 
-  r= getgid(); if (r==REALLY_CHECK_GID) return;
+  r= getgid(); if (r==REALLY_CHECK_GID) return 0;
   if (r<0) { perror("getgid check"); exit(-1); }
   r= getgroups(sizeof(groups)/sizeof(groups[0]),groups);
   if (r<0) { perror("getgroups check"); exit(-1); }
   for (i=0; i<r; i++)
-    if (groups[i] == REALLY_CHECK_GID) return;
-  fputs("sorry\n",stderr); exit(-1);
+    if (groups[i] == REALLY_CHECK_GID) return 0;
+  return -1;
 }
 #endif
 #ifdef REALLY_CHECK_NONE
-static void checkroot(void) {
+static int checkroot(void) {
+  return 0;
 }
 #endif
 
@@ -98,7 +132,8 @@ int main(int argc, const char *const *argv) {
   int i, j, ngroups, ngroups_in, maingid, orgmaingid, mainuid, orgmainuid, r;
   const char *cp;
   
-  checkroot();
+  orgmainuid= getuid();
+  if (orgmainuid && checkroot()) { perror("sorry"); exit(-1); }
   myopt(&argv,cmdinfos);
 
   if (opt_groupsclear && !opt_ngids)
@@ -119,8 +154,10 @@ int main(int argc, const char *const *argv) {
     if (!pw) { fprintf(stderr,"unknown user `%s'\n",cp); exit(-1); }
     opt_uidonly= pw->pw_uid;
   }
+  if (opt_chroot) {
+    if (chroot(opt_chroot)) { perror("chroot failed"); exit(-1); }
+  }
   orgmaingid= getgid();
-  orgmainuid= getuid();
   if (orgmaingid<0) { perror("getgid failed"); exit(-1); }
   if (opt_user) {
     r= initgroups(opt_user,pw->pw_gid);