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