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.12 2021/10/30 10:46:57 nia 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 DesData ck;
65 IdeaData ik;
66 
67 extern int auth_debug_mode;
68 extern char *line;            /* see sys_term.c */
69 
70 static int sra_valid = 0;
71 static int passwd_sent = 0;
72 
73 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
74                                                   AUTHTYPE_SRA, };
75 
76 #define SMALL_LEN   256
77 #define XSMALL_LEN  513
78 #define SRA_KEY     0
79 #define SRA_USER 1
80 #define SRA_CONTINUE 2
81 #define SRA_PASS 3
82 #define SRA_ACCEPT 4
83 #define SRA_REJECT 5
84 
85 static int check_user(char *, const char *);
86 
87 /* support routine to send out authentication message */
88 static int
Data(Authenticator * ap,int type,void * d,int c)89 Data(Authenticator *ap, int type, void *d, int c)
90 {
91         unsigned char *p = str_data + 4;
92           unsigned char *cd = d;
93 
94           if (c == -1)
95                     c = strlen(d);
96 
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);
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
sra_init(Authenticator * ap __unused,int server)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 = 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);
132 
133           if (user == NULL || xuser == NULL || pass == NULL || xpass ==
134               NULL || passprompt == NULL || xpassprompt == NULL)
135                     return 0; /* malloc failed */
136 
137           passwd_sent = 0;
138 
139           genkeys(pka, ska);
140           return 1;
141 }
142 
143 /* client received a go-ahead for sra */
144 int
sra_send(Authenticator * ap)145 sra_send(Authenticator *ap)
146 {
147           /* send PKA */
148 
149           if (auth_debug_mode)
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)) {
153                     if (auth_debug_mode)
154                               printf("Not enough room for authentication data\r\n");
155                     return 0;
156           }
157 
158           return 1;
159 }
160 
161 /* server received an IS -- could be SRA KEY, USER, or PASS */
162 void
sra_is(Authenticator * ap,unsigned char * data,int cnt)163 sra_is(Authenticator *ap, unsigned char *data, int cnt)
164 {
165           int valid;
166           Session_Key skey;
167 
168           if (cnt-- < 1)
169                     goto bad;
170           switch (*data++) {
171 
172           case SRA_KEY:
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");
178                               }
179                               return;
180                     }
181                     if (auth_debug_mode)
182                               printf("Sent pka\r\n");
183                     if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
184                               if (auth_debug_mode)
185                                         printf("Not enough room\r\n");
186                               return;
187                     }
188                     memcpy(pkb, data, HEXKEYBYTES);
189                     pkb[HEXKEYBYTES] = '\0';
190                     common_key(ska, pkb, &ik, &ck);
191                     return;
192 
193           case SRA_USER:
194                     /* decode KAB(u) */
195                     if (cnt > XSMALL_LEN - 1) /* Attempted buffer overflow */
196                               break;
197                     memcpy(xuser, data, cnt);
198                     xuser[cnt] = '\0';
199                     pk_decode(xuser, user, &ck);
200                     auth_encrypt_user(user);
201 #ifndef NOPAM
202                     (void)check_user(user, "*");
203 #endif
204                     pk_encode(passprompt, xpassprompt, &ck);
205                     Data(ap, SRA_CONTINUE, xpassprompt, XSMALL_LEN - 1);
206 
207                     return;
208 
209           case SRA_PASS:
210                     if (cnt > XSMALL_LEN - 1) /* Attempted buffer overflow */
211                               break;
212                     /* decode KAB(P) */
213                     memcpy(xpass, data, cnt);
214                     xpass[cnt] = '\0';
215                     pk_decode(xpass, pass, &ck);
216 
217                     /* check user's password */
218                     valid = check_user(user, pass);
219 
220                     if(valid) {
221                               /* PAM (via check_user()) may have changed 'user' */
222                               auth_encrypt_user(user);
223                               Data(ap, SRA_ACCEPT, (void *)0, 0);
224                               skey.data = ck;
225                               skey.type = SK_DES;
226                               skey.length = 8;
227                               encrypt_session_key(&skey, 1);
228 
229                               sra_valid = 1;
230                               auth_finished(ap, AUTH_VALID);
231                               if (auth_debug_mode) {
232                                         printf("SRA user accepted\r\n");
233                               }
234                     }
235                     else {
236                               pk_encode(passprompt, xpassprompt, &ck);
237                               Data(ap, SRA_CONTINUE, (void *)xpassprompt,
238                                   XSMALL_LEN - 1);
239                               if (auth_debug_mode) {
240                                         printf("SRA user failed\r\n");
241                               }
242                     }
243                     return;
244 
245           default:
246                     if (auth_debug_mode)
247                               printf("Unknown SRA option %d\r\n", data[-1]);
248           }
249 bad:
250           Data(ap, SRA_REJECT, 0, 0);
251           sra_valid = 0;
252           auth_finished(ap, AUTH_REJECT);
253 }
254 
255 /* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
256 void
sra_reply(Authenticator * ap,unsigned char * data,int cnt)257 sra_reply(Authenticator *ap, unsigned char *data, int cnt)
258 {
259           char uprompt[SMALL_LEN], tuser[SMALL_LEN];
260           Session_Key skey;
261           size_t i;
262 
263           if (cnt-- < 1)
264                     return;
265           switch (*data++) {
266 
267           case SRA_KEY:
268                     /* calculate common key */
269                     if (cnt < HEXKEYBYTES) {
270                               if (auth_debug_mode) {
271                                         printf("SRA user rejected for bad PKB\r\n");
272                               }
273                               return;
274                     }
275                     memcpy(pkb, data, HEXKEYBYTES);
276                     pkb[HEXKEYBYTES] = '\0';
277 
278                     common_key(ska, pkb, &ik, &ck);
279 
280           enc_user:
281 
282                     /* encode user */
283                     memset(tuser, 0, sizeof(tuser));
284                     snprintf(uprompt, sizeof(uprompt), "User (%s): ",
285                         UserNameRequested);
286                     if (telnet_gets(uprompt, tuser, SMALL_LEN - 1, 1) == NULL) {
287                               printf("\n");
288                               exit(1);
289                     }
290                     if (tuser[0] == '\n' || tuser[0] == '\r' )
291                               strlcpy(user, UserNameRequested, SMALL_LEN);
292                     else {
293                               /* telnet_gets leaves the newline on */
294                               for(i = 0; i < sizeof(tuser); i++) {
295                                         if (tuser[i] == '\n') {
296                                                   tuser[i] = '\0';
297                                                   break;
298                                         }
299                               }
300                               strlcpy(user, tuser, SMALL_LEN);
301                     }
302                     pk_encode(user, xuser, &ck);
303 
304                     /* send it off */
305                     if (auth_debug_mode)
306                               printf("Sent KAB(U)\r\n");
307                     if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
308                               if (auth_debug_mode)
309                                         printf("Not enough room\r\n");
310                               return;
311                     }
312                     break;
313 
314           case SRA_CONTINUE:
315                     if (passwd_sent) {
316                               passwd_sent = 0;
317                               printf("[ SRA login failed ]\r\n");
318                               goto enc_user;
319                     }
320                     if (cnt > XSMALL_LEN - 1) {
321                               break;
322                     } else if (cnt > 0) {
323                               (void)memcpy(xpassprompt, data, cnt);
324                               pk_decode(xpassprompt, passprompt, &ck);
325                     } else {
326                               (void)strlcpy(passprompt, "Password: ", SMALL_LEN);
327                     }
328                     /* encode password */
329                     memset(pass, 0, SMALL_LEN);
330                     if (telnet_gets(passprompt, pass, SMALL_LEN - 1, 0) == NULL) {
331                               printf("\n");
332                               exit(1);
333                     }
334                     pk_encode(pass, xpass, &ck);
335                     /* send it off */
336                     if (auth_debug_mode)
337                               printf("Sent KAB(P)\r\n");
338                     if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
339                               if (auth_debug_mode)
340                                         printf("Not enough room\r\n");
341                               return;
342                     }
343                     passwd_sent = 1;
344                     break;
345 
346           case SRA_REJECT:
347                     printf("[ SRA refuses authentication ]\r\n");
348                     printf("Trying plaintext login:\r\n");
349                     auth_finished(0, AUTH_REJECT);
350                     return;
351 
352           case SRA_ACCEPT:
353                     printf("[ SRA accepts you ]\r\n");
354                     skey.data = ck;
355                     skey.type = SK_DES;
356                     skey.length = 8;
357                     encrypt_session_key(&skey, 0);
358 
359                     auth_finished(ap, AUTH_VALID);
360                     return;
361           default:
362                     if (auth_debug_mode)
363                               printf("Unknown SRA option %d\r\n", data[-1]);
364                     return;
365           }
366 }
367 
368 int
sra_status(Authenticator * ap __unused,char * name,size_t len,int level)369 sra_status(Authenticator *ap __unused, char *name, size_t len, int level)
370 {
371           if (level < AUTH_USER)
372                     return level;
373           if (UserNameRequested && sra_valid) {
374                     strlcpy(name, UserNameRequested, len);
375                     return AUTH_VALID;
376           } else
377                     return AUTH_USER;
378 }
379 
380 #define   BUMP(buf, len)                while (*(buf)) { ++(buf), --(len); }
381 #define   ADDC(buf, len, c)   if ((len) > 0) { *(buf)++ = (c); --(len); }
382 
383 void
sra_printsub(unsigned char * data,int cnt,unsigned char * ubuf,int buflen)384 sra_printsub(unsigned char *data, int cnt, unsigned char *ubuf, int buflen)
385 {
386           char lbuf[32], *buf = (char *)ubuf;
387           int i;
388 
389           buf[buflen - 1] = '\0';                 /* make sure its NULL terminated */
390           buflen -= 1;
391 
392           switch(data[3]) {
393 
394           case SRA_CONTINUE:
395                     strncpy(buf, " CONTINUE ", buflen);
396                     goto common;
397 
398           case SRA_REJECT:              /* Rejected (reason might follow) */
399                     strncpy(buf, " REJECT ", buflen);
400                     goto common;
401 
402           case SRA_ACCEPT:              /* Accepted (name might follow) */
403                     strncpy(buf, " ACCEPT ", buflen);
404 
405           common:
406                     BUMP(buf, buflen);
407                     if (cnt <= 4)
408                               break;
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');
414                     break;
415 
416           case SRA_KEY:                           /* Authentication data follows */
417                     strncpy(buf, " KEY ", buflen);
418                     goto common2;
419 
420           case SRA_USER:
421                     strncpy(buf, " USER ", buflen);
422                     goto common2;
423 
424           case SRA_PASS:
425                     strncpy(buf, " PASS ", buflen);
426                     goto common2;
427 
428           default:
429                     snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[3]);
430                     strncpy(buf, lbuf, buflen);
431           common2:
432                     BUMP(buf, buflen);
433                     for (i = 4; i < cnt; i++) {
434                               snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
435                               strncpy(buf, lbuf, buflen);
436                               BUMP(buf, buflen);
437                     }
438                     break;
439           }
440 }
441 
442 #ifdef NOPAM
443 static int
isroot(const char * usr)444 isroot(const char *usr)
445 {
446           struct passwd pws, *pwd;
447           char pwbuf[1024];
448 
449           if (getpwnam_r(usr, &pws, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
450               pwd == NULL)
451                     return 0;
452           return (!pwd->pw_uid);
453 }
454 
455 static int
rootterm(const char * ttyname)456 rootterm(const char *ttyname)
457 {
458           struct ttyent *t;
459           const char *ttyn;
460 
461           ttyn = ttyname;
462           if (strncmp(ttyn, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
463                     ttyn += sizeof(_PATH_DEV) - 1;
464 
465           return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
466 }
467 
468 static int
check_user(char * name,const char * cred)469 check_user(char *name, const char *cred)
470 {
471           struct passwd pws, *pw;
472           char pwbuf[1024];
473           char *xpasswd, *salt;
474 
475           if (isroot(name) && !rootterm(line))
476           {
477                     crypt("AA", "*"); /* Waste some time to simulate success */
478                     return 0;
479           }
480 
481           if (getpwnam_r(name, &pws, pwbuf, sizeof(pwbuf), &pw) == 0 &&
482               pw != NULL) {
483                     if (pw->pw_shell == NULL) {
484                               return 0;
485                     }
486 
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)) {
491                               return 0;
492                     }
493                     return 1;
494           }
495           return 0;
496 }
497 #else     /* !NOPAM */
498 
499 /*
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.
504  */
505 
506 #define COPY_STRING(s) (s ? strdup(s) : NULL)
507 
508 struct cred_t {
509           const char *uname;
510           const char *pass;
511 };
512 typedef struct cred_t cred_t;
513 
514 static int
auth_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata)515 auth_conv(int num_msg, const struct pam_message **msg,
516     struct pam_response **resp, void *appdata)
517 {
518           int i;
519           cred_t *cred = appdata;
520           struct pam_response *reply = NULL;
521 
522           if (reallocarr(&reply, num_msg, sizeof(*reply)) != 0)
523                     return PAM_BUF_ERR;
524 
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. */
531                               break;
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. */
537                         break;
538                     case PAM_TEXT_INFO:
539                     case PAM_ERROR_MSG:
540                               reply[i].resp_retcode = PAM_SUCCESS;
541                               reply[i].resp = NULL;
542                               break;
543                     default:                        /* unknown message style */
544                               free(reply);
545                               return PAM_CONV_ERR;
546                     }
547           }
548 
549           *resp = reply;
550           return PAM_SUCCESS;
551 }
552 
553 /*
554  * The PAM version as a side effect may put a new username in *name.
555  */
556 static int
check_user(char * name,const char * cred)557 check_user(char *name, const char *cred)
558 {
559           pam_handle_t *pamh = NULL;
560           const void *item;
561           int rval;
562           int e;
563           cred_t auth_cred = { name, cred };
564           struct pam_conv conv = { &auth_conv, &auth_cred };
565 
566           e = pam_start("telnetd", name, &conv, &pamh);
567           if (e != PAM_SUCCESS) {
568                     syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
569                     return 0;
570           }
571 
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));
577                     return 0;
578           }
579 #endif
580 
581           e = pam_authenticate(pamh, 0);
582           switch (e) {
583           case PAM_SUCCESS:
584                     /*
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
594                      * database.
595                      *
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.
600                      */
601                     if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
602                         PAM_SUCCESS) {
603                               strlcpy(name, item, SMALL_LEN);
604                     } else
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))
609                               rval = 0;
610                     else
611 #endif
612                               rval = 1;
613                     break;
614 
615           case PAM_AUTH_ERR:
616           case PAM_USER_UNKNOWN:
617           case PAM_MAXTRIES:
618                     rval = 0;
619           break;
620 
621           default:
622                     syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
623                     rval = 0;
624                     break;
625           }
626 
627           if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
628                     syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
629                     rval = 0;
630           }
631           return rval;
632 }
633 
634 #endif /* !NOPAM */
635 
636 #endif /* ENCRYPTION */
637 #endif /* SRA */
638