Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/appl/telnet/telnetd/sys_term.c
34907 views
1
/*
2
* Copyright (c) 1989, 1993
3
* The Regents of the University of California. All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. All advertising materials mentioning features or use of this software
14
* must display the following acknowledgement:
15
* This product includes software developed by the University of
16
* California, Berkeley and its contributors.
17
* 4. Neither the name of the University nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "telnetd.h"
35
36
RCSID("$Id$");
37
38
#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
39
# define PARENT_DOES_UTMP
40
#endif
41
42
#ifdef HAVE_UTMP_H
43
#include <utmp.h>
44
#endif
45
46
#ifdef HAVE_UTMPX_H
47
#include <utmpx.h>
48
#endif
49
50
#ifdef HAVE_UTMPX_H
51
struct utmpx wtmp;
52
#elif defined(HAVE_UTMP_H)
53
struct utmp wtmp;
54
#endif /* HAVE_UTMPX_H */
55
56
#ifdef HAVE_STRUCT_UTMP_UT_HOST
57
int utmp_len = sizeof(wtmp.ut_host);
58
#else
59
int utmp_len = MaxHostNameLen;
60
#endif
61
62
#ifndef UTMP_FILE
63
#ifdef _PATH_UTMP
64
#define UTMP_FILE _PATH_UTMP
65
#else
66
#define UTMP_FILE "/etc/utmp"
67
#endif
68
#endif
69
70
/* really, mac os uses wtmpx (or asl) */
71
#ifdef __APPLE__
72
#undef _PATH_WTMP
73
#endif
74
75
#if !defined(WTMP_FILE) && defined(_PATH_WTMP)
76
#define WTMP_FILE _PATH_WTMP
77
#endif
78
79
#ifndef PARENT_DOES_UTMP
80
#ifdef WTMP_FILE
81
char wtmpf[] = WTMP_FILE;
82
#else
83
char wtmpf[] = "/usr/adm/wtmp";
84
#endif
85
char utmpf[] = UTMP_FILE;
86
#else /* PARENT_DOES_UTMP */
87
#ifdef WTMP_FILE
88
char wtmpf[] = WTMP_FILE;
89
#else
90
char wtmpf[] = "/etc/wtmp";
91
#endif
92
#endif /* PARENT_DOES_UTMP */
93
94
#ifdef HAVE_TMPDIR_H
95
#include <tmpdir.h>
96
#endif /* CRAY */
97
98
#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
99
#include <sys/tty.h>
100
#endif
101
#ifdef t_erase
102
#undef t_erase
103
#undef t_kill
104
#undef t_intrc
105
#undef t_quitc
106
#undef t_startc
107
#undef t_stopc
108
#undef t_eofc
109
#undef t_brkc
110
#undef t_suspc
111
#undef t_dsuspc
112
#undef t_rprntc
113
#undef t_flushc
114
#undef t_werasc
115
#undef t_lnextc
116
#endif
117
118
#ifdef HAVE_TERMIOS_H
119
#include <termios.h>
120
#else
121
#ifdef HAVE_TERMIO_H
122
#include <termio.h>
123
#endif
124
#endif
125
126
#ifdef HAVE_UTIL_H
127
#include <util.h>
128
#endif
129
#ifdef HAVE_LIBUTIL_H
130
#include <libutil.h>
131
#endif
132
133
# ifndef TCSANOW
134
# ifdef TCSETS
135
# define TCSANOW TCSETS
136
# define TCSADRAIN TCSETSW
137
# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
138
# else
139
# ifdef TCSETA
140
# define TCSANOW TCSETA
141
# define TCSADRAIN TCSETAW
142
# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
143
# else
144
# define TCSANOW TIOCSETA
145
# define TCSADRAIN TIOCSETAW
146
# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
147
# endif
148
# endif
149
# define tcsetattr(f, a, t) ioctl(f, a, t)
150
# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
151
(tp)->c_cflag |= (val)
152
# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
153
# ifdef CIBAUD
154
# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
155
(tp)->c_cflag |= ((val)<<IBSHIFT)
156
# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
157
# else
158
# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
159
(tp)->c_cflag |= (val)
160
# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
161
# endif
162
# endif /* TCSANOW */
163
struct termios termbuf, termbuf2; /* pty control structure */
164
# ifdef STREAMSPTY
165
static int ttyfd = -1;
166
int really_stream = 0;
167
# else
168
#define really_stream 0
169
# endif
170
171
const char *new_login = _PATH_LOGIN;
172
173
/*
174
* init_termbuf()
175
* copy_termbuf(cp)
176
* set_termbuf()
177
*
178
* These three routines are used to get and set the "termbuf" structure
179
* to and from the kernel. init_termbuf() gets the current settings.
180
* copy_termbuf() hands in a new "termbuf" to write to the kernel, and
181
* set_termbuf() writes the structure into the kernel.
182
*/
183
184
void
185
init_termbuf(void)
186
{
187
# ifdef STREAMSPTY
188
if (really_stream)
189
tcgetattr(ttyfd, &termbuf);
190
else
191
# endif
192
tcgetattr(ourpty, &termbuf);
193
termbuf2 = termbuf;
194
}
195
196
void
197
set_termbuf(void)
198
{
199
/*
200
* Only make the necessary changes.
201
*/
202
if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
203
# ifdef STREAMSPTY
204
if (really_stream)
205
tcsetattr(ttyfd, TCSANOW, &termbuf);
206
else
207
# endif
208
tcsetattr(ourpty, TCSANOW, &termbuf);
209
}
210
}
211
212
213
/*
214
* spcset(func, valp, valpp)
215
*
216
* This function takes various special characters (func), and
217
* sets *valp to the current value of that character, and
218
* *valpp to point to where in the "termbuf" structure that
219
* value is kept.
220
*
221
* It returns the SLC_ level of support for this function.
222
*/
223
224
225
int
226
spcset(int func, cc_t *valp, cc_t **valpp)
227
{
228
229
#define setval(a, b) *valp = termbuf.c_cc[a]; \
230
*valpp = &termbuf.c_cc[a]; \
231
return(b);
232
#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
233
234
switch(func) {
235
case SLC_EOF:
236
setval(VEOF, SLC_VARIABLE);
237
case SLC_EC:
238
setval(VERASE, SLC_VARIABLE);
239
case SLC_EL:
240
setval(VKILL, SLC_VARIABLE);
241
case SLC_IP:
242
setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
243
case SLC_ABORT:
244
setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
245
case SLC_XON:
246
#ifdef VSTART
247
setval(VSTART, SLC_VARIABLE);
248
#else
249
defval(0x13);
250
#endif
251
case SLC_XOFF:
252
#ifdef VSTOP
253
setval(VSTOP, SLC_VARIABLE);
254
#else
255
defval(0x11);
256
#endif
257
case SLC_EW:
258
#ifdef VWERASE
259
setval(VWERASE, SLC_VARIABLE);
260
#else
261
defval(0);
262
#endif
263
case SLC_RP:
264
#ifdef VREPRINT
265
setval(VREPRINT, SLC_VARIABLE);
266
#else
267
defval(0);
268
#endif
269
case SLC_LNEXT:
270
#ifdef VLNEXT
271
setval(VLNEXT, SLC_VARIABLE);
272
#else
273
defval(0);
274
#endif
275
case SLC_AO:
276
#if !defined(VDISCARD) && defined(VFLUSHO)
277
# define VDISCARD VFLUSHO
278
#endif
279
#ifdef VDISCARD
280
setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
281
#else
282
defval(0);
283
#endif
284
case SLC_SUSP:
285
#ifdef VSUSP
286
setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
287
#else
288
defval(0);
289
#endif
290
#ifdef VEOL
291
case SLC_FORW1:
292
setval(VEOL, SLC_VARIABLE);
293
#endif
294
#ifdef VEOL2
295
case SLC_FORW2:
296
setval(VEOL2, SLC_VARIABLE);
297
#endif
298
case SLC_AYT:
299
#ifdef VSTATUS
300
setval(VSTATUS, SLC_VARIABLE);
301
#else
302
defval(0);
303
#endif
304
305
case SLC_BRK:
306
case SLC_SYNCH:
307
case SLC_EOR:
308
defval(0);
309
310
default:
311
*valp = 0;
312
*valpp = 0;
313
return(SLC_NOSUPPORT);
314
}
315
}
316
317
#ifdef _CRAY
318
/*
319
* getnpty()
320
*
321
* Return the number of pty's configured into the system.
322
*/
323
int
324
getnpty()
325
{
326
#ifdef _SC_CRAY_NPTY
327
int numptys;
328
329
if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
330
return numptys;
331
else
332
#endif /* _SC_CRAY_NPTY */
333
return 128;
334
}
335
#endif /* CRAY */
336
337
/*
338
* getpty()
339
*
340
* Allocate a pty. As a side effect, the external character
341
* array "line" contains the name of the slave side.
342
*
343
* Returns the file descriptor of the opened pty.
344
*/
345
346
static int ptyslavefd = -1;
347
348
static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
349
char *line = Xline;
350
351
#ifdef _CRAY
352
char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
353
#endif /* CRAY */
354
355
#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
356
static char *ptsname(int fd)
357
{
358
#ifdef HAVE_TTYNAME
359
return ttyname(fd);
360
#else
361
return NULL;
362
#endif
363
}
364
#endif
365
366
int getpty(int *ptynum)
367
{
368
#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
369
{
370
int master;
371
int slave;
372
if(openpty(&master, &slave, line, 0, 0) == 0){
373
ptyslavefd = slave;
374
return master;
375
}
376
}
377
#endif /* HAVE_OPENPTY .... */
378
#ifdef HAVE__GETPTY
379
{
380
int master;
381
char *p;
382
p = _getpty(&master, O_RDWR, 0600, 1);
383
if(p == NULL)
384
return -1;
385
strlcpy(line, p, sizeof(Xline));
386
return master;
387
}
388
#endif
389
390
#ifdef STREAMSPTY
391
{
392
char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
393
"/dev/ptym/clone", 0 };
394
395
char **q;
396
int p;
397
for(q=clone; *q; q++){
398
p=open(*q, O_RDWR);
399
if(p >= 0){
400
#ifdef HAVE_GRANTPT
401
grantpt(p);
402
#endif
403
#ifdef HAVE_UNLOCKPT
404
unlockpt(p);
405
#endif
406
strlcpy(line, ptsname(p), sizeof(Xline));
407
really_stream = 1;
408
return p;
409
}
410
}
411
}
412
#endif /* STREAMSPTY */
413
#ifndef _CRAY
414
{
415
int p;
416
char *cp, *p1, *p2;
417
int i;
418
419
#ifndef __hpux
420
snprintf(line, sizeof(Xline), "/dev/ptyXX");
421
p1 = &line[8];
422
p2 = &line[9];
423
#else
424
snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
425
p1 = &line[13];
426
p2 = &line[14];
427
#endif
428
429
430
for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
431
struct stat stb;
432
433
*p1 = *cp;
434
*p2 = '0';
435
/*
436
* This stat() check is just to keep us from
437
* looping through all 256 combinations if there
438
* aren't that many ptys available.
439
*/
440
if (stat(line, &stb) < 0)
441
break;
442
for (i = 0; i < 16; i++) {
443
*p2 = "0123456789abcdef"[i];
444
p = open(line, O_RDWR);
445
if (p > 0) {
446
#if SunOS == 40
447
int dummy;
448
#endif
449
450
#ifndef __hpux
451
line[5] = 't';
452
#else
453
for (p1 = &line[8]; *p1; p1++)
454
*p1 = *(p1+1);
455
line[9] = 't';
456
#endif
457
chown(line, 0, 0);
458
chmod(line, 0600);
459
#if SunOS == 40
460
if (ioctl(p, TIOCGPGRP, &dummy) == 0
461
|| errno != EIO) {
462
chmod(line, 0666);
463
close(p);
464
line[5] = 'p';
465
} else
466
#endif /* SunOS == 40 */
467
return(p);
468
}
469
}
470
}
471
}
472
#else /* CRAY */
473
{
474
extern lowpty, highpty;
475
struct stat sb;
476
int p;
477
478
for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
479
snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
480
p = open(myline, 2);
481
if (p < 0)
482
continue;
483
snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
484
/*
485
* Here are some shenanigans to make sure that there
486
* are no listeners lurking on the line.
487
*/
488
if(stat(line, &sb) < 0) {
489
close(p);
490
continue;
491
}
492
if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
493
chown(line, 0, 0);
494
chmod(line, 0600);
495
close(p);
496
p = open(myline, 2);
497
if (p < 0)
498
continue;
499
}
500
/*
501
* Now it should be safe...check for accessability.
502
*/
503
if (access(line, 6) == 0)
504
return(p);
505
else {
506
/* no tty side to pty so skip it */
507
close(p);
508
}
509
}
510
}
511
#endif /* CRAY */
512
return(-1);
513
}
514
515
516
int
517
tty_isecho(void)
518
{
519
return (termbuf.c_lflag & ECHO);
520
}
521
522
int
523
tty_flowmode(void)
524
{
525
return((termbuf.c_iflag & IXON) ? 1 : 0);
526
}
527
528
int
529
tty_restartany(void)
530
{
531
return((termbuf.c_iflag & IXANY) ? 1 : 0);
532
}
533
534
void
535
tty_setecho(int on)
536
{
537
if (on)
538
termbuf.c_lflag |= ECHO;
539
else
540
termbuf.c_lflag &= ~ECHO;
541
}
542
543
int
544
tty_israw(void)
545
{
546
return(!(termbuf.c_lflag & ICANON));
547
}
548
549
void
550
tty_binaryin(int on)
551
{
552
if (on) {
553
termbuf.c_iflag &= ~ISTRIP;
554
} else {
555
termbuf.c_iflag |= ISTRIP;
556
}
557
}
558
559
void
560
tty_binaryout(int on)
561
{
562
if (on) {
563
termbuf.c_cflag &= ~(CSIZE|PARENB);
564
termbuf.c_cflag |= CS8;
565
termbuf.c_oflag &= ~OPOST;
566
} else {
567
termbuf.c_cflag &= ~CSIZE;
568
termbuf.c_cflag |= CS7|PARENB;
569
termbuf.c_oflag |= OPOST;
570
}
571
}
572
573
int
574
tty_isbinaryin(void)
575
{
576
return(!(termbuf.c_iflag & ISTRIP));
577
}
578
579
int
580
tty_isbinaryout(void)
581
{
582
return(!(termbuf.c_oflag&OPOST));
583
}
584
585
586
int
587
tty_issofttab(void)
588
{
589
# ifdef OXTABS
590
return (termbuf.c_oflag & OXTABS);
591
# endif
592
# ifdef TABDLY
593
return ((termbuf.c_oflag & TABDLY) == TAB3);
594
# endif
595
}
596
597
void
598
tty_setsofttab(int on)
599
{
600
if (on) {
601
# ifdef OXTABS
602
termbuf.c_oflag |= OXTABS;
603
# endif
604
# ifdef TABDLY
605
termbuf.c_oflag &= ~TABDLY;
606
termbuf.c_oflag |= TAB3;
607
# endif
608
} else {
609
# ifdef OXTABS
610
termbuf.c_oflag &= ~OXTABS;
611
# endif
612
# ifdef TABDLY
613
termbuf.c_oflag &= ~TABDLY;
614
termbuf.c_oflag |= TAB0;
615
# endif
616
}
617
}
618
619
int
620
tty_islitecho(void)
621
{
622
# ifdef ECHOCTL
623
return (!(termbuf.c_lflag & ECHOCTL));
624
# endif
625
# ifdef TCTLECH
626
return (!(termbuf.c_lflag & TCTLECH));
627
# endif
628
# if !defined(ECHOCTL) && !defined(TCTLECH)
629
return (0); /* assumes ctl chars are echoed '^x' */
630
# endif
631
}
632
633
void
634
tty_setlitecho(int on)
635
{
636
# ifdef ECHOCTL
637
if (on)
638
termbuf.c_lflag &= ~ECHOCTL;
639
else
640
termbuf.c_lflag |= ECHOCTL;
641
# endif
642
# ifdef TCTLECH
643
if (on)
644
termbuf.c_lflag &= ~TCTLECH;
645
else
646
termbuf.c_lflag |= TCTLECH;
647
# endif
648
}
649
650
int
651
tty_iscrnl(void)
652
{
653
return (termbuf.c_iflag & ICRNL);
654
}
655
656
/*
657
* Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
658
*/
659
#if B4800 != 4800
660
#define DECODE_BAUD
661
#endif
662
663
#ifdef DECODE_BAUD
664
665
/*
666
* A table of available terminal speeds
667
*/
668
struct termspeeds {
669
int speed;
670
int value;
671
} termspeeds[] = {
672
{ 0, B0 }, { 50, B50 }, { 75, B75 },
673
{ 110, B110 }, { 134, B134 }, { 150, B150 },
674
{ 200, B200 }, { 300, B300 }, { 600, B600 },
675
{ 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
676
{ 4800, B4800 },
677
#ifdef B7200
678
{ 7200, B7200 },
679
#endif
680
{ 9600, B9600 },
681
#ifdef B14400
682
{ 14400, B14400 },
683
#endif
684
#ifdef B19200
685
{ 19200, B19200 },
686
#endif
687
#ifdef B28800
688
{ 28800, B28800 },
689
#endif
690
#ifdef B38400
691
{ 38400, B38400 },
692
#endif
693
#ifdef B57600
694
{ 57600, B57600 },
695
#endif
696
#ifdef B115200
697
{ 115200, B115200 },
698
#endif
699
#ifdef B230400
700
{ 230400, B230400 },
701
#endif
702
{ -1, 0 }
703
};
704
#endif /* DECODE_BUAD */
705
706
void
707
tty_tspeed(int val)
708
{
709
#ifdef DECODE_BAUD
710
struct termspeeds *tp;
711
712
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
713
;
714
if (tp->speed == -1) /* back up to last valid value */
715
--tp;
716
cfsetospeed(&termbuf, tp->value);
717
#else /* DECODE_BUAD */
718
cfsetospeed(&termbuf, val);
719
#endif /* DECODE_BUAD */
720
}
721
722
void
723
tty_rspeed(int val)
724
{
725
#ifdef DECODE_BAUD
726
struct termspeeds *tp;
727
728
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
729
;
730
if (tp->speed == -1) /* back up to last valid value */
731
--tp;
732
cfsetispeed(&termbuf, tp->value);
733
#else /* DECODE_BAUD */
734
cfsetispeed(&termbuf, val);
735
#endif /* DECODE_BAUD */
736
}
737
738
#ifdef PARENT_DOES_UTMP
739
extern struct utmp wtmp;
740
extern char wtmpf[];
741
742
extern void utmp_sig_init (void);
743
extern void utmp_sig_reset (void);
744
extern void utmp_sig_wait (void);
745
extern void utmp_sig_notify (int);
746
# endif /* PARENT_DOES_UTMP */
747
748
#ifdef STREAMSPTY
749
750
/* I_FIND seems to live a life of its own */
751
static int my_find(int fd, char *module)
752
{
753
#if defined(I_FIND) && defined(I_LIST)
754
static int flag;
755
static struct str_list sl;
756
int n;
757
int i;
758
759
if(!flag){
760
n = ioctl(fd, I_LIST, 0);
761
if(n < 0){
762
perror("ioctl(fd, I_LIST, 0)");
763
return -1;
764
}
765
sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
766
sl.sl_nmods = n;
767
n = ioctl(fd, I_LIST, &sl);
768
if(n < 0){
769
perror("ioctl(fd, I_LIST, n)");
770
return -1;
771
}
772
flag = 1;
773
}
774
775
for(i=0; i<sl.sl_nmods; i++)
776
if(!strcmp(sl.sl_modlist[i].l_name, module))
777
return 1;
778
#endif
779
return 0;
780
}
781
782
static void maybe_push_modules(int fd, char **modules)
783
{
784
char **p;
785
int err;
786
787
for(p=modules; *p; p++){
788
err = my_find(fd, *p);
789
if(err == 1)
790
break;
791
if(err < 0 && errno != EINVAL)
792
fatalperror(net, "my_find()");
793
/* module not pushed or does not exist */
794
}
795
/* p points to null or to an already pushed module, now push all
796
modules before this one */
797
798
for(p--; p >= modules; p--){
799
err = ioctl(fd, I_PUSH, *p);
800
if(err < 0 && errno != EINVAL)
801
fatalperror(net, "I_PUSH");
802
}
803
}
804
#endif
805
806
/*
807
* getptyslave()
808
*
809
* Open the slave side of the pty, and do any initialization
810
* that is necessary. The return value is a file descriptor
811
* for the slave side.
812
*/
813
void getptyslave(void)
814
{
815
int t = -1;
816
817
struct winsize ws;
818
/*
819
* Opening the slave side may cause initilization of the
820
* kernel tty structure. We need remember the state of
821
* if linemode was turned on
822
* terminal window size
823
* terminal speed
824
* so that we can re-set them if we need to.
825
*/
826
827
828
/*
829
* Make sure that we don't have a controlling tty, and
830
* that we are the session (process group) leader.
831
*/
832
833
#ifdef HAVE_SETSID
834
if(setsid()<0)
835
fatalperror(net, "setsid()");
836
#else
837
# ifdef TIOCNOTTY
838
t = open(_PATH_TTY, O_RDWR);
839
if (t >= 0) {
840
ioctl(t, TIOCNOTTY, (char *)0);
841
close(t);
842
}
843
# endif
844
#endif
845
846
# ifdef PARENT_DOES_UTMP
847
/*
848
* Wait for our parent to get the utmp stuff to get done.
849
*/
850
utmp_sig_wait();
851
# endif
852
853
t = cleanopen(line);
854
if (t < 0)
855
fatalperror(net, line);
856
857
#ifdef STREAMSPTY
858
ttyfd = t;
859
860
861
/*
862
* Not all systems have (or need) modules ttcompat and pckt so
863
* don't flag it as a fatal error if they don't exist.
864
*/
865
866
if (really_stream)
867
{
868
/* these are the streams modules that we want pushed. note
869
that they are in reverse order, ptem will be pushed
870
first. maybe_push_modules() will try to push all modules
871
before the first one that isn't already pushed. i.e if
872
ldterm is pushed, only ttcompat will be attempted.
873
874
all this is because we don't know which modules are
875
available, and we don't know which modules are already
876
pushed (via autopush, for instance).
877
878
*/
879
880
char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
881
char *ptymodules[] = { "pckt", NULL };
882
883
maybe_push_modules(t, ttymodules);
884
maybe_push_modules(ourpty, ptymodules);
885
}
886
#endif
887
/*
888
* set up the tty modes as we like them to be.
889
*/
890
init_termbuf();
891
# ifdef TIOCSWINSZ
892
if (def_row || def_col) {
893
memset(&ws, 0, sizeof(ws));
894
ws.ws_col = def_col;
895
ws.ws_row = def_row;
896
ioctl(t, TIOCSWINSZ, (char *)&ws);
897
}
898
# endif
899
900
/*
901
* Settings for sgtty based systems
902
*/
903
904
/*
905
* Settings for UNICOS (and HPUX)
906
*/
907
# if defined(_CRAY) || defined(__hpux)
908
termbuf.c_oflag = OPOST|ONLCR|TAB3;
909
termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
910
termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
911
termbuf.c_cflag = EXTB|HUPCL|CS8;
912
# endif
913
914
/*
915
* Settings for all other termios/termio based
916
* systems, other than 4.4BSD. In 4.4BSD the
917
* kernel does the initial terminal setup.
918
*/
919
# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
920
# ifndef OXTABS
921
# define OXTABS 0
922
# endif
923
termbuf.c_lflag |= ECHO;
924
termbuf.c_oflag |= ONLCR|OXTABS;
925
termbuf.c_iflag |= ICRNL;
926
termbuf.c_iflag &= ~IXOFF;
927
# endif
928
tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
929
tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
930
931
/*
932
* Set the tty modes, and make this our controlling tty.
933
*/
934
set_termbuf();
935
if (login_tty(t) == -1)
936
fatalperror(net, "login_tty");
937
if (net > 2)
938
close(net);
939
if (ourpty > 2) {
940
close(ourpty);
941
ourpty = -1;
942
}
943
}
944
945
#ifndef O_NOCTTY
946
#define O_NOCTTY 0
947
#endif
948
/*
949
* Open the specified slave side of the pty,
950
* making sure that we have a clean tty.
951
*/
952
953
int cleanopen(char *line)
954
{
955
int t;
956
957
if (ptyslavefd != -1)
958
return ptyslavefd;
959
960
#ifdef STREAMSPTY
961
if (!really_stream)
962
#endif
963
{
964
/*
965
* Make sure that other people can't open the
966
* slave side of the connection.
967
*/
968
chown(line, 0, 0);
969
chmod(line, 0600);
970
}
971
972
#ifdef HAVE_REVOKE
973
revoke(line);
974
#endif
975
976
t = open(line, O_RDWR|O_NOCTTY);
977
978
if (t < 0)
979
return(-1);
980
981
/*
982
* Hangup anybody else using this ttyp, then reopen it for
983
* ourselves.
984
*/
985
# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
986
signal(SIGHUP, SIG_IGN);
987
#ifdef HAVE_VHANGUP
988
vhangup();
989
#else
990
#endif
991
signal(SIGHUP, SIG_DFL);
992
t = open(line, O_RDWR|O_NOCTTY);
993
if (t < 0)
994
return(-1);
995
# endif
996
# if defined(_CRAY) && defined(TCVHUP)
997
{
998
int i;
999
signal(SIGHUP, SIG_IGN);
1000
ioctl(t, TCVHUP, (char *)0);
1001
signal(SIGHUP, SIG_DFL);
1002
1003
i = open(line, O_RDWR);
1004
1005
if (i < 0)
1006
return(-1);
1007
close(t);
1008
t = i;
1009
}
1010
# endif /* defined(CRAY) && defined(TCVHUP) */
1011
return(t);
1012
}
1013
1014
#if !defined(BSD4_4)
1015
1016
int login_tty(int t)
1017
{
1018
/* Dont need to set this as the controlling PTY on steams sockets,
1019
* don't abort on failure. */
1020
# if defined(TIOCSCTTY) && !defined(__hpux)
1021
if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream)
1022
fatalperror(net, "ioctl(sctty)");
1023
# ifdef _CRAY
1024
/*
1025
* Close the hard fd to /dev/ttypXXX, and re-open through
1026
* the indirect /dev/tty interface.
1027
*/
1028
close(t);
1029
if ((t = open("/dev/tty", O_RDWR)) < 0)
1030
fatalperror(net, "open(/dev/tty)");
1031
# endif
1032
# else
1033
/*
1034
* We get our controlling tty assigned as a side-effect
1035
* of opening up a tty device. But on BSD based systems,
1036
* this only happens if our process group is zero. The
1037
* setsid() call above may have set our pgrp, so clear
1038
* it out before opening the tty...
1039
*/
1040
#ifdef HAVE_SETPGID
1041
setpgid(0, 0);
1042
#else
1043
setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1044
probably takes arguments */
1045
#endif
1046
close(open(line, O_RDWR));
1047
# endif
1048
if (t != 0)
1049
dup2(t, 0);
1050
if (t != 1)
1051
dup2(t, 1);
1052
if (t != 2)
1053
dup2(t, 2);
1054
if (t > 2)
1055
close(t);
1056
return(0);
1057
}
1058
#endif /* BSD <= 43 */
1059
1060
/*
1061
* This comes from ../../bsd/tty.c and should not really be here.
1062
*/
1063
1064
/*
1065
* Clean the tty name. Return a pointer to the cleaned version.
1066
*/
1067
1068
static char * clean_ttyname (char *) __attribute__((unused));
1069
1070
static char *
1071
clean_ttyname (char *tty)
1072
{
1073
char *res = tty;
1074
1075
if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1076
res += strlen(_PATH_DEV);
1077
if (strncmp (res, "pty/", 4) == 0)
1078
res += 4;
1079
if (strncmp (res, "ptym/", 5) == 0)
1080
res += 5;
1081
return res;
1082
}
1083
1084
/*
1085
* Generate a name usable as an `ut_id', typically without `tty'.
1086
*/
1087
1088
#ifdef HAVE_STRUCT_UTMP_UT_ID
1089
static char *
1090
make_id (char *tty)
1091
{
1092
char *res = tty;
1093
1094
if (strncmp (res, "pts/", 4) == 0)
1095
res += 4;
1096
if (strncmp (res, "tty", 3) == 0)
1097
res += 3;
1098
return res;
1099
}
1100
#endif
1101
1102
/*
1103
* startslave(host)
1104
*
1105
* Given a hostname, do whatever
1106
* is necessary to startup the login process on the slave side of the pty.
1107
*/
1108
1109
/* ARGSUSED */
1110
void
1111
startslave(const char *host, const char *utmp_host,
1112
int autologin, char *autoname)
1113
{
1114
int i;
1115
1116
#ifdef AUTHENTICATION
1117
if (!autoname || !autoname[0])
1118
autologin = 0;
1119
1120
if (autologin < auth_level) {
1121
fatal(net, "Authorization failed");
1122
exit(1);
1123
}
1124
#endif
1125
1126
{
1127
char *tbuf =
1128
"\r\n*** Connection not encrypted! "
1129
"Communication may be eavesdropped. ***\r\n";
1130
#ifdef ENCRYPTION
1131
if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1132
#endif
1133
writenet(tbuf, strlen(tbuf));
1134
}
1135
# ifdef PARENT_DOES_UTMP
1136
utmp_sig_init();
1137
# endif /* PARENT_DOES_UTMP */
1138
1139
if ((i = fork()) < 0)
1140
fatalperror(net, "fork");
1141
if (i) {
1142
# ifdef PARENT_DOES_UTMP
1143
/*
1144
* Cray parent will create utmp entry for child and send
1145
* signal to child to tell when done. Child waits for signal
1146
* before doing anything important.
1147
*/
1148
int pid = i;
1149
void sigjob (int);
1150
1151
setpgrp();
1152
utmp_sig_reset(); /* reset handler to default */
1153
/*
1154
* Create utmp entry for child
1155
*/
1156
wtmp.ut_time = time(NULL);
1157
wtmp.ut_type = LOGIN_PROCESS;
1158
wtmp.ut_pid = pid;
1159
strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user));
1160
strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host));
1161
strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line));
1162
#ifdef HAVE_STRUCT_UTMP_UT_ID
1163
strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1164
#endif
1165
1166
pututline(&wtmp);
1167
endutent();
1168
if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1169
write(i, &wtmp, sizeof(struct utmp));
1170
close(i);
1171
}
1172
#ifdef _CRAY
1173
signal(WJSIGNAL, sigjob);
1174
#endif
1175
utmp_sig_notify(pid);
1176
# endif /* PARENT_DOES_UTMP */
1177
} else {
1178
getptyslave();
1179
#if defined(DCE)
1180
/* if we authenticated via K5, try and join the PAG */
1181
kerberos5_dfspag();
1182
#endif
1183
start_login(host, autologin, autoname);
1184
/*NOTREACHED*/
1185
}
1186
}
1187
1188
char *envinit[3];
1189
#if !HAVE_DECL_ENVIRON
1190
extern char **environ;
1191
#endif
1192
1193
void
1194
init_env(void)
1195
{
1196
char **envp;
1197
1198
envp = envinit;
1199
if ((*envp = getenv("TZ")))
1200
*envp++ -= 3;
1201
#if defined(_CRAY) || defined(__hpux)
1202
else
1203
*envp++ = "TZ=GMT0";
1204
#endif
1205
*envp = 0;
1206
environ = envinit;
1207
}
1208
1209
/*
1210
* scrub_env()
1211
*
1212
* We only accept the environment variables listed below.
1213
*/
1214
1215
static void
1216
scrub_env(void)
1217
{
1218
static const char *reject[] = {
1219
"TERMCAP=/",
1220
NULL
1221
};
1222
1223
static const char *accept[] = {
1224
"XAUTH=", "XAUTHORITY=", "DISPLAY=",
1225
"TERM=",
1226
"EDITOR=",
1227
"PAGER=",
1228
"PRINTER=",
1229
"LOGNAME=",
1230
"POSIXLY_CORRECT=",
1231
"TERMCAP=",
1232
NULL
1233
};
1234
1235
char **cpp, **cpp2;
1236
const char **p;
1237
1238
for (cpp2 = cpp = environ; *cpp; cpp++) {
1239
int reject_it = 0;
1240
1241
for(p = reject; *p; p++)
1242
if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1243
reject_it = 1;
1244
break;
1245
}
1246
if (reject_it)
1247
continue;
1248
1249
for(p = accept; *p; p++)
1250
if(strncmp(*cpp, *p, strlen(*p)) == 0)
1251
break;
1252
if(*p != NULL)
1253
*cpp2++ = *cpp;
1254
}
1255
*cpp2 = NULL;
1256
}
1257
1258
1259
struct arg_val {
1260
int size;
1261
int argc;
1262
char **argv;
1263
};
1264
1265
static void addarg(struct arg_val*, const char*);
1266
1267
/*
1268
* start_login(host)
1269
*
1270
* Assuming that we are now running as a child processes, this
1271
* function will turn us into the login process.
1272
*/
1273
1274
void
1275
start_login(const char *host, int autologin, char *name)
1276
{
1277
struct arg_val argv;
1278
char *user;
1279
int save_errno;
1280
1281
#ifdef ENCRYPTION
1282
encrypt_output = NULL;
1283
decrypt_input = NULL;
1284
#endif
1285
1286
#ifdef HAVE_UTMPX_H
1287
{
1288
int pid = getpid();
1289
struct utmpx utmpx;
1290
struct timeval tv;
1291
char *clean_tty;
1292
1293
/*
1294
* Create utmp entry for child
1295
*/
1296
1297
clean_tty = clean_ttyname(line);
1298
memset(&utmpx, 0, sizeof(utmpx));
1299
strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));
1300
strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1301
#ifdef HAVE_STRUCT_UTMP_UT_ID
1302
strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1303
#endif
1304
utmpx.ut_pid = pid;
1305
1306
utmpx.ut_type = LOGIN_PROCESS;
1307
1308
gettimeofday (&tv, NULL);
1309
utmpx.ut_tv.tv_sec = tv.tv_sec;
1310
utmpx.ut_tv.tv_usec = tv.tv_usec;
1311
1312
if (pututxline(&utmpx) == NULL)
1313
fatal(net, "pututxline failed");
1314
}
1315
#endif
1316
1317
scrub_env();
1318
1319
/*
1320
* -h : pass on name of host.
1321
* WARNING: -h is accepted by login if and only if
1322
* getuid() == 0.
1323
* -p : don't clobber the environment (so terminal type stays set).
1324
*
1325
* -f : force this login, he has already been authenticated
1326
*/
1327
1328
/* init argv structure */
1329
argv.size=0;
1330
argv.argc=0;
1331
argv.argv=malloc(0); /*so we can call realloc later */
1332
addarg(&argv, "login");
1333
addarg(&argv, "-h");
1334
addarg(&argv, host);
1335
addarg(&argv, "-p");
1336
if(name && name[0])
1337
user = name;
1338
else
1339
user = getenv("USER");
1340
#ifdef AUTHENTICATION
1341
if (auth_level < 0 || autologin != AUTH_VALID) {
1342
if(!no_warn) {
1343
printf("User not authenticated. ");
1344
if (require_otp)
1345
printf("Using one-time password\r\n");
1346
else
1347
printf("Using plaintext username and password\r\n");
1348
}
1349
if (require_otp) {
1350
addarg(&argv, "-a");
1351
addarg(&argv, "otp");
1352
}
1353
if(log_unauth)
1354
syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1355
host, user ? user : "unknown user");
1356
}
1357
if (auth_level >= 0 && autologin == AUTH_VALID)
1358
addarg(&argv, "-f");
1359
#endif
1360
if(user){
1361
addarg(&argv, "--");
1362
addarg(&argv, strdup(user));
1363
}
1364
if (getenv("USER")) {
1365
/*
1366
* Assume that login will set the USER variable
1367
* correctly. For SysV systems, this means that
1368
* USER will no longer be set, just LOGNAME by
1369
* login. (The problem is that if the auto-login
1370
* fails, and the user then specifies a different
1371
* account name, he can get logged in with both
1372
* LOGNAME and USER in his environment, but the
1373
* USER value will be wrong.
1374
*/
1375
unsetenv("USER");
1376
}
1377
closelog();
1378
/*
1379
* This sleep(1) is in here so that telnetd can
1380
* finish up with the tty. There's a race condition
1381
* the login banner message gets lost...
1382
*/
1383
sleep(1);
1384
1385
execv(new_login, argv.argv);
1386
save_errno = errno;
1387
syslog(LOG_ERR, "%s: %m", new_login);
1388
fatalperror_errno(net, new_login, save_errno);
1389
/*NOTREACHED*/
1390
}
1391
1392
static void
1393
addarg(struct arg_val *argv, const char *val)
1394
{
1395
if(argv->size <= argv->argc+1) {
1396
argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1397
if (argv->argv == NULL)
1398
fatal (net, "realloc: out of memory");
1399
argv->size+=10;
1400
}
1401
if((argv->argv[argv->argc++] = strdup(val)) == NULL)
1402
fatal (net, "strdup: out of memory");
1403
argv->argv[argv->argc] = NULL;
1404
}
1405
1406
1407
/*
1408
* rmut()
1409
*
1410
* This is the function called by cleanup() to
1411
* remove the utmp entry for this person.
1412
*/
1413
1414
#ifdef HAVE_UTMPX_H
1415
static void
1416
rmut(void)
1417
{
1418
struct utmpx utmpx, *non_save_utxp;
1419
char *clean_tty = clean_ttyname(line);
1420
1421
/*
1422
* This updates the utmpx and utmp entries and make a wtmp/x entry
1423
*/
1424
1425
setutxent();
1426
memset(&utmpx, 0, sizeof(utmpx));
1427
strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1428
utmpx.ut_type = LOGIN_PROCESS;
1429
non_save_utxp = getutxline(&utmpx);
1430
if (non_save_utxp) {
1431
struct utmpx *utxp;
1432
struct timeval tv;
1433
char user0;
1434
1435
utxp = malloc(sizeof(struct utmpx));
1436
*utxp = *non_save_utxp;
1437
user0 = utxp->ut_user[0];
1438
utxp->ut_user[0] = '\0';
1439
utxp->ut_type = DEAD_PROCESS;
1440
#ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1441
#ifdef _STRUCT___EXIT_STATUS
1442
utxp->ut_exit.__e_termination = 0;
1443
utxp->ut_exit.__e_exit = 0;
1444
#elif defined(__osf__) /* XXX */
1445
utxp->ut_exit.ut_termination = 0;
1446
utxp->ut_exit.ut_exit = 0;
1447
#else
1448
utxp->ut_exit.e_termination = 0;
1449
utxp->ut_exit.e_exit = 0;
1450
#endif
1451
#endif
1452
gettimeofday (&tv, NULL);
1453
utxp->ut_tv.tv_sec = tv.tv_sec;
1454
utxp->ut_tv.tv_usec = tv.tv_usec;
1455
1456
pututxline(utxp);
1457
#ifdef WTMPX_FILE
1458
utxp->ut_user[0] = user0;
1459
updwtmpx(WTMPX_FILE, utxp);
1460
#elif defined(WTMP_FILE)
1461
/* This is a strange system with a utmpx and a wtmp! */
1462
{
1463
int f = open(wtmpf, O_WRONLY|O_APPEND);
1464
struct utmp wtmp;
1465
if (f >= 0) {
1466
strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1467
strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1468
#ifdef HAVE_STRUCT_UTMP_UT_HOST
1469
strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1470
#endif
1471
wtmp.ut_time = time(NULL);
1472
write(f, &wtmp, sizeof(wtmp));
1473
close(f);
1474
}
1475
}
1476
#endif
1477
free (utxp);
1478
}
1479
endutxent();
1480
} /* end of rmut */
1481
#endif
1482
1483
#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1484
static void
1485
rmut(void)
1486
{
1487
int f;
1488
int found = 0;
1489
struct utmp *u, *utmp;
1490
int nutmp;
1491
struct stat statbf;
1492
char *clean_tty = clean_ttyname(line);
1493
1494
f = open(utmpf, O_RDWR);
1495
if (f >= 0) {
1496
fstat(f, &statbf);
1497
utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1498
if (!utmp)
1499
syslog(LOG_ERR, "utmp malloc failed");
1500
if (statbf.st_size && utmp) {
1501
nutmp = read(f, utmp, (int)statbf.st_size);
1502
nutmp /= sizeof(struct utmp);
1503
1504
for (u = utmp ; u < &utmp[nutmp] ; u++) {
1505
if (strncmp(u->ut_line,
1506
clean_tty,
1507
sizeof(u->ut_line)) ||
1508
u->ut_name[0]==0)
1509
continue;
1510
lseek(f, ((long)u)-((long)utmp), L_SET);
1511
strncpy(u->ut_name, "", sizeof(u->ut_name));
1512
#ifdef HAVE_STRUCT_UTMP_UT_HOST
1513
strncpy(u->ut_host, "", sizeof(u->ut_host));
1514
#endif
1515
u->ut_time = time(NULL);
1516
write(f, u, sizeof(wtmp));
1517
found++;
1518
}
1519
}
1520
close(f);
1521
}
1522
if (found) {
1523
f = open(wtmpf, O_WRONLY|O_APPEND);
1524
if (f >= 0) {
1525
strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1526
strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1527
#ifdef HAVE_STRUCT_UTMP_UT_HOST
1528
strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1529
#endif
1530
wtmp.ut_time = time(NULL);
1531
write(f, &wtmp, sizeof(wtmp));
1532
close(f);
1533
}
1534
}
1535
chmod(line, 0666);
1536
chown(line, 0, 0);
1537
line[strlen("/dev/")] = 'p';
1538
chmod(line, 0666);
1539
chown(line, 0, 0);
1540
} /* end of rmut */
1541
#endif /* CRAY */
1542
1543
#if defined(__hpux) && !defined(HAVE_UTMPX_H)
1544
static void
1545
rmut (char *line)
1546
{
1547
struct utmp utmp;
1548
struct utmp *utptr;
1549
int fd; /* for /etc/wtmp */
1550
1551
utmp.ut_type = USER_PROCESS;
1552
strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1553
setutent();
1554
utptr = getutline(&utmp);
1555
/* write it out only if it exists */
1556
if (utptr) {
1557
utptr->ut_type = DEAD_PROCESS;
1558
utptr->ut_time = time(NULL);
1559
pututline(utptr);
1560
/* set wtmp entry if wtmp file exists */
1561
if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1562
write(fd, utptr, sizeof(utmp));
1563
close(fd);
1564
}
1565
}
1566
endutent();
1567
1568
chmod(line, 0666);
1569
chown(line, 0, 0);
1570
line[14] = line[13];
1571
line[13] = line[12];
1572
line[8] = 'm';
1573
line[9] = '/';
1574
line[10] = 'p';
1575
line[11] = 't';
1576
line[12] = 'y';
1577
chmod(line, 0666);
1578
chown(line, 0, 0);
1579
}
1580
#endif
1581
1582
/*
1583
* cleanup()
1584
*
1585
* This is the routine to call when we are all through, to
1586
* clean up anything that needs to be cleaned up.
1587
*/
1588
1589
#ifdef PARENT_DOES_UTMP
1590
1591
void
1592
cleanup(int sig)
1593
{
1594
#ifdef _CRAY
1595
static int incleanup = 0;
1596
int t;
1597
int child_status; /* status of child process as returned by waitpid */
1598
int flags = WNOHANG|WUNTRACED;
1599
1600
/*
1601
* 1: Pick up the zombie, if we are being called
1602
* as the signal handler.
1603
* 2: If we are a nested cleanup(), return.
1604
* 3: Try to clean up TMPDIR.
1605
* 4: Fill in utmp with shutdown of process.
1606
* 5: Close down the network and pty connections.
1607
* 6: Finish up the TMPDIR cleanup, if needed.
1608
*/
1609
if (sig == SIGCHLD) {
1610
while (waitpid(-1, &child_status, flags) > 0)
1611
; /* VOID */
1612
/* Check if the child process was stopped
1613
* rather than exited. We want cleanup only if
1614
* the child has died.
1615
*/
1616
if (WIFSTOPPED(child_status)) {
1617
return;
1618
}
1619
}
1620
t = sigblock(sigmask(SIGCHLD));
1621
if (incleanup) {
1622
sigsetmask(t);
1623
return;
1624
}
1625
incleanup = 1;
1626
sigsetmask(t);
1627
1628
t = cleantmp(&wtmp);
1629
setutent(); /* just to make sure */
1630
#endif /* CRAY */
1631
rmut(line);
1632
close(ourpty);
1633
shutdown(net, 2);
1634
#ifdef _CRAY
1635
if (t == 0)
1636
cleantmp(&wtmp);
1637
#endif /* CRAY */
1638
exit(1);
1639
}
1640
1641
#else /* PARENT_DOES_UTMP */
1642
1643
void
1644
cleanup(int sig)
1645
{
1646
#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1647
rmut();
1648
#ifdef HAVE_VHANGUP
1649
#ifndef __sgi
1650
vhangup(); /* XXX */
1651
#endif
1652
#endif
1653
#else
1654
char *p;
1655
1656
p = line + sizeof("/dev/") - 1;
1657
if (logout(p))
1658
logwtmp(p, "", "");
1659
chmod(line, 0666);
1660
chown(line, 0, 0);
1661
*p = 'p';
1662
chmod(line, 0666);
1663
chown(line, 0, 0);
1664
#endif
1665
shutdown(net, 2);
1666
exit(1);
1667
}
1668
1669
#endif /* PARENT_DOES_UTMP */
1670
1671
#ifdef PARENT_DOES_UTMP
1672
/*
1673
* _utmp_sig_rcv
1674
* utmp_sig_init
1675
* utmp_sig_wait
1676
* These three functions are used to coordinate the handling of
1677
* the utmp file between the server and the soon-to-be-login shell.
1678
* The server actually creates the utmp structure, the child calls
1679
* utmp_sig_wait(), until the server calls utmp_sig_notify() and
1680
* signals the future-login shell to proceed.
1681
*/
1682
static int caught=0; /* NZ when signal intercepted */
1683
static void (*func)(); /* address of previous handler */
1684
1685
void
1686
_utmp_sig_rcv(sig)
1687
int sig;
1688
{
1689
caught = 1;
1690
signal(SIGUSR1, func);
1691
}
1692
1693
void
1694
utmp_sig_init()
1695
{
1696
/*
1697
* register signal handler for UTMP creation
1698
*/
1699
if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1700
fatalperror(net, "telnetd/signal");
1701
}
1702
1703
void
1704
utmp_sig_reset()
1705
{
1706
signal(SIGUSR1, func); /* reset handler to default */
1707
}
1708
1709
# ifdef __hpux
1710
# define sigoff() /* do nothing */
1711
# define sigon() /* do nothing */
1712
# endif
1713
1714
void
1715
utmp_sig_wait()
1716
{
1717
/*
1718
* Wait for parent to write our utmp entry.
1719
*/
1720
sigoff();
1721
while (caught == 0) {
1722
pause(); /* wait until we get a signal (sigon) */
1723
sigoff(); /* turn off signals while we check caught */
1724
}
1725
sigon(); /* turn on signals again */
1726
}
1727
1728
void
1729
utmp_sig_notify(pid)
1730
{
1731
kill(pid, SIGUSR1);
1732
}
1733
1734
#ifdef _CRAY
1735
static int gotsigjob = 0;
1736
1737
/*ARGSUSED*/
1738
void
1739
sigjob(sig)
1740
int sig;
1741
{
1742
int jid;
1743
struct jobtemp *jp;
1744
1745
while ((jid = waitjob(NULL)) != -1) {
1746
if (jid == 0) {
1747
return;
1748
}
1749
gotsigjob++;
1750
jobend(jid, NULL, NULL);
1751
}
1752
}
1753
1754
/*
1755
* jid_getutid:
1756
* called by jobend() before calling cleantmp()
1757
* to find the correct $TMPDIR to cleanup.
1758
*/
1759
1760
struct utmp *
1761
jid_getutid(jid)
1762
int jid;
1763
{
1764
struct utmp *cur = NULL;
1765
1766
setutent(); /* just to make sure */
1767
while (cur = getutent()) {
1768
if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1769
return(cur);
1770
}
1771
}
1772
1773
return(0);
1774
}
1775
1776
/*
1777
* Clean up the TMPDIR that login created.
1778
* The first time this is called we pick up the info
1779
* from the utmp. If the job has already gone away,
1780
* then we'll clean up and be done. If not, then
1781
* when this is called the second time it will wait
1782
* for the signal that the job is done.
1783
*/
1784
int
1785
cleantmp(wtp)
1786
struct utmp *wtp;
1787
{
1788
struct utmp *utp;
1789
static int first = 1;
1790
int mask, omask, ret;
1791
extern struct utmp *getutid (const struct utmp *_Id);
1792
1793
1794
mask = sigmask(WJSIGNAL);
1795
1796
if (first == 0) {
1797
omask = sigblock(mask);
1798
while (gotsigjob == 0)
1799
sigpause(omask);
1800
return(1);
1801
}
1802
first = 0;
1803
setutent(); /* just to make sure */
1804
1805
utp = getutid(wtp);
1806
if (utp == 0) {
1807
syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1808
return(-1);
1809
}
1810
/*
1811
* Nothing to clean up if the user shell was never started.
1812
*/
1813
if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1814
return(1);
1815
1816
/*
1817
* Block the WJSIGNAL while we are in jobend().
1818
*/
1819
omask = sigblock(mask);
1820
ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1821
sigsetmask(omask);
1822
return(ret);
1823
}
1824
1825
int
1826
jobend(jid, path, user)
1827
int jid;
1828
char *path;
1829
char *user;
1830
{
1831
static int saved_jid = 0;
1832
static int pty_saved_jid = 0;
1833
static char saved_path[sizeof(wtmp.ut_tpath)+1];
1834
static char saved_user[sizeof(wtmp.ut_user)+1];
1835
1836
/*
1837
* this little piece of code comes into play
1838
* only when ptyreconnect is used to reconnect
1839
* to an previous session.
1840
*
1841
* this is the only time when the
1842
* "saved_jid != jid" code is executed.
1843
*/
1844
1845
if ( saved_jid && saved_jid != jid ) {
1846
if (!path) { /* called from signal handler */
1847
pty_saved_jid = jid;
1848
} else {
1849
pty_saved_jid = saved_jid;
1850
}
1851
}
1852
1853
if (path) {
1854
strlcpy(saved_path, path, sizeof(saved_path));
1855
strlcpy(saved_user, user, sizeof(saved_user));
1856
}
1857
if (saved_jid == 0) {
1858
saved_jid = jid;
1859
return(0);
1860
}
1861
1862
/* if the jid has changed, get the correct entry from the utmp file */
1863
1864
if ( saved_jid != jid ) {
1865
struct utmp *utp = NULL;
1866
struct utmp *jid_getutid();
1867
1868
utp = jid_getutid(pty_saved_jid);
1869
1870
if (utp == 0) {
1871
syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1872
return(-1);
1873
}
1874
1875
cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1876
return(1);
1877
}
1878
1879
cleantmpdir(jid, saved_path, saved_user);
1880
return(1);
1881
}
1882
1883
/*
1884
* Fork a child process to clean up the TMPDIR
1885
*/
1886
cleantmpdir(jid, tpath, user)
1887
int jid;
1888
char *tpath;
1889
char *user;
1890
{
1891
switch(fork()) {
1892
case -1:
1893
syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1894
tpath);
1895
break;
1896
case 0:
1897
execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);
1898
syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1899
tpath, CLEANTMPCMD);
1900
exit(1);
1901
default:
1902
/*
1903
* Forget about child. We will exit, and
1904
* /etc/init will pick it up.
1905
*/
1906
break;
1907
}
1908
}
1909
#endif /* CRAY */
1910
#endif /* defined(PARENT_DOES_UTMP) */
1911
1912