Initial version imported to CVS
[Samba/gbeck.git] / source / smbd / vt_mode.c
blob83b62a38ac238903e1181f415d735203ae280876
1 /* vt_mode.c */
2 /*
3 support vtp-sessions
5 written by Christian A. Lademann <cal@zls.com>
6 */
8 /*
9 02.05.95:cal:ported to samba-1.9.13
12 #define __vt_mode_c__
15 /* #include <stdio.h> */
16 /* #include <fcntl.h> */
17 /* #include <sys/types.h> */
18 /* #include <unistd.h> */
19 /* #include <signal.h> */
20 /* #include <errno.h> */
21 /* #include <ctype.h> */
22 /* #include <utmp.h> */
23 /* #include <sys/param.h> */
24 /* #include <sys/ioctl.h> */
25 /* #include <stdlib.h> */
26 /* #include <string.h> */
28 #include "includes.h"
29 #include "vt_mode.h"
30 #include <utmp.h>
32 #ifdef SCO
33 extern char *strdup();
34 #endif
36 extern int Client;
38 #ifdef LINUX
39 # define HAS_VTY
40 #endif
42 #ifdef SCO
43 # define HAS_PTY
44 # define HAS_VTY
46 # include <sys/tty.h>
47 #endif
49 extern int DEBUGLEVEL;
50 extern char *InBuffer, *OutBuffer;
51 extern int done_become_user;
53 char master_name [64], slave_name [64];
54 int master, slave, i, o, e;
56 int ms_type = MS_NONE,
57 ms_poll = 0;
61 VT_Check: test incoming packet for "vtp" or "iVT1\0"
63 int VT_Check(buffer)
64 char *buffer;
66 DEBUG(3,("Checking packet: <%10s...>\n", buffer+4));
67 if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5))
68 return(1);
69 else
70 return(0);
75 VT_Start_utmp: prepare /etc/utmp for /bin/login
77 VT_Start_utmp()
79 struct utmp u, *v;
80 char *tt;
83 setutent();
85 strcpy(u.ut_line, VT_Line);
87 if((v = getutline(&u)) == NULL) {
88 if(strncmp(VT_Line, "tty", 3) == 0)
89 tt = VT_Line + 3;
90 else if(strlen(VT_Line) > 4)
91 tt = VT_Line + strlen(VT_Line) - 4;
92 else
93 tt = VT_Line;
95 strcpy(u.ut_id, tt);
96 u.ut_time = time((time_t*)0);
99 strcpy(u.ut_user, "LOGIN");
100 strcpy(u.ut_line, VT_Line);
101 u.ut_pid = getpid();
102 u.ut_type = LOGIN_PROCESS;
103 pututline(&u);
105 endutent();
107 return(0);
112 VT_Stop_utmp: prepare /etc/utmp for other processes
114 VT_Stop_utmp()
116 struct utmp u, *v;
119 if(VT_Line != NULL) {
120 setutent();
122 strcpy(u.ut_line, VT_Line);
124 if((v = getutline(&u)) != NULL) {
125 strcpy(v->ut_user, "");
126 v->ut_type = DEAD_PROCESS;
127 v->ut_time = time((time_t*)0);
128 pututline(v);
131 endutent();
134 return(0);
139 VT_AtExit: Things to do when the program exits
141 void VT_AtExit()
143 if(VT_ChildPID > 0) {
144 kill(VT_ChildPID, SIGHUP);
145 (void)wait(NULL);
148 VT_Stop_utmp();
153 VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
155 void VT_SigCLD(sig)
156 int sig;
158 if(wait(NULL) == VT_ChildPID)
159 VT_ChildDied = True;
160 else
161 signal(SIGCLD, VT_SigCLD);
166 VT_SigEXIT: signalhandler for signals that cause the process to exit
168 void VT_SigEXIT(sig)
169 int sig;
171 VT_AtExit();
173 exit(1);
178 VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
180 int VT_Start()
182 char OutBuf [64], *X, *Y;
185 ms_type = MS_NONE;
186 master = slave = -1;
188 #ifdef HAS_VTY
189 #ifdef LINUX
190 # define MASTER_TMPL "/dev/pty "
191 # define SLAVE_TMPL "/dev/tty "
192 # define LETTER1 "pqrs"
193 # define POS1 8
194 # define LETTER2 "0123456789abcdef"
195 # define POS2 9
196 #endif
198 #ifdef SCO
199 # define MASTER_TMPL "/dev/ptyp_ "
200 # define SLAVE_TMPL "/dev/ttyp_ "
201 # define LETTER1 "0123456"
202 # define POS1 10
203 # define LETTER2 "0123456789abcdef"
204 # define POS2 11
205 #endif
207 if(ms_poll == MS_VTY || ms_poll == 0) {
208 strcpy(master_name, MASTER_TMPL);
209 strcpy(slave_name, SLAVE_TMPL);
211 for(X = LETTER1; *X && master < 0; X++)
212 for(Y = LETTER2; *Y && master < 0; Y++) {
213 master_name [POS1] = *X;
214 master_name [POS2] = *Y;
215 if((master = open(master_name, O_RDWR)) >= 0) {
216 slave_name [POS1] = *X;
217 slave_name [POS2] = *Y;
218 if((slave = open(slave_name, O_RDWR)) < 0)
219 close(master);
223 if(master >= 0 && slave >= 0)
224 ms_type = MS_VTY;
227 # undef MASTER_TMPL
228 # undef SLAVE_TMPL
229 # undef LETTER1
230 # undef LETTER2
231 # undef POS1
232 # undef POS2
233 #endif
236 #ifdef HAS_PTY
237 #ifdef SCO
238 # define MASTER_TMPL "/dev/ptyp%d"
239 # define SLAVE_TMPL "/dev/ttyp%d"
240 # define MIN_I 0
241 # define MAX_I 63
242 #endif
244 if(ms_poll == MS_PTY || ms_poll == 0) {
245 int i;
247 for(i = MIN_I; i <= MAX_I && master < 0; i++) {
248 sprintf(master_name, MASTER_TMPL, i);
249 if((master = open(master_name, O_RDWR)) >= 0) {
250 sprintf(slave_name, SLAVE_TMPL, i);
251 if((slave = open(slave_name, O_RDWR)) < 0)
252 close(master);
256 if(master >= 0 && slave >= 0)
257 ms_type = MS_PTY;
260 # undef MASTER_TMPL
261 # undef SLAVE_TMPL
262 # undef MIN_I
263 # undef MAX_I
264 #endif
267 if(! ms_type)
268 return(-1);
270 VT_Line = strdup(strrchr(slave_name, '/') + 1);
272 switch((VT_ChildPID = fork())) {
273 case -1:
274 return(-1);
275 break;
277 case 0:
278 #ifdef SCO
279 setsid();
280 #endif
281 close(0);
282 close(1);
283 close(2);
285 i = open(slave_name, O_RDWR);
286 o = open(slave_name, O_RDWR);
287 e = open(slave_name, O_RDWR);
289 #ifdef LINUX
290 setsid();
291 if (ioctl(slave, TIOCSCTTY, (char *)NULL) == -1)
292 exit(1);
293 #endif
294 #ifdef SCO
295 tcsetpgrp(0, getpid());
296 #endif
298 VT_Start_utmp();
300 system("stty sane");
301 execlp("/bin/login", "login", "-c", (char*)0);
302 exit(1);
303 break;
305 default:
306 VT_Mode = True;
307 VT_Status = VT_OPEN;
308 VT_ChildDied = False;
309 VT_Fd = master;
311 signal(SIGCLD, VT_SigCLD);
313 signal(SIGHUP, VT_SigEXIT);
314 signal(SIGTERM, VT_SigEXIT);
315 signal(SIGINT, VT_SigEXIT);
316 signal(SIGQUIT, VT_SigEXIT);
318 memset(OutBuf, 0, sizeof(OutBuf));
319 OutBuf [4] = 0x06;
320 _smb_setlen(OutBuf, 1);
322 send_smb(Client,OutBuf);
324 return(0);
325 break;
331 VT_Output: transport data from socket to pty
333 int VT_Output(Buffer)
334 char *Buffer;
336 int i, len, nb;
339 if(VT_Status != VT_OPEN)
340 return(-1);
342 len = smb_len(Buffer);
344 nb = write(VT_Fd, Buffer + 4, len);
346 return((nb == len) ? 0 : -1);
351 VT_Input: transport data from pty to socket
353 int VT_Input(Buffer, Size)
354 char *Buffer;
355 int Size;
357 int len;
360 if(VT_Status != VT_OPEN)
361 return(-1);
363 memset(Buffer, 0, Size);
364 len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size));
366 _smb_setlen(Buffer, len);
368 return(len + 4);
373 VT_Process: main loop while in vt-mode
375 void VT_Process()
377 static int trans_num = 0;
378 extern int Client;
379 int nread;
382 VT_Start();
384 atexit(VT_AtExit);
386 while (True) {
387 int32 len;
388 int msg_type;
389 int msg_flags;
390 int counter;
391 int last_keepalive=0;
392 struct fd_set si;
393 struct timeval to, *top;
394 int n, ret, t;
397 errno = 0;
398 t = SMBD_SELECT_LOOP*1000;
401 FD_ZERO(&si);
402 FD_SET(Client, &si);
404 FD_SET(VT_Fd, &si);
406 if(t >= 0) {
407 to.tv_sec = t / 1000;
408 to.tv_usec = t - (to.tv_sec * 1000);
410 top = &to;
411 } else
412 top = NULL;
414 if(VT_ChildDied)
415 goto leave_VT_Process;
417 n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top);
419 if(VT_ChildDied)
420 goto leave_VT_Process;
422 if(n == 0) {
423 int i;
424 time_t t;
425 BOOL allidle = True;
426 extern int keepalive;
428 counter += SMBD_SELECT_LOOP;
430 t = time(NULL);
432 if (keepalive && (counter-last_keepalive)>keepalive) {
433 if (!send_keepalive(Client))
434 goto leave_VT_Process;
435 last_keepalive = counter;
437 } else if(n > 0) {
438 counter = 0;
440 if(FD_ISSET(VT_Fd, &si)) {
441 /* got input from vt */
442 nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit()));
444 if(nread > 0)
445 send_smb(Client,OutBuffer);
448 if(FD_ISSET(Client, &si)) {
449 /* got input from socket */
451 if(receive_smb(Client,InBuffer, 0)) {
452 msg_type = CVAL(InBuffer,0);
453 msg_flags = CVAL(InBuffer,1);
455 len = smb_len(InBuffer);
457 DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
459 nread = len + 4;
461 DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
463 if(msg_type == 0)
464 VT_Output(InBuffer);
465 else {
466 nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit()));
468 if(nread > 0) {
469 if (nread != smb_len(OutBuffer) + 4) {
470 DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
471 nread,
472 smb_len(OutBuffer)));
473 } else
474 send_smb(Client,OutBuffer);
477 } else
478 if(errno == EBADF)
479 goto leave_VT_Process;
483 trans_num++;
486 leave_VT_Process:
488 if(VT_ChildPID > 0)
489 kill(VT_ChildPID, SIGHUP);
491 VT_Stop_utmp(VT_Line);
492 return;
494 close_sockets();
495 exit(0);