This is a security audit change of the main source.
[tprouty/samba.git] / source3 / smbd / vt_mode.c
1 /* vt_mode.c */
2 /*
3 support vtp-sessions
4
5 (C) 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 fstring master_name, slave_name;
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(char   *buffer)
64 {
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);
70 }
71
72
73 /*
74 VT_Start_utmp: prepare /etc/utmp for /bin/login
75 */
76 int VT_Start_utmp(void)
77 {
78         struct utmp     u, *v;
79         char            *tt;
80
81
82         setutent();
83
84         fstrcpy(u.ut_line, VT_Line);
85
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;
93
94                 fstrcpy(u.ut_id, tt);
95                 u.ut_time = time((time_t*)0);
96         }
97
98         fstrcpy(u.ut_user, "LOGIN");
99         fstrcpy(u.ut_line, VT_Line);
100         u.ut_pid = getpid();
101         u.ut_type = LOGIN_PROCESS;
102         pututline(&u);
103
104         endutent();
105
106         return(0);
107 }
108
109
110 /*
111 VT_Stop_utmp: prepare /etc/utmp for other processes
112 */
113 int VT_Stop_utmp(void)
114 {
115         struct utmp     u, *v;
116
117
118         if(VT_Line != NULL) {
119                 setutent();
120
121                 fstrcpy(u.ut_line, VT_Line);
122
123                 if((v = getutline(&u)) != NULL) {
124                         fstrcpy(v->ut_user, "");
125                         v->ut_type = DEAD_PROCESS;
126                         v->ut_time = time((time_t*)0);
127                         pututline(v);
128                 }
129
130                 endutent();
131         }
132
133         return(0);
134 }
135
136
137 /*
138 VT_AtExit: Things to do when the program exits
139 */
140 void    VT_AtExit(void)
141 {
142         if(VT_ChildPID > 0) {
143                 kill(VT_ChildPID, SIGHUP);
144                 (void)wait(NULL);
145         }
146
147         VT_Stop_utmp();
148 }
149
150
151 /*
152 VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
153 */
154 void    VT_SigCLD(int   sig)
155 {
156         if(wait(NULL) == VT_ChildPID)
157                 VT_ChildDied = True;
158         else
159                 signal(SIGCLD, VT_SigCLD);
160 }
161
162
163 /*
164 VT_SigEXIT: signalhandler for signals that cause the process to exit
165 */
166 void    VT_SigEXIT(int  sig)
167 {
168         VT_AtExit();
169
170         exit(1);
171 }
172
173
174 /*
175 VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
176 */
177 int     VT_Start(void)
178 {
179         char    OutBuf [64], *X, *Y;
180
181
182         ms_type = MS_NONE;
183         master = slave = -1;
184
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
194
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
203
204         if(ms_poll == MS_VTY || ms_poll == 0) {
205                 fstrcpy(master_name, MASTER_TMPL);
206                 fstrcpy(slave_name, SLAVE_TMPL);
207
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);
217                                 }
218                         }
219
220                 if(master >= 0 && slave >= 0)
221                         ms_type = MS_VTY;
222         }
223
224 #       undef   MASTER_TMPL
225 #       undef   SLAVE_TMPL
226 #       undef   LETTER1
227 #       undef   LETTER2
228 #       undef   POS1
229 #       undef   POS2
230 #endif
231
232
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
240
241         if(ms_poll == MS_PTY || ms_poll == 0) {
242                 int     i;
243
244                 for(i = MIN_I; i <= MAX_I && master < 0; i++) {
245                         slprintf(master_name, sizeof(fstring) - 1, MASTER_TMPL, i);
246                         if((master = open(master_name, O_RDWR)) >= 0) {
247                                 slprintf(slave_name, sizeof(fstring) - 1, SLAVE_TMPL, i);
248                                 if((slave = open(slave_name, O_RDWR)) < 0)
249                                         close(master);
250                         }
251                 }
252
253                 if(master >= 0 && slave >= 0)
254                         ms_type = MS_PTY;
255         }
256
257 #       undef   MASTER_TMPL
258 #       undef   SLAVE_TMPL
259 #       undef   MIN_I
260 #       undef   MAX_I
261 #endif
262
263
264         if(! ms_type)
265                 return(-1);
266
267         VT_Line = strdup(strrchr(slave_name, '/') + 1);
268
269         switch((VT_ChildPID = fork())) {
270         case -1:
271                 return(-1);
272                 break;
273
274         case 0:
275 #ifdef SCO
276                 setsid();
277 #endif
278                 close(0);
279                 close(1);
280                 close(2);
281
282                 i = open(slave_name, O_RDWR);
283                 o = open(slave_name, O_RDWR);
284                 e = open(slave_name, O_RDWR);
285
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
294
295                 VT_Start_utmp();
296
297                 system("stty sane");
298                 execlp("/bin/login", "login", "-c", (char*)0);
299                 exit(1);
300                 break;
301
302         default:
303                 VT_Mode = True;
304                 VT_Status = VT_OPEN;
305                 VT_ChildDied = False;
306                 VT_Fd = master;
307
308                 signal(SIGCLD, VT_SigCLD);
309
310                 signal(SIGHUP, VT_SigEXIT);
311                 signal(SIGTERM, VT_SigEXIT);
312                 signal(SIGINT, VT_SigEXIT);
313                 signal(SIGQUIT, VT_SigEXIT);
314
315                 memset(OutBuf, 0, sizeof(OutBuf));
316                 OutBuf [4] = 0x06;
317                 _smb_setlen(OutBuf, 1);
318
319                 send_smb(Client,OutBuf);
320
321                 return(0);
322                 break;
323         }
324 }
325
326
327 /*
328 VT_Output: transport data from socket to pty
329 */
330 int     VT_Output(char  *Buffer)
331 {
332         int             i, len, nb;
333
334
335         if(VT_Status != VT_OPEN)
336                 return(-1);
337
338         len = smb_len(Buffer);
339
340         nb = write(VT_Fd, Buffer + 4, len);
341
342         return((nb == len) ? 0 : -1);
343 }
344
345
346 /*
347 VT_Input: transport data from pty to socket
348 */
349 int     VT_Input(char   *Buffer,int             Size)
350 {
351         int             len;
352
353
354         if(VT_Status != VT_OPEN)
355                 return(-1);
356
357         memset(Buffer, 0, Size);
358         len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size));
359
360         _smb_setlen(Buffer, len);
361
362         return(len + 4);
363 }
364
365
366 /*
367 VT_Process: main loop while in vt-mode
368 */
369 void VT_Process(void)
370 {
371         static int      trans_num = 0;
372         extern int      Client;
373         int                     nread;
374
375
376         VT_Start();
377
378         atexit(VT_AtExit);
379
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;
389
390
391                 errno = 0;
392                 t = SMBD_SELECT_LOOP*1000;
393
394
395                 FD_ZERO(&si);
396                 FD_SET(Client, &si);
397
398                 FD_SET(VT_Fd, &si);
399
400                 if(t >= 0) {
401                         to.tv_sec = t / 1000;
402                         to.tv_usec = t - (to.tv_sec * 1000);
403
404                         top = &to;
405                 } else
406                         top = NULL;
407
408                 if(VT_ChildDied)
409                         goto leave_VT_Process;
410
411                 n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top);
412
413                 if(VT_ChildDied)
414                         goto leave_VT_Process;
415         
416                 if(n == 0) {
417                         int i;
418                         time_t t;
419                         BOOL allidle = True;
420                         extern int keepalive;
421         
422                         counter += SMBD_SELECT_LOOP;
423
424                         t = time(NULL);
425         
426                         if (keepalive && (counter-last_keepalive)>keepalive) {
427                                 if (!send_keepalive(Client))
428                                         goto leave_VT_Process;
429                                 last_keepalive = counter;
430                         }
431                 } else if(n > 0) {
432                         counter = 0;
433
434                         if(FD_ISSET(VT_Fd, &si)) {
435                                 /* got input from vt */
436                                 nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit()));
437
438                                 if(nread > 0)
439                                         send_smb(Client,OutBuffer);
440                         }
441
442                         if(FD_ISSET(Client, &si)) {
443                                 /* got input from socket */
444
445                                 if(receive_smb(Client,InBuffer, 0)) {
446                                         msg_type = CVAL(InBuffer,0);
447                                         msg_flags = CVAL(InBuffer,1);
448         
449                                         len = smb_len(InBuffer);
450         
451                                         DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
452         
453                                         nread = len + 4;
454          
455                                         DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
456         
457                                         if(msg_type == 0)
458                                                 VT_Output(InBuffer);
459                                         else {
460                                                 nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit()));
461         
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);
469                                                 }
470                                         }
471                                 } else
472                                         if(errno == EBADF)
473                                                 goto leave_VT_Process;
474                         }
475                 }
476
477                 trans_num++;
478         }
479
480         leave_VT_Process:
481 /*
482                 if(VT_ChildPID > 0)
483                         kill(VT_ChildPID, SIGHUP);
484
485                 VT_Stop_utmp(VT_Line);
486                 return;
487 */
488                 close_sockets();
489                 exit(0);
490 }