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