Oh GACK! src-clean doesn't quite work that easily since cleandist rebuilds the
[unix-history] / lib / libtelnet / auth.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * 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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)auth.c 5.2 (Berkeley) 3/22/91";
36#endif /* not lint */
37
38/*
39 * Copyright (C) 1990 by the Massachusetts Institute of Technology
40 *
41 * Export of this software from the United States of America is assumed
42 * to require a specific license from the United States Government.
43 * It is the responsibility of any person or organization contemplating
44 * export to obtain such a license before exporting.
45 *
46 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
47 * distribute this software and its documentation for any purpose and
48 * without fee is hereby granted, provided that the above copyright
49 * notice appear in all copies and that both that copyright notice and
50 * this permission notice appear in supporting documentation, and that
51 * the name of M.I.T. not be used in advertising or publicity pertaining
52 * to distribution of the software without specific, written prior
53 * permission. M.I.T. makes no representations about the suitability of
54 * this software for any purpose. It is provided "as is" without express
55 * or implied warranty.
56 */
57
58
59#if defined(AUTHENTICATE)
60#include <stdio.h>
61#include <sys/types.h>
62#include <signal.h>
63#define AUTH_NAMES
64#include <arpa/telnet.h>
65#ifdef __STDC__
66#include <stdlib.h>
67#endif
68#ifdef NO_STRING_H
69#include <strings.h>
70#else
71#include <string.h>
72#endif
73
74#include "encrypt.h"
75#include "auth.h"
76#include "misc-proto.h"
77#include "auth-proto.h"
78
79#define typemask(x) (1<<((x)-1))
80
81int auth_debug_mode = 0;
82static char *Name = "Noname";
83static int Server = 0;
84static Authenticator *authenticated = 0;
85static int authenticating = 0;
86static int validuser = 0;
87static unsigned char _auth_send_data[256];
88static unsigned char *auth_send_data;
89static int auth_send_cnt = 0;
90
91/*
92 * Authentication types supported. Plese note that these are stored
93 * in priority order, i.e. try the first one first.
94 */
95Authenticator authenticators[] = {
96#ifdef KRB5
97 { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
98 kerberos5_init,
99 kerberos5_send,
100 kerberos5_is,
101 kerberos5_reply,
102 kerberos5_status,
103 kerberos5_printsub },
104 { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
105 kerberos5_init,
106 kerberos5_send,
107 kerberos5_is,
108 kerberos5_reply,
109 kerberos5_status,
110 kerberos5_printsub },
111#endif
112#ifdef KRB4
113 { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
114 kerberos4_init,
115 kerberos4_send,
116 kerberos4_is,
117 kerberos4_reply,
118 kerberos4_status,
119 kerberos4_printsub },
120 { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
121 kerberos4_init,
122 kerberos4_send,
123 kerberos4_is,
124 kerberos4_reply,
125 kerberos4_status,
126 kerberos4_printsub },
127#endif
128 { 0, },
129};
130
131static Authenticator NoAuth = { 0 };
132
133static int i_support = 0;
134static int i_wont_support = 0;
135
136 Authenticator *
137findauthenticator(type, way)
138 int type;
139 int way;
140{
141 Authenticator *ap = authenticators;
142
143 while (ap->type && (ap->type != type || ap->way != way))
144 ++ap;
145 return(ap->type ? ap : 0);
146}
147
148 void
149auth_init(name, server)
150 char *name;
151 int server;
152{
153 Authenticator *ap = authenticators;
154
155 Server = server;
156 Name = name;
157
158 i_support = 0;
159 authenticated = 0;
160 authenticating = 0;
161 while (ap->type) {
162 if (!ap->init || (*ap->init)(ap, server)) {
163 i_support |= typemask(ap->type);
164 if (auth_debug_mode)
165 printf(">>>%s: I support auth type %d %d\r\n",
166 Name,
167 ap->type, ap->way);
168 }
169 ++ap;
170 }
171}
172
173 void
174auth_disable_name(name)
175 char *name;
176{
177 int x;
178 for (x = 0; x < AUTHTYPE_CNT; ++x) {
179 if (!strcasecmp(name, AUTHTYPE_NAME(x))) {
180 i_wont_support |= typemask(x);
181 break;
182 }
183 }
184}
185
186 int
187getauthmask(type, maskp)
188 char *type;
189 int *maskp;
190{
191 register int x;
192
193 if (strcasecmp(type, AUTHTYPE_NAME(0))) {
194 *maskp = -1;
195 return(1);
196 }
197
198 for (x = 1; x < AUTHTYPE_CNT; ++x) {
199 if (!strcasecmp(type, AUTHTYPE_NAME(x))) {
200 *maskp = typemask(x);
201 return(1);
202 }
203 }
204 return(0);
205}
206
207 int
208auth_enable(type)
209 int type;
210{
211 return(auth_onoff(type, 1));
212}
213
214 int
215auth_disable(type)
216 int type;
217{
218 return(auth_onoff(type, 0));
219}
220
221 int
222auth_onoff(type, on)
223 char *type;
224 int on;
225{
226 int mask = -1;
227 Authenticator *ap;
228
229 if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
230 printf("auth %s 'type'\n", on ? "enable" : "disable");
231 printf("Where 'type' is one of:\n");
232 printf("\t%s\n", AUTHTYPE_NAME(0));
233 for (ap = authenticators; ap->type; ap++)
234 printf("\t%s\n", AUTHTYPE_NAME(ap->type));
235 return(0);
236 }
237
238 if (!getauthmask(type, &mask)) {
239 printf("%s: invalid authentication type\n", type);
240 return(0);
241 }
242 mask = getauthmask(type, &mask);
243 if (on)
244 i_wont_support &= ~mask;
245 else
246 i_wont_support |= mask;
247 return(1);
248}
249
250 int
251auth_togdebug(on)
252 int on;
253{
254 if (on < 0)
255 auth_debug_mode ^= 1;
256 else
257 auth_debug_mode = on;
258 printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
259 return(1);
260}
261
262 int
263auth_status()
264{
265 Authenticator *ap;
266
267 if (i_wont_support == -1)
268 printf("Authentication disabled\n");
269 else
270 printf("Authentication enabled\n");
271
272 for (ap = authenticators; ap->type; ap++)
273 printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
274 (i_wont_support & typemask(ap->type)) ?
275 "disabled" : "enabled");
276 return(1);
277}
278
279/*
280 * This routine is called by the server to start authentication
281 * negotiation.
282 */
283 void
284auth_request()
285{
286 static unsigned char str_request[64] = { IAC, SB,
287 TELOPT_AUTHENTICATION,
288 TELQUAL_SEND, };
289 Authenticator *ap = authenticators;
290 unsigned char *e = str_request + 4;
291
292 if (!authenticating) {
293 authenticating = 1;
294 while (ap->type) {
295 if (i_support & ~i_wont_support & typemask(ap->type)) {
296 if (auth_debug_mode) {
297 printf(">>>%s: Sending type %d %d\r\n",
298 Name, ap->type, ap->way);
299 }
300 *e++ = ap->type;
301 *e++ = ap->way;
302 }
303 ++ap;
304 }
305 *e++ = IAC;
306 *e++ = SE;
307 net_write(str_request, e - str_request);
308 printsub('>', &str_request[2], e - str_request - 2);
309 }
310}
311
312/*
313 * This is called when an AUTH SEND is received.
314 * It should never arrive on the server side (as only the server can
315 * send an AUTH SEND).
316 * You should probably respond to it if you can...
317 *
318 * If you want to respond to the types out of order (i.e. even
319 * if he sends LOGIN KERBEROS and you support both, you respond
320 * with KERBEROS instead of LOGIN (which is against what the
321 * protocol says)) you will have to hack this code...
322 */
323 void
324auth_send(data, cnt)
325 unsigned char *data;
326 int cnt;
327{
328 Authenticator *ap;
329 static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
330 TELQUAL_IS, AUTHTYPE_NULL, 0,
331 IAC, SE };
332 if (Server) {
333 if (auth_debug_mode) {
334 printf(">>>%s: auth_send called!\r\n", Name);
335 }
336 return;
337 }
338
339 if (auth_debug_mode) {
340 printf(">>>%s: auth_send got:", Name);
341 printd(data, cnt); printf("\r\n");
342 }
343
344 /*
345 * Save the data, if it is new, so that we can continue looking
346 * at it if the authorization we try doesn't work
347 */
348 if (data < _auth_send_data ||
349 data > _auth_send_data + sizeof(_auth_send_data)) {
350 auth_send_cnt = cnt > sizeof(_auth_send_data)
351 ? sizeof(_auth_send_data)
352 : cnt;
353 bcopy((void *)data, (void *)_auth_send_data, auth_send_cnt);
354 auth_send_data = _auth_send_data;
355 } else {
356 /*
357 * This is probably a no-op, but we just make sure
358 */
359 auth_send_data = data;
360 auth_send_cnt = cnt;
361 }
362 while ((auth_send_cnt -= 2) >= 0) {
363 if (auth_debug_mode)
364 printf(">>>%s: He supports %d\r\n",
365 Name, *auth_send_data);
366 if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
367 ap = findauthenticator(auth_send_data[0],
368 auth_send_data[1]);
369 if (!ap) {
370 printf("Internal state error: cannot find authentication type %d a second time\r\n", *auth_send_data);
371 } else if (ap->send) {
372 if (auth_debug_mode)
373 printf(">>>%s: Trying %d %d\r\n",
374 Name, auth_send_data[0],
375 auth_send_data[1]);
376 if ((*ap->send)(ap)) {
377 /*
378 * Okay, we found one we like
379 * and did it.
380 * we can go home now.
381 */
382 if (auth_debug_mode)
383 printf(">>>%s: Using type %d\r\n",
384 Name, *auth_send_data);
385 auth_send_data += 2;
386 return;
387 }
388 }
389 /* else
390 * just continue on and look for the
391 * next one if we didn't do anything.
392 */
393 }
394 auth_send_data += 2;
395 }
396 net_write(str_none, sizeof(str_none));
397 printsub('>', &str_none[2], sizeof(str_none) - 2);
398 if (auth_debug_mode)
399 printf(">>>%s: Sent failure message\r\n", Name);
400 auth_finished(0, AUTH_REJECT);
401}
402
403 void
404auth_send_retry()
405{
406 /*
407 * if auth_send_cnt <= 0 then auth_send will end up rejecting
408 * the authentication and informing the other side of this.
409 */
410 auth_send(auth_send_data, auth_send_cnt);
411}
412
413 void
414auth_is(data, cnt)
415 unsigned char *data;
416 int cnt;
417{
418 Authenticator *ap;
419
420 if (cnt < 2)
421 return;
422
423 if (data[0] == AUTHTYPE_NULL) {
424 auth_finished(0, AUTH_REJECT);
425 return;
426 }
427
428 if (ap = findauthenticator(data[0], data[1])) {
429 if (ap->is)
430 (*ap->is)(ap, data+2, cnt-2);
431 } else if (auth_debug_mode)
432 printf(">>>%s: Invalid authentication in IS: %d\r\n",
433 Name, *data);
434}
435
436 void
437auth_reply(data, cnt)
438 unsigned char *data;
439 int cnt;
440{
441 Authenticator *ap;
442
443 if (cnt < 2)
444 return;
445
446 if (ap = findauthenticator(data[0], data[1])) {
447 if (ap->reply)
448 (*ap->reply)(ap, data+2, cnt-2);
449 } else if (auth_debug_mode)
450 printf(">>>%s: Invalid authentication in SEND: %d\r\n",
451 Name, *data);
452}
453
454 void
455auth_name(data, cnt)
456 unsigned char *data;
457 int cnt;
458{
459 Authenticator *ap;
460 unsigned char savename[256];
461
462 if (cnt < 1) {
463 if (auth_debug_mode)
464 printf(">>>%s: Empty name in NAME\r\n", Name);
465 return;
466 }
467 if (cnt > sizeof(savename) - 1) {
468 if (auth_debug_mode)
469 printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n",
470 Name, cnt, sizeof(savename)-1);
471 return;
472 }
473 bcopy((void *)data, (void *)savename, cnt);
474 savename[cnt] = '\0'; /* Null terminate */
475 if (auth_debug_mode)
476 printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
477 auth_encrypt_user(savename);
478}
479
480 int
481auth_sendname(cp, len)
482 unsigned char *cp;
483 int len;
484{
485 static unsigned char str_request[256+6]
486 = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
487 register unsigned char *e = str_request + 4;
488 register unsigned char *ee = &str_request[sizeof(str_request)-2];
489
490 while (--len >= 0) {
491 if ((*e++ = *cp++) == IAC)
492 *e++ = IAC;
493 if (e >= ee)
494 return(0);
495 }
496 *e++ = IAC;
497 *e++ = SE;
498 net_write(str_request, e - str_request);
499 printsub('>', &str_request[2], e - &str_request[2]);
500 return(1);
501}
502
503 void
504auth_finished(ap, result)
505 Authenticator *ap;
506 int result;
507{
508 if (!(authenticated = ap))
509 authenticated = &NoAuth;
510 validuser = result;
511}
512
513 /* ARGSUSED */
514 static void
515auth_intr(sig)
516 int sig;
517{
518 auth_finished(0, AUTH_REJECT);
519}
520
521 int
522auth_wait(name)
523 char *name;
524{
525 if (auth_debug_mode)
526 printf(">>>%s: in auth_wait.\r\n", Name);
527
528 if (Server && !authenticating)
529 return(0);
530
531 (void) signal(SIGALRM, auth_intr);
532 alarm(30);
533 while (!authenticated)
534 if (telnet_spin())
535 break;
536 alarm(0);
537 (void) signal(SIGALRM, SIG_DFL);
538
539 /*
540 * Now check to see if the user is valid or not
541 */
542 if (!authenticated || authenticated == &NoAuth)
543 return(AUTH_REJECT);
544
545 if (validuser == AUTH_VALID)
546 validuser = AUTH_USER;
547
548 if (authenticated->status)
549 validuser = (*authenticated->status)(authenticated,
550 name, validuser);
551 return(validuser);
552}
553
554 void
555auth_debug(mode)
556 int mode;
557{
558 auth_debug_mode = mode;
559}
560
561 void
562auth_printsub(data, cnt, buf, buflen)
563 unsigned char *data, *buf;
564 int cnt, buflen;
565{
566 Authenticator *ap;
567
568 if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
569 (*ap->printsub)(data, cnt, buf, buflen);
570 else
571 auth_gen_printsub(data, cnt, buf, buflen);
572}
573
574 void
575auth_gen_printsub(data, cnt, buf, buflen)
576 unsigned char *data, *buf;
577 int cnt, buflen;
578{
579 register unsigned char *cp;
580 unsigned char tbuf[16];
581
582 cnt -= 3;
583 data += 3;
584 buf[buflen-1] = '\0';
585 buf[buflen-2] = '*';
586 buflen -= 2;
587 for (; cnt > 0; cnt--, data++) {
588 sprintf((char *)tbuf, " %d", *data);
589 for (cp = tbuf; *cp && buflen > 0; --buflen)
590 *buf++ = *cp++;
591 if (buflen <= 0)
592 return;
593 }
594 *buf = '\0';
595}
596#endif