Home | History | Annotate | Line # | Download | only in libtelnet
sra.c revision 1.1
      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.1 2005/02/19 21:55:52 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 *pwd;
    423 
    424 	if ((pwd=getpwnam(usr))==NULL)
    425 		return 0;
    426 	return (!pwd->pw_uid);
    427 }
    428 
    429 static int
    430 rootterm(char *ttyn)
    431 {
    432 	struct ttyent *t;
    433 
    434 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    435 }
    436 
    437 #ifdef NOPAM
    438 static int
    439 check_user(char *name, char *cred)
    440 {
    441 	char *cp;
    442 	char *xpasswd, *salt;
    443 
    444 	if (isroot(name) && !rootterm(line))
    445 	{
    446 		crypt("AA","*"); /* Waste some time to simulate success */
    447 		return(0);
    448 	}
    449 
    450 	if (pw = sgetpwnam(name)) {
    451 		if (pw->pw_shell == NULL) {
    452 			pw = (struct passwd *) NULL;
    453 			return(0);
    454 		}
    455 
    456 		salt = pw->pw_passwd;
    457 		xpasswd = crypt(cred, salt);
    458 		/* The strcmp does not catch null passwords! */
    459 		if (pw == NULL || *pw->pw_passwd == '\0' ||
    460 			strcmp(xpasswd, pw->pw_passwd)) {
    461 			pw = (struct passwd *) NULL;
    462 			return(0);
    463 		}
    464 		return(1);
    465 	}
    466 	return(0);
    467 }
    468 #else
    469 
    470 /*
    471  * The following is stolen from ftpd, which stole it from the imap-uw
    472  * PAM module and login.c. It is needed because we can't really
    473  * "converse" with the user, having already gone to the trouble of
    474  * getting their username and password through an encrypted channel.
    475  */
    476 
    477 #define COPY_STRING(s) (s ? strdup(s):NULL)
    478 
    479 struct cred_t {
    480 	const char *uname;
    481 	const char *pass;
    482 };
    483 typedef struct cred_t cred_t;
    484 
    485 static int
    486 auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
    487 {
    488 	int i;
    489 	cred_t *cred = (cred_t *) appdata;
    490 	struct pam_response *reply =
    491 		malloc(sizeof(struct pam_response) * num_msg);
    492 
    493 	if (reply == NULL)
    494 		return PAM_BUF_ERR;
    495 
    496 	for (i = 0; i < num_msg; i++) {
    497 		switch (msg[i]->msg_style) {
    498 		case PAM_PROMPT_ECHO_ON:        /* assume want user name */
    499 			reply[i].resp_retcode = PAM_SUCCESS;
    500 			reply[i].resp = COPY_STRING(cred->uname);
    501 			/* PAM frees resp. */
    502 			break;
    503 		case PAM_PROMPT_ECHO_OFF:       /* assume want password */
    504 			reply[i].resp_retcode = PAM_SUCCESS;
    505 			reply[i].resp = COPY_STRING(cred->pass);
    506 			/* PAM frees resp. */
    507 			break;
    508 		case PAM_TEXT_INFO:
    509 		case PAM_ERROR_MSG:
    510 			reply[i].resp_retcode = PAM_SUCCESS;
    511 			reply[i].resp = NULL;
    512 			break;
    513 		default:                        /* unknown message style */
    514 			free(reply);
    515 			return PAM_CONV_ERR;
    516 		}
    517 	}
    518 
    519 	*resp = reply;
    520 	return PAM_SUCCESS;
    521 }
    522 
    523 /*
    524  * The PAM version as a side effect may put a new username in *name.
    525  */
    526 static int
    527 check_user(char *name, char *cred)
    528 {
    529 	pam_handle_t *pamh = NULL;
    530 	const void *item;
    531 	int rval;
    532 	int e;
    533 	cred_t auth_cred = { name, cred };
    534 	struct pam_conv conv = { &auth_conv, &auth_cred };
    535 
    536 	e = pam_start("telnetd", name, &conv, &pamh);
    537 	if (e != PAM_SUCCESS) {
    538 		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
    539 		return 0;
    540 	}
    541 
    542 #if 0 /* Where can we find this value? */
    543 	e = pam_set_item(pamh, PAM_RHOST, remotehost);
    544 	if (e != PAM_SUCCESS) {
    545 		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
    546 			pam_strerror(pamh, e));
    547 		return 0;
    548 	}
    549 #endif
    550 
    551 	e = pam_authenticate(pamh, 0);
    552 	switch (e) {
    553 	case PAM_SUCCESS:
    554 		/*
    555 		 * With PAM we support the concept of a "template"
    556 		 * user.  The user enters a login name which is
    557 		 * authenticated by PAM, usually via a remote service
    558 		 * such as RADIUS or TACACS+.  If authentication
    559 		 * succeeds, a different but related "template" name
    560 		 * is used for setting the credentials, shell, and
    561 		 * home directory.  The name the user enters need only
    562 		 * exist on the remote authentication server, but the
    563 		 * template name must be present in the local password
    564 		 * database.
    565 		 *
    566 		 * This is supported by two various mechanisms in the
    567 		 * individual modules.  However, from the application's
    568 		 * point of view, the template user is always passed
    569 		 * back as a changed value of the PAM_USER item.
    570 		 */
    571 		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
    572 		    PAM_SUCCESS) {
    573 			strcpy(name, item);
    574 		} else
    575 			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
    576 			pam_strerror(pamh, e));
    577 		if (isroot(name) && !rootterm(line))
    578 			rval = 0;
    579 		else
    580 			rval = 1;
    581 		break;
    582 
    583 	case PAM_AUTH_ERR:
    584 	case PAM_USER_UNKNOWN:
    585 	case PAM_MAXTRIES:
    586 		rval = 0;
    587 	break;
    588 
    589 	default:
    590 		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
    591 		rval = 0;
    592 		break;
    593 	}
    594 
    595 	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
    596 		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
    597 		rval = 0;
    598 	}
    599 	return rval;
    600 }
    601 
    602 #endif
    603 
    604 #endif /* ENCRYPTION */
    605 #endif /* SRA */
    606