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