This commit was generated by cvs2svn to compensate for changes in r4,
[samba.git] / source3 / smbd / vt_mode.c
1 /* vt_mode.c */
2 /*
3 support vtp-sessions
4
5 written by Christian A. Lademann <cal@zls.com>
6 */
7
8 /*
9 02.05.95:cal:ported to samba-1.9.13
10 */
11
12 #define __vt_mode_c__
13
14
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> */
27
28 #include        "includes.h"
29 #include        "vt_mode.h"
30 #include        <utmp.h>
31
32 #ifdef SCO
33         extern char     *strdup();
34 #endif
35
36 extern int Client;
37
38 #ifdef LINUX
39 #       define  HAS_VTY
40 #endif
41
42 #ifdef SCO
43 #       define  HAS_PTY
44 #       define  HAS_VTY
45
46 #       include <sys/tty.h>
47 #endif
48
49 extern int      DEBUGLEVEL;
50 extern char     *InBuffer, *OutBuffer;
51 extern int      done_become_user;
52
53 char    master_name [64], slave_name [64];
54 int             master, slave, i, o, e;
55
56 int             ms_type = MS_NONE,
57                 ms_poll = 0;
58
59
60 /*
61 VT_Check: test incoming packet for "vtp" or "iVT1\0"
62 */
63 int     VT_Check(buffer)
64 char    *buffer;
65 {
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);
71 }
72
73
74 /*
75 VT_Start_utmp: prepare /etc/utmp for /bin/login
76 */
77 VT_Start_utmp()
78 {
79         struct utmp     u, *v;
80         char            *tt;
81
82
83         setutent();
84
85         strcpy(u.ut_line, VT_Line);
86
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;
94
95                 strcpy(u.ut_id, tt);
96                 u.ut_time = time((time_t*)0);
97         }
98
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);
104
105         endutent();
106
107         return(0);
108 }
109
110
111 /*
112 VT_Stop_utmp: prepare /etc/utmp for other processes
113 */
114 VT_Stop_utmp()
115 {
116         struct utmp     u, *v;
117
118
119         if(VT_Line != NULL) {
120                 setutent();
121
122                 strcpy(u.ut_line, VT_Line);
123
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);
129                 }
130
131                 endutent();
132         }
133
134         return(0);
135 }
136
137
138 /*
139 VT_AtExit: Things to do when the program exits
140 */
141 void    VT_AtExit()
142 {
143         if(VT_ChildPID > 0) {
144                 kill(VT_ChildPID, SIGHUP);
145                 (void)wait(NULL);
146         }
147
148         VT_Stop_utmp();
149 }
150
151
152 /*
153 VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
154 */
155 void    VT_SigCLD(sig)
156 int     sig;
157 {
158         if(wait(NULL) == VT_ChildPID)
159                 VT_ChildDied = True;
160         else
161                 signal(SIGCLD, VT_SigCLD);
162 }
163
164
165 /*
166 VT_SigEXIT: signalhandler for signals that cause the process to exit
167 */
168 void    VT_SigEXIT(sig)
169 int     sig;
170 {
171         VT_AtExit();
172
173         exit(1);
174 }
175
176
177 /*
178 VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
179 */
180 int     VT_Start()
181 {
182         char    OutBuf [64], *X, *Y;
183
184
185         ms_type = MS_NONE;
186         master = slave = -1;
187
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
197
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
206
207         if(ms_poll == MS_VTY || ms_poll == 0) {
208                 strcpy(master_name, MASTER_TMPL);
209                 strcpy(slave_name, SLAVE_TMPL);
210
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);
220                                 }
221                         }
222
223                 if(master >= 0 && slave >= 0)
224                         ms_type = MS_VTY;
225         }
226
227 #       undef   MASTER_TMPL
228 #       undef   SLAVE_TMPL
229 #       undef   LETTER1
230 #       undef   LETTER2
231 #       undef   POS1
232 #       undef   POS2
233 #endif
234
235
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
243
244         if(ms_poll == MS_PTY || ms_poll == 0) {
245                 int     i;
246
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);
253                         }
254                 }
255
256                 if(master >= 0 && slave >= 0)
257                         ms_type = MS_PTY;
258         }
259
260 #       undef   MASTER_TMPL
261 #       undef   SLAVE_TMPL
262 #       undef   MIN_I
263 #       undef   MAX_I
264 #endif
265
266
267         if(! ms_type)
268                 return(-1);
269
270         VT_Line = strdup(strrchr(slave_name, '/') + 1);
271
272         switch((VT_ChildPID = fork())) {
273         case -1:
274                 return(-1);
275                 break;
276
277         case 0:
278 #ifdef SCO
279                 setsid();
280 #endif
281                 close(0);
282                 close(1);
283                 close(2);
284
285                 i = open(slave_name, O_RDWR);
286                 o = open(slave_name, O_RDWR);
287                 e = open(slave_name, O_RDWR);
288
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
297
298                 VT_Start_utmp();
299
300                 system("stty sane");
301                 execlp("/bin/login", "login", "-c", (char*)0);
302                 exit(1);
303                 break;
304
305         default:
306                 VT_Mode = True;
307                 VT_Status = VT_OPEN;
308                 VT_ChildDied = False;
309                 VT_Fd = master;
310
311                 signal(SIGCLD, VT_SigCLD);
312
313                 signal(SIGHUP, VT_SigEXIT);
314                 signal(SIGTERM, VT_SigEXIT);
315                 signal(SIGINT, VT_SigEXIT);
316                 signal(SIGQUIT, VT_SigEXIT);
317
318                 memset(OutBuf, 0, sizeof(OutBuf));
319                 OutBuf [4] = 0x06;
320                 _smb_setlen(OutBuf, 1);
321
322                 send_smb(Client,OutBuf);
323
324                 return(0);
325                 break;
326         }
327 }
328
329
330 /*
331 VT_Output: transport data from socket to pty
332 */
333 int     VT_Output(Buffer)
334 char    *Buffer;
335 {
336         int             i, len, nb;
337
338
339         if(VT_Status != VT_OPEN)
340                 return(-1);
341
342         len = smb_len(Buffer);
343
344         nb = write(VT_Fd, Buffer + 4, len);
345
346         return((nb == len) ? 0 : -1);
347 }
348
349
350 /*
351 VT_Input: transport data from pty to socket
352 */
353 int     VT_Input(Buffer, Size)
354 char    *Buffer;
355 int             Size;
356 {
357         int             len;
358
359
360         if(VT_Status != VT_OPEN)
361                 return(-1);
362
363         memset(Buffer, 0, Size);
364         len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size));
365
366         _smb_setlen(Buffer, len);
367
368         return(len + 4);
369 }
370
371
372 /*
373 VT_Process: main loop while in vt-mode
374 */
375 void VT_Process()
376 {
377         static int      trans_num = 0;
378         extern int      Client;
379         int                     nread;
380
381
382         VT_Start();
383
384         atexit(VT_AtExit);
385
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;
395
396
397                 errno = 0;
398                 t = SMBD_SELECT_LOOP*1000;
399
400
401                 FD_ZERO(&si);
402                 FD_SET(Client, &si);
403
404                 FD_SET(VT_Fd, &si);
405
406                 if(t >= 0) {
407                         to.tv_sec = t / 1000;
408                         to.tv_usec = t - (to.tv_sec * 1000);
409
410                         top = &to;
411                 } else
412                         top = NULL;
413
414                 if(VT_ChildDied)
415                         goto leave_VT_Process;
416
417                 n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top);
418
419                 if(VT_ChildDied)
420                         goto leave_VT_Process;
421         
422                 if(n == 0) {
423                         int i;
424                         time_t t;
425                         BOOL allidle = True;
426                         extern int keepalive;
427         
428                         counter += SMBD_SELECT_LOOP;
429
430                         t = time(NULL);
431         
432                         if (keepalive && (counter-last_keepalive)>keepalive) {
433                                 if (!send_keepalive(Client))
434                                         goto leave_VT_Process;
435                                 last_keepalive = counter;
436                         }
437                 } else if(n > 0) {
438                         counter = 0;
439
440                         if(FD_ISSET(VT_Fd, &si)) {
441                                 /* got input from vt */
442                                 nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit()));
443
444                                 if(nread > 0)
445                                         send_smb(Client,OutBuffer);
446                         }
447
448                         if(FD_ISSET(Client, &si)) {
449                                 /* got input from socket */
450
451                                 if(receive_smb(Client,InBuffer, 0)) {
452                                         msg_type = CVAL(InBuffer,0);
453                                         msg_flags = CVAL(InBuffer,1);
454         
455                                         len = smb_len(InBuffer);
456         
457                                         DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
458         
459                                         nread = len + 4;
460          
461                                         DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
462         
463                                         if(msg_type == 0)
464                                                 VT_Output(InBuffer);
465                                         else {
466                                                 nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit()));
467         
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);
475                                                 }
476                                         }
477                                 } else
478                                         if(errno == EBADF)
479                                                 goto leave_VT_Process;
480                         }
481                 }
482
483                 trans_num++;
484         }
485
486         leave_VT_Process:
487 /*
488                 if(VT_ChildPID > 0)
489                         kill(VT_ChildPID, SIGHUP);
490
491                 VT_Stop_utmp(VT_Line);
492                 return;
493 */
494                 close_sockets();
495                 exit(0);
496 }