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