1 /*
2 * open.c open a vt to run a new command (or shell).
3 *
4 * Copyright (c) 1994 by Jon Tombs <jon@gtex02.us.es>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12 #include "open.h"
13
14 const char *OPENversion = "open: 1.4 (c) Jon Tombs 1994";
15
16 #ifndef VTNAME
17 #error vt device name must be defined in open.h
18 #endif
19
20
21 int
main(int argc,char * argv[])22 main(int argc, char *argv[])
23 {
24
25 int fd = 0;
26 int opt, pid;
27 #if defined(__FreeBSD__)
28 int vt_active;
29 #else
30 struct vt_stat vt;
31 #define vt_active vt.v_active
32 #endif
33 struct passwd *pwnam=NULL;
34 int vtno = -1;
35 char show = FALSE;
36 char login = FALSE;
37 char verbose = FALSE;
38 char do_wait = FALSE;
39 char as_user= FALSE;
40 char vtname[sizeof VTNAME + 2]; /* allow 999 possible VTs */
41 char *cmd = NULL, *def_cmd = NULL;
42
43 /*
44 * I don't like using getopt for this, but otherwise this gets messy.
45 * POSIX/Gnu getopt forces the use of -- to separate child/program
46 * options. RTFM.
47 */
48 while ((opt = getopt(argc, argv, "c:lsvuw")) != -1) {
49 switch (opt) {
50 case 'c':
51 vtno = (int) atol(optarg);
52 #if defined(__FreeBSD__)
53 if (vtno <= 0 || vtno > 99) {
54 #else
55 if (vtno < 0 || vtno > 99) {
56 #endif
57 fprintf(stderr, "open: %s illegal vt number\n", optarg);
58 return 5;
59 }
60 /* close security holes - until we can do this safely */
61 (void) setuid(getuid());
62 break;
63 case 'l':
64 login = TRUE;
65 break;
66 case 's':
67 show = TRUE;
68 break;
69 case 'v':
70 verbose = TRUE;
71 break;
72 case 'w':
73 do_wait = TRUE;
74 break;
75 case 'u':
76 /* we'll let 'em get away with the meaningless -ul combo */
77 if(getuid()) {
78 fprintf(stderr,"%s: only root can use the -u flag.\n",argv[0]);
79 exit(1);
80 }
81 as_user = TRUE;
82 break;
83 default:
84 usage(1);
85
86 }
87 }
88
89
90
91 if (vtno == -1) {
92 if ((fd = open("/dev/console",O_WRONLY,0)) < 0) {
93 perror("open: Failed to open /dev/console\n");
94 return(2);
95 }
96
97
98 if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) {
99 perror("open: Cannot find a free VT\n");
100 close(fd);
101 return(3);
102 }
103
104 #if defined(__FreeBSD__)
105 if (ioctl(fd, VT_GETACTIVE, &vt_active) < 0) {
106 perror("open: can't get active VT\n");
107 #else
108 if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
109 perror("open: can't get VTstate\n");
110 #endif
111 close(fd);
112 return(4);
113 }
114 }
115
116 #if defined(__FreeBSD__)
117 sprintf(vtname, VTNAME, vtno - 1);
118 #else
119 sprintf(vtname, VTNAME, vtno);
120 #endif
121
122 /* support for Spawn_Console; running from init
123 added by Joshua Spoerri, Thu Jul 18 21:13:16 EDT 1996 */
124 if (as_user) {
125 DIR *dp;
126 struct dirent *dentp;
127 struct stat buf;
128 dev_t console_dev;
129 ino_t console_ino;
130 uid_t console_uid;
131 char filename[sizeof VTNAME + 2];
132
133 if (!(dp=opendir("/proc"))) {
134 perror("/proc");
135 exit(1);
136 }
137
138 /* get the current tty */
139 #if defined(__FreeBSD__)
140 sprintf(filename,VTNAME,vt_active - 1);
141 #else
142 sprintf(filename,VTNAME,vt_active);
143 #endif
144 if (stat(filename,&buf)) {
145 perror(filename);
146 exit(1);
147 }
148 console_dev=buf.st_dev;
149 console_ino=buf.st_ino;
150 console_uid=buf.st_uid;
151
152 /* get the owner of current tty */
153 if (!(pwnam=getpwuid(console_uid))) {
154 perror("can't getpwuid");
155 exit(1);
156 }
157
158 /* check to make sure that user has process on that tty */
159 while ((dentp=readdir(dp))) {
160 sprintf(filename,"/proc/%s/fd/0",dentp->d_name);
161 if (stat(filename,&buf)) /*stat will fail if prcs lacks stdin*/
162 continue;
163 if(buf.st_dev == console_dev && buf.st_ino == console_ino
164 && buf.st_uid == console_uid)
165 break;
166 }
167
168 if(!(buf.st_dev == console_dev && buf.st_ino == console_ino
169 && buf.st_uid == console_uid)) {
170 fprintf(stderr,"couldn't find owner of current tty!\n");
171 exit(1);
172 }
173
174 } else {
175 if (!geteuid()) {
176 uid_t uid = getuid();
177 chown(vtname, uid, getgid());
178 setuid(uid);
179 }
180 }
181
182 if (verbose)
183 fprintf(stderr, "open: using VT %s\n", vtname);
184
185 if(!as_user) {
186 if (!(argc > optind)) {
187 def_cmd = getenv("SHELL");
188 if (def_cmd == NULL)
189 usage(0);
190 cmd = malloc(strlen(def_cmd + 2));
191 } else {
192 cmd = malloc(strlen(argv[optind] + 2));
193 }
194
195 if (login)
196 strcpy(cmd, "-");
197 else
198 cmd[0] = '\0';
199
200 if (def_cmd)
201 strcat(cmd, def_cmd);
202 else
203 strcat(cmd, argv[optind]);
204
205 if (login)
206 argv[optind] = cmd++;
207 }
208
209 if((pid=fork()) == 0) {
210 /* leave current vt */
211 #ifdef ESIX_5_3_2_D
212 if (setpgrp() < 0) {
213 #else
214 if (setsid() < 0) {
215 #endif
216 fprintf(stderr, "open: Unable to set new session (%s)\n",
217 strerror(errno));
218 }
219 close(0);
220 close(1);
221 close(2);
222 close(fd);
223
224 /* and grab new one */
225 if ((fd = open(vtname, O_RDWR)) == -1) { /* Shouldn't happen */
226 _exit (4); /* silently die */
227 }
228 dup(fd); dup(fd);
229 if (ioctl(fd, TIOCSCTTY, NULL) < 0)
230 _exit(4);
231 if (show) {
232 /*
233 * Can't tell anyone if any of these fail, so throw away
234 * the return values
235 */
236 if (ioctl(fd, VT_ACTIVATE, vtno) < 0)
237 _exit(4);
238 /* wait to be really sure we have switched */
239 if (ioctl(fd, VT_WAITACTIVE, vtno) < 0)
240 _exit(4);
241 }
242 if(as_user)
243 execlp("login","login","-f",pwnam->pw_name,NULL);
244 else if (def_cmd)
245 execlp(cmd, def_cmd, NULL);
246 else
247 execvp(cmd, &argv[optind]);
248 }
249 if ( pid < 0 ) {
250 perror("open: fork() error");
251 return(6);
252 }
253
254
255 if ( do_wait ) {
256 wait(NULL);
257 if (show) { /* Switch back... */
258 if (ioctl(fd, VT_ACTIVATE, vt_active) < 0)
259 _exit(4);
260 /* wait to be really sure we have switched */
261 if (ioctl(fd, VT_WAITACTIVE, vt_active) < 0)
262 _exit(4);
263 }
264 }
265
266 close (fd);
267 return 0;
268 }
269
270
271 void usage(int stat)
272 {
273 fprintf(stderr,
274 "Usage: open [-c vtnumer ][-l] [-u] [-s] [-v] -- command_line\n");
275 exit (stat);
276 }
277
278
279