Home | History | Annotate | Line # | Download | only in libtelnet
sra.c revision 1.5
      1 /*-
      2  * Copyright (c) 1991, 1993
      3  *      Dave Safford.  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. Neither the name of the University nor the names of its contributors
     14  *    may be used to endorse or promote products derived from this software
     15  *    without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  *
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 #ifdef notdef
     33 __FBSDID("$FreeBSD: src/contrib/telnet/libtelnet/sra.c,v 1.16 2002/05/06 09:48:02 markm Exp $");
     34 #else
     35 __RCSID("$NetBSD: sra.c,v 1.5 2005/05/05 22:43:56 lukem Exp $");
     36 #endif
     37 
     38 #ifdef	SRA
     39 #ifdef	ENCRYPTION
     40 #include <sys/types.h>
     41 #include <arpa/telnet.h>
     42 #include <paths.h>
     43 #include <pwd.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include <syslog.h>
     48 #include <ttyent.h>
     49 
     50 #ifndef NOPAM
     51 #include <security/pam_appl.h>
     52 #else
     53 #include <unistd.h>
     54 #endif
     55 
     56 #include "auth.h"
     57 #include "misc.h"
     58 #include "encrypt.h"
     59 #include "pk.h"
     60 
     61 char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
     62 char *user, *pass, *xuser, *xpass;
     63 DesData ck;
     64 IdeaData ik;
     65 
     66 extern int auth_debug_mode;
     67 extern char *line;		/* see sys_term.c */
     68 
     69 static int sra_valid = 0;
     70 static int passwd_sent = 0;
     71 
     72 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
     73 			  		AUTHTYPE_SRA, };
     74 
     75 #define SRA_KEY	0
     76 #define SRA_USER 1
     77 #define SRA_CONTINUE 2
     78 #define SRA_PASS 3
     79 #define SRA_ACCEPT 4
     80 #define SRA_REJECT 5
     81 
     82 static int check_user(char *, char *);
     83 
     84 /* support routine to send out authentication message */
     85 static int
     86 Data(Authenticator *ap, int type, void *d, int c)
     87 {
     88         unsigned char *p = str_data + 4;
     89 	unsigned char *cd = (unsigned char *)d;
     90 
     91 	if (c == -1)
     92 		c = strlen((char *)cd);
     93 
     94         if (auth_debug_mode) {
     95                 printf("%s:%d: [%d] (%d)",
     96                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
     97                         str_data[3],
     98                         type, c);
     99                 printd(d, c);
    100                 printf("\r\n");
    101         }
    102 	*p++ = ap->type;
    103 	*p++ = ap->way;
    104 	*p++ = type;
    105         while (c-- > 0) {
    106                 if ((*p++ = *cd++) == IAC)
    107                         *p++ = IAC;
    108         }
    109         *p++ = IAC;
    110         *p++ = SE;
    111 	if (str_data[3] == TELQUAL_IS)
    112 		printsub('>', &str_data[2], p - (&str_data[2]));
    113         return(telnet_net_write(str_data, p - str_data));
    114 }
    115 
    116 int
    117 sra_init(Authenticator *ap __unused, int server)
    118 {
    119 	if (server)
    120 		str_data[3] = TELQUAL_REPLY;
    121 	else
    122 		str_data[3] = TELQUAL_IS;
    123 
    124 	user = (char *)malloc(256);
    125 	xuser = (char *)malloc(513);
    126 	pass = (char *)malloc(256);
    127 	xpass = (char *)malloc(513);
    128 
    129 	if (user == NULL || xuser == NULL || pass == NULL || xpass ==
    130 	NULL)
    131 		return 0; /* malloc failed */
    132 
    133 	passwd_sent = 0;
    134 
    135 	genkeys(pka,ska);
    136 	return(1);
    137 }
    138 
    139 /* client received a go-ahead for sra */
    140 int
    141 sra_send(Authenticator *ap)
    142 {
    143 	/* send PKA */
    144 
    145 	if (auth_debug_mode)
    146 		printf("Sent PKA to server.\r\n" );
    147 	printf("Trying SRA secure login:\r\n");
    148 	if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
    149 		if (auth_debug_mode)
    150 			printf("Not enough room for authentication data\r\n");
    151 		return(0);
    152 	}
    153 
    154 	return(1);
    155 }
    156 
    157 /* server received an IS -- could be SRA KEY, USER, or PASS */
    158 void
    159 sra_is(Authenticator *ap, unsigned char *data, int cnt)
    160 {
    161 	int valid;
    162 	Session_Key skey;
    163 
    164 	if (cnt-- < 1)
    165 		goto bad;
    166 	switch (*data++) {
    167 
    168 	case SRA_KEY:
    169 		if (cnt < HEXKEYBYTES) {
    170 			Data(ap, SRA_REJECT, (void *)0, 0);
    171 			auth_finished(ap, AUTH_USER);
    172 			if (auth_debug_mode) {
    173 				printf("SRA user rejected for bad PKB\r\n");
    174 			}
    175 			return;
    176 		}
    177 		if (auth_debug_mode)
    178 			printf("Sent pka\r\n");
    179 		if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
    180 			if (auth_debug_mode)
    181 				printf("Not enough room\r\n");
    182 			return;
    183 		}
    184 		memcpy(pkb,data,HEXKEYBYTES);
    185 		pkb[HEXKEYBYTES] = '\0';
    186 		common_key(ska,pkb,&ik,&ck);
    187 		return;
    188 
    189 	case SRA_USER:
    190 		/* decode KAB(u) */
    191 		if (cnt > 512) /* Attempted buffer overflow */
    192 			break;
    193 		memcpy(xuser,data,cnt);
    194 		xuser[cnt] = '\0';
    195 		pk_decode(xuser,user,&ck);
    196 		auth_encrypt_user(user);
    197 		Data(ap, SRA_CONTINUE, (void *)0, 0);
    198 
    199 		return;
    200 
    201 	case SRA_PASS:
    202 		if (cnt > 512) /* Attempted buffer overflow */
    203 			break;
    204 		/* decode KAB(P) */
    205 		memcpy(xpass,data,cnt);
    206 		xpass[cnt] = '\0';
    207 		pk_decode(xpass,pass,&ck);
    208 
    209 		/* check user's password */
    210 		valid = check_user(user,pass);
    211 
    212 		if(valid) {
    213 			    /* PAM (via check_user()) may have changed 'user' */
    214 			auth_encrypt_user(user);
    215 			Data(ap, SRA_ACCEPT, (void *)0, 0);
    216 			skey.data = ck;
    217 			skey.type = SK_DES;
    218 			skey.length = 8;
    219 			encrypt_session_key(&skey, 1);
    220 
    221 			sra_valid = 1;
    222 			auth_finished(ap, AUTH_VALID);
    223 			if (auth_debug_mode) {
    224 				printf("SRA user accepted\r\n");
    225 			}
    226 		}
    227 		else {
    228 			Data(ap, SRA_CONTINUE, (void *)0, 0);
    229 /*
    230 			Data(ap, SRA_REJECT, (void *)0, 0);
    231 			sra_valid = 0;
    232 			auth_finished(ap, AUTH_REJECT);
    233 */
    234 			if (auth_debug_mode) {
    235 				printf("SRA user failed\r\n");
    236 			}
    237 		}
    238 		return;
    239 
    240 	default:
    241 		if (auth_debug_mode)
    242 			printf("Unknown SRA option %d\r\n", data[-1]);
    243 	}
    244 bad:
    245 	Data(ap, SRA_REJECT, 0, 0);
    246 	sra_valid = 0;
    247 	auth_finished(ap, AUTH_REJECT);
    248 }
    249 
    250 /* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
    251 void
    252 sra_reply(Authenticator *ap, unsigned char *data, int cnt)
    253 {
    254 	char uprompt[256],tuser[256];
    255 	Session_Key skey;
    256 	size_t i;
    257 
    258 	if (cnt-- < 1)
    259 		return;
    260 	switch (*data++) {
    261 
    262 	case SRA_KEY:
    263 		/* calculate common key */
    264 		if (cnt < HEXKEYBYTES) {
    265 			if (auth_debug_mode) {
    266 				printf("SRA user rejected for bad PKB\r\n");
    267 			}
    268 			return;
    269 		}
    270 		memcpy(pkb,data,HEXKEYBYTES);
    271 		pkb[HEXKEYBYTES] = '\0';
    272 
    273 		common_key(ska,pkb,&ik,&ck);
    274 
    275 	enc_user:
    276 
    277 		/* encode user */
    278 		memset(tuser,0,sizeof(tuser));
    279 		sprintf(uprompt,"User (%s): ",UserNameRequested);
    280 		telnet_gets(uprompt,tuser,255,1);
    281 		if (tuser[0] == '\n' || tuser[0] == '\r' )
    282 			strcpy(user,UserNameRequested);
    283 		else {
    284 			/* telnet_gets leaves the newline on */
    285 			for(i=0;i<sizeof(tuser);i++) {
    286 				if (tuser[i] == '\n') {
    287 					tuser[i] = '\0';
    288 					break;
    289 				}
    290 			}
    291 			strcpy(user,tuser);
    292 		}
    293 		pk_encode(user,xuser,&ck);
    294 
    295 		/* send it off */
    296 		if (auth_debug_mode)
    297 			printf("Sent KAB(U)\r\n");
    298 		if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
    299 			if (auth_debug_mode)
    300 				printf("Not enough room\r\n");
    301 			return;
    302 		}
    303 		break;
    304 
    305 	case SRA_CONTINUE:
    306 		if (passwd_sent) {
    307 			passwd_sent = 0;
    308 			printf("[ SRA login failed ]\r\n");
    309 			goto enc_user;
    310 		}
    311 		/* encode password */
    312 		memset(pass,0,sizeof(pass));
    313 		telnet_gets("Password: ",pass,255,0);
    314 		pk_encode(pass,xpass,&ck);
    315 		/* send it off */
    316 		if (auth_debug_mode)
    317 			printf("Sent KAB(P)\r\n");
    318 		if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
    319 			if (auth_debug_mode)
    320 				printf("Not enough room\r\n");
    321 			return;
    322 		}
    323 		passwd_sent = 1;
    324 		break;
    325 
    326 	case SRA_REJECT:
    327 		printf("[ SRA refuses authentication ]\r\n");
    328 		printf("Trying plaintext login:\r\n");
    329 		auth_finished(0,AUTH_REJECT);
    330 		return;
    331 
    332 	case SRA_ACCEPT:
    333 		printf("[ SRA accepts you ]\r\n");
    334 		skey.data = ck;
    335 		skey.type = SK_DES;
    336 		skey.length = 8;
    337 		encrypt_session_key(&skey, 0);
    338 
    339 		auth_finished(ap, AUTH_VALID);
    340 		return;
    341 	default:
    342 		if (auth_debug_mode)
    343 			printf("Unknown SRA option %d\r\n", data[-1]);
    344 		return;
    345 	}
    346 }
    347 
    348 int
    349 sra_status(Authenticator *ap __unused, char *name, size_t len, int level)
    350 {
    351 	if (level < AUTH_USER)
    352 		return(level);
    353 	if (UserNameRequested && sra_valid) {
    354 		strlcpy(name, UserNameRequested, len);
    355 		return(AUTH_VALID);
    356 	} else
    357 		return(AUTH_USER);
    358 }
    359 
    360 #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
    361 #define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
    362 
    363 void
    364 sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
    365 {
    366 	char lbuf[32];
    367 	int i;
    368 
    369 	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
    370 	buflen -= 1;
    371 
    372 	switch(data[3]) {
    373 
    374 	case SRA_CONTINUE:
    375 		strncpy((char *)buf, " CONTINUE ", buflen);
    376 		goto common;
    377 
    378 	case SRA_REJECT:		/* Rejected (reason might follow) */
    379 		strncpy((char *)buf, " REJECT ", buflen);
    380 		goto common;
    381 
    382 	case SRA_ACCEPT:		/* Accepted (name might follow) */
    383 		strncpy((char *)buf, " ACCEPT ", buflen);
    384 
    385 	common:
    386 		BUMP(buf, buflen);
    387 		if (cnt <= 4)
    388 			break;
    389 		ADDC(buf, buflen, '"');
    390 		for (i = 4; i < cnt; i++)
    391 			ADDC(buf, buflen, data[i]);
    392 		ADDC(buf, buflen, '"');
    393 		ADDC(buf, buflen, '\0');
    394 		break;
    395 
    396 	case SRA_KEY:			/* Authentication data follows */
    397 		strncpy((char *)buf, " KEY ", buflen);
    398 		goto common2;
    399 
    400 	case SRA_USER:
    401 		strncpy((char *)buf, " USER ", buflen);
    402 		goto common2;
    403 
    404 	case SRA_PASS:
    405 		strncpy((char *)buf, " PASS ", buflen);
    406 		goto common2;
    407 
    408 	default:
    409 		sprintf(lbuf, " %d (unknown)", data[3]);
    410 		strncpy((char *)buf, lbuf, buflen);
    411 	common2:
    412 		BUMP(buf, buflen);
    413 		for (i = 4; i < cnt; i++) {
    414 			sprintf(lbuf, " %d", data[i]);
    415 			strncpy((char *)buf, lbuf, buflen);
    416 			BUMP(buf, buflen);
    417 		}
    418 		break;
    419 	}
    420 }
    421 
    422 static int
    423 isroot(const char *usr)
    424 {
    425 	struct passwd pws, *pwd;
    426 	char pwbuf[1024];
    427 
    428 	if (getpwnam_r(usr, &pws, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
    429 	    pwd == NULL)
    430 		return 0;
    431 	return (!pwd->pw_uid);
    432 }
    433 
    434 static int
    435 rootterm(const char *ttyname)
    436 {
    437 	struct ttyent *t;
    438 	const char *ttyn;
    439 
    440 	ttyn = ttyname;
    441 	if (strncmp(ttyn, _PATH_DEV, sizeof(_PATH_DEV)-1) == 0)
    442 		ttyn += sizeof(_PATH_DEV) - 1;
    443 
    444 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    445 }
    446 
    447 #ifdef NOPAM
    448 static int
    449 check_user(char *name, char *cred)
    450 {
    451 	char *cp;
    452 	char *xpasswd, *salt;
    453 
    454 	if (isroot(name) && !rootterm(line))
    455 	{
    456 		crypt("AA","*"); /* Waste some time to simulate success */
    457 		return(0);
    458 	}
    459 
    460 	if (pw = sgetpwnam(name)) {
    461 		if (pw->pw_shell == NULL) {
    462 			pw = (struct passwd *) NULL;
    463 			return(0);
    464 		}
    465 
    466 		salt = pw->pw_passwd;
    467 		xpasswd = crypt(cred, salt);
    468 		/* The strcmp does not catch null passwords! */
    469 		if (pw == NULL || *pw->pw_passwd == '\0' ||
    470 			strcmp(xpasswd, pw->pw_passwd)) {
    471 			pw = (struct passwd *) NULL;
    472 			return(0);
    473 		}
    474 		return(1);
    475 	}
    476 	return(0);
    477 }
    478 #else
    479 
    480 /*
    481  * The following is stolen from ftpd, which stole it from the imap-uw
    482  * PAM module and login.c. It is needed because we can't really
    483  * "converse" with the user, having already gone to the trouble of
    484  * getting their username and password through an encrypted channel.
    485  */
    486 
    487 #define COPY_STRING(s) (s ? strdup(s):NULL)
    488 
    489 struct cred_t {
    490 	const char *uname;
    491 	const char *pass;
    492 };
    493 typedef struct cred_t cred_t;
    494 
    495 static int
    496 auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
    497 {
    498 	int i;
    499 	cred_t *cred = (cred_t *) appdata;
    500 	struct pam_response *reply =
    501 		malloc(sizeof(struct pam_response) * num_msg);
    502 
    503 	if (reply == NULL)
    504 		return PAM_BUF_ERR;
    505 
    506 	for (i = 0; i < num_msg; i++) {
    507 		switch (msg[i]->msg_style) {
    508 		case PAM_PROMPT_ECHO_ON:        /* assume want user name */
    509 			reply[i].resp_retcode = PAM_SUCCESS;
    510 			reply[i].resp = COPY_STRING(cred->uname);
    511 			/* PAM frees resp. */
    512 			break;
    513 		case PAM_PROMPT_ECHO_OFF:       /* assume want password */
    514 			reply[i].resp_retcode = PAM_SUCCESS;
    515 			reply[i].resp = COPY_STRING(cred->pass);
    516 			/* PAM frees resp. */
    517 			break;
    518 		case PAM_TEXT_INFO:
    519 		case PAM_ERROR_MSG:
    520 			reply[i].resp_retcode = PAM_SUCCESS;
    521 			reply[i].resp = NULL;
    522 			break;
    523 		default:                        /* unknown message style */
    524 			free(reply);
    525 			return PAM_CONV_ERR;
    526 		}
    527 	}
    528 
    529 	*resp = reply;
    530 	return PAM_SUCCESS;
    531 }
    532 
    533 /*
    534  * The PAM version as a side effect may put a new username in *name.
    535  */
    536 static int
    537 check_user(char *name, char *cred)
    538 {
    539 	pam_handle_t *pamh = NULL;
    540 	const void *item;
    541 	int rval;
    542 	int e;
    543 	cred_t auth_cred = { name, cred };
    544 	struct pam_conv conv = { &auth_conv, &auth_cred };
    545 
    546 	e = pam_start("telnetd", name, &conv, &pamh);
    547 	if (e != PAM_SUCCESS) {
    548 		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
    549 		return 0;
    550 	}
    551 
    552 #if 0 /* Where can we find this value? */
    553 	e = pam_set_item(pamh, PAM_RHOST, remotehost);
    554 	if (e != PAM_SUCCESS) {
    555 		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
    556 			pam_strerror(pamh, e));
    557 		return 0;
    558 	}
    559 #endif
    560 
    561 	e = pam_authenticate(pamh, 0);
    562 	switch (e) {
    563 	case PAM_SUCCESS:
    564 		/*
    565 		 * With PAM we support the concept of a "template"
    566 		 * user.  The user enters a login name which is
    567 		 * authenticated by PAM, usually via a remote service
    568 		 * such as RADIUS or TACACS+.  If authentication
    569 		 * succeeds, a different but related "template" name
    570 		 * is used for setting the credentials, shell, and
    571 		 * home directory.  The name the user enters need only
    572 		 * exist on the remote authentication server, but the
    573 		 * template name must be present in the local password
    574 		 * database.
    575 		 *
    576 		 * This is supported by two various mechanisms in the
    577 		 * individual modules.  However, from the application's
    578 		 * point of view, the template user is always passed
    579 		 * back as a changed value of the PAM_USER item.
    580 		 */
    581 		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
    582 		    PAM_SUCCESS) {
    583 			strcpy(name, item);
    584 		} else
    585 			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
    586 			pam_strerror(pamh, e));
    587 		if (isroot(name) && !rootterm(line))
    588 			rval = 0;
    589 		else
    590 			rval = 1;
    591 		break;
    592 
    593 	case PAM_AUTH_ERR:
    594 	case PAM_USER_UNKNOWN:
    595 	case PAM_MAXTRIES:
    596 		rval = 0;
    597 	break;
    598 
    599 	default:
    600 		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
    601 		rval = 0;
    602 		break;
    603 	}
    604 
    605 	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
    606 		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
    607 		rval = 0;
    608 	}
    609 	return rval;
    610 }
    611 
    612 #endif
    613 
    614 #endif /* ENCRYPTION */
    615 #endif /* SRA */
    616