Make it easier to add rsync arguments.
[util-vserver.git] / src / capchroot.c
1 // $Id$
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
70 #if !defined(VC_ENABLE_API_COMPAT) && !defined(VC_ENABLE_API_LEGACY)
71   WRITE_MSG(1, "ERROR: tools were built without legacy API support; capchroot will not work!\n\n");
72 #endif
73   
74   WRITE_MSG(fd, "Usage:  ");
75   WRITE_STR(fd, cmd);
76   WRITE_MSG(fd,
77             " --nochroot [--suid <user>] [--] <directory> <command> <args>*\n"
78             "\n"
79             "Options:\n"
80             "    --nochroot     ... remove the CAP_SYS_CHROOT capability\n"
81             "                       after the chroot system call.\n"
82             "    --suid <user>  ... switch to a different user (in the vserver\n"
83             "                       context) before executing the command.\n"
84             "\n"
85             "Please report bugs to " PACKAGE_BUGREPORT "\n");
86   exit(res);
87 }
88
89 static void
90 showVersion()
91 {
92   WRITE_MSG(1,
93             "capchroot " VERSION " -- a capability aware chroot\n"
94             "This program is part of " PACKAGE_STRING "\n\n"
95             "Copyright (C) 2004 Enrico Scholz\n"
96             VERSION_COPYRIGHT_DISCLAIMER);
97   exit(0);
98 }
99
100 static UNUSED void
101 setUser(char const *user)
102 {
103   struct passwd         *p = 0;
104   if (user!=0 && strcmp(user, "root")!=0 && strcmp(user, "0")!=0) {
105     errno = 0;
106     p     = getpwnam(user);
107     if (p==0) {
108       if (errno==0) errno = ENOENT;
109       PERROR_Q(ENSC_WRAPPERS_PREFIX "getpwnam", user);
110       exit(wrapper_exit_code);
111     }
112   }
113
114   if (p!=0) {
115     Esetgroups(1, &p->pw_gid);
116     Esetgid(p->pw_gid);
117     Esetuid(p->pw_uid);
118
119     if (getuid()!=p->pw_uid || getgid()!=p->pw_gid) {
120       WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "Something went wrong while changing uid; expected uid/gid do not match the actual one\n");
121       exit(wrapper_exit_code);
122     }
123   }
124 }
125     
126 int main (int argc, char *argv[])
127 {
128   bool                  nochroot  = false;
129   char const *          suid_user = 0;
130   
131   while (1) {
132     int         c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
133     if (c==-1) break;
134
135     switch (c) {
136       case CMD_HELP     :  showHelp(1, argv[0], 0);
137       case CMD_VERSION  :  showVersion();
138       case CMD_NOCHROOT :  nochroot  = true;   break;
139       case CMD_SUID     :  suid_user = optarg; break;
140       default           :
141         WRITE_MSG(2, "Try '");
142         WRITE_STR(2, argv[0]);
143         WRITE_MSG(2, " --help' for more information.\n");
144         return EXIT_FAILURE;
145         break;
146     }
147   }
148
149 #if defined(VC_ENABLE_API_COMPAT) || defined(VC_ENABLE_API_LEGACY)
150   if (optind==argc)
151     WRITE_MSG(2, "No directory specified; try '--help' for more information\n");
152   else if (optind+1==argc)
153     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
154   else {
155       // We resolve the UID before doing the chroot.
156       // If we do the getpwnam after the chroot, we will end
157       // up loading shared object from the vserver.
158       // This is causing two kind of problem: Incompatibilities
159       // and also a security flaw. The shared objects in the vserver
160       // may be tweaked to get control of the root server ...
161     getpwnam("root");
162     Echroot(argv[optind]);
163     if (nochroot)
164       Evc_new_s_context(VC_SAMECTX, 1<<VC_CAP_SYS_CHROOT,0);
165     setUser(suid_user);
166     EexecvpD(argv[optind+1], argv+optind+1);
167   }
168 #else
169   WRITE_MSG(2, "capchroot: tools were built without legacy API support; can not continue\n");
170 #endif
171   
172   return EXIT_FAILURE;
173 }