chroot-sh.c (8103B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; version 2 of the License. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 19 #ifdef HAVE_CONFIG_H 20 # include <config.h> 21 #endif 22 23 #include <lib_internal/util.h> 24 25 #include <unistd.h> 26 #include <stdlib.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <sys/stat.h> 30 31 #define ENSC_WRAPPERS_PREFIX "chroot-sh: " 32 #define ENSC_WRAPPERS_UNISTD 1 33 #define ENSC_WRAPPERS_IO 1 34 #define ENSC_WRAPPERS_FCNTL 1 35 #include <ensc_wrappers/wrappers.h> 36 37 int wrapper_exit_code = EXIT_FAILURE; 38 39 static void 40 showFD(int fd_in, int fd_out) 41 { 42 for (;;) { 43 char buf[4096]; 44 char const * ptr=buf; 45 ssize_t len; 46 47 len = Eread(fd_in, buf, sizeof(buf)); 48 if (len<=0) break; 49 50 EwriteAll(fd_out, ptr, len); 51 } 52 } 53 54 static int 55 redirectFileInternal(int argc, char *argv[], 56 int mode, bool is_input, 57 char const *operation) 58 { 59 int fd; 60 61 if (argc<2) { 62 WRITE_MSG(2, "Not enough parameters for '"); 63 WRITE_STR(2, operation); 64 WRITE_MSG(2, "' operation; use '--help' for more information\n"); 65 return wrapper_exit_code; 66 } 67 68 fd = EopenD(argv[1], mode, 0644); 69 if (is_input) showFD(fd, 1); 70 else showFD( 0, fd); 71 Eclose(fd); 72 73 return EXIT_SUCCESS; 74 } 75 76 static mode_t 77 testInternal(int argc, char *argv[], char const *operation) 78 { 79 struct stat st; 80 81 if (argc<2) { 82 WRITE_MSG(2, "Not enough parameters for '"); 83 WRITE_STR(2, operation); 84 WRITE_MSG(2, "' operation; use '--help' for more information\n"); 85 return wrapper_exit_code; 86 } 87 88 if (stat(argv[1], &st)==-1) return -1; 89 else return st.st_mode; 90 } 91 92 static int 93 execCat(int argc, char *argv[]) 94 { 95 return redirectFileInternal(argc, argv, 96 O_RDONLY|O_NOCTTY, true, 97 "cat"); 98 } 99 100 static int 101 execAppend(int argc, char *argv[]) 102 { 103 return redirectFileInternal(argc, argv, 104 O_WRONLY|O_CREAT|O_APPEND, false, 105 "append"); 106 } 107 108 static int 109 execTruncate(int argc, char *argv[]) 110 { 111 return redirectFileInternal(argc, argv, 112 O_WRONLY|O_CREAT|O_TRUNC, false, 113 "truncate"); 114 } 115 116 static int 117 execRm(int argc, char *argv[]) 118 { 119 int i = 1; 120 int res = EXIT_SUCCESS; 121 122 if (argc<2) { 123 WRITE_MSG(2, "No files specified for 'rm' operation; try '--help' for more information\n"); 124 return wrapper_exit_code; 125 } 126 127 for (;i<argc; ++i) { 128 if (unlink(argv[i])==-1) { 129 PERROR_Q(ENSC_WRAPPERS_PREFIX "unlink", argv[i]); 130 res = EXIT_FAILURE; 131 } 132 } 133 134 return res; 135 } 136 137 static int 138 execTestFile(int argc, char *argv[]) 139 { 140 int res = testInternal(argc, argv, "testfile"); 141 142 return res!=-1 && S_ISREG(res) ? EXIT_SUCCESS : EXIT_FAILURE; 143 } 144 145 static int 146 execMkdir(int argc, char *argv[]) 147 { 148 int i = 1; 149 int res = EXIT_SUCCESS; 150 151 if (argc<2) { 152 WRITE_MSG(2, "No files specified for 'mkdir' operation; try '--help' for more information\n"); 153 return wrapper_exit_code; 154 } 155 156 for (;i<argc; ++i) { 157 if (mkdir(argv[i], 0755)==-1) { 158 PERROR_Q(ENSC_WRAPPERS_PREFIX "mkdir", argv[i]); 159 res = EXIT_FAILURE; 160 } 161 } 162 163 return res; 164 } 165 166 static int 167 execChmod(int argc, char *argv[]) 168 { 169 int i = 2; 170 int res = EXIT_SUCCESS; 171 unsigned long mode; 172 173 if (argc<3) { 174 WRITE_MSG(2, "No files specified for 'chmod' operation; try '--help' for more information\n"); 175 return wrapper_exit_code; 176 } 177 178 if (!isNumberUnsigned(argv[1], &mode, 1)) { 179 WRITE_MSG(2, "Invalid mode: '"); 180 WRITE_STR(2, argv[1]); 181 WRITE_MSG(2, "'\n"); 182 return EXIT_FAILURE; 183 } 184 185 for (;i<argc; ++i) { 186 if (chmod(argv[i], mode)==-1) { 187 PERROR_Q(ENSC_WRAPPERS_PREFIX "chmod", argv[i]); 188 res = EXIT_FAILURE; 189 } 190 } 191 192 return res; 193 } 194 195 static int 196 execLink(int argc, char *argv[]) 197 { 198 int res = EXIT_SUCCESS; 199 200 if (argc!=3) { 201 WRITE_MSG(2, "Need exactly two files for 'link' operation; try '--help' for more information\n"); 202 return wrapper_exit_code; 203 } 204 205 if (symlink(argv[1], argv[2])==-1) { 206 PERROR_Q(ENSC_WRAPPERS_PREFIX "link", argv[1]); 207 res = EXIT_FAILURE; 208 } 209 210 return res; 211 } 212 213 static int 214 execMv(int argc, char *argv[]) 215 { 216 int res = EXIT_SUCCESS; 217 218 if (argc!=3) { 219 WRITE_MSG(2, "Need exactly two files for 'mv' operation; try '--help' for more information\n"); 220 return wrapper_exit_code; 221 } 222 223 if (rename(argv[1], argv[2])==-1) { 224 PERROR_Q(ENSC_WRAPPERS_PREFIX "mv", argv[1]); 225 res = EXIT_FAILURE; 226 } 227 228 return res; 229 } 230 231 static int 232 execRealpath(int argc, char *argv[]) 233 { 234 int res = EXIT_SUCCESS, 235 i; 236 237 if (argc < 2) { 238 WRITE_MSG(2, "Need some files to work on for 'realpath' operation; try '--help' for more information\n"); 239 return wrapper_exit_code; 240 } 241 242 for (i = 1; i< argc; i++) { 243 char buf[4096]; 244 245 if (realpath(argv[i], buf) == NULL) { 246 PERROR_Q(ENSC_WRAPPERS_PREFIX "realpath", argv[i]); 247 res = EXIT_FAILURE; 248 } 249 else { 250 WRITE_STR(1, buf); 251 WRITE_MSG(1, "\n"); 252 } 253 } 254 255 return res; 256 } 257 258 static struct Command { 259 char const *cmd; 260 int (*handler)(int argc, char *argv[]); 261 } const COMMANDS[] = { 262 { "cat", execCat }, 263 { "append", execAppend }, 264 { "truncate", execTruncate }, 265 { "testfile", execTestFile }, 266 { "rm", execRm }, 267 { "mkdir", execMkdir }, 268 { "chmod", execChmod }, 269 { "link", execLink }, 270 { "mv", execMv }, 271 { "realpath", execRealpath }, 272 { 0,0 } 273 }; 274 275 static void 276 showHelp() 277 { 278 WRITE_MSG(1, 279 "Usage: chroot-sh " 280 " [--] <cmd> <args>*\n\n" 281 "This program chroots into the current directory and executes the specified\n" 282 "commands there. This means that all used paths are relative to the current\n" 283 "directory, and symlinks can point to files under the current path only.\n" 284 "\n" 285 "The supported commands are:\n" 286 " cat <file> ... gives out <file> to stdout\n" 287 " append <file> ... appends stdin to <file> which is created when needed\n" 288 " truncate <file> ... clear <file> and fill it with stdin; the <file> is\n" 289 " created when needed\n" 290 " rm <file>+ ... unlink the given files\n" 291 " mkdir <file>+ ... create the given directories\n" 292 " chmod <mode> <file>+\n" 293 " ... change access permissions of files\n" 294 " link <src> <dst> ... create a symbolic link from <src> to <dst>\n" 295 " mv <src> <dst> ... rename <src> to <dst>\n" 296 " realpath <file>+ ... output real path of each <file>\n" 297 "\nPlease report bugs to " PACKAGE_BUGREPORT "\n"); 298 exit(0); 299 } 300 301 static void 302 showVersion() 303 { 304 WRITE_MSG(1, 305 "chroot-sh " VERSION " -- execute commands within a chroot\n" 306 "This program is part of " PACKAGE_STRING "\n\n" 307 "Copyright (C) 2005 Enrico Scholz\n" 308 VERSION_COPYRIGHT_DISCLAIMER); 309 exit(0); 310 } 311 312 313 int main(int argc, char *argv[]) 314 { 315 struct Command const *cmd; 316 int idx = 1; 317 318 if (argc>=2) { 319 if (strcmp(argv[idx], "--help") ==0) showHelp(); 320 if (strcmp(argv[idx], "--version")==0) showVersion(); 321 if (strcmp(argv[idx], "--")==0) ++idx; 322 } 323 324 if (argc<idx+1) { 325 WRITE_MSG(2, "No command specified; try '--help' for more information\n"); 326 return wrapper_exit_code; 327 } 328 329 Echroot("."); 330 Echdir("/"); 331 332 for (cmd=COMMANDS+0; cmd->cmd!=0; ++cmd) { 333 if (strcmp(cmd->cmd, argv[idx])==0) 334 return cmd->handler(argc-idx, argv+idx); 335 } 336 337 WRITE_MSG(2, "Invalid command '"); 338 WRITE_STR(2, argv[idx]); 339 WRITE_MSG(2, "'; try '--help' for more information\n"); 340 341 return wrapper_exit_code; 342 }