1 1.21 mrg /* $NetBSD: kerberos5.c,v 1.21 2021/04/12 09:17:48 mrg Exp $ */ 2 1.4 thorpej 3 1.1 cgd /*- 4 1.4 thorpej * Copyright (c) 1991, 1993 5 1.4 thorpej * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.12 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.1 cgd /* 33 1.1 cgd * Copyright (C) 1990 by the Massachusetts Institute of Technology 34 1.1 cgd * 35 1.4 thorpej * Export of this software from the United States of America may 36 1.4 thorpej * require a specific license from the United States Government. 37 1.1 cgd * It is the responsibility of any person or organization contemplating 38 1.1 cgd * export to obtain such a license before exporting. 39 1.1 cgd * 40 1.1 cgd * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 41 1.1 cgd * distribute this software and its documentation for any purpose and 42 1.1 cgd * without fee is hereby granted, provided that the above copyright 43 1.1 cgd * notice appear in all copies and that both that copyright notice and 44 1.1 cgd * this permission notice appear in supporting documentation, and that 45 1.1 cgd * the name of M.I.T. not be used in advertising or publicity pertaining 46 1.1 cgd * to distribution of the software without specific, written prior 47 1.1 cgd * permission. M.I.T. makes no representations about the suitability of 48 1.1 cgd * this software for any purpose. It is provided "as is" without express 49 1.1 cgd * or implied warranty. 50 1.1 cgd */ 51 1.1 cgd 52 1.1 cgd #ifdef KRB5 53 1.1 cgd #include <arpa/telnet.h> 54 1.1 cgd #include <stdio.h> 55 1.4 thorpej #include <stdlib.h> 56 1.4 thorpej #include <string.h> 57 1.4 thorpej #include <unistd.h> 58 1.1 cgd #include <netdb.h> 59 1.1 cgd #include <ctype.h> 60 1.4 thorpej #include <pwd.h> 61 1.4 thorpej #define Authenticator k5_Authenticator 62 1.4 thorpej #include <krb5.h> 63 1.4 thorpej #undef Authenticator 64 1.4 thorpej /* #include <roken.h> */ 65 1.1 cgd 66 1.1 cgd #include "encrypt.h" 67 1.1 cgd #include "auth.h" 68 1.1 cgd #include "misc.h" 69 1.1 cgd 70 1.6 christos extern int net; 71 1.6 christos 72 1.4 thorpej int forward_flags; /* Flags get set in telnet/main.c on -f and -F */ 73 1.4 thorpej int got_forwarded_creds;/* Tell telnetd to pass -F or -f to login. */ 74 1.1 cgd 75 1.4 thorpej int require_hwpreauth; 76 1.1 cgd 77 1.18 elric const char *get_krb5_err_text(krb5_context, krb5_error_code); 78 1.4 thorpej void kerberos5_forward(Authenticator *); 79 1.4 thorpej 80 1.4 thorpej static unsigned char str_data[1024] = {IAC, SB, TELOPT_AUTHENTICATION, 0, 81 1.4 thorpej AUTHTYPE_KERBEROS_V5,}; 82 1.4 thorpej 83 1.4 thorpej #define KRB_AUTH 0 /* Authentication data follows */ 84 1.4 thorpej #define KRB_REJECT 1 /* Rejected (reason might follow) */ 85 1.4 thorpej #define KRB_ACCEPT 2 /* Accepted */ 86 1.4 thorpej #define KRB_RESPONSE 3 /* Response for mutual auth. */ 87 1.4 thorpej 88 1.4 thorpej #define KRB_FORWARD 4 /* Forwarded credentials follow */ 89 1.4 thorpej #define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ 90 1.4 thorpej #define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ 91 1.4 thorpej 92 1.4 thorpej static krb5_data auth; 93 1.4 thorpej static krb5_ticket *ticket; 94 1.4 thorpej 95 1.4 thorpej krb5_context telnet_context; 96 1.4 thorpej static krb5_auth_context auth_context; 97 1.4 thorpej 98 1.4 thorpej static int 99 1.19 christos Data(Authenticator *ap, int type, const void *d, int c) 100 1.1 cgd { 101 1.4 thorpej unsigned char *p = str_data + 4; 102 1.19 christos const unsigned char *cd = (const unsigned char *) d; 103 1.1 cgd 104 1.1 cgd if (c == -1) 105 1.4 thorpej c = strlen(cd); 106 1.1 cgd 107 1.4 thorpej if (auth_debug_mode) { 108 1.4 thorpej printf("%s:%d: [%d] (%d)", 109 1.4 thorpej str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 110 1.4 thorpej str_data[3], 111 1.4 thorpej type, c); 112 1.4 thorpej printd(d, c); 113 1.4 thorpej printf("\r\n"); 114 1.4 thorpej } 115 1.1 cgd *p++ = ap->type; 116 1.1 cgd *p++ = ap->way; 117 1.1 cgd *p++ = type; 118 1.4 thorpej while (c-- > 0) { 119 1.4 thorpej if ((*p++ = *cd++) == IAC) 120 1.4 thorpej *p++ = IAC; 121 1.4 thorpej } 122 1.4 thorpej *p++ = IAC; 123 1.4 thorpej *p++ = SE; 124 1.1 cgd if (str_data[3] == TELQUAL_IS) 125 1.1 cgd printsub('>', &str_data[2], p - &str_data[2]); 126 1.4 thorpej return (telnet_net_write(str_data, p - str_data)); 127 1.1 cgd } 128 1.1 cgd 129 1.18 elric const char * 130 1.18 elric get_krb5_err_text(krb5_context ctx, krb5_error_code ret) 131 1.18 elric { 132 1.18 elric static const char *str = NULL; 133 1.18 elric 134 1.18 elric if (str) 135 1.18 elric krb5_free_error_message(ctx, str); 136 1.18 elric 137 1.18 elric str = krb5_get_error_message(ctx, ret); 138 1.18 elric 139 1.18 elric if (str != NULL) 140 1.18 elric return str; 141 1.18 elric 142 1.18 elric return "unknown"; 143 1.18 elric } 144 1.18 elric 145 1.4 thorpej int 146 1.4 thorpej kerberos5_init(Authenticator *ap, int server) 147 1.1 cgd { 148 1.5 thorpej krb5_error_code ret; 149 1.4 thorpej 150 1.5 thorpej if (telnet_context == 0) { 151 1.5 thorpej ret = krb5_init_context(&telnet_context); 152 1.5 thorpej if (ret) 153 1.5 thorpej return 0; 154 1.5 thorpej } 155 1.4 thorpej 156 1.4 thorpej if (server) { 157 1.4 thorpej krb5_keytab kt; 158 1.4 thorpej krb5_kt_cursor cursor; 159 1.4 thorpej 160 1.4 thorpej ret = krb5_kt_default(telnet_context, &kt); 161 1.4 thorpej if (ret) 162 1.4 thorpej return 0; 163 1.4 thorpej 164 1.4 thorpej ret = krb5_kt_start_seq_get(telnet_context, kt, &cursor); 165 1.4 thorpej if (ret) { 166 1.4 thorpej krb5_kt_close(telnet_context, kt); 167 1.4 thorpej return 0; 168 1.4 thorpej } 169 1.4 thorpej krb5_kt_end_seq_get(telnet_context, kt, &cursor); 170 1.4 thorpej krb5_kt_close(telnet_context, kt); 171 1.4 thorpej 172 1.1 cgd str_data[3] = TELQUAL_REPLY; 173 1.4 thorpej } else 174 1.1 cgd str_data[3] = TELQUAL_IS; 175 1.4 thorpej return (1); 176 1.1 cgd } 177 1.1 cgd 178 1.4 thorpej int 179 1.4 thorpej kerberos5_send(Authenticator *ap) 180 1.1 cgd { 181 1.4 thorpej krb5_error_code ret; 182 1.1 cgd krb5_ccache ccache; 183 1.4 thorpej int ap_opts; 184 1.4 thorpej krb5_data cksum_data; 185 1.4 thorpej char foo[2]; 186 1.1 cgd 187 1.4 thorpej printf("[ Trying KERBEROS5 ... ]\r\n"); 188 1.1 cgd 189 1.4 thorpej if (!UserNameRequested) { 190 1.1 cgd if (auth_debug_mode) { 191 1.4 thorpej printf("Kerberos V5: no user name supplied\r\n"); 192 1.1 cgd } 193 1.4 thorpej return (0); 194 1.1 cgd } 195 1.4 thorpej ret = krb5_cc_default(telnet_context, &ccache); 196 1.4 thorpej if (ret) { 197 1.1 cgd if (auth_debug_mode) { 198 1.4 thorpej printf( 199 1.4 thorpej "Kerberos V5: could not get default ccache: %s\r\n", 200 1.18 elric get_krb5_err_text(telnet_context, ret)); 201 1.1 cgd } 202 1.4 thorpej return (0); 203 1.1 cgd } 204 1.4 thorpej if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 205 1.4 thorpej ap_opts = AP_OPTS_MUTUAL_REQUIRED; 206 1.4 thorpej else 207 1.4 thorpej ap_opts = 0; 208 1.1 cgd 209 1.9 joda ap_opts |= AP_OPTS_USE_SUBKEY; 210 1.9 joda 211 1.4 thorpej ret = krb5_auth_con_init(telnet_context, &auth_context); 212 1.4 thorpej if (ret) { 213 1.1 cgd if (auth_debug_mode) { 214 1.4 thorpej printf( 215 1.4 thorpej "Kerberos V5: krb5_auth_con_init failed: %s\r\n", 216 1.18 elric get_krb5_err_text(telnet_context, ret)); 217 1.4 thorpej } 218 1.4 thorpej return (0); 219 1.4 thorpej } 220 1.4 thorpej ret = krb5_auth_con_setaddrs_from_fd(telnet_context, 221 1.4 thorpej auth_context, &net); 222 1.4 thorpej if (ret) { 223 1.4 thorpej if (auth_debug_mode) { 224 1.4 thorpej printf("Kerberos V5: " 225 1.4 thorpej "krb5_auth_con_setaddrs_from_fd failed: %s\r\n", 226 1.18 elric get_krb5_err_text(telnet_context, ret)); 227 1.1 cgd } 228 1.4 thorpej return (0); 229 1.1 cgd } 230 1.20 joerg krb5_auth_con_setkeytype(telnet_context, auth_context, 231 1.21 mrg KRB5_ENCTYPE_DES_CBC_CRC); 232 1.1 cgd 233 1.4 thorpej foo[0] = ap->type; 234 1.4 thorpej foo[1] = ap->way; 235 1.1 cgd 236 1.4 thorpej cksum_data.length = sizeof(foo); 237 1.4 thorpej cksum_data.data = foo; 238 1.4 thorpej ret = krb5_mk_req(telnet_context, &auth_context, ap_opts, "host", 239 1.4 thorpej RemoteHostName, &cksum_data, ccache, &auth); 240 1.4 thorpej if (ret) { 241 1.4 thorpej if (1 || auth_debug_mode) { 242 1.4 thorpej printf("Kerberos V5: mk_req failed (%s)\r\n", 243 1.18 elric get_krb5_err_text(telnet_context, ret)); 244 1.1 cgd } 245 1.4 thorpej return (0); 246 1.1 cgd } 247 1.1 cgd 248 1.4 thorpej if (!auth_sendname((unsigned char *) UserNameRequested, 249 1.4 thorpej strlen(UserNameRequested))) { 250 1.4 thorpej if (auth_debug_mode) 251 1.4 thorpej printf("Not enough room for user name\r\n"); 252 1.4 thorpej return (0); 253 1.4 thorpej } 254 1.1 cgd if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 255 1.1 cgd if (auth_debug_mode) 256 1.1 cgd printf("Not enough room for authentication data\r\n"); 257 1.4 thorpej return (0); 258 1.1 cgd } 259 1.1 cgd if (auth_debug_mode) { 260 1.1 cgd printf("Sent Kerberos V5 credentials to server\r\n"); 261 1.1 cgd } 262 1.4 thorpej return (1); 263 1.1 cgd } 264 1.1 cgd 265 1.4 thorpej void 266 1.4 thorpej kerberos5_is(Authenticator * ap, unsigned char *data, int cnt) 267 1.1 cgd { 268 1.4 thorpej krb5_error_code ret; 269 1.4 thorpej krb5_data outbuf; 270 1.4 thorpej krb5_keyblock *key_block; 271 1.1 cgd char *name; 272 1.4 thorpej krb5_principal server; 273 1.4 thorpej int zero = 0; 274 1.1 cgd 275 1.1 cgd if (cnt-- < 1) 276 1.1 cgd return; 277 1.1 cgd switch (*data++) { 278 1.1 cgd case KRB_AUTH: 279 1.4 thorpej auth.data = (char *) data; 280 1.1 cgd auth.length = cnt; 281 1.1 cgd 282 1.4 thorpej auth_context = NULL; 283 1.4 thorpej 284 1.4 thorpej ret = krb5_auth_con_init(telnet_context, &auth_context); 285 1.4 thorpej if (ret) { 286 1.4 thorpej Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); 287 1.4 thorpej auth_finished(ap, AUTH_REJECT); 288 1.1 cgd if (auth_debug_mode) 289 1.4 thorpej printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", 290 1.18 elric get_krb5_err_text(telnet_context, ret)); 291 1.4 thorpej return; 292 1.4 thorpej } 293 1.4 thorpej ret = krb5_auth_con_setaddrs_from_fd(telnet_context, 294 1.4 thorpej auth_context, &zero); 295 1.4 thorpej if (ret) { 296 1.4 thorpej Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); 297 1.1 cgd auth_finished(ap, AUTH_REJECT); 298 1.4 thorpej if (auth_debug_mode) 299 1.4 thorpej printf("Kerberos V5: " 300 1.4 thorpej "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", 301 1.18 elric get_krb5_err_text(telnet_context, ret)); 302 1.1 cgd return; 303 1.1 cgd } 304 1.4 thorpej ret = krb5_sock_to_principal(telnet_context, 0, "host", 305 1.4 thorpej KRB5_NT_SRV_HST, &server); 306 1.4 thorpej if (ret) { 307 1.4 thorpej Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); 308 1.4 thorpej auth_finished(ap, AUTH_REJECT); 309 1.1 cgd if (auth_debug_mode) 310 1.4 thorpej printf("Kerberos V5: " 311 1.4 thorpej "krb5_sock_to_principal failed (%s)\r\n", 312 1.18 elric get_krb5_err_text(telnet_context, ret)); 313 1.1 cgd return; 314 1.1 cgd } 315 1.4 thorpej ret = krb5_rd_req(telnet_context, &auth_context, &auth, 316 1.4 thorpej server, NULL, NULL, &ticket); 317 1.4 thorpej krb5_free_principal(telnet_context, server); 318 1.4 thorpej 319 1.4 thorpej if (ret) { 320 1.4 thorpej char *errbuf; 321 1.4 thorpej 322 1.4 thorpej asprintf(&errbuf, 323 1.4 thorpej "Read req failed: %s", 324 1.18 elric get_krb5_err_text(telnet_context, ret)); 325 1.4 thorpej Data(ap, KRB_REJECT, errbuf, -1); 326 1.1 cgd if (auth_debug_mode) 327 1.4 thorpej printf("%s\r\n", errbuf); 328 1.4 thorpej free(errbuf); 329 1.1 cgd return; 330 1.4 thorpej } { 331 1.4 thorpej char foo[2]; 332 1.4 thorpej 333 1.4 thorpej foo[0] = ap->type; 334 1.4 thorpej foo[1] = ap->way; 335 1.4 thorpej 336 1.4 thorpej ret = krb5_verify_authenticator_checksum(telnet_context, 337 1.4 thorpej auth_context, foo, sizeof(foo)); 338 1.4 thorpej 339 1.4 thorpej if (ret) { 340 1.4 thorpej char *errbuf; 341 1.4 thorpej asprintf(&errbuf, "Bad checksum: %s", 342 1.18 elric get_krb5_err_text(telnet_context, ret)); 343 1.4 thorpej Data(ap, KRB_REJECT, errbuf, -1); 344 1.4 thorpej if (auth_debug_mode) 345 1.4 thorpej printf("%s\r\n", errbuf); 346 1.4 thorpej free(errbuf); 347 1.4 thorpej return; 348 1.4 thorpej } 349 1.1 cgd } 350 1.4 thorpej ret = krb5_auth_con_getremotesubkey(telnet_context, 351 1.4 thorpej auth_context, &key_block); 352 1.1 cgd 353 1.4 thorpej if (ret) { 354 1.4 thorpej Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); 355 1.4 thorpej auth_finished(ap, AUTH_REJECT); 356 1.1 cgd if (auth_debug_mode) 357 1.4 thorpej printf("Kerberos V5: " 358 1.4 thorpej "krb5_auth_con_getremotesubkey failed (%s)\r\n", 359 1.18 elric get_krb5_err_text(telnet_context, ret)); 360 1.9 joda return; 361 1.9 joda } 362 1.9 joda if (key_block == NULL) { 363 1.10 thorpej ret = krb5_auth_con_getkey(telnet_context, 364 1.9 joda auth_context, 365 1.9 joda &key_block); 366 1.9 joda } 367 1.9 joda if (ret) { 368 1.9 joda Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); 369 1.9 joda auth_finished(ap, AUTH_REJECT); 370 1.9 joda if (auth_debug_mode) 371 1.9 joda printf("Kerberos V5: " 372 1.9 joda "krb5_auth_con_getkey failed (%s)\r\n", 373 1.18 elric get_krb5_err_text(telnet_context, ret)); 374 1.9 joda return; 375 1.9 joda } 376 1.9 joda if (key_block == NULL) { 377 1.9 joda Data(ap, KRB_REJECT, "no subkey received", -1); 378 1.9 joda auth_finished(ap, AUTH_REJECT); 379 1.9 joda if (auth_debug_mode) 380 1.9 joda printf("Kerberos V5: " 381 1.9 joda "krb5_auth_con_getremotesubkey returned NULL key\r\n"); 382 1.1 cgd return; 383 1.1 cgd } 384 1.4 thorpej if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 385 1.4 thorpej ret = krb5_mk_rep(telnet_context, 386 1.7 assar auth_context, &outbuf); 387 1.4 thorpej if (ret) { 388 1.4 thorpej Data(ap, KRB_REJECT, 389 1.4 thorpej "krb5_mk_rep failed", -1); 390 1.4 thorpej auth_finished(ap, AUTH_REJECT); 391 1.4 thorpej if (auth_debug_mode) 392 1.4 thorpej printf("Kerberos V5: " 393 1.4 thorpej "krb5_mk_rep failed (%s)\r\n", 394 1.18 elric get_krb5_err_text(telnet_context, 395 1.4 thorpej ret)); 396 1.17 christos krb5_free_keyblock(telnet_context, key_block); 397 1.4 thorpej return; 398 1.4 thorpej } 399 1.4 thorpej Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); 400 1.4 thorpej } 401 1.4 thorpej if (krb5_unparse_name(telnet_context, ticket->client, &name)) 402 1.1 cgd name = 0; 403 1.4 thorpej 404 1.4 thorpej if (UserNameRequested && krb5_kuserok(telnet_context, 405 1.4 thorpej ticket->client, UserNameRequested)) { 406 1.16 christos Data(ap, KRB_ACCEPT, name ? name : "", name ? -1 : 0); 407 1.4 thorpej if (auth_debug_mode) { 408 1.4 thorpej printf("Kerberos5 identifies him as ``%s''\r\n", 409 1.4 thorpej name ? name : ""); 410 1.4 thorpej } 411 1.4 thorpej if (key_block->keytype == ETYPE_DES_CBC_MD5 || 412 1.4 thorpej key_block->keytype == ETYPE_DES_CBC_MD4 || 413 1.4 thorpej key_block->keytype == ETYPE_DES_CBC_CRC) { 414 1.4 thorpej Session_Key skey; 415 1.4 thorpej 416 1.4 thorpej skey.type = SK_DES; 417 1.4 thorpej skey.length = 8; 418 1.4 thorpej skey.data = key_block->keyvalue.data; 419 1.4 thorpej encrypt_session_key(&skey, 0); 420 1.4 thorpej } 421 1.4 thorpej } else { 422 1.4 thorpej char *msg; 423 1.4 thorpej 424 1.4 thorpej asprintf(&msg, "user `%s' is not authorized to " 425 1.4 thorpej "login as `%s'", 426 1.4 thorpej name ? name : "<unknown>", 427 1.4 thorpej UserNameRequested ? UserNameRequested : "<nobody>"); 428 1.4 thorpej if (msg == NULL) 429 1.4 thorpej Data(ap, KRB_REJECT, NULL, 0); 430 1.4 thorpej else { 431 1.4 thorpej Data(ap, KRB_REJECT, (void *) msg, -1); 432 1.4 thorpej free(msg); 433 1.4 thorpej } 434 1.4 thorpej auth_finished(ap, AUTH_REJECT); 435 1.17 christos krb5_free_keyblock(telnet_context, key_block); 436 1.4 thorpej break; 437 1.1 cgd } 438 1.4 thorpej auth_finished(ap, AUTH_USER); 439 1.17 christos krb5_free_keyblock(telnet_context, key_block); 440 1.1 cgd break; 441 1.4 thorpej case KRB_FORWARD:{ 442 1.13 christos struct passwd pws, *pwd; 443 1.13 christos char pwbuf[1024]; 444 1.4 thorpej char ccname[1024]; /* XXX */ 445 1.4 thorpej krb5_data inbuf; 446 1.4 thorpej krb5_ccache ccache; 447 1.4 thorpej inbuf.data = (char *) data; 448 1.4 thorpej inbuf.length = cnt; 449 1.4 thorpej 450 1.13 christos if (getpwnam_r(UserNameRequested, &pws, pwbuf, 451 1.14 christos sizeof(pwbuf), &pwd) != 0 || pwd == NULL) 452 1.4 thorpej break; 453 1.1 cgd 454 1.4 thorpej snprintf(ccname, sizeof(ccname), 455 1.4 thorpej "FILE:/tmp/krb5cc_%u", pwd->pw_uid); 456 1.1 cgd 457 1.4 thorpej ret = krb5_cc_resolve(telnet_context, ccname, &ccache); 458 1.4 thorpej if (ret) { 459 1.4 thorpej if (auth_debug_mode) 460 1.4 thorpej printf("Kerberos V5: could not get ccache: %s\r\n", 461 1.18 elric get_krb5_err_text(telnet_context, 462 1.4 thorpej ret)); 463 1.4 thorpej break; 464 1.4 thorpej } 465 1.4 thorpej ret = krb5_cc_initialize(telnet_context, ccache, 466 1.4 thorpej ticket->client); 467 1.4 thorpej if (ret) { 468 1.4 thorpej if (auth_debug_mode) 469 1.4 thorpej printf("Kerberos V5: could not init ccache: %s\r\n", 470 1.18 elric get_krb5_err_text(telnet_context, 471 1.4 thorpej ret)); 472 1.1 cgd break; 473 1.4 thorpej } 474 1.7 assar ret = krb5_rd_cred2(telnet_context, auth_context, 475 1.4 thorpej ccache, &inbuf); 476 1.4 thorpej if (ret) { 477 1.4 thorpej char *errbuf; 478 1.4 thorpej 479 1.4 thorpej asprintf(&errbuf, 480 1.4 thorpej "Read forwarded creds failed: %s", 481 1.18 elric get_krb5_err_text(telnet_context, ret)); 482 1.4 thorpej if (errbuf == NULL) 483 1.4 thorpej Data(ap, KRB_FORWARD_REJECT, NULL, 0); 484 1.4 thorpej else 485 1.4 thorpej Data(ap, KRB_FORWARD_REJECT, errbuf, -1); 486 1.4 thorpej if (auth_debug_mode) 487 1.4 thorpej printf("Could not read forwarded credentials: %s\r\n", 488 1.4 thorpej errbuf); 489 1.4 thorpej free(errbuf); 490 1.4 thorpej } else 491 1.4 thorpej Data(ap, KRB_FORWARD_ACCEPT, 0, 0); 492 1.4 thorpej chown(ccname + 5, pwd->pw_uid, -1); 493 1.4 thorpej if (auth_debug_mode) 494 1.4 thorpej printf("Forwarded credentials obtained\r\n"); 495 1.4 thorpej break; 496 1.1 cgd } 497 1.1 cgd default: 498 1.1 cgd if (auth_debug_mode) 499 1.1 cgd printf("Unknown Kerberos option %d\r\n", data[-1]); 500 1.1 cgd Data(ap, KRB_REJECT, 0, 0); 501 1.1 cgd break; 502 1.1 cgd } 503 1.1 cgd } 504 1.1 cgd 505 1.4 thorpej void 506 1.4 thorpej kerberos5_reply(Authenticator * ap, unsigned char *data, int cnt) 507 1.1 cgd { 508 1.4 thorpej static int mutual_complete = 0; 509 1.1 cgd 510 1.1 cgd if (cnt-- < 1) 511 1.1 cgd return; 512 1.1 cgd switch (*data++) { 513 1.1 cgd case KRB_REJECT: 514 1.1 cgd if (cnt > 0) { 515 1.1 cgd printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 516 1.4 thorpej cnt, data); 517 1.1 cgd } else 518 1.1 cgd printf("[ Kerberos V5 refuses authentication ]\r\n"); 519 1.1 cgd auth_send_retry(); 520 1.1 cgd return; 521 1.4 thorpej case KRB_ACCEPT:{ 522 1.4 thorpej krb5_error_code ret; 523 1.4 thorpej Session_Key skey; 524 1.4 thorpej krb5_keyblock *keyblock; 525 1.4 thorpej 526 1.4 thorpej if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && 527 1.4 thorpej !mutual_complete) { 528 1.4 thorpej printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); 529 1.4 thorpej auth_send_retry(); 530 1.4 thorpej return; 531 1.4 thorpej } 532 1.4 thorpej if (cnt) 533 1.4 thorpej printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); 534 1.4 thorpej else 535 1.4 thorpej printf("[ Kerberos V5 accepts you ]\r\n"); 536 1.4 thorpej 537 1.4 thorpej ret = krb5_auth_con_getlocalsubkey(telnet_context, 538 1.4 thorpej auth_context, &keyblock); 539 1.4 thorpej if (ret) 540 1.4 thorpej ret = krb5_auth_con_getkey(telnet_context, 541 1.4 thorpej auth_context, &keyblock); 542 1.4 thorpej if (ret) { 543 1.4 thorpej printf("[ krb5_auth_con_getkey: %s ]\r\n", 544 1.18 elric get_krb5_err_text(telnet_context, ret)); 545 1.4 thorpej auth_send_retry(); 546 1.4 thorpej return; 547 1.4 thorpej } 548 1.1 cgd skey.type = SK_DES; 549 1.1 cgd skey.length = 8; 550 1.4 thorpej skey.data = keyblock->keyvalue.data; 551 1.1 cgd encrypt_session_key(&skey, 0); 552 1.15 christos krb5_free_keyblock(telnet_context, keyblock); 553 1.4 thorpej auth_finished(ap, AUTH_USER); 554 1.4 thorpej if (forward_flags & OPTS_FORWARD_CREDS) 555 1.4 thorpej kerberos5_forward(ap); 556 1.4 thorpej break; 557 1.1 cgd } 558 1.1 cgd case KRB_RESPONSE: 559 1.4 thorpej if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 560 1.4 thorpej /* the rest of the reply should contain a krb_ap_rep */ 561 1.4 thorpej krb5_ap_rep_enc_part *reply; 562 1.4 thorpej krb5_data inbuf; 563 1.4 thorpej krb5_error_code ret; 564 1.4 thorpej 565 1.4 thorpej inbuf.length = cnt; 566 1.4 thorpej inbuf.data = (char *) data; 567 1.4 thorpej 568 1.4 thorpej ret = krb5_rd_rep(telnet_context, 569 1.4 thorpej auth_context, &inbuf, &reply); 570 1.4 thorpej if (ret) { 571 1.4 thorpej printf("[ Mutual authentication failed: %s ]\r\n", 572 1.18 elric get_krb5_err_text(telnet_context, ret)); 573 1.4 thorpej auth_send_retry(); 574 1.4 thorpej return; 575 1.4 thorpej } 576 1.4 thorpej krb5_free_ap_rep_enc_part(telnet_context, reply); 577 1.4 thorpej mutual_complete = 1; 578 1.1 cgd } 579 1.4 thorpej return; 580 1.4 thorpej case KRB_FORWARD_ACCEPT: 581 1.4 thorpej printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); 582 1.4 thorpej return; 583 1.4 thorpej case KRB_FORWARD_REJECT: 584 1.4 thorpej printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", 585 1.4 thorpej cnt, data); 586 1.4 thorpej return; 587 1.1 cgd default: 588 1.1 cgd if (auth_debug_mode) 589 1.1 cgd printf("Unknown Kerberos option %d\r\n", data[-1]); 590 1.1 cgd return; 591 1.1 cgd } 592 1.1 cgd } 593 1.1 cgd 594 1.4 thorpej int 595 1.11 itojun kerberos5_status(Authenticator *ap, char *name, size_t l, int level) 596 1.1 cgd { 597 1.1 cgd if (level < AUTH_USER) 598 1.4 thorpej return (level); 599 1.1 cgd 600 1.1 cgd if (UserNameRequested && 601 1.4 thorpej krb5_kuserok(telnet_context, ticket->client, UserNameRequested)) { 602 1.11 itojun strlcpy(name, UserNameRequested, l); 603 1.4 thorpej return (AUTH_VALID); 604 1.1 cgd } else 605 1.4 thorpej return (AUTH_USER); 606 1.1 cgd } 607 1.1 cgd #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 608 1.4 thorpej #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 609 1.1 cgd 610 1.4 thorpej void 611 1.4 thorpej kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen) 612 1.1 cgd { 613 1.4 thorpej int i; 614 1.1 cgd 615 1.4 thorpej buf[buflen - 1] = '\0'; /* make sure its NULL terminated */ 616 1.1 cgd buflen -= 1; 617 1.1 cgd 618 1.4 thorpej switch (data[3]) { 619 1.4 thorpej case KRB_REJECT: /* Rejected (reason might follow) */ 620 1.4 thorpej strlcpy((char *) buf, " REJECT ", buflen); 621 1.1 cgd goto common; 622 1.1 cgd 623 1.4 thorpej case KRB_ACCEPT: /* Accepted (name might follow) */ 624 1.4 thorpej strlcpy((char *) buf, " ACCEPT ", buflen); 625 1.4 thorpej common: 626 1.1 cgd BUMP(buf, buflen); 627 1.1 cgd if (cnt <= 4) 628 1.1 cgd break; 629 1.1 cgd ADDC(buf, buflen, '"'); 630 1.1 cgd for (i = 4; i < cnt; i++) 631 1.1 cgd ADDC(buf, buflen, data[i]); 632 1.1 cgd ADDC(buf, buflen, '"'); 633 1.1 cgd ADDC(buf, buflen, '\0'); 634 1.1 cgd break; 635 1.1 cgd 636 1.4 thorpej 637 1.4 thorpej case KRB_AUTH: /* Authentication data follows */ 638 1.4 thorpej strlcpy((char *) buf, " AUTH", buflen); 639 1.4 thorpej goto common2; 640 1.4 thorpej 641 1.4 thorpej case KRB_RESPONSE: 642 1.4 thorpej strlcpy((char *) buf, " RESPONSE", buflen); 643 1.1 cgd goto common2; 644 1.1 cgd 645 1.4 thorpej case KRB_FORWARD: /* Forwarded credentials follow */ 646 1.4 thorpej strlcpy((char *) buf, " FORWARD", buflen); 647 1.1 cgd goto common2; 648 1.1 cgd 649 1.4 thorpej case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 650 1.4 thorpej strlcpy((char *) buf, " FORWARD_ACCEPT", buflen); 651 1.4 thorpej goto common2; 652 1.4 thorpej 653 1.4 thorpej case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 654 1.4 thorpej /* (reason might follow) */ 655 1.4 thorpej strlcpy((char *) buf, " FORWARD_REJECT", buflen); 656 1.1 cgd goto common2; 657 1.1 cgd 658 1.1 cgd default: 659 1.4 thorpej snprintf(buf, buflen, " %d (unknown)", data[3]); 660 1.4 thorpej common2: 661 1.1 cgd BUMP(buf, buflen); 662 1.1 cgd for (i = 4; i < cnt; i++) { 663 1.4 thorpej snprintf(buf, buflen, " %d", data[i]); 664 1.1 cgd BUMP(buf, buflen); 665 1.1 cgd } 666 1.1 cgd break; 667 1.1 cgd } 668 1.1 cgd } 669 1.4 thorpej 670 1.4 thorpej void 671 1.4 thorpej kerberos5_forward(Authenticator * ap) 672 1.4 thorpej { 673 1.4 thorpej krb5_error_code ret; 674 1.4 thorpej krb5_ccache ccache; 675 1.4 thorpej krb5_creds creds; 676 1.4 thorpej krb5_kdc_flags flags; 677 1.4 thorpej krb5_data out_data; 678 1.4 thorpej krb5_principal principal; 679 1.4 thorpej 680 1.4 thorpej ret = krb5_cc_default(telnet_context, &ccache); 681 1.4 thorpej if (ret) { 682 1.4 thorpej if (auth_debug_mode) 683 1.4 thorpej printf("KerberosV5: could not get default ccache: %s\r\n", 684 1.18 elric get_krb5_err_text(telnet_context, ret)); 685 1.4 thorpej return; 686 1.4 thorpej } 687 1.4 thorpej ret = krb5_cc_get_principal(telnet_context, ccache, &principal); 688 1.4 thorpej if (ret) { 689 1.4 thorpej if (auth_debug_mode) 690 1.4 thorpej printf("KerberosV5: could not get principal: %s\r\n", 691 1.18 elric get_krb5_err_text(telnet_context, ret)); 692 1.4 thorpej return; 693 1.4 thorpej } 694 1.4 thorpej memset(&creds, 0, sizeof(creds)); 695 1.4 thorpej 696 1.4 thorpej creds.client = principal; 697 1.4 thorpej 698 1.4 thorpej ret = krb5_build_principal(telnet_context, &creds.server, 699 1.4 thorpej strlen(principal->realm), principal->realm, "krbtgt", 700 1.4 thorpej principal->realm, NULL); 701 1.4 thorpej 702 1.4 thorpej if (ret) { 703 1.4 thorpej if (auth_debug_mode) 704 1.4 thorpej printf("KerberosV5: could not get principal: %s\r\n", 705 1.18 elric get_krb5_err_text(telnet_context, ret)); 706 1.4 thorpej return; 707 1.4 thorpej } 708 1.4 thorpej creds.times.endtime = 0; 709 1.4 thorpej 710 1.4 thorpej flags.i = 0; 711 1.4 thorpej flags.b.forwarded = 1; 712 1.4 thorpej if (forward_flags & OPTS_FORWARDABLE_CREDS) 713 1.4 thorpej flags.b.forwardable = 1; 714 1.4 thorpej 715 1.4 thorpej ret = krb5_get_forwarded_creds(telnet_context, auth_context, 716 1.4 thorpej ccache, flags.i, RemoteHostName, &creds, &out_data); 717 1.4 thorpej if (ret) { 718 1.4 thorpej if (auth_debug_mode) 719 1.4 thorpej printf("Kerberos V5: error getting forwarded creds: %s\r\n", 720 1.18 elric get_krb5_err_text(telnet_context, ret)); 721 1.4 thorpej return; 722 1.4 thorpej } 723 1.4 thorpej if (!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) { 724 1.4 thorpej if (auth_debug_mode) 725 1.4 thorpej printf("Not enough room for authentication data\r\n"); 726 1.4 thorpej } else { 727 1.4 thorpej if (auth_debug_mode) 728 1.4 thorpej printf("Forwarded local Kerberos V5 credentials to server\r\n"); 729 1.4 thorpej } 730 1.4 thorpej } 731 1.4 thorpej #endif /* KRB5 */ 732