Now reading in the S_CAPS values from the vserver's /etc/vservers/<name>.conf
[util-vserver.git] / src / vsh.c
1 /*
2  * Marc E. Fiuczynski <mef@cs.princeton.edu>
3  *
4  * Copyright (c) 2004 The Trustees of Princeton University (Trustees).
5  *
6  * vsh is free software; you can redistribute it and/or modify it
7  * 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  * vsh is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Poptop; see the file COPYING.  If not, write to the Free
18  * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <pwd.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #define DEFAULT_SHELL "/bin/sh"
31
32 /* Exit statuses for programs like 'env' that exec other programs.
33    EXIT_FAILURE might not be 1, so use EXIT_FAIL in such programs.  */
34 enum
35 {
36   EXIT_CANNOT_INVOKE = 126,
37   EXIT_ENOENT = 127
38 };
39
40 extern void slice_enter(char *);
41 extern void runas_slice_user(char *);
42
43 int main(int argc, char **argv)
44 {
45     char *context, *username, *shell;
46     struct passwd   *pwd;
47     uid_t           uid;
48     int index, i;
49
50     if (argv[0][0]=='-') 
51       index = 1;
52     else
53       index = 0;
54
55     uid = getuid();
56     if ((pwd = getpwuid(uid)) == NULL) {
57       fprintf(stderr,"vsh: getpwnam error failed for %d\n",uid); 
58       exit(1);
59     }
60
61     context = (char*)strdup(pwd->pw_name);
62     if (!context) {
63       perror("vsh: strdup failed");
64       exit(2);
65     }
66
67     /* enter vserver "context" */
68     slice_enter(context);
69
70     /* Now run as username in this context. Note that for PlanetLab's
71        vserver configuration the context name also happens to be the
72        "default" username within the vserver context.
73     */
74     username = context;
75     runas_slice_user(username);
76
77     /* With the uid/gid appropriately set. Let's figure out what the
78      * shell in the vserver's /etc/passwd is for the given username.
79      */
80     if ((pwd = getpwnam(username)) == NULL) {
81         fprintf(stderr,"vsh: getpwnam error failed for %s\n",username); 
82         exit(1);
83     }
84
85     /* Make sure pw->pw_shell is non-NULL.*/
86     if (pwd->pw_shell == NULL || pwd->pw_shell[0] == '\0') {
87       pwd->pw_shell = (char *) DEFAULT_SHELL;
88     }
89
90     shell = (char *)strdup(pwd->pw_shell);
91     if (!shell) {
92       perror("vsh: strdup failed");
93       exit(2);
94     }
95
96     /* Check whether 'su' or 'sshd' invoked us as a login shell or
97        not; did this above when testing argv[0]=='-'.
98     */
99     argv[0] = shell;
100     if (index == 1) {
101       char **args;
102       args = (char**)malloc(sizeof(char*)*(argc+2));
103       if (!args) {
104         perror("vsh: malloc failed");
105       }
106       args[0] = argv[0];
107       args[1] = "-l";
108       for(i=1;i<argc+1;i++) {
109         args[i+1] = argv[i];
110       }
111       argv = args;
112     }
113     (void) execvp(shell,argv);
114     {
115       int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
116       exit (exit_status);
117     }
118
119     return 0; /* shutup compiler */
120 }