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
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
31 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD: src/contrib/telnet/libtelnet/sra.c,v 1.16 2002/05/06 09:48:02 markm Exp $");
35 __RCSID("$NetBSD: sra.c,v 1.11 2012/01/09 15:25:34 christos Exp $");
40 #include <sys/types.h>
41 #include <arpa/telnet.h>
51 #include <security/pam_appl.h>
61 char pka
[HEXKEYBYTES
+1], ska
[HEXKEYBYTES
+1], pkb
[HEXKEYBYTES
+1];
62 char *user
, *pass
, *xuser
, *xpass
;
63 char *passprompt
, *xpassprompt
;
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,
77 #define XSMALL_LEN 513
80 #define SRA_CONTINUE 2
85 static int check_user(char *, const char *);
87 /* support routine to send out authentication message */
89 Data(Authenticator
*ap
, int type
, void *d
, int c
)
91 unsigned char *p
= str_data
+ 4;
92 unsigned char *cd
= d
;
97 if (auth_debug_mode
) {
98 printf("%s:%d: [%d] (%d)",
99 str_data
[3] == TELQUAL_IS
? ">>>IS" : ">>>REPLY",
100 str_data
[3], type
, c
);
108 if ((*p
++ = *cd
++) == IAC
)
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
);
119 sra_init(Authenticator
*ap __unused
, int server
)
122 str_data
[3] = TELQUAL_REPLY
;
124 str_data
[3] = TELQUAL_IS
;
126 user
= malloc(SMALL_LEN
);
127 xuser
= malloc(XSMALL_LEN
);
128 pass
= malloc(SMALL_LEN
);
129 xpass
= malloc(XSMALL_LEN
);
130 passprompt
= malloc(SMALL_LEN
);
131 xpassprompt
= malloc(XSMALL_LEN
);
133 if (user
== NULL
|| xuser
== NULL
|| pass
== NULL
|| xpass
==
134 NULL
|| passprompt
== NULL
|| xpassprompt
== NULL
)
135 return 0; /* malloc failed */
143 /* client received a go-ahead for sra */
145 sra_send(Authenticator
*ap
)
150 printf("Sent PKA to server.\r\n" );
151 printf("Trying SRA secure login:\r\n");
152 if (!Data(ap
, SRA_KEY
, (void *)pka
, HEXKEYBYTES
)) {
154 printf("Not enough room for authentication data\r\n");
161 /* server received an IS -- could be SRA KEY, USER, or PASS */
163 sra_is(Authenticator
*ap
, unsigned char *data
, int cnt
)
173 if (cnt
< HEXKEYBYTES
) {
174 Data(ap
, SRA_REJECT
, (void *)0, 0);
175 auth_finished(ap
, AUTH_USER
);
176 if (auth_debug_mode
) {
177 printf("SRA user rejected for bad PKB\r\n");
182 printf("Sent pka\r\n");
183 if (!Data(ap
, SRA_KEY
, (void *)pka
, HEXKEYBYTES
)) {
185 printf("Not enough room\r\n");
188 memcpy(pkb
, data
, HEXKEYBYTES
);
189 pkb
[HEXKEYBYTES
] = '\0';
190 common_key(ska
, pkb
, &ik
, &ck
);
195 if (cnt
> XSMALL_LEN
- 1) /* Attempted buffer overflow */
197 memcpy(xuser
, data
, cnt
);
199 pk_decode(xuser
, user
, &ck
);
200 auth_encrypt_user(user
);
202 (void)check_user(user
, "*");
204 pk_encode(passprompt
, xpassprompt
, &ck
);
205 Data(ap
, SRA_CONTINUE
, xpassprompt
, XSMALL_LEN
- 1);
210 if (cnt
> XSMALL_LEN
- 1) /* Attempted buffer overflow */
213 memcpy(xpass
, data
, cnt
);
215 pk_decode(xpass
, pass
, &ck
);
217 /* check user's password */
218 valid
= check_user(user
, pass
);
221 /* PAM (via check_user()) may have changed 'user' */
222 auth_encrypt_user(user
);
223 Data(ap
, SRA_ACCEPT
, (void *)0, 0);
227 encrypt_session_key(&skey
, 1);
230 auth_finished(ap
, AUTH_VALID
);
231 if (auth_debug_mode
) {
232 printf("SRA user accepted\r\n");
236 pk_encode(passprompt
, xpassprompt
, &ck
);
237 Data(ap
, SRA_CONTINUE
, (void *)xpassprompt
,
239 if (auth_debug_mode
) {
240 printf("SRA user failed\r\n");
247 printf("Unknown SRA option %d\r\n", data
[-1]);
250 Data(ap
, SRA_REJECT
, 0, 0);
252 auth_finished(ap
, AUTH_REJECT
);
255 /* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
257 sra_reply(Authenticator
*ap
, unsigned char *data
, int cnt
)
259 char uprompt
[SMALL_LEN
], tuser
[SMALL_LEN
];
268 /* calculate common key */
269 if (cnt
< HEXKEYBYTES
) {
270 if (auth_debug_mode
) {
271 printf("SRA user rejected for bad PKB\r\n");
275 memcpy(pkb
, data
, HEXKEYBYTES
);
276 pkb
[HEXKEYBYTES
] = '\0';
278 common_key(ska
, pkb
, &ik
, &ck
);
283 memset(tuser
, 0, sizeof(tuser
));
284 snprintf(uprompt
, sizeof(uprompt
), "User (%s): ",
286 if (telnet_gets(uprompt
, tuser
, SMALL_LEN
- 1, 1) == NULL
) {
290 if (tuser
[0] == '\n' || tuser
[0] == '\r' )
291 strlcpy(user
, UserNameRequested
, SMALL_LEN
);
293 /* telnet_gets leaves the newline on */
294 for(i
= 0; i
< sizeof(tuser
); i
++) {
295 if (tuser
[i
] == '\n') {
300 strlcpy(user
, tuser
, SMALL_LEN
);
302 pk_encode(user
, xuser
, &ck
);
306 printf("Sent KAB(U)\r\n");
307 if (!Data(ap
, SRA_USER
, (void *)xuser
, strlen(xuser
))) {
309 printf("Not enough room\r\n");
317 printf("[ SRA login failed ]\r\n");
320 if (cnt
> XSMALL_LEN
- 1) {
322 } else if (cnt
> 0) {
323 (void)memcpy(xpassprompt
, data
, cnt
);
324 pk_decode(xpassprompt
, passprompt
, &ck
);
326 (void)strlcpy(passprompt
, "Password: ", SMALL_LEN
);
328 /* encode password */
329 memset(pass
, 0, SMALL_LEN
);
330 if (telnet_gets(passprompt
, pass
, SMALL_LEN
- 1, 0) == NULL
) {
334 pk_encode(pass
, xpass
, &ck
);
337 printf("Sent KAB(P)\r\n");
338 if (!Data(ap
, SRA_PASS
, (void *)xpass
, strlen(xpass
))) {
340 printf("Not enough room\r\n");
347 printf("[ SRA refuses authentication ]\r\n");
348 printf("Trying plaintext login:\r\n");
349 auth_finished(0, AUTH_REJECT
);
353 printf("[ SRA accepts you ]\r\n");
357 encrypt_session_key(&skey
, 0);
359 auth_finished(ap
, AUTH_VALID
);
363 printf("Unknown SRA option %d\r\n", data
[-1]);
369 sra_status(Authenticator
*ap __unused
, char *name
, size_t len
, int level
)
371 if (level
< AUTH_USER
)
373 if (UserNameRequested
&& sra_valid
) {
374 strlcpy(name
, UserNameRequested
, len
);
380 #define BUMP(buf, len) while (*(buf)) { ++(buf), --(len); }
381 #define ADDC(buf, len, c) if ((len) > 0) { *(buf)++ = (c); --(len); }
384 sra_printsub(unsigned char *data
, int cnt
, unsigned char *ubuf
, int buflen
)
386 char lbuf
[32], *buf
= (char *)ubuf
;
389 buf
[buflen
- 1] = '\0'; /* make sure its NULL terminated */
395 strncpy(buf
, " CONTINUE ", buflen
);
398 case SRA_REJECT
: /* Rejected (reason might follow) */
399 strncpy(buf
, " REJECT ", buflen
);
402 case SRA_ACCEPT
: /* Accepted (name might follow) */
403 strncpy(buf
, " ACCEPT ", buflen
);
409 ADDC(buf
, buflen
, '"');
410 for (i
= 4; i
< cnt
; i
++)
411 ADDC(buf
, buflen
, data
[i
]);
412 ADDC(buf
, buflen
, '"');
413 ADDC(buf
, buflen
, '\0');
416 case SRA_KEY
: /* Authentication data follows */
417 strncpy(buf
, " KEY ", buflen
);
421 strncpy(buf
, " USER ", buflen
);
425 strncpy(buf
, " PASS ", buflen
);
429 snprintf(lbuf
, sizeof(lbuf
), " %d (unknown)", data
[3]);
430 strncpy(buf
, lbuf
, buflen
);
433 for (i
= 4; i
< cnt
; i
++) {
434 snprintf(lbuf
, sizeof(lbuf
), " %d", data
[i
]);
435 strncpy(buf
, lbuf
, buflen
);
444 isroot(const char *usr
)
446 struct passwd pws
, *pwd
;
449 if (getpwnam_r(usr
, &pws
, pwbuf
, sizeof(pwbuf
), &pwd
) != 0 ||
452 return (!pwd
->pw_uid
);
456 rootterm(const char *ttyname
)
462 if (strncmp(ttyn
, _PATH_DEV
, sizeof(_PATH_DEV
) - 1) == 0)
463 ttyn
+= sizeof(_PATH_DEV
) - 1;
465 return ((t
= getttynam(ttyn
)) && t
->ty_status
& TTY_SECURE
);
469 check_user(char *name
, const char *cred
)
471 struct passwd pws
, *pw
;
473 char *xpasswd
, *salt
;
475 if (isroot(name
) && !rootterm(line
))
477 crypt("AA", "*"); /* Waste some time to simulate success */
481 if (getpwnam_r(name
, &pws
, pwbuf
, sizeof(pwbuf
), &pw
) == 0 &&
483 if (pw
->pw_shell
== NULL
) {
487 salt
= pw
->pw_passwd
;
488 xpasswd
= crypt(cred
, salt
);
489 /* The strcmp does not catch null passwords! */
490 if (*pw
->pw_passwd
== '\0' || strcmp(xpasswd
, pw
->pw_passwd
)) {
500 * The following is stolen from ftpd, which stole it from the imap-uw
501 * PAM module and login.c. It is needed because we can't really
502 * "converse" with the user, having already gone to the trouble of
503 * getting their username and password through an encrypted channel.
506 #define COPY_STRING(s) (s ? strdup(s) : NULL)
512 typedef struct cred_t cred_t
;
515 auth_conv(int num_msg
, const struct pam_message
**msg
,
516 struct pam_response
**resp
, void *appdata
)
519 cred_t
*cred
= appdata
;
520 struct pam_response
*reply
= malloc(sizeof(*reply
) * num_msg
);
525 for (i
= 0; i
< num_msg
; i
++) {
526 switch (msg
[i
]->msg_style
) {
527 case PAM_PROMPT_ECHO_ON
: /* assume want user name */
528 reply
[i
].resp_retcode
= PAM_SUCCESS
;
529 reply
[i
].resp
= COPY_STRING(cred
->uname
);
530 /* PAM frees resp. */
532 case PAM_PROMPT_ECHO_OFF
: /* assume want password */
533 (void)strlcpy(passprompt
, msg
[i
]->msg
, SMALL_LEN
);
534 reply
[i
].resp_retcode
= PAM_SUCCESS
;
535 reply
[i
].resp
= COPY_STRING(cred
->pass
);
536 /* PAM frees resp. */
540 reply
[i
].resp_retcode
= PAM_SUCCESS
;
541 reply
[i
].resp
= NULL
;
543 default: /* unknown message style */
554 * The PAM version as a side effect may put a new username in *name.
557 check_user(char *name
, const char *cred
)
559 pam_handle_t
*pamh
= NULL
;
563 cred_t auth_cred
= { name
, cred
};
564 struct pam_conv conv
= { &auth_conv
, &auth_cred
};
566 e
= pam_start("telnetd", name
, &conv
, &pamh
);
567 if (e
!= PAM_SUCCESS
) {
568 syslog(LOG_ERR
, "pam_start: %s", pam_strerror(pamh
, e
));
572 #if 0 /* Where can we find this value? */
573 e
= pam_set_item(pamh
, PAM_RHOST
, remotehost
);
574 if (e
!= PAM_SUCCESS
) {
575 syslog(LOG_ERR
, "pam_set_item(PAM_RHOST): %s",
576 pam_strerror(pamh
, e
));
581 e
= pam_authenticate(pamh
, 0);
585 * With PAM we support the concept of a "template"
586 * user. The user enters a login name which is
587 * authenticated by PAM, usually via a remote service
588 * such as RADIUS or TACACS+. If authentication
589 * succeeds, a different but related "template" name
590 * is used for setting the credentials, shell, and
591 * home directory. The name the user enters need only
592 * exist on the remote authentication server, but the
593 * template name must be present in the local password
596 * This is supported by two various mechanisms in the
597 * individual modules. However, from the application's
598 * point of view, the template user is always passed
599 * back as a changed value of the PAM_USER item.
601 if ((e
= pam_get_item(pamh
, PAM_USER
, &item
)) ==
603 strlcpy(name
, item
, SMALL_LEN
);
605 syslog(LOG_ERR
, "Couldn't get PAM_USER: %s",
606 pam_strerror(pamh
, e
));
607 #if 0 /* pam_securetty(8) should be used to enforce this */
608 if (isroot(name
) && !rootterm(line
))
616 case PAM_USER_UNKNOWN
:
622 syslog(LOG_ERR
, "auth_pam: %s", pam_strerror(pamh
, e
));
627 if ((e
= pam_end(pamh
, e
)) != PAM_SUCCESS
) {
628 syslog(LOG_ERR
, "pam_end: %s", pam_strerror(pamh
, e
));
636 #endif /* ENCRYPTION */