GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: libexec/getty/main.c Lines: 0 259 0.0 %
Date: 2017-11-07 Branches: 0 175 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: main.c,v 1.48 2017/05/29 04:40:35 deraadt Exp $	*/
2
3
/*-
4
 * Copyright (c) 1980, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. Neither the name of the University nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include <sys/stat.h>
33
#include <termios.h>
34
#include <sys/ioctl.h>
35
#include <sys/resource.h>
36
#include <sys/utsname.h>
37
#include <errno.h>
38
#include <signal.h>
39
#include <fcntl.h>
40
#include <time.h>
41
#include <ctype.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <syslog.h>
45
#include <stdio.h>
46
#include <unistd.h>
47
#include <limits.h>
48
#include <util.h>
49
50
#include "gettytab.h"
51
#include "pathnames.h"
52
#include "extern.h"
53
54
/*
55
 * Set the amount of running time that getty should accumulate
56
 * before deciding that something is wrong and exit.
57
 */
58
#define GETTY_TIMEOUT	60 /* seconds */
59
60
struct termios tmode, omode;
61
62
int crmod, digit, lower, upper;
63
64
char	hostname[HOST_NAME_MAX+1];
65
char	globalhostname[HOST_NAME_MAX+1];
66
struct	utsname kerninfo;
67
char	name[LOGIN_NAME_MAX];
68
char	ttyn[32];
69
char	*portselector(void);
70
71
#define	OBUFSIZ		128
72
#define	TABBUFSIZ	512
73
74
char	defent[TABBUFSIZ];
75
char	tabent[TABBUFSIZ];
76
77
char	*env[128];
78
79
char partab[] = {
80
	0001,0201,0201,0001,0201,0001,0001,0201,
81
	0202,0004,0003,0205,0005,0206,0201,0001,
82
	0201,0001,0001,0201,0001,0201,0201,0001,
83
	0001,0201,0201,0001,0201,0001,0001,0201,
84
	0200,0000,0000,0200,0000,0200,0200,0000,
85
	0000,0200,0200,0000,0200,0000,0000,0200,
86
	0000,0200,0200,0000,0200,0000,0000,0200,
87
	0200,0000,0000,0200,0000,0200,0200,0000,
88
	0200,0000,0000,0200,0000,0200,0200,0000,
89
	0000,0200,0200,0000,0200,0000,0000,0200,
90
	0000,0200,0200,0000,0200,0000,0000,0200,
91
	0200,0000,0000,0200,0000,0200,0200,0000,
92
	0000,0200,0200,0000,0200,0000,0000,0200,
93
	0200,0000,0000,0200,0000,0200,0200,0000,
94
	0200,0000,0000,0200,0000,0200,0200,0000,
95
	0000,0200,0200,0000,0200,0000,0000,0201
96
};
97
98
#define	ERASE	tmode.c_cc[VERASE]
99
#define	KILL	tmode.c_cc[VKILL]
100
#define	EOT	tmode.c_cc[VEOF]
101
102
static void
103
dingdong(int signo)
104
{
105
	tmode.c_ispeed = tmode.c_ospeed = 0;
106
	(void)tcsetattr(0, TCSANOW, &tmode);
107
	_exit(1);
108
}
109
110
volatile sig_atomic_t interrupt_flag;
111
112
static void
113
interrupt(int signo)
114
{
115
	int save_errno = errno;
116
117
	interrupt_flag = 1;
118
	signal(SIGINT, interrupt);
119
	errno = save_errno;
120
}
121
122
/*
123
 * Action to take when getty is running too long.
124
 */
125
static void
126
timeoverrun(int signo)
127
{
128
	struct syslog_data sdata = SYSLOG_DATA_INIT;
129
130
	syslog_r(LOG_ERR, &sdata,
131
	    "getty exiting due to excessive running time");
132
	_exit(1);
133
}
134
135
static int	getname(void);
136
static void	oflush(void);
137
static void	prompt(void);
138
static void	putchr(int);
139
static void	putf(char *);
140
static void	putpad(char *);
141
static void	xputs(char *);
142
143
int
144
main(int argc, char *argv[])
145
{
146
	extern char **environ;
147
	char *tname;
148
	int repcnt = 0, failopenlogged = 0;
149
	struct rlimit limit;
150
	int off = 0;
151
152
	signal(SIGINT, SIG_IGN);
153
/*
154
	signal(SIGQUIT, SIG_DFL);
155
*/
156
	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
157
	gethostname(hostname, sizeof(hostname));
158
	if (hostname[0] == '\0')
159
		strlcpy(hostname, "Amnesiac", sizeof hostname);
160
	uname(&kerninfo);
161
162
	/*
163
	 * Limit running time to deal with broken or dead lines.
164
	 */
165
	(void)signal(SIGXCPU, timeoverrun);
166
	limit.rlim_max = RLIM_INFINITY;
167
	limit.rlim_cur = GETTY_TIMEOUT;
168
	(void)setrlimit(RLIMIT_CPU, &limit);
169
170
	ioctl(0, FIOASYNC, &off);	/* turn off async mode */
171
172
	/*
173
	 * The following is a work around for vhangup interactions
174
	 * which cause great problems getting window systems started.
175
	 * If the tty line is "-", we do the old style getty presuming
176
	 * that the file descriptors are already set up for us.
177
	 * J. Gettys - MIT Project Athena.
178
	 */
179
	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
180
		if (pledge("stdio rpath proc exec tty", NULL) == -1) {
181
			syslog(LOG_ERR, "pledge: %m");
182
			exit(1);
183
		}
184
185
		if ((tname = ttyname(0)) == NULL) {
186
			syslog(LOG_ERR, "stdin: %m");
187
			exit(1);
188
		}
189
		if (strlcpy(ttyn, tname, sizeof(ttyn)) >= sizeof(ttyn)) {
190
			errno = ENAMETOOLONG;
191
			syslog(LOG_ERR, "%s: %m", tname);
192
			exit(1);
193
		}
194
	} else {
195
		int i;
196
197
		snprintf(ttyn, sizeof ttyn, "%s%s", _PATH_DEV, argv[2]);
198
		if (strcmp(argv[0], "+") != 0) {
199
			chown(ttyn, 0, 0);
200
			chmod(ttyn, 0600);
201
			revoke(ttyn);
202
			/*
203
			 * Delay the open so DTR stays down long enough to be detected.
204
			 */
205
			sleep(2);
206
			while ((i = open(ttyn, O_RDWR)) == -1) {
207
				if ((repcnt % 10 == 0) &&
208
				    (errno != ENXIO || !failopenlogged)) {
209
					syslog(LOG_ERR, "%s: %m", ttyn);
210
					closelog();
211
					failopenlogged = 1;
212
				}
213
				repcnt++;
214
				sleep(60);
215
			}
216
			login_tty(i);
217
		}
218
	}
219
220
	if (pledge("stdio rpath proc exec tty", NULL) == -1) {
221
		syslog(LOG_ERR, "pledge: %m");
222
		exit(1);
223
	}
224
225
	/* Start with default tty settings */
226
	if (tcgetattr(0, &tmode) < 0) {
227
		syslog(LOG_ERR, "%s: %m", ttyn);
228
		exit(1);
229
	}
230
	omode = tmode;
231
232
	gettable("default", defent);
233
	gendefaults();
234
	tname = "default";
235
	if (argc > 1)
236
		tname = argv[1];
237
	for (;;) {
238
		gettable(tname, tabent);
239
		if (OPset || EPset || APset)
240
			APset++, OPset++, EPset++;
241
		setdefaults();
242
		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
243
		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
244
245
		if (IS)
246
			cfsetispeed(&tmode, IS);
247
		else if (SP)
248
			cfsetispeed(&tmode, SP);
249
		if (OS)
250
			cfsetospeed(&tmode, OS);
251
		else if (SP)
252
			cfsetospeed(&tmode, SP);
253
		setflags(0);
254
		setchars();
255
		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
256
			syslog(LOG_ERR, "%s: %m", ttyn);
257
			exit(1);
258
		}
259
		if (AB) {
260
			tname = autobaud();
261
			continue;
262
		}
263
		if (PS) {
264
			tname = portselector();
265
			continue;
266
		}
267
		if (CL && *CL)
268
			putpad(CL);
269
		strlcpy(globalhostname, HN, sizeof(globalhostname));
270
		if (IM && *IM)
271
			putf(IM);
272
		if (TO) {
273
			signal(SIGALRM, dingdong);
274
			alarm(TO);
275
		}
276
		if (getname()) {
277
			int i;
278
279
			oflush();
280
			alarm(0);
281
			signal(SIGALRM, SIG_DFL);
282
			if (name[0] == '-') {
283
				xputs("user names may not start with '-'.");
284
				continue;
285
			}
286
			if (!(upper || lower || digit))
287
				continue;
288
			setflags(2);
289
			if (crmod) {
290
				tmode.c_iflag |= ICRNL;
291
				tmode.c_oflag |= ONLCR;
292
			}
293
			if (UC) {
294
				tmode.c_iflag |= IUCLC;
295
				tmode.c_oflag |= OLCUC;
296
				tmode.c_lflag |= XCASE;
297
			}
298
			if (lower || LC) {
299
				tmode.c_iflag &= ~IUCLC;
300
				tmode.c_oflag &= ~OLCUC;
301
				tmode.c_lflag &= ~XCASE;
302
			}
303
			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
304
				syslog(LOG_ERR, "%s: %m", ttyn);
305
				exit(1);
306
			}
307
			signal(SIGINT, SIG_DFL);
308
			for (i = 0; environ[i] != NULL; i++)
309
				env[i] = environ[i];
310
			makeenv(&env[i]);
311
312
			limit.rlim_max = RLIM_INFINITY;
313
			limit.rlim_cur = RLIM_INFINITY;
314
			(void)setrlimit(RLIMIT_CPU, &limit);
315
			execle(LO, "login", "-p", "--", name, NULL, env);
316
			syslog(LOG_ERR, "%s: %m", LO);
317
			exit(1);
318
		}
319
		alarm(0);
320
		signal(SIGALRM, SIG_DFL);
321
		signal(SIGINT, SIG_IGN);
322
		if (NX && *NX)
323
			tname = NX;
324
	}
325
}
326
327
static int
328
getname(void)
329
{
330
	unsigned char cs;
331
	int c, r;
332
	char *np;
333
334
	/*
335
	 * Interrupt may happen if we use CBREAK mode
336
	 */
337
	signal(SIGINT, interrupt);
338
	setflags(1);
339
	prompt();
340
	if (PF > 0) {
341
		oflush();
342
		sleep(PF);
343
		PF = 0;
344
	}
345
	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
346
		syslog(LOG_ERR, "%s: %m", ttyn);
347
		exit(1);
348
	}
349
	crmod = digit = lower = upper = 0;
350
	np = name;
351
	for (;;) {
352
		oflush();
353
		r = read(STDIN_FILENO, &cs, 1);
354
		if (r <= 0) {
355
			if (r == -1 && errno == EINTR && interrupt_flag) {
356
				interrupt_flag = 0;
357
				return (0);
358
			}
359
			exit(0);
360
		}
361
		/* Handle 'printables' we cannot erase */
362
		if (cs == CTRL('L') || cs == CTRL('K'))
363
			continue;
364
		if (cs == '\t')
365
			cs = ' ';
366
		if ((c = cs&0177) == 0)
367
			return (0);
368
369
		if (c == EOT)
370
			exit(1);
371
		if (c == '\r' || c == '\n' || np >= name + sizeof name -1) {
372
			putf("\r\n");
373
			break;
374
		}
375
		if (islower(c))
376
			lower = 1;
377
		else if (isupper(c))
378
			upper = 1;
379
		else if (c == ERASE || c == '\b') {
380
			if (np > name) {
381
				if (*--np == '\033')
382
					xputs("\b\b  \b\b");
383
				else if (isprint(*np))
384
					xputs("\b \b");
385
			}
386
			continue;
387
		} else if (c == KILL) {
388
			putchr('\r');
389
			putf(LM);
390
			while (np > name) {
391
				if (*--np == '\033')
392
					xputs("  ");
393
				else if (isprint(*np))
394
					putchr(' ');
395
			}
396
			putchr('\r');
397
			prompt();
398
			np = name;
399
			continue;
400
		} else if (isdigit(c))
401
			digit++;
402
		if (IG && (c <= ' ' || c > 0176))
403
			continue;
404
		*np++ = c;
405
		if (c == '\033') {
406
			putchr('^');
407
			putchr('[');
408
		} else
409
			putchr(cs);
410
	}
411
	signal(SIGINT, SIG_IGN);
412
	if (interrupt_flag) {
413
		interrupt_flag = 0;
414
		return (0);
415
	}
416
	*np = 0;
417
	if (c == '\r')
418
		crmod = 1;
419
	return (1);
420
}
421
422
static void
423
putpad(char *s)
424
{
425
	int pad = 0;
426
	speed_t ospeed = cfgetospeed(&tmode);
427
428
	if (isdigit((unsigned char)*s)) {
429
		while (isdigit((unsigned char)*s)) {
430
			pad *= 10;
431
			pad += *s++ - '0';
432
		}
433
		pad *= 10;
434
		if (*s == '.' && isdigit((unsigned char)s[1])) {
435
			pad += s[1] - '0';
436
			s += 2;
437
		}
438
	}
439
440
	xputs(s);
441
	/*
442
	 * If no delay needed, or output speed is
443
	 * not comprehensible, then don't try to delay.
444
	 */
445
	if (pad == 0 || ospeed <= 0)
446
		return;
447
448
	/*
449
	 * Round up by a half a character frame, and then do the delay.
450
	 * Too bad there are no user program accessible programmed delays.
451
	 * Transmitting pad characters slows many terminals down and also
452
	 * loads the system.
453
	 */
454
	pad = (pad * ospeed + 50000) / 100000;
455
	while (pad--)
456
		putchr(*PC);
457
}
458
459
static void
460
xputs(char *s)
461
{
462
	while (*s)
463
		putchr(*s++);
464
}
465
466
char	outbuf[OBUFSIZ];
467
int	obufcnt = 0;
468
469
static void
470
putchr(int cc)
471
{
472
	char c;
473
474
	c = cc;
475
	if (!NP) {
476
		c |= partab[c&0177] & 0200;
477
		if (OP)
478
			c ^= 0200;
479
	}
480
	if (!UB) {
481
		outbuf[obufcnt++] = c;
482
		if (obufcnt >= OBUFSIZ)
483
			oflush();
484
	} else
485
		write(STDOUT_FILENO, &c, 1);
486
}
487
488
static void
489
oflush(void)
490
{
491
	if (obufcnt)
492
		write(STDOUT_FILENO, outbuf, obufcnt);
493
	obufcnt = 0;
494
}
495
496
static void
497
prompt(void)
498
{
499
500
	putf(LM);
501
	if (CO)
502
		putchr('\n');
503
}
504
505
static void
506
putf(char *cp)
507
{
508
	char *slash, db[100];
509
	time_t t;
510
511
	while (*cp) {
512
		if (*cp != '%') {
513
			putchr(*cp++);
514
			continue;
515
		}
516
		switch (*++cp) {
517
518
		case 't':
519
			slash = strrchr(ttyn, '/');
520
			if (slash == (char *) 0)
521
				xputs(ttyn);
522
			else
523
				xputs(&slash[1]);
524
			break;
525
526
		case 'h':
527
			xputs(globalhostname);
528
			break;
529
530
		case 'd': {
531
			(void)time(&t);
532
			(void)strftime(db, sizeof(db),
533
			    "%l:%M%p on %A, %d %B %Y", localtime(&t));
534
			xputs(db);
535
			break;
536
		}
537
538
		case 's':
539
			xputs(kerninfo.sysname);
540
			break;
541
542
		case 'm':
543
			xputs(kerninfo.machine);
544
			break;
545
546
		case 'r':
547
			xputs(kerninfo.release);
548
			break;
549
550
		case 'v':
551
			xputs(kerninfo.version);
552
			break;
553
554
		case '%':
555
			putchr('%');
556
			break;
557
		}
558
		cp++;
559
	}
560
}