client.c: New print queue query code from Jeff C. Foster " <jfoste@wgc.woodward...
[Samba/gbeck.git] / source / smbd / vt_mode.c
blob0a4d50c217f4f1b3e3ddf03869a3a3ebb1a35b72
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(char *buffer)
65 DEBUG(3,("Checking packet: <%10s...>\n", buffer+4));
66 if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5))
67 return(1);
68 else
69 return(0);
74 VT_Start_utmp: prepare /etc/utmp for /bin/login
76 int VT_Start_utmp(void)
78 struct utmp u, *v;
79 char *tt;
82 setutent();
84 strcpy(u.ut_line, VT_Line);
86 if((v = getutline(&u)) == NULL) {
87 if(strncmp(VT_Line, "tty", 3) == 0)
88 tt = VT_Line + 3;
89 else if(strlen(VT_Line) > 4)
90 tt = VT_Line + strlen(VT_Line) - 4;
91 else
92 tt = VT_Line;
94 strcpy(u.ut_id, tt);
95 u.ut_time = time((time_t*)0);
98 strcpy(u.ut_user, "LOGIN");
99 strcpy(u.ut_line, VT_Line);
100 u.ut_pid = getpid();
101 u.ut_type = LOGIN_PROCESS;
102 pututline(&u);
104 endutent();
106 return(0);
111 VT_Stop_utmp: prepare /etc/utmp for other processes
113 int VT_Stop_utmp(void)
115 struct utmp u, *v;
118 if(VT_Line != NULL) {
119 setutent();
121 strcpy(u.ut_line, VT_Line);
123 if((v = getutline(&u)) != NULL) {
124 strcpy(v->ut_user, "");
125 v->ut_type = DEAD_PROCESS;
126 v->ut_time = time((time_t*)0);
127 pututline(v);
130 endutent();
133 return(0);
138 VT_AtExit: Things to do when the program exits
140 void VT_AtExit(void)
142 if(VT_ChildPID > 0) {
143 kill(VT_ChildPID, SIGHUP);
144 (void)wait(NULL);
147 VT_Stop_utmp();
152 VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
154 void VT_SigCLD(int sig)
156 if(wait(NULL) == VT_ChildPID)
157 VT_ChildDied = True;
158 else
159 signal(SIGCLD, VT_SigCLD);
164 VT_SigEXIT: signalhandler for signals that cause the process to exit
166 void VT_SigEXIT(int sig)
168 VT_AtExit();
170 exit(1);
175 VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
177 int VT_Start(void)
179 char OutBuf [64], *X, *Y;
182 ms_type = MS_NONE;
183 master = slave = -1;
185 #ifdef HAS_VTY
186 #ifdef LINUX
187 # define MASTER_TMPL "/dev/pty "
188 # define SLAVE_TMPL "/dev/tty "
189 # define LETTER1 "pqrs"
190 # define POS1 8
191 # define LETTER2 "0123456789abcdef"
192 # define POS2 9
193 #endif
195 #ifdef SCO
196 # define MASTER_TMPL "/dev/ptyp_ "
197 # define SLAVE_TMPL "/dev/ttyp_ "
198 # define LETTER1 "0123456"
199 # define POS1 10
200 # define LETTER2 "0123456789abcdef"
201 # define POS2 11
202 #endif
204 if(ms_poll == MS_VTY || ms_poll == 0) {
205 strcpy(master_name, MASTER_TMPL);
206 strcpy(slave_name, SLAVE_TMPL);
208 for(X = LETTER1; *X && master < 0; X++)
209 for(Y = LETTER2; *Y && master < 0; Y++) {
210 master_name [POS1] = *X;
211 master_name [POS2] = *Y;
212 if((master = open(master_name, O_RDWR)) >= 0) {
213 slave_name [POS1] = *X;
214 slave_name [POS2] = *Y;
215 if((slave = open(slave_name, O_RDWR)) < 0)
216 close(master);
220 if(master >= 0 && slave >= 0)
221 ms_type = MS_VTY;
224 # undef MASTER_TMPL
225 # undef SLAVE_TMPL
226 # undef LETTER1
227 # undef LETTER2
228 # undef POS1
229 # undef POS2
230 #endif
233 #ifdef HAS_PTY
234 #ifdef SCO
235 # define MASTER_TMPL "/dev/ptyp%d"
236 # define SLAVE_TMPL "/dev/ttyp%d"
237 # define MIN_I 0
238 # define MAX_I 63
239 #endif
241 if(ms_poll == MS_PTY || ms_poll == 0) {
242 int i;
244 for(i = MIN_I; i <= MAX_I && master < 0; i++) {
245 sprintf(master_name, MASTER_TMPL, i);
246 if((master = open(master_name, O_RDWR)) >= 0) {
247 sprintf(slave_name, SLAVE_TMPL, i);
248 if((slave = open(slave_name, O_RDWR)) < 0)
249 close(master);
253 if(master >= 0 && slave >= 0)
254 ms_type = MS_PTY;
257 # undef MASTER_TMPL
258 # undef SLAVE_TMPL
259 # undef MIN_I
260 # undef MAX_I
261 #endif
264 if(! ms_type)
265 return(-1);
267 VT_Line = strdup(strrchr(slave_name, '/') + 1);
269 switch((VT_ChildPID = fork())) {
270 case -1:
271 return(-1);
272 break;
274 case 0:
275 #ifdef SCO
276 setsid();
277 #endif
278 close(0);
279 close(1);
280 close(2);
282 i = open(slave_name, O_RDWR);
283 o = open(slave_name, O_RDWR);
284 e = open(slave_name, O_RDWR);
286 #ifdef LINUX
287 setsid();
288 if (ioctl(slave, TIOCSCTTY, (char *)NULL) == -1)
289 exit(1);
290 #endif
291 #ifdef SCO
292 tcsetpgrp(0, getpid());
293 #endif
295 VT_Start_utmp();
297 system("stty sane");
298 execlp("/bin/login", "login", "-c", (char*)0);
299 exit(1);
300 break;
302 default:
303 VT_Mode = True;
304 VT_Status = VT_OPEN;
305 VT_ChildDied = False;
306 VT_Fd = master;
308 signal(SIGCLD, VT_SigCLD);
310 signal(SIGHUP, VT_SigEXIT);
311 signal(SIGTERM, VT_SigEXIT);
312 signal(SIGINT, VT_SigEXIT);
313 signal(SIGQUIT, VT_SigEXIT);
315 memset(OutBuf, 0, sizeof(OutBuf));
316 OutBuf [4] = 0x06;
317 _smb_setlen(OutBuf, 1);
319 send_smb(Client,OutBuf);
321 return(0);
322 break;
328 VT_Output: transport data from socket to pty
330 int VT_Output(char *Buffer)
332 int i, len, nb;
335 if(VT_Status != VT_OPEN)
336 return(-1);
338 len = smb_len(Buffer);
340 nb = write(VT_Fd, Buffer + 4, len);
342 return((nb == len) ? 0 : -1);
347 VT_Input: transport data from pty to socket
349 int VT_Input(char *Buffer,int Size)
351 int len;
354 if(VT_Status != VT_OPEN)
355 return(-1);
357 memset(Buffer, 0, Size);
358 len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size));
360 _smb_setlen(Buffer, len);
362 return(len + 4);
367 VT_Process: main loop while in vt-mode
369 void VT_Process(void)
371 static int trans_num = 0;
372 extern int Client;
373 int nread;
376 VT_Start();
378 atexit(VT_AtExit);
380 while (True) {
381 int32 len;
382 int msg_type;
383 int msg_flags;
384 int counter;
385 int last_keepalive=0;
386 struct fd_set si;
387 struct timeval to, *top;
388 int n, ret, t;
391 errno = 0;
392 t = SMBD_SELECT_LOOP*1000;
395 FD_ZERO(&si);
396 FD_SET(Client, &si);
398 FD_SET(VT_Fd, &si);
400 if(t >= 0) {
401 to.tv_sec = t / 1000;
402 to.tv_usec = t - (to.tv_sec * 1000);
404 top = &to;
405 } else
406 top = NULL;
408 if(VT_ChildDied)
409 goto leave_VT_Process;
411 n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top);
413 if(VT_ChildDied)
414 goto leave_VT_Process;
416 if(n == 0) {
417 int i;
418 time_t t;
419 BOOL allidle = True;
420 extern int keepalive;
422 counter += SMBD_SELECT_LOOP;
424 t = time(NULL);
426 if (keepalive && (counter-last_keepalive)>keepalive) {
427 if (!send_keepalive(Client))
428 goto leave_VT_Process;
429 last_keepalive = counter;
431 } else if(n > 0) {
432 counter = 0;
434 if(FD_ISSET(VT_Fd, &si)) {
435 /* got input from vt */
436 nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit()));
438 if(nread > 0)
439 send_smb(Client,OutBuffer);
442 if(FD_ISSET(Client, &si)) {
443 /* got input from socket */
445 if(receive_smb(Client,InBuffer, 0)) {
446 msg_type = CVAL(InBuffer,0);
447 msg_flags = CVAL(InBuffer,1);
449 len = smb_len(InBuffer);
451 DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
453 nread = len + 4;
455 DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
457 if(msg_type == 0)
458 VT_Output(InBuffer);
459 else {
460 nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit()));
462 if(nread > 0) {
463 if (nread != smb_len(OutBuffer) + 4) {
464 DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
465 nread,
466 smb_len(OutBuffer)));
467 } else
468 send_smb(Client,OutBuffer);
471 } else
472 if(errno == EBADF)
473 goto leave_VT_Process;
477 trans_num++;
480 leave_VT_Process:
482 if(VT_ChildPID > 0)
483 kill(VT_ChildPID, SIGHUP);
485 VT_Stop_utmp(VT_Line);
486 return;
488 close_sockets();
489 exit(0);