nvmm: Port to DragonFly #14: device & module operations
[dragonfly.git] / lib / 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  * $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
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
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
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
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
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
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
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
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
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
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
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
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 */