129088Smarkm/*- 229088Smarkm * Copyright (c) 1991, 1993 329088Smarkm * The Regents of the University of California. All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice, this list of conditions and the following disclaimer. 1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1129088Smarkm * notice, this list of conditions and the following disclaimer in the 1229088Smarkm * documentation and/or other materials provided with the distribution. 1329088Smarkm * 3. All advertising materials mentioning features or use of this software 1429088Smarkm * must display the following acknowledgement: 1529088Smarkm * This product includes software developed by the University of 1629088Smarkm * California, Berkeley and its contributors. 1729088Smarkm * 4. Neither the name of the University nor the names of its contributors 1829088Smarkm * may be used to endorse or promote products derived from this software 1929088Smarkm * without specific prior written permission. 2029088Smarkm * 2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2429088Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3129088Smarkm * SUCH DAMAGE. 3229088Smarkm */ 3329088Smarkm 3429088Smarkm/* 3529088Smarkm * Copyright (C) 1990 by the Massachusetts Institute of Technology 3629088Smarkm * 3729088Smarkm * Export of this software from the United States of America may 3829088Smarkm * require a specific license from the United States Government. 3929088Smarkm * It is the responsibility of any person or organization contemplating 4029088Smarkm * export to obtain such a license before exporting. 4129088Smarkm * 4229088Smarkm * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 4329088Smarkm * distribute this software and its documentation for any purpose and 4429088Smarkm * without fee is hereby granted, provided that the above copyright 4529088Smarkm * notice appear in all copies and that both that copyright notice and 4629088Smarkm * this permission notice appear in supporting documentation, and that 4729088Smarkm * the name of M.I.T. not be used in advertising or publicity pertaining 4829088Smarkm * to distribution of the software without specific, written prior 4929088Smarkm * permission. M.I.T. makes no representations about the suitability of 5029088Smarkm * this software for any purpose. It is provided "as is" without express 5129088Smarkm * or implied warranty. 5229088Smarkm */ 5329088Smarkm 5487139Smarkm#include <sys/cdefs.h> 5529088Smarkm 5687139Smarkm__FBSDID("$FreeBSD$"); 5787139Smarkm 5829088Smarkm#ifdef KRB5 5987139Smarkm 6029088Smarkm#include <arpa/telnet.h> 6181965Smarkm#include <stdio.h> 6281965Smarkm#include <stdlib.h> 6381965Smarkm#include <string.h> 6487139Smarkm#include <unistd.h> 6587139Smarkm#include <netdb.h> 6687139Smarkm#include <ctype.h> 6787139Smarkm#include <pwd.h> 6887139Smarkm#define Authenticator k5_Authenticator 6987139Smarkm#include <krb5.h> 7087139Smarkm#undef Authenticator 7129088Smarkm 7229088Smarkm#include "encrypt.h" 7329088Smarkm#include "auth.h" 7429088Smarkm#include "misc.h" 7529088Smarkm 7629088Smarkmint forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ 7729088Smarkm 7829088Smarkm/* These values need to be the same as those defined in telnet/main.c. */ 7929088Smarkm/* Either define them in both places, or put in some common header file. */ 8029088Smarkm#define OPTS_FORWARD_CREDS 0x00000002 8129088Smarkm#define OPTS_FORWARDABLE_CREDS 0x00000001 8229088Smarkm 8387139Smarkmvoid kerberos5_forward (Authenticator *); 8429088Smarkm 8529088Smarkmstatic unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, 8629088Smarkm AUTHTYPE_KERBEROS_V5, }; 8729088Smarkm 8829088Smarkm#define KRB_AUTH 0 /* Authentication data follows */ 8929088Smarkm#define KRB_REJECT 1 /* Rejected (reason might follow) */ 9029088Smarkm#define KRB_ACCEPT 2 /* Accepted */ 9129088Smarkm#define KRB_RESPONSE 3 /* Response for mutual auth. */ 9229088Smarkm 9329088Smarkm#define KRB_FORWARD 4 /* Forwarded credentials follow */ 9429088Smarkm#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ 9529088Smarkm#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ 9629088Smarkm 9729088Smarkmstatic krb5_data auth; 9887139Smarkmstatic krb5_ticket *ticket; 9929088Smarkm 10087139Smarkmstatic krb5_context context; 10187139Smarkmstatic krb5_auth_context auth_context; 10229088Smarkm 103233932Sstasstatic void 104233932Sstasprint_krb5_error(krb5_context context, krb5_error_code code, const char *msg) 105233932Sstas{ 106233932Sstas const char *error_message; 107233932Sstas 108233932Sstas error_message = krb5_get_error_message(context, code); 109233932Sstas printf(msg, error_message); 110233932Sstas krb5_free_error_message(context, error_message); 111233932Sstas} 112233932Sstas 11387139Smarkmstatic int 11487139SmarkmData(Authenticator *ap, int type, const char *d, int c) 11587139Smarkm{ 11687139Smarkm unsigned char *p = str_data + 4; 11787139Smarkm const unsigned char *cd = d; 11829088Smarkm 11987139Smarkm if (c == -1) 12087139Smarkm c = strlen(cd); 12129088Smarkm 12287139Smarkm if (auth_debug_mode) { 12387139Smarkm printf("%s:%d: [%d] (%d)", 12487139Smarkm str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 12587139Smarkm str_data[3], 12687139Smarkm type, c); 12787139Smarkm printd(d, c); 12887139Smarkm printf("\r\n"); 12987139Smarkm } 13087139Smarkm *p++ = ap->type; 13187139Smarkm *p++ = ap->way; 13287139Smarkm *p++ = type; 13387139Smarkm while (c-- > 0) { 13487139Smarkm if ((*p++ = *cd++) == IAC) 13587139Smarkm *p++ = IAC; 13687139Smarkm } 13787139Smarkm *p++ = IAC; 13887139Smarkm *p++ = SE; 13987139Smarkm if (str_data[3] == TELQUAL_IS) 14087139Smarkm printsub('>', &str_data[2], p - &str_data[2]); 14187139Smarkm return(net_write(str_data, p - str_data)); 14287139Smarkm} 14387139Smarkm 14487139Smarkmint 14587139Smarkmkerberos5_init(Authenticator *ap __unused, int server) 14629088Smarkm{ 14787139Smarkm krb5_error_code ret; 14829088Smarkm 14987139Smarkm ret = krb5_init_context(&context); 15087139Smarkm if (ret) 15187139Smarkm return 0; 15287139Smarkm if (server) { 15387139Smarkm krb5_keytab kt; 15487139Smarkm krb5_kt_cursor cursor; 15529088Smarkm 15687139Smarkm ret = krb5_kt_default(context, &kt); 15787139Smarkm if (ret) 15887139Smarkm return 0; 15987139Smarkm 16087139Smarkm ret = krb5_kt_start_seq_get (context, kt, &cursor); 16187139Smarkm if (ret) { 16287139Smarkm krb5_kt_close (context, kt); 16387139Smarkm return 0; 16429088Smarkm } 16587139Smarkm krb5_kt_end_seq_get (context, kt, &cursor); 16687139Smarkm krb5_kt_close (context, kt); 16729088Smarkm 16887139Smarkm str_data[3] = TELQUAL_REPLY; 16987139Smarkm } else 17087139Smarkm str_data[3] = TELQUAL_IS; 17187139Smarkm return(1); 17229088Smarkm} 17329088Smarkm 17487139Smarkmextern int net; 17587139Smarkm 17687139Smarkmstatic int 17787139Smarkmkerberos5_send(const char *name, Authenticator *ap) 17829088Smarkm{ 17987139Smarkm krb5_error_code ret; 18087139Smarkm krb5_ccache ccache; 18187139Smarkm int ap_opts; 18287139Smarkm krb5_data cksum_data; 18387139Smarkm char foo[2]; 18487139Smarkm 18587139Smarkm if (!UserNameRequested) { 18687139Smarkm if (auth_debug_mode) { 18787139Smarkm printf("Kerberos V5: no user name supplied\r\n"); 18887139Smarkm } 18987139Smarkm return(0); 19087139Smarkm } 19187139Smarkm 19287139Smarkm ret = krb5_cc_default(context, &ccache); 19387139Smarkm if (ret) { 19487139Smarkm if (auth_debug_mode) { 195233932Sstas print_krb5_error(context, ret, "Kerberos V5: could not get default ccache: %s\r\n"); 19687139Smarkm } 19787139Smarkm return 0; 19887139Smarkm } 19987139Smarkm 20087139Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 20187139Smarkm ap_opts = AP_OPTS_MUTUAL_REQUIRED; 20287139Smarkm else 20387139Smarkm ap_opts = 0; 204111946Snectar ap_opts |= AP_OPTS_USE_SUBKEY; 20587139Smarkm 20687139Smarkm ret = krb5_auth_con_init (context, &auth_context); 20787139Smarkm if (ret) { 20887139Smarkm if (auth_debug_mode) { 209233932Sstas print_krb5_error(context, ret, "Kerberos V5: krb5_auth_con_init failed (%s)\r\n"); 21087139Smarkm } 21187139Smarkm return(0); 21287139Smarkm } 21329088Smarkm 21487139Smarkm ret = krb5_auth_con_setaddrs_from_fd (context, 21587139Smarkm auth_context, 21687139Smarkm &net); 21787139Smarkm if (ret) { 21887139Smarkm if (auth_debug_mode) { 219233932Sstas print_krb5_error(context, ret, "Kerberos V5:" 220233932Sstas " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n"); 22187139Smarkm } 22287139Smarkm return(0); 22387139Smarkm } 22429088Smarkm 22590931Snectar krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES); 22629088Smarkm 22787139Smarkm foo[0] = ap->type; 22887139Smarkm foo[1] = ap->way; 22929088Smarkm 23087139Smarkm cksum_data.length = sizeof(foo); 23187139Smarkm cksum_data.data = foo; 23229088Smarkm 23329088Smarkm 23487139Smarkm { 23587139Smarkm krb5_principal service; 23687139Smarkm char sname[128]; 23729088Smarkm 23829088Smarkm 23987139Smarkm ret = krb5_sname_to_principal (context, 24087139Smarkm RemoteHostName, 24187139Smarkm NULL, 24287139Smarkm KRB5_NT_SRV_HST, 24387139Smarkm &service); 24487139Smarkm if(ret) { 24587139Smarkm if (auth_debug_mode) { 246233932Sstas const char *err_str; 247233932Sstas 248233932Sstas err_str = krb5_get_error_message(context, ret); 249233932Sstas printf("Kerberosr V5:" 25087139Smarkm " krb5_sname_to_principal(%s) failed (%s)\r\n", 251233932Sstas RemoteHostName, err_str); 252233932Sstas krb5_free_error_message(context, err_str); 25387139Smarkm } 25487139Smarkm return 0; 25529088Smarkm } 25687139Smarkm ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname)); 25787139Smarkm if(ret) { 25887139Smarkm if (auth_debug_mode) { 259233932Sstas print_krb5_error(context, ret, "Kerberos V5:" 260233932Sstas " krb5_unparse_name_fixed failed (%s)\r\n"); 26187139Smarkm } 26287139Smarkm return 0; 26387139Smarkm } 26487139Smarkm printf("[ Trying %s (%s)... ]\r\n", name, sname); 26587139Smarkm ret = krb5_mk_req_exact(context, &auth_context, ap_opts, 26687139Smarkm service, 26787139Smarkm &cksum_data, ccache, &auth); 26887139Smarkm krb5_free_principal (context, service); 26929088Smarkm 27087139Smarkm } 27187139Smarkm if (ret) { 27287139Smarkm if (1 || auth_debug_mode) { 273233932Sstas print_krb5_error(context, ret, "Kerberos V5: mk_req failed (%s)\r\n"); 27429088Smarkm } 27587139Smarkm return(0); 27687139Smarkm } 27729088Smarkm 27887139Smarkm if (!auth_sendname((unsigned char *)UserNameRequested, 27987139Smarkm strlen(UserNameRequested))) { 28087139Smarkm if (auth_debug_mode) 28187139Smarkm printf("Not enough room for user name\r\n"); 28287139Smarkm return(0); 28387139Smarkm } 28487139Smarkm if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 28587139Smarkm if (auth_debug_mode) 28687139Smarkm printf("Not enough room for authentication data\r\n"); 28787139Smarkm return(0); 28887139Smarkm } 28987139Smarkm if (auth_debug_mode) { 29087139Smarkm printf("Sent Kerberos V5 credentials to server\r\n"); 29187139Smarkm } 29287139Smarkm return(1); 29387139Smarkm} 29429088Smarkm 29587139Smarkmint 29687139Smarkmkerberos5_send_mutual(Authenticator *ap) 29787139Smarkm{ 29887139Smarkm return kerberos5_send("mutual KERBEROS5", ap); 29987139Smarkm} 30029088Smarkm 30187139Smarkmint 30287139Smarkmkerberos5_send_oneway(Authenticator *ap) 30387139Smarkm{ 30487139Smarkm return kerberos5_send("KERBEROS5", ap); 30587139Smarkm} 30687139Smarkm 30787139Smarkmvoid 30887139Smarkmkerberos5_is(Authenticator *ap, unsigned char *data, int cnt) 30987139Smarkm{ 31087139Smarkm krb5_error_code ret; 31187139Smarkm krb5_data outbuf; 31287139Smarkm krb5_keyblock *key_block; 31387139Smarkm char *name; 31487139Smarkm krb5_principal server; 31587139Smarkm int zero = 0; 31687139Smarkm 31787139Smarkm if (cnt-- < 1) 31887139Smarkm return; 31987139Smarkm switch (*data++) { 32087139Smarkm case KRB_AUTH: 32187139Smarkm auth.data = (char *)data; 32287139Smarkm auth.length = cnt; 32387139Smarkm 32487139Smarkm auth_context = NULL; 32587139Smarkm 32687139Smarkm ret = krb5_auth_con_init (context, &auth_context); 32787139Smarkm if (ret) { 32887139Smarkm Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); 32987139Smarkm auth_finished(ap, AUTH_REJECT); 33087139Smarkm if (auth_debug_mode) 331233932Sstas print_krb5_error(context, ret, "Kerberos V5: krb5_auth_con_init failed (%s)\r\n"); 33287139Smarkm return; 33329088Smarkm } 33429088Smarkm 33587139Smarkm ret = krb5_auth_con_setaddrs_from_fd (context, 33687139Smarkm auth_context, 33787139Smarkm &zero); 33887139Smarkm if (ret) { 33987139Smarkm Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); 34087139Smarkm auth_finished(ap, AUTH_REJECT); 34187139Smarkm if (auth_debug_mode) 342233932Sstas print_krb5_error(context, ret, "Kerberos V5: " 343233932Sstas "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n"); 34487139Smarkm return; 34529088Smarkm } 34629088Smarkm 34787139Smarkm ret = krb5_sock_to_principal (context, 34887139Smarkm 0, 34987139Smarkm "host", 35087139Smarkm KRB5_NT_SRV_HST, 35187139Smarkm &server); 35287139Smarkm if (ret) { 35387139Smarkm Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); 35487139Smarkm auth_finished(ap, AUTH_REJECT); 35587139Smarkm if (auth_debug_mode) 356233932Sstas print_krb5_error(context, ret, "Kerberos V5: " 357233932Sstas "krb5_sock_to_principal failed (%s)\r\n"); 35887139Smarkm return; 35987139Smarkm } 36029088Smarkm 36187139Smarkm ret = krb5_rd_req(context, 36287139Smarkm &auth_context, 36387139Smarkm &auth, 36487139Smarkm server, 36587139Smarkm NULL, 36687139Smarkm NULL, 36787139Smarkm &ticket); 36829088Smarkm 36987139Smarkm krb5_free_principal (context, server); 37087139Smarkm if (ret) { 37187139Smarkm char *errbuf; 372233932Sstas const char *err_str; 37387139Smarkm 374233932Sstas err_str = krb5_get_error_message(context, ret); 37587139Smarkm asprintf(&errbuf, 376233932Sstas "Read req failed: %s", err_str); 377233932Sstas krb5_free_error_message(context, err_str); 37887139Smarkm Data(ap, KRB_REJECT, errbuf, -1); 37987139Smarkm if (auth_debug_mode) 38087139Smarkm printf("%s\r\n", errbuf); 38187139Smarkm free (errbuf); 38287139Smarkm return; 38329088Smarkm } 38487139Smarkm 38587139Smarkm { 38687139Smarkm char foo[2]; 38787139Smarkm 38887139Smarkm foo[0] = ap->type; 38987139Smarkm foo[1] = ap->way; 39087139Smarkm 39187139Smarkm ret = krb5_verify_authenticator_checksum(context, 39287139Smarkm auth_context, 39387139Smarkm foo, 39487139Smarkm sizeof(foo)); 39529088Smarkm 39687139Smarkm if (ret) { 39787139Smarkm char *errbuf; 398233932Sstas const char *err_str; 399233932Sstas 400233932Sstas err_str = krb5_get_error_message(context, ret); 401233932Sstas asprintf(&errbuf, "Bad checksum: %s", err_str); 402233932Sstas krb5_free_error_message(context, err_str); 40387139Smarkm Data(ap, KRB_REJECT, errbuf, -1); 40429088Smarkm if (auth_debug_mode) 40587139Smarkm printf ("%s\r\n", errbuf); 40687139Smarkm free(errbuf); 40787139Smarkm return; 40887139Smarkm } 40929088Smarkm } 41087139Smarkm ret = krb5_auth_con_getremotesubkey (context, 41187139Smarkm auth_context, 41287139Smarkm &key_block); 41387139Smarkm 41487139Smarkm if (ret) { 41587139Smarkm Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); 41687139Smarkm auth_finished(ap, AUTH_REJECT); 41787139Smarkm if (auth_debug_mode) 418233932Sstas print_krb5_error(context, ret, "Kerberos V5: " 419233932Sstas "krb5_auth_con_getremotesubkey failed (%s)\r\n"); 42087139Smarkm return; 42129088Smarkm } 42229088Smarkm 423111946Snectar if (key_block == NULL) { 424111946Snectar ret = krb5_auth_con_getkey(context, 425111946Snectar auth_context, 426111946Snectar &key_block); 427111946Snectar } 428111946Snectar if (ret) { 429111946Snectar Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); 430111946Snectar auth_finished(ap, AUTH_REJECT); 431111946Snectar if (auth_debug_mode) 432233932Sstas print_krb5_error(context, ret, "Kerberos V5: " 433233932Sstas "krb5_auth_con_getkey failed (%s)\r\n"); 434111946Snectar return; 435111946Snectar } 436111946Snectar if (key_block == NULL) { 437111946Snectar Data(ap, KRB_REJECT, "no subkey received", -1); 438111946Snectar auth_finished(ap, AUTH_REJECT); 439111946Snectar if (auth_debug_mode) 440111946Snectar printf("Kerberos V5: " 441111946Snectar "krb5_auth_con_getremotesubkey returned NULL key\r\n"); 442111946Snectar return; 443111946Snectar } 444111946Snectar 44587139Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 44687139Smarkm ret = krb5_mk_rep(context, auth_context, &outbuf); 44787139Smarkm if (ret) { 44887139Smarkm Data(ap, KRB_REJECT, 44987139Smarkm "krb5_mk_rep failed", -1); 45087139Smarkm auth_finished(ap, AUTH_REJECT); 45187139Smarkm if (auth_debug_mode) 452233932Sstas print_krb5_error(context, ret, "Kerberos V5: " 453233932Sstas "krb5_mk_rep failed (%s)\r\n"); 45429088Smarkm return; 45587139Smarkm } 45687139Smarkm Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); 45787139Smarkm } 45887139Smarkm if (krb5_unparse_name(context, ticket->client, &name)) 45987139Smarkm name = 0; 46029088Smarkm 46187139Smarkm if(UserNameRequested && krb5_kuserok(context, 46287139Smarkm ticket->client, 46387139Smarkm UserNameRequested)) { 46487139Smarkm Data(ap, KRB_ACCEPT, name, name ? -1 : 0); 46587139Smarkm if (auth_debug_mode) { 46687139Smarkm printf("Kerberos5 identifies him as ``%s''\r\n", 46787139Smarkm name ? name : ""); 46887139Smarkm } 46929088Smarkm 47087139Smarkm if(key_block->keytype == ETYPE_DES_CBC_MD5 || 47187139Smarkm key_block->keytype == ETYPE_DES_CBC_MD4 || 47287139Smarkm key_block->keytype == ETYPE_DES_CBC_CRC) { 47387139Smarkm Session_Key skey; 47429088Smarkm 47587139Smarkm skey.type = SK_DES; 47687139Smarkm skey.length = 8; 47787139Smarkm skey.data = key_block->keyvalue.data; 47887139Smarkm encrypt_session_key(&skey, 0); 47987139Smarkm } 48029088Smarkm 48187139Smarkm } else { 48287139Smarkm char *msg; 48329088Smarkm 48487139Smarkm asprintf (&msg, "user `%s' is not authorized to " 48587139Smarkm "login as `%s'", 48687139Smarkm name ? name : "<unknown>", 48787139Smarkm UserNameRequested ? UserNameRequested : "<nobody>"); 48887139Smarkm if (msg == NULL) 48987139Smarkm Data(ap, KRB_REJECT, NULL, 0); 49087139Smarkm else { 49187139Smarkm Data(ap, KRB_REJECT, (void *)msg, -1); 49287139Smarkm free(msg); 49387139Smarkm } 49487139Smarkm auth_finished (ap, AUTH_REJECT); 49587139Smarkm krb5_free_keyblock_contents(context, key_block); 49687139Smarkm break; 49787139Smarkm } 49887139Smarkm auth_finished(ap, AUTH_USER); 49987139Smarkm krb5_free_keyblock_contents(context, key_block); 50087139Smarkm 50187139Smarkm break; 50287139Smarkm case KRB_FORWARD: { 50387139Smarkm struct passwd *pwd; 50487139Smarkm char ccname[1024]; /* XXX */ 50587139Smarkm krb5_data inbuf; 50687139Smarkm krb5_ccache ccache; 50787139Smarkm inbuf.data = (char *)data; 50887139Smarkm inbuf.length = cnt; 50929088Smarkm 51087139Smarkm pwd = getpwnam (UserNameRequested); 51187139Smarkm if (pwd == NULL) 51287139Smarkm break; 51329088Smarkm 51487139Smarkm snprintf (ccname, sizeof(ccname), 51587139Smarkm "FILE:/tmp/krb5cc_%u", pwd->pw_uid); 51629088Smarkm 51787139Smarkm ret = krb5_cc_resolve (context, ccname, &ccache); 51887139Smarkm if (ret) { 51987139Smarkm if (auth_debug_mode) 520233932Sstas print_krb5_error(context, ret, "Kerberos V5: could not get ccache: %s\r\n"); 52187139Smarkm break; 52287139Smarkm } 52329088Smarkm 52487139Smarkm ret = krb5_cc_initialize (context, 52587139Smarkm ccache, 52687139Smarkm ticket->client); 52787139Smarkm if (ret) { 52887139Smarkm if (auth_debug_mode) 529233932Sstas print_krb5_error(context, ret, "Kerberos V5: could not init ccache: %s\r\n"); 53087139Smarkm break; 53187139Smarkm } 53229088Smarkm 53387139Smarkm#if defined(DCE) 53487139Smarkm esetenv("KRB5CCNAME", ccname, 1); 53587139Smarkm#endif 53687139Smarkm ret = krb5_rd_cred2 (context, 53787139Smarkm auth_context, 53887139Smarkm ccache, 53987139Smarkm &inbuf); 54087139Smarkm if(ret) { 54187139Smarkm char *errbuf; 542233932Sstas const char *err_str; 54329088Smarkm 544233932Sstas err_str = krb5_get_error_message(context, ret); 54587139Smarkm asprintf (&errbuf, 546233932Sstas "Read forwarded creds failed: %s", err_str); 547233932Sstas krb5_free_error_message(context, err_str); 54887139Smarkm if(errbuf == NULL) 54987139Smarkm Data(ap, KRB_FORWARD_REJECT, NULL, 0); 55087139Smarkm else 55187139Smarkm Data(ap, KRB_FORWARD_REJECT, errbuf, -1); 55287139Smarkm if (auth_debug_mode) 55387139Smarkm printf("Could not read forwarded credentials: %s\r\n", 55487139Smarkm errbuf); 55587139Smarkm free (errbuf); 55687139Smarkm } else { 55787139Smarkm Data(ap, KRB_FORWARD_ACCEPT, 0, 0); 55887139Smarkm#if defined(DCE) 55987139Smarkm dfsfwd = 1; 56087139Smarkm#endif 56129088Smarkm } 56287139Smarkm chown (ccname + 5, pwd->pw_uid, -1); 56387139Smarkm if (auth_debug_mode) 56487139Smarkm printf("Forwarded credentials obtained\r\n"); 56587139Smarkm break; 56687139Smarkm } 56787139Smarkm default: 56887139Smarkm if (auth_debug_mode) 56987139Smarkm printf("Unknown Kerberos option %d\r\n", data[-1]); 57087139Smarkm Data(ap, KRB_REJECT, 0, 0); 57187139Smarkm break; 57287139Smarkm } 57329088Smarkm} 57429088Smarkm 57587139Smarkmvoid 57687139Smarkmkerberos5_reply(Authenticator *ap, unsigned char *data, int cnt) 57729088Smarkm{ 57887139Smarkm static int mutual_complete = 0; 57987139Smarkm 58087139Smarkm if (cnt-- < 1) 58187139Smarkm return; 58287139Smarkm switch (*data++) { 58387139Smarkm case KRB_REJECT: 58487139Smarkm if (cnt > 0) { 58587139Smarkm printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 58687139Smarkm cnt, data); 58787139Smarkm } else 58887139Smarkm printf("[ Kerberos V5 refuses authentication ]\r\n"); 58987139Smarkm auth_send_retry(); 59087139Smarkm return; 59187139Smarkm case KRB_ACCEPT: { 59287139Smarkm krb5_error_code ret; 59329088Smarkm Session_Key skey; 59487139Smarkm krb5_keyblock *keyblock; 59587139Smarkm 59687139Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && 59787139Smarkm !mutual_complete) { 59887139Smarkm printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); 59987139Smarkm auth_send_retry(); 60087139Smarkm return; 60187139Smarkm } 60287139Smarkm if (cnt) 60387139Smarkm printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); 60487139Smarkm else 60587139Smarkm printf("[ Kerberos V5 accepts you ]\r\n"); 60687139Smarkm 60787139Smarkm ret = krb5_auth_con_getlocalsubkey (context, 60887139Smarkm auth_context, 60987139Smarkm &keyblock); 61087139Smarkm if (ret) 61187139Smarkm ret = krb5_auth_con_getkey (context, 61287139Smarkm auth_context, 61387139Smarkm &keyblock); 61487139Smarkm if(ret) { 615233932Sstas print_krb5_error(context, ret, "[ krb5_auth_con_getkey: %s ]\r\n"); 61687139Smarkm auth_send_retry(); 61787139Smarkm return; 61887139Smarkm } 61987139Smarkm 62087139Smarkm skey.type = SK_DES; 62187139Smarkm skey.length = 8; 62287139Smarkm skey.data = keyblock->keyvalue.data; 62387139Smarkm encrypt_session_key(&skey, 0); 62487139Smarkm krb5_free_keyblock_contents (context, keyblock); 62587139Smarkm auth_finished(ap, AUTH_USER); 62687139Smarkm if (forward_flags & OPTS_FORWARD_CREDS) 62787139Smarkm kerberos5_forward(ap); 62887139Smarkm break; 62987139Smarkm } 63087139Smarkm case KRB_RESPONSE: 63187139Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 63287139Smarkm /* the rest of the reply should contain a krb_ap_rep */ 63387139Smarkm krb5_ap_rep_enc_part *reply; 63487139Smarkm krb5_data inbuf; 63587139Smarkm krb5_error_code ret; 63687139Smarkm 63787139Smarkm inbuf.length = cnt; 63887139Smarkm inbuf.data = (char *)data; 63929088Smarkm 64087139Smarkm ret = krb5_rd_rep(context, auth_context, &inbuf, &reply); 64187139Smarkm if (ret) { 642233932Sstas print_krb5_error(context, ret, "[ Mutual authentication failed: %s ]\r\n"); 64387139Smarkm auth_send_retry(); 64487139Smarkm return; 64587139Smarkm } 64687139Smarkm krb5_free_ap_rep_enc_part(context, reply); 64787139Smarkm mutual_complete = 1; 64829088Smarkm } 64987139Smarkm return; 65087139Smarkm case KRB_FORWARD_ACCEPT: 65187139Smarkm printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); 65287139Smarkm return; 65387139Smarkm case KRB_FORWARD_REJECT: 65487139Smarkm printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", 65587139Smarkm cnt, data); 65687139Smarkm return; 65787139Smarkm default: 65887139Smarkm if (auth_debug_mode) 65987139Smarkm printf("Unknown Kerberos option %d\r\n", data[-1]); 66087139Smarkm return; 66187139Smarkm } 66229088Smarkm} 66329088Smarkm 66487139Smarkmint 66587139Smarkmkerberos5_status(Authenticator *ap __unused, char *name, int level) 66629088Smarkm{ 66787139Smarkm if (level < AUTH_USER) 66887139Smarkm return(level); 66929088Smarkm 67087139Smarkm if (UserNameRequested && 67187139Smarkm krb5_kuserok(context, 67287139Smarkm ticket->client, 67387139Smarkm UserNameRequested)) 67429088Smarkm { 67587139Smarkm strcpy(name, UserNameRequested); 67687139Smarkm return(AUTH_VALID); 67729088Smarkm } else 67887139Smarkm return(AUTH_USER); 67929088Smarkm} 68029088Smarkm 68129088Smarkm#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 68229088Smarkm#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 68329088Smarkm 68487139Smarkmvoid 68587139Smarkmkerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen) 68629088Smarkm{ 68787139Smarkm int i; 68829088Smarkm 68987139Smarkm buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 69087139Smarkm buflen -= 1; 69129088Smarkm 69287139Smarkm switch(data[3]) { 69387139Smarkm case KRB_REJECT: /* Rejected (reason might follow) */ 69487139Smarkm strlcpy((char *)buf, " REJECT ", buflen); 69587139Smarkm goto common; 69629088Smarkm 69787139Smarkm case KRB_ACCEPT: /* Accepted (name might follow) */ 69887139Smarkm strlcpy((char *)buf, " ACCEPT ", buflen); 69987139Smarkm common: 70087139Smarkm BUMP(buf, buflen); 70187139Smarkm if (cnt <= 4) 70287139Smarkm break; 70387139Smarkm ADDC(buf, buflen, '"'); 70487139Smarkm for (i = 4; i < cnt; i++) 70587139Smarkm ADDC(buf, buflen, data[i]); 70687139Smarkm ADDC(buf, buflen, '"'); 70787139Smarkm ADDC(buf, buflen, '\0'); 70887139Smarkm break; 70929088Smarkm 71029088Smarkm 71187139Smarkm case KRB_AUTH: /* Authentication data follows */ 71287139Smarkm strlcpy((char *)buf, " AUTH", buflen); 71387139Smarkm goto common2; 71429088Smarkm 71587139Smarkm case KRB_RESPONSE: 71687139Smarkm strlcpy((char *)buf, " RESPONSE", buflen); 71787139Smarkm goto common2; 71829088Smarkm 71987139Smarkm case KRB_FORWARD: /* Forwarded credentials follow */ 72087139Smarkm strlcpy((char *)buf, " FORWARD", buflen); 72187139Smarkm goto common2; 72229088Smarkm 72387139Smarkm case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 72487139Smarkm strlcpy((char *)buf, " FORWARD_ACCEPT", buflen); 72587139Smarkm goto common2; 72629088Smarkm 72787139Smarkm case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 72887139Smarkm /* (reason might follow) */ 72987139Smarkm strlcpy((char *)buf, " FORWARD_REJECT", buflen); 73087139Smarkm goto common2; 73129088Smarkm 73287139Smarkm default: 73387139Smarkm snprintf(buf, buflen, " %d (unknown)", data[3]); 73487139Smarkm common2: 73587139Smarkm BUMP(buf, buflen); 73687139Smarkm for (i = 4; i < cnt; i++) { 73787139Smarkm snprintf(buf, buflen, " %d", data[i]); 73887139Smarkm BUMP(buf, buflen); 73929088Smarkm } 74087139Smarkm break; 74187139Smarkm } 74229088Smarkm} 74329088Smarkm 74487139Smarkmvoid 74587139Smarkmkerberos5_forward(Authenticator *ap) 74629088Smarkm{ 74787139Smarkm krb5_error_code ret; 74887139Smarkm krb5_ccache ccache; 74987139Smarkm krb5_creds creds; 75087139Smarkm krb5_kdc_flags flags; 75187139Smarkm krb5_data out_data; 75287139Smarkm krb5_principal principal; 75329088Smarkm 75487139Smarkm ret = krb5_cc_default (context, &ccache); 75587139Smarkm if (ret) { 75629088Smarkm if (auth_debug_mode) 757233932Sstas print_krb5_error(context, ret, "KerberosV5: could not get default ccache: %s\r\n"); 75829088Smarkm return; 75929088Smarkm } 76029088Smarkm 76187139Smarkm ret = krb5_cc_get_principal (context, ccache, &principal); 76287139Smarkm if (ret) { 76329088Smarkm if (auth_debug_mode) 764233932Sstas print_krb5_error(context, ret, "KerberosV5: could not get principal: %s\r\n"); 76529088Smarkm return; 76629088Smarkm } 76729088Smarkm 76887139Smarkm memset (&creds, 0, sizeof(creds)); 76929088Smarkm 77087139Smarkm creds.client = principal; 77187139Smarkm 77287139Smarkm ret = krb5_build_principal (context, 77387139Smarkm &creds.server, 77487139Smarkm strlen(principal->realm), 77587139Smarkm principal->realm, 77687139Smarkm "krbtgt", 77787139Smarkm principal->realm, 77887139Smarkm NULL); 77929088Smarkm 78087139Smarkm if (ret) { 78129088Smarkm if (auth_debug_mode) 782233932Sstas print_krb5_error(context, ret, "KerberosV5: could not get principal: %s\r\n"); 78329088Smarkm return; 78429088Smarkm } 78529088Smarkm 78687139Smarkm creds.times.endtime = 0; 78787139Smarkm 78887139Smarkm flags.i = 0; 78987139Smarkm flags.b.forwarded = 1; 79087139Smarkm if (forward_flags & OPTS_FORWARDABLE_CREDS) 79187139Smarkm flags.b.forwardable = 1; 79287139Smarkm 79387139Smarkm ret = krb5_get_forwarded_creds (context, 79487139Smarkm auth_context, 79587139Smarkm ccache, 79687139Smarkm flags.i, 79787139Smarkm RemoteHostName, 79887139Smarkm &creds, 79987139Smarkm &out_data); 80087139Smarkm if (ret) { 80129088Smarkm if (auth_debug_mode) 802233932Sstas print_krb5_error(context, ret, "Kerberos V5: error getting forwarded creds: %s\r\n"); 80329088Smarkm return; 80429088Smarkm } 80529088Smarkm 80687139Smarkm if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) { 80729088Smarkm if (auth_debug_mode) 80887139Smarkm printf("Not enough room for authentication data\r\n"); 80987139Smarkm } else { 81029088Smarkm if (auth_debug_mode) 81187139Smarkm printf("Forwarded local Kerberos V5 credentials to server\r\n"); 81229088Smarkm } 81387139Smarkm} 81429088Smarkm 81587139Smarkm#if defined(DCE) 81687139Smarkm/* if this was a K5 authentication try and join a PAG for the user. */ 81787139Smarkmvoid 81887139Smarkmkerberos5_dfspag(void) 81987139Smarkm{ 82087139Smarkm if (dfsk5ok) { 82187139Smarkm dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client, 82287139Smarkm UserNameRequested); 82387139Smarkm } 82429088Smarkm} 82587139Smarkm#endif 82629088Smarkm 82729088Smarkm#endif /* KRB5 */ 828