69dbe3725fdbf6d33bedd5b6286b1424fec2b818
[util-vserver.git] / src / capchroot.c
1 // $Id: capchroot.c,v 1.7 2004/03/24 01:41:28 ensc Exp $
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on capchroot.cc by Jacques Gelinas
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 //  
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //  
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 /*
21         This chroot command does very little. Once the chroot
22         system call is executed, it (option) remove the CAP_SYS_CHROOT
23         capability. Then it executes its argument
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29
30 #include "vserver.h"
31 #include "util.h"
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <pwd.h>
36 #include <grp.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdbool.h>
40 #include <stdlib.h>
41 #include <getopt.h>
42 #include <libgen.h>
43
44 #define ENSC_WRAPPERS_PREFIX    "capchroot: "
45 #define ENSC_WRAPPERS_UNISTD    1
46 #define ENSC_WRAPPERS_VSERVER   1
47 #include <wrappers.h>
48
49 #define CMD_HELP                0x1000
50 #define CMD_VERSION             0x1001
51 #define CMD_NOCHROOT            0x2000
52 #define CMD_SUID                0x2001
53
54 int                     wrapper_exit_code = 255;
55
56 static struct option const
57 CMDLINE_OPTIONS[] = {
58   { "help",        no_argument,       0, CMD_HELP },
59   { "version",     no_argument,       0, CMD_VERSION },
60   { "nochroot",    no_argument,       0, CMD_NOCHROOT },
61   { "suid",        required_argument, 0, CMD_SUID },
62   {0,0,0,0}
63 };
64
65 static void
66 showHelp(int fd, char const *cmd, int res)
67 {
68   VSERVER_DECLARE_CMD(cmd);
69   WRITE_MSG(fd, "Usage:  ");
70   WRITE_STR(fd, cmd);
71   WRITE_MSG(fd,
72             " --nochroot [--suid <user>] [--] <directory> <command> <args>*\n"
73             "\n"
74             "Options:\n"
75             "    --nochroot     ... remove the CAP_SYS_CHROOT capability\n"
76             "                       after the chroot system call.\n"
77             "    --suid <user>  ... switch to a different user (in the vserver\n"
78             "                       context) before executing the command.\n"
79             "\n"
80             "Please report bugs to " PACKAGE_BUGREPORT "\n");
81   exit(res);
82 }
83
84 static void
85 showVersion()
86 {
87   WRITE_MSG(1,
88             "capchroot " VERSION " -- a capability aware chroot\n"
89             "This program is part of " PACKAGE_STRING "\n\n"
90             "Copyright (C) 2004 Enrico Scholz\n"
91             VERSION_COPYRIGHT_DISCLAIMER);
92   exit(0);
93 }
94
95 static void
96 setUser(char const *user)
97 {
98   struct passwd         *p = 0;
99   if (user!=0 && strcmp(user, "root")!=0) {
100     errno = 0;
101     p     = getpwnam(user);
102     if (p==0) {
103       if (errno==0) errno = ENOENT;
104       PERROR_Q(ENSC_WRAPPERS_PREFIX "getpwnam", user);
105       exit(wrapper_exit_code);
106     }
107   }
108
109   if (p!=0) {
110     Esetgroups(1, &p->pw_gid);
111     Esetgid(p->pw_gid);
112     Esetuid(p->pw_uid);
113
114     if (getuid()!=p->pw_uid || getgid()!=p->pw_gid) {
115       WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Something went wrong while changing uid; expected uid/gid do not match the actual one\n");
116       exit(wrapper_exit_code);
117     }
118   }
119 }
120     
121 int main (int argc, char *argv[])
122 {
123   bool                  nochroot  = false;
124   char const *          suid_user = 0;
125   
126   while (1) {
127     int         c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
128     if (c==-1) break;
129
130     switch (c) {
131       case CMD_HELP     :  showHelp(1, argv[0], 0);
132       case CMD_VERSION  :  showVersion();
133       case CMD_NOCHROOT :  nochroot  = true;   break;
134       case CMD_SUID     :  suid_user = optarg; break;
135       default           :
136         WRITE_MSG(2, "Try '");
137         WRITE_STR(2, argv[0]);
138         WRITE_MSG(2, " --help\" for more information.\n");
139         return EXIT_FAILURE;
140         break;
141     }
142   }
143
144   if (optind==argc)
145     WRITE_MSG(2, "No directory specified; try '--help' for more information\n");
146   else if (optind+1==argc)
147     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
148   else {
149       // We resolve the UID before doing the chroot.
150       // If we do the getpwnam after the chroot, we will end
151       // up loading shared object from the vserver.
152       // This is causing two kind of problem: Incompatibilities
153       // and also a security flaw. The shared objects in the vserver
154       // may be tweaked to get control of the root server ...
155     getpwnam("root");
156     Echroot(argv[optind]);
157     if (nochroot)
158       Evc_new_s_context(VC_SAMECTX, 1<<VC_CAP_SYS_CHROOT,0);
159     setUser(suid_user);
160     EexecvpD(argv[optind+1], argv+optind+1);
161   }
162
163   return EXIT_FAILURE;
164 }