Merge from vendor branch OPENSSH:
[dragonfly.git] / crypto / telnet / libtelnet / sra.c
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  * $FreeBSD: src/crypto/telnet/libtelnet/sra.c,v 1.1.2.7 2002/05/16 08:46:49 markm Exp $
31  * $DragonFly: src/crypto/telnet/libtelnet/sra.c,v 1.3 2006/01/17 23:50:34 dillon Exp $
32  */
33
34 #ifdef  SRA
35 #ifdef  ENCRYPTION
36 #include <sys/types.h>
37 #include <arpa/telnet.h>
38 #include <pwd.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <ttyent.h>
44
45 #ifndef NOPAM
46 #include <security/pam_appl.h>
47 #else
48 #include <unistd.h>
49 #endif
50
51 #include "auth.h"
52 #include "misc.h"
53 #include "encrypt.h"
54 #include "pk.h"
55
56 char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
57 char *user, *pass, *xuser, *xpass;
58 DesData ck;
59 IdeaData ik;
60
61 #define PASS_SIZE       256
62
63 extern int auth_debug_mode;
64 extern char line[];
65
66 static int sra_valid = 0;
67 static int passwd_sent = 0;
68
69 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
70                                         AUTHTYPE_SRA, };
71
72 #define SRA_KEY 0
73 #define SRA_USER 1
74 #define SRA_CONTINUE 2
75 #define SRA_PASS 3
76 #define SRA_ACCEPT 4
77 #define SRA_REJECT 5
78
79 static int check_user(char *, char *);
80
81 /* support routine to send out authentication message */
82 static int
83 Data(Authenticator *ap, int type, void *d, int c)
84 {
85         unsigned char *p = str_data + 4;
86         unsigned char *cd = (unsigned char *)d;
87
88         if (c == -1)
89                 c = strlen((char *)cd);
90
91         if (auth_debug_mode) {
92                 printf("%s:%d: [%d] (%d)",
93                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
94                         str_data[3],
95                         type, c);
96                 printd(d, c);
97                 printf("\r\n");
98         }
99         *p++ = ap->type;
100         *p++ = ap->way;
101         *p++ = type;
102         while (c-- > 0) {
103                 if ((*p++ = *cd++) == IAC)
104                         *p++ = IAC;
105         }
106         *p++ = IAC;
107         *p++ = SE;
108         if (str_data[3] == TELQUAL_IS)
109                 printsub('>', &str_data[2], p - (&str_data[2]));
110         return(net_write(str_data, p - str_data));
111 }
112
113 int
114 sra_init(Authenticator *ap __unused, int server)
115 {
116         if (server)
117                 str_data[3] = TELQUAL_REPLY;
118         else
119                 str_data[3] = TELQUAL_IS;
120
121         user = (char *)malloc(256);
122         xuser = (char *)malloc(513);
123         pass = (char *)malloc(PASS_SIZE);
124         xpass = (char *)malloc(513);
125
126         if (user == NULL || xuser == NULL || pass == NULL || xpass ==
127         NULL)
128                 return 0; /* malloc failed */
129
130         passwd_sent = 0;
131         
132         genkeys(pka,ska);
133         return(1);
134 }
135
136 /* client received a go-ahead for sra */
137 int
138 sra_send(Authenticator *ap)
139 {
140         /* send PKA */
141
142         if (auth_debug_mode)
143                 printf("Sent PKA to server.\r\n" );
144         printf("Trying SRA secure login:\r\n");
145         if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
146                 if (auth_debug_mode)
147                         printf("Not enough room for authentication data\r\n");
148                 return(0);
149         }
150
151         return(1);
152 }
153
154 /* server received an IS -- could be SRA KEY, USER, or PASS */
155 void
156 sra_is(Authenticator *ap, unsigned char *data, int cnt)
157 {
158         int valid;
159         Session_Key skey;
160
161         if (cnt-- < 1)
162                 goto bad;
163         switch (*data++) {
164
165         case SRA_KEY:
166                 if (cnt < HEXKEYBYTES) {
167                         Data(ap, SRA_REJECT, (void *)0, 0);
168                         auth_finished(ap, AUTH_USER);
169                         if (auth_debug_mode) {
170                                 printf("SRA user rejected for bad PKB\r\n");
171                         }
172                         return;
173                 }
174                 if (auth_debug_mode)
175                         printf("Sent pka\r\n");
176                 if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
177                         if (auth_debug_mode)
178                                 printf("Not enough room\r\n");
179                         return;
180                 }
181                 memcpy(pkb,data,HEXKEYBYTES);
182                 pkb[HEXKEYBYTES] = '\0';
183                 common_key(ska,pkb,&ik,&ck);
184                 return;
185
186         case SRA_USER:
187                 /* decode KAB(u) */
188                 if (cnt > 512) /* Attempted buffer overflow */
189                         break;
190                 memcpy(xuser,data,cnt);
191                 xuser[cnt] = '\0';
192                 pk_decode(xuser,user,&ck);
193                 auth_encrypt_user(user);
194                 Data(ap, SRA_CONTINUE, (void *)0, 0);
195
196                 return;
197
198         case SRA_PASS:
199                 if (cnt > 512) /* Attempted buffer overflow */
200                         break;
201                 /* decode KAB(P) */
202                 memcpy(xpass,data,cnt);
203                 xpass[cnt] = '\0';
204                 pk_decode(xpass,pass,&ck);
205
206                 /* check user's password */
207                 valid = check_user(user,pass);
208
209                 if(valid) {
210                         Data(ap, SRA_ACCEPT, (void *)0, 0);
211                         skey.data = ck;
212                         skey.type = SK_DES;
213                         skey.length = 8;
214                         encrypt_session_key(&skey, 1);
215
216                         sra_valid = 1;
217                         auth_finished(ap, AUTH_VALID);
218                         if (auth_debug_mode) {
219                                 printf("SRA user accepted\r\n");
220                         }
221                 }
222                 else {
223                         Data(ap, SRA_CONTINUE, (void *)0, 0);
224 /*
225                         Data(ap, SRA_REJECT, (void *)0, 0);
226                         sra_valid = 0;
227                         auth_finished(ap, AUTH_REJECT);
228 */
229                         if (auth_debug_mode) {
230                                 printf("SRA user failed\r\n");
231                         }
232                 }
233                 return;
234
235         default:
236                 if (auth_debug_mode)
237                         printf("Unknown SRA option %d\r\n", data[-1]);
238         }
239 bad:
240         Data(ap, SRA_REJECT, 0, 0);
241         sra_valid = 0;
242         auth_finished(ap, AUTH_REJECT);
243 }
244
245 /* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
246 void
247 sra_reply(Authenticator *ap, unsigned char *data, int cnt)
248 {
249         char uprompt[256],tuser[256];
250         Session_Key skey;
251         size_t i;
252
253         if (cnt-- < 1)
254                 return;
255         switch (*data++) {
256
257         case SRA_KEY:
258                 /* calculate common key */
259                 if (cnt < HEXKEYBYTES) {
260                         if (auth_debug_mode) {
261                                 printf("SRA user rejected for bad PKB\r\n");
262                         }
263                         return;
264                 }
265                 memcpy(pkb,data,HEXKEYBYTES);
266                 pkb[HEXKEYBYTES] = '\0';                
267
268                 common_key(ska,pkb,&ik,&ck);
269
270         enc_user:
271
272                 /* encode user */
273                 memset(tuser,0,sizeof(tuser));
274                 sprintf(uprompt,"User (%s): ",UserNameRequested);
275                 telnet_gets(uprompt,tuser,255,1);
276                 if (tuser[0] == '\n' || tuser[0] == '\r' )
277                         strcpy(user,UserNameRequested);
278                 else {
279                         /* telnet_gets leaves the newline on */
280                         for(i=0;i<sizeof(tuser);i++) {
281                                 if (tuser[i] == '\n') {
282                                         tuser[i] = '\0';
283                                         break;
284                                 }
285                         }
286                         strcpy(user,tuser);
287                 }
288                 pk_encode(user,xuser,&ck);
289
290                 /* send it off */
291                 if (auth_debug_mode)
292                         printf("Sent KAB(U)\r\n");
293                 if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
294                         if (auth_debug_mode)
295                                 printf("Not enough room\r\n");
296                         return;
297                 }
298                 break;
299
300         case SRA_CONTINUE:
301                 if (passwd_sent) {
302                         passwd_sent = 0;
303                         printf("[ SRA login failed ]\r\n");
304                         goto enc_user;
305                 }
306                 /* encode password */
307                 memset(pass,0,PASS_SIZE);
308                 telnet_gets("Password: ",pass,PASS_SIZE-1,0);
309                 pk_encode(pass,xpass,&ck);
310                 /* send it off */
311                 if (auth_debug_mode)
312                         printf("Sent KAB(P)\r\n");
313                 if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
314                         if (auth_debug_mode)
315                                 printf("Not enough room\r\n");
316                         return;
317                 }
318                 passwd_sent = 1;
319                 break;
320
321         case SRA_REJECT:
322                 printf("[ SRA refuses authentication ]\r\n");
323                 printf("Trying plaintext login:\r\n");
324                 auth_finished(0,AUTH_REJECT);
325                 return;
326
327         case SRA_ACCEPT:
328                 printf("[ SRA accepts you ]\r\n");
329                 skey.data = ck;
330                 skey.type = SK_DES;
331                 skey.length = 8;
332                 encrypt_session_key(&skey, 0);
333
334                 auth_finished(ap, AUTH_VALID);
335                 return;
336         default:
337                 if (auth_debug_mode)
338                         printf("Unknown SRA option %d\r\n", data[-1]);
339                 return;
340         }
341 }
342
343 int
344 sra_status(Authenticator *ap __unused, char *name, int level)
345 {
346         if (level < AUTH_USER)
347                 return(level);
348         if (UserNameRequested && sra_valid) {
349                 strcpy(name, UserNameRequested);
350                 return(AUTH_VALID);
351         } else
352                 return(AUTH_USER);
353 }
354
355 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
356 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
357
358 void
359 sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
360 {
361         char lbuf[32];
362         int i;
363
364         buf[buflen-1] = '\0';           /* make sure its NULL terminated */
365         buflen -= 1;
366
367         switch(data[3]) {
368
369         case SRA_CONTINUE:
370                 strncpy((char *)buf, " CONTINUE ", buflen);
371                 goto common;
372
373         case SRA_REJECT:                /* Rejected (reason might follow) */
374                 strncpy((char *)buf, " REJECT ", buflen);
375                 goto common;
376
377         case SRA_ACCEPT:                /* Accepted (name might follow) */
378                 strncpy((char *)buf, " ACCEPT ", buflen);
379
380         common:
381                 BUMP(buf, buflen);
382                 if (cnt <= 4)
383                         break;
384                 ADDC(buf, buflen, '"');
385                 for (i = 4; i < cnt; i++)
386                         ADDC(buf, buflen, data[i]);
387                 ADDC(buf, buflen, '"');
388                 ADDC(buf, buflen, '\0');
389                 break;
390
391         case SRA_KEY:                   /* Authentication data follows */
392                 strncpy((char *)buf, " KEY ", buflen);
393                 goto common2;
394
395         case SRA_USER:
396                 strncpy((char *)buf, " USER ", buflen);
397                 goto common2;
398
399         case SRA_PASS:
400                 strncpy((char *)buf, " PASS ", buflen);
401                 goto common2;
402
403         default:
404                 sprintf(lbuf, " %d (unknown)", data[3]);
405                 strncpy((char *)buf, lbuf, buflen);
406         common2:
407                 BUMP(buf, buflen);
408                 for (i = 4; i < cnt; i++) {
409                         sprintf(lbuf, " %d", data[i]);
410                         strncpy((char *)buf, lbuf, buflen);
411                         BUMP(buf, buflen);
412                 }
413                 break;
414         }
415 }
416
417 static int
418 isroot(const char *usr)
419 {
420         struct passwd *pwd;
421
422         if ((pwd=getpwnam(usr))==NULL)
423                 return 0;
424         return (!pwd->pw_uid);
425 }
426
427 static int
428 rootterm(char *ttyn)
429 {
430         struct ttyent *t;
431
432         return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
433 }
434
435 #ifdef NOPAM
436 static int
437 check_user(char *name, char *cred)
438 {
439         char *cp;
440         char *xpasswd, *salt;
441
442         if (isroot(name) && !rootterm(line))
443         {
444                 crypt("AA","*"); /* Waste some time to simulate success */
445                 return(0);
446         }
447
448         if (pw = sgetpwnam(name)) {
449                 if (pw->pw_shell == NULL) {
450                         pw = (struct passwd *) NULL;
451                         return(0);
452                 }
453
454                 salt = pw->pw_passwd;
455                 xpasswd = crypt(cred, salt);
456                 /* The strcmp does not catch null passwords! */
457                 if (pw == NULL || *pw->pw_passwd == '\0' ||
458                         strcmp(xpasswd, pw->pw_passwd)) {
459                         pw = (struct passwd *) NULL;
460                         return(0);
461                 }
462                 return(1);
463         }
464         return(0);
465 }
466 #else
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
484 auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
485 {
486         int i;
487         cred_t *cred = (cred_t *) appdata;
488         struct pam_response *reply =
489                 malloc(sizeof(struct pam_response) * 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
525 check_user(char *name, 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, &item)) ==
570                     PAM_SUCCESS) {
571                         strcpy(name, item);
572                 } else
573                         syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
574                         pam_strerror(pamh, e));
575                 if (isroot(name) && !rootterm(line))
576                         rval = 0;
577                 else
578                         rval = 1;
579                 break;
580
581         case PAM_AUTH_ERR:
582         case PAM_USER_UNKNOWN:
583         case PAM_MAXTRIES:
584                 rval = 0;
585         break;
586
587         default:
588                 syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
589                 rval = 0;
590                 break;
591         }
592
593         if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
594                 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
595                 rval = 0;
596         }
597         return rval;
598 }
599
600 #endif
601
602 #endif /* ENCRYPTION */
603 #endif /* SRA */