2
* Copyright (c) 2000 David A. Holland.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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 David A. Holland.
16
* 4. Neither the name of the Author nor the names of any contributors
17
* may be used to endorse or promote products derived from this software
18
* without specific prior written permission.
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND ANY CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
"@(#) Copyright (c) 2000 David A. Holland.\n"
35
"All rights reserved.\n";
38
"$Id: telnetlogin.c,v 1.2 2004/11/07 15:47:43 ianb Exp $";
39
#include "../version.h"
41
#include <sys/types.h>
43
#include <sys/ioctl.h>
57
#define _PATH_LOGIN "/bin/login"
60
extern char **environ;
62
static const char *remhost = NULL;
64
static void die(const char *, ...) __attribute__ ((noreturn));
66
static void die(const char *fmt, ...) {
68
openlog("telnetlogin", LOG_PID, LOG_AUTHPRIV);
70
vsyslog(LOG_CRIT, fmt, ap);
75
static int check_a_hostname(char *hname) {
77
/* should we check length? */
78
for (i=0; hname[i]; i++) {
79
if ((hname[i]<=32) || (hname[i]>126)) return -1;
84
static int check_username(char *username) {
86
if (strlen(username) > 32) return -1;
87
for (i=0; username[i]; i++) {
88
if ((username[i]<=32) || (username[i]>126)) return -1;
93
static int check_term(char *termtype) {
95
if (strlen(termtype) > 32) return -1;
96
for (i=0; termtype[i]; i++) {
97
if (!isalnum(termtype[i]) && !strchr("+._-", termtype[i])) return -1;
102
static int check_remotehost(char *val) {
103
if (check_a_hostname(val)) return -1;
104
if (remhost && strcmp(val, remhost)) return -1;
110
int (*validator)(char *);
112
{ "TERM", check_term },
113
{ "REMOTEHOST", check_remotehost },
117
static void validate_tty(void) {
118
struct stat buf, buf2;
123
if (!tty) die("stdin not a tty");
125
if (fstat(0, &buf)) die("fstat stdin");
126
if (!S_ISCHR(buf.st_mode)) die("stdin not char device");
128
if (fstat(1, &buf2)) die("fstat stdout");
129
if (!S_ISCHR(buf2.st_mode)) die("stdout not char device");
130
if (buf.st_rdev!=buf2.st_rdev) die("stdout and stdin not same tty");
132
if (fstat(2, &buf2)) die("fstat stderr");
133
if (!S_ISCHR(buf2.st_mode)) die("stderr not char device");
134
if (buf.st_rdev!=buf2.st_rdev) die("stderr and stdin not same tty");
136
if (ioctl(0, TIOCGPGRP, &pgrp)) die("cannot get tty process group");
137
if (pgrp != getpgrp()) die("not foreground pgrp of tty");
138
if (pgrp != getpid()) die("not process group leader");
141
int main(int argc, char *argv[]) {
142
static char argv0[] = "login";
144
const char *rh = NULL;
145
char **envs = environ;
147
/* first, make sure our stdin/stdout/stderr are aimed somewhere */
148
i = open("/", O_RDONLY);
150
/* Oops. Can't even print an error message... */
158
die("Illegal args: argc < 1");
160
if (argn < argc && !strcmp(argv[argn], "-h")) {
162
if (argn==argc) die("Illegal args: -h requires argument");
163
if (check_a_hostname(argv[argn])) die("Illegal remote host specified");
167
if (argn < argc && !strcmp(argv[argn], "-p")) {
170
if (argn < argc && !strcmp(argv[argn], "-f")) {
172
if (argn==argc) die("Illegal args: -f requires argument");
173
if (check_username(argv[argn])) die("Illegal remote username specified");
176
if (argn < argc && argv[argn][0] != '-') {
179
if (argn < argc) die("Illegal args: too many args");
182
/* check environment */
183
if (envs) for (i=0; envs[i]; i++) {
184
char *testenv = envs[i];
185
size_t testlen = strlen(testenv);
186
for (j=0; legal_envs[j].name; j++) {
187
const char *okenv = legal_envs[j].name;
188
size_t oklen = strlen(okenv);
191
if (testlen < oklen) continue;
192
if (testenv[oklen]!='=') continue;
193
if ((sign = memcmp(testenv, okenv, oklen)) < 0) {
195
} else if (sign > 0) {
198
if (legal_envs[j].validator(testenv+oklen+1)) {
199
die("Invalid environment: bad value for %s", okenv);
205
/* unignore all signals so they get cleared at exec time */
206
for (i=1; i<NSIG; i++) {
211
if (chdir("/")) die("chdir to / failed");
214
* don't do anything with uids and gids, as login is normally meant
215
* to be able to take care of them.
217
* but, should we insist that ruid==nobody?
222
* Debian's /bin/login doesn't work properly unless we're really root.
228
* don't do anything with limits, itimers, or process priority either
232
* should we check to make sure stdin=stdout=stderr and they're a tty
233
* and it's our controlling tty [hard] and we're the leader of the
234
* foreground process group?
242
* argv[0] was set up above.
244
execve(_PATH_LOGIN, argv, envs);