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 * 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 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 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 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 227 auth_enable(char *type) 228 { 229 return (auth_onoff(type, B_TRUE)); 230 } 231 232 int 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 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 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 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 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 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 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 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 448 auth_finished(Authenticator *ap, int result) 449 { 450 authenticated = ap; 451 if (authenticated == NULL) 452 authenticated = &NoAuth; 453 } 454 455 void 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 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