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