1 /*
2 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "%Z%%M% %I% %E% SMI"
7
8 /*
9 * usr/src/cmd/cmd-inet/usr.bin/telnet/auth.c
10 */
11
12 /*
13 * Copyright (c) 1991, 1993
14 * The Regents of the University of California. All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45 /* based on @(#)auth.c 8.1 (Berkeley) 6/4/93 */
46
47 /*
48 * Copyright (C) 1990 by the Massachusetts Institute of Technology
49 *
50 * Export of this software from the United States of America may
51 * require a specific license from the United States Government.
52 * It is the responsibility of any person or organization contemplating
53 * export to obtain such a license before exporting.
54 *
55 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
56 * distribute this software and its documentation for any purpose and
57 * without fee is hereby granted, provided that the above copyright
58 * notice appear in all copies and that both that copyright notice and
59 * this permission notice appear in supporting documentation, and that
60 * the name of M.I.T. not be used in advertising or publicity pertaining
61 * to distribution of the software without specific, written prior
62 * permission. Furthermore if you modify this software you must label
63 * your software as modified software and not distribute it in such a
64 * fashion that it might be confused with the original M.I.T. software.
65 * M.I.T. makes no representations about the suitability of
66 * this software for any purpose. It is provided "as is" without express
67 * or implied warranty.
68 */
69
70
71 #include <stdio.h>
72 #include <sys/types.h>
73 #include <signal.h>
74
75 #define AUTHTYPE_NAMES /* this is needed for arpa/telnet.h */
76 #include <arpa/telnet.h>
77
78 #ifdef __STDC__
79 #include <stdlib.h>
80 #endif
81
82 #include <string.h>
83
84 #include "externs.h"
85 #include "encrypt.h"
86 #include "auth.h"
87
88 #define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0)
89
90 static int auth_onoff(const char *type, boolean_t on);
91 static void auth_gen_printsub(uchar_t *, uint_t, uchar_t *, uint_t);
92
93 boolean_t auth_debug_mode = B_FALSE;
94 boolean_t auth_has_failed = B_FALSE;
95 boolean_t auth_enable_encrypt = B_FALSE;
96
97 static char *Name = "Noname";
98 static Authenticator *authenticated = NULL;
99 static uchar_t _auth_send_data[BUFSIZ];
100 static uchar_t *auth_send_data;
101 static int auth_send_cnt = 0;
102
103 /*
104 * Authentication types supported. Note that these are stored
105 * in priority order, i.e. try the first one first.
106 */
107 static Authenticator authenticators[] = {
108 { AUTHTYPE_KERBEROS_V5,
109 AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL|AUTH_ENCRYPT_ON,
110 kerberos5_init,
111 kerberos5_send,
112 kerberos5_reply,
113 kerberos5_status,
114 kerberos5_printsub },
115 { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
116 kerberos5_init,
117 kerberos5_send,
118 kerberos5_reply,
119 kerberos5_status,
120 kerberos5_printsub },
121 { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
122 kerberos5_init,
123 kerberos5_send,
124 kerberos5_reply,
125 kerberos5_status,
126 kerberos5_printsub },
127 { 0, },
128 };
129
130 static Authenticator NoAuth = { 0 };
131
132 static uint_t i_support = 0;
133 static uint_t i_wont_support = 0;
134
135 /*
136 * Traverse the Authenticator array until we find the authentication type
137 * and matching direction we are looking for. Return a pointer into the
138 * Authenticator type array.
139 *
140 * Returns: 0 - type not found (error)
141 * nonzero - pointer to authenticator
142 */
143 static Authenticator *
findauthenticator(int type,int way)144 findauthenticator(int type, int way)
145 {
146 Authenticator *ap = authenticators;
147
148 while (ap->type && (ap->type != type || ap->way != way))
149 ++ap;
150 return (ap->type ? ap : NULL);
151 }
152
153 /*
154 * For each authentication type in the Authenticator array,
155 * call the associated init routine, and update the i_support bitfield.
156 */
157 void
auth_init(const char * name)158 auth_init(const char *name)
159 {
160 Authenticator *ap = authenticators;
161
162 Name = name ? strdup(name) : "Noname";
163
164 i_support = 0;
165 authenticated = NULL;
166 while (ap->type) {
167 if (!ap->init || (*ap->init)(ap)) {
168 i_support |= typemask(ap->type);
169 if (auth_debug_mode)
170 (void) printf(gettext
171 (">>>%s: I support auth type %d %d\r\n"),
172 Name, ap->type, ap->way);
173 }
174 ++ap;
175 }
176 }
177
178 /*
179 * Search the Authenticator array for the authentication type 'name',
180 * and disable this type by updating the i_wont_support bitfield.
181 */
182 void
auth_disable_name(const char * name)183 auth_disable_name(const char *name)
184 {
185 uint_t x;
186 for (x = 0; x < AUTHTYPE_CNT; ++x) {
187 if (!strcasecmp(name, AUTHTYPE_NAME(x))) {
188 i_wont_support |= typemask(x);
189 break;
190 }
191 }
192
193 if (!i_wont_support)
194 (void) printf(
195 gettext("%s : invalid authentication type\n"),
196 name);
197 }
198
199 /*
200 * Search the Authenticator array for the authentication type given
201 * by the character string 'type', and return its integer bitmask
202 * in maskp.
203 *
204 * Returns: 1 - no error
205 * 0 - type not found (error)
206 */
207 static int
getauthmask(const char * type,uint_t * maskp)208 getauthmask(const char *type, uint_t *maskp)
209 {
210 uint_t x;
211
212 if (!strcasecmp(type, AUTHTYPE_NAME(0))) {
213 *maskp = (uint_t)-1;
214 return (1);
215 }
216
217 for (x = 1; x < AUTHTYPE_CNT; ++x) {
218 if (!strcasecmp(type, AUTHTYPE_NAME(x))) {
219 *maskp = typemask(x);
220 return (1);
221 }
222 }
223 return (0);
224 }
225
226 int
auth_enable(char * type)227 auth_enable(char *type)
228 {
229 return (auth_onoff(type, B_TRUE));
230 }
231
232 int
auth_disable(char * type)233 auth_disable(char *type)
234 {
235 return (auth_onoff(type, B_FALSE));
236 }
237
238 /*
239 * Responds to the 'auth enable <option>' and 'auth disable <option>' commands.
240 *
241 * If <option> is:
242 * - a valid authentication type, turns support on / off
243 * - "?" or "help", print a usage message
244 * - not recognized, print an error message.
245 *
246 * Returns: 1 - no error, authentication is enabled or disabled
247 * 0 - error, or help requested
248 */
249 static int
auth_onoff(const char * type,boolean_t on)250 auth_onoff(const char *type, boolean_t on)
251 {
252 uint_t i, mask = 0;
253 Authenticator *ap;
254
255 if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
256 (void) printf(on ?
257 gettext("auth enable 'type'\n") :
258 gettext("auth disable 'type'\n"));
259 (void) printf(
260 gettext("Where 'type' is one of:\n"));
261 (void) printf("\t%s\n", AUTHTYPE_NAME(0));
262 for (ap = authenticators; ap->type; ap++) {
263 if ((mask & (i = typemask(ap->type))) != 0)
264 continue;
265 mask |= i;
266 (void) printf("\t%s\n", AUTHTYPE_NAME(ap->type));
267 }
268 return (0);
269 }
270
271 if (!getauthmask(type, &mask)) {
272 (void) printf(
273 gettext("%s: invalid authentication type\n"), type);
274 return (0);
275 }
276 if (on)
277 i_wont_support &= ~mask;
278 else
279 i_wont_support |= mask;
280 return (1);
281 }
282
283 /*
284 * Responds to the 'toggle authdebug' command.
285 *
286 * Returns: 1 - always
287 */
288 int
auth_togdebug(int on)289 auth_togdebug(int on)
290 {
291 if (on < 0)
292 auth_debug_mode = !auth_debug_mode;
293 else
294 auth_debug_mode = on > 0 ? B_TRUE : B_FALSE;
295 (void) printf(auth_debug_mode ?
296 gettext("auth debugging enabled\n") :
297 gettext("auth debugging disabled\n"));
298 return (1);
299 }
300
301 /*
302 * Responds to the 'auth status' command.
303 * Traverses the authenticator array and prints enabled or disabled for
304 * each authentication type, depencing on the i_wont_support bitfield.
305 *
306 * Returns: 1 - always
307 */
308 int
auth_status(void)309 auth_status(void)
310 {
311 Authenticator *ap;
312 uint_t i, mask;
313
314 if (i_wont_support == (uint_t)-1)
315 (void) printf(gettext("Authentication disabled\n"));
316 else
317 (void) printf(gettext("Authentication enabled\n"));
318
319 mask = 0;
320 for (ap = authenticators; ap->type; ap++) {
321 if ((mask & (i = typemask(ap->type))) != 0)
322 continue;
323 mask |= i;
324 (void) printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
325 (i_wont_support & typemask(ap->type)) ?
326 gettext("disabled") : gettext("enabled"));
327 }
328 return (1);
329 }
330
331 /*
332 * This is called when an AUTH SEND is received.
333 * data is a list of authentication mechanisms we support
334 */
335 void
auth_send(uchar_t * data,int cnt)336 auth_send(uchar_t *data, int cnt)
337 {
338
339 if (auth_debug_mode) {
340 (void) printf(gettext(">>>%s: auth_send got:"), Name);
341 printd(data, cnt);
342 (void) printf("\r\n");
343 }
344
345 /*
346 * Save the list of authentication mechanisms
347 */
348 auth_send_cnt = cnt;
349 if (auth_send_cnt > sizeof (_auth_send_data))
350 auth_send_cnt = sizeof (_auth_send_data);
351 (void) memcpy((void *)_auth_send_data, (void *)data, auth_send_cnt);
352 auth_send_data = _auth_send_data;
353
354 auth_send_retry();
355 }
356
357 /*
358 * Try the next authentication mechanism on the list, and see if it
359 * works.
360 */
361 void
auth_send_retry(void)362 auth_send_retry(void)
363 {
364 Authenticator *ap;
365 static uchar_t str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
366 TELQUAL_IS, AUTHTYPE_NULL, 0, IAC, SE };
367
368 for (; (auth_send_cnt -= 2) >= 0; auth_send_data += 2) {
369 if (auth_debug_mode)
370 (void) printf(
371 gettext(">>>%s: Remote host supports %d\r\n"),
372 Name, *auth_send_data);
373 if (!(i_support & typemask(*auth_send_data)))
374 continue;
375 if (i_wont_support & typemask(*auth_send_data))
376 continue;
377 ap = findauthenticator(auth_send_data[0], auth_send_data[1]);
378 if (!ap || !ap->send)
379 continue;
380 if ((ap->way & AUTH_ENCRYPT_MASK) && !auth_enable_encrypt)
381 continue;
382
383 if (auth_debug_mode)
384 (void) printf(
385 gettext(">>>%s: Trying %d %d\r\n"), Name,
386 auth_send_data[0], auth_send_data[1]);
387 if ((*ap->send)(ap)) {
388 /*
389 * Okay, we found one we like and did it. we can go
390 * home now.
391 */
392 if (auth_debug_mode)
393 (void) printf(gettext(">>>%s: Using type %d\r\n"),
394 Name, *auth_send_data);
395 auth_send_data += 2;
396 return;
397 }
398 }
399 (void) net_write(str_none, sizeof (str_none));
400 printsub('>', &str_none[2], sizeof (str_none) - 2);
401 if (auth_debug_mode)
402 (void) printf(
403 gettext(">>>%s: Sent failure message\r\n"), Name);
404 auth_finished(0, AUTH_REJECT);
405 auth_has_failed = B_TRUE;
406 }
407
408 void
auth_reply(uchar_t * data,int cnt)409 auth_reply(uchar_t *data, int cnt)
410 {
411 Authenticator *ap;
412
413 if (cnt < 2)
414 return;
415
416 if (ap = findauthenticator(data[0], data[1])) {
417 if (ap->reply)
418 (*ap->reply)(ap, data+2, cnt-2);
419 } else if (auth_debug_mode)
420 (void) printf(gettext
421 (">>>%s: Invalid authentication in SEND: %d\r\n"),
422 Name, *data);
423 }
424
425 int
auth_sendname(uchar_t * cp,int len)426 auth_sendname(uchar_t *cp, int len)
427 {
428 static uchar_t str_request[AUTH_NAME_BUFSIZ + 6] = { IAC, SB,
429 TELOPT_AUTHENTICATION, TELQUAL_NAME, };
430 register uchar_t *e = str_request + 4;
431 register uchar_t *ee = &str_request[sizeof (str_request) - 2];
432
433 while (--len >= 0) {
434 if ((*e++ = *cp++) == IAC)
435 *e++ = IAC;
436 if (e >= ee)
437 return (0);
438 }
439 *e++ = IAC;
440 *e++ = SE;
441 (void) net_write(str_request, e - str_request);
442 printsub('>', &str_request[2], e - &str_request[2]);
443 return (1);
444 }
445
446 /* ARGSUSED */
447 void
auth_finished(Authenticator * ap,int result)448 auth_finished(Authenticator *ap, int result)
449 {
450 authenticated = ap;
451 if (authenticated == NULL)
452 authenticated = &NoAuth;
453 }
454
455 void
auth_printsub(uchar_t * data,uint_t cnt,uchar_t * buf,uint_t buflen)456 auth_printsub(uchar_t *data, uint_t cnt, uchar_t *buf, uint_t buflen)
457 {
458 Authenticator *ap;
459
460 ap = findauthenticator(data[1], data[2]);
461 if (ap && ap->printsub)
462 (*ap->printsub)(data, cnt, buf, buflen);
463 else
464 auth_gen_printsub(data, cnt, buf, buflen);
465 }
466
467 static void
auth_gen_printsub(uchar_t * data,uint_t cnt,uchar_t * buf,uint_t buflen)468 auth_gen_printsub(uchar_t *data, uint_t cnt, uchar_t *buf, uint_t buflen)
469 {
470 register uchar_t *cp;
471 uchar_t lbuf[AUTH_LBUF_BUFSIZ];
472
473 if (buflen < 2)
474 return;
475 cnt = (cnt > 3) ? cnt - 3 : 0;
476 data += 3;
477 buf[buflen - 1] = '\0';
478 buf[buflen - 2] = '*';
479 buflen -= 2;
480 for (; cnt > 0; cnt--, data++) {
481 (void) snprintf((char *)lbuf, AUTH_LBUF_BUFSIZ, " %d", *data);
482 for (cp = lbuf; (*cp != '\0') && (buflen > 0); --buflen)
483 *buf++ = *cp++;
484 if (buflen == 0)
485 return;
486 }
487 *buf = '\0';
488 }
489