157416Smarkm/*- 257416Smarkm * Copyright (c) 1991, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm/* 3557416Smarkm * Copyright (C) 1990 by the Massachusetts Institute of Technology 3657416Smarkm * 3757416Smarkm * Export of this software from the United States of America may 3857416Smarkm * require a specific license from the United States Government. 3957416Smarkm * It is the responsibility of any person or organization contemplating 4057416Smarkm * export to obtain such a license before exporting. 4157416Smarkm * 4257416Smarkm * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 4357416Smarkm * distribute this software and its documentation for any purpose and 4457416Smarkm * without fee is hereby granted, provided that the above copyright 4557416Smarkm * notice appear in all copies and that both that copyright notice and 4657416Smarkm * this permission notice appear in supporting documentation, and that 4757416Smarkm * the name of M.I.T. not be used in advertising or publicity pertaining 4857416Smarkm * to distribution of the software without specific, written prior 4957416Smarkm * permission. M.I.T. makes no representations about the suitability of 5057416Smarkm * this software for any purpose. It is provided "as is" without express 5157416Smarkm * or implied warranty. 5257416Smarkm */ 5357416Smarkm 5457416Smarkm#include <config.h> 5557416Smarkm 56233294SstasRCSID("$Id$"); 5757416Smarkm 5857416Smarkm#ifdef KRB5 5957416Smarkm 6057416Smarkm#include <arpa/telnet.h> 6157416Smarkm#include <stdio.h> 6257416Smarkm#include <stdlib.h> 6357416Smarkm#include <string.h> 6457416Smarkm#include <unistd.h> 6557416Smarkm#include <netdb.h> 6657416Smarkm#include <ctype.h> 6757416Smarkm#include <pwd.h> 6857416Smarkm#define Authenticator k5_Authenticator 6957416Smarkm#include <krb5.h> 7057416Smarkm#undef Authenticator 7157416Smarkm#include <roken.h> 7257416Smarkm#ifdef SOCKS 7357416Smarkm#include <socks.h> 7457416Smarkm#endif 7557416Smarkm 7657416Smarkm 7757416Smarkm#include "encrypt.h" 7857416Smarkm#include "auth.h" 7957416Smarkm#include "misc.h" 8057416Smarkm 8172445Sassar#if defined(DCE) 8272445Sassarint dfsk5ok = 0; 8372445Sassarint dfspag = 0; 8472445Sassarint dfsfwd = 0; 8572445Sassar#endif 8672445Sassar 8757416Smarkmint forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ 8857416Smarkm 89102644Snectarint forward(int); 90102644Snectarint forwardable(int); 91102644Snectar 9257416Smarkm/* These values need to be the same as those defined in telnet/main.c. */ 9357416Smarkm/* Either define them in both places, or put in some common header file. */ 9457416Smarkm#define OPTS_FORWARD_CREDS 0x00000002 9557416Smarkm#define OPTS_FORWARDABLE_CREDS 0x00000001 9657416Smarkm 97102644Snectar 9857416Smarkmvoid kerberos5_forward (Authenticator *); 9957416Smarkm 100142403Snectarstatic unsigned char str_data[4] = { IAC, SB, TELOPT_AUTHENTICATION, 0 }; 10157416Smarkm 10257416Smarkm#define KRB_AUTH 0 /* Authentication data follows */ 10357416Smarkm#define KRB_REJECT 1 /* Rejected (reason might follow) */ 10457416Smarkm#define KRB_ACCEPT 2 /* Accepted */ 10557416Smarkm#define KRB_RESPONSE 3 /* Response for mutual auth. */ 10657416Smarkm 10757416Smarkm#define KRB_FORWARD 4 /* Forwarded credentials follow */ 10857416Smarkm#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ 10957416Smarkm#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ 11057416Smarkm 11157416Smarkmstatic krb5_data auth; 11257416Smarkmstatic krb5_ticket *ticket; 11357416Smarkm 11457416Smarkmstatic krb5_context context; 11557416Smarkmstatic krb5_auth_context auth_context; 11657416Smarkm 11757416Smarkmstatic int 118178825SdfrData(Authenticator *ap, int type, const void *d, int c) 11957416Smarkm{ 120178825Sdfr const unsigned char *cp, *cd = d; 121142403Snectar unsigned char *p0, *p; 122142403Snectar size_t len = sizeof(str_data) + 3 + 2; 123142403Snectar int ret; 12457416Smarkm 12557416Smarkm if (c == -1) 126178825Sdfr c = strlen((const char*)cd); 12757416Smarkm 128178825Sdfr for (cp = cd; cp - cd < c; cp++, len++) 129178825Sdfr if (*cp == IAC) 130142403Snectar len++; 131142403Snectar 132142403Snectar p0 = malloc(len); 133142403Snectar if (p0 == NULL) 134142403Snectar return 0; 135233294Sstas 136142403Snectar memcpy(p0, str_data, sizeof(str_data)); 137142403Snectar p = p0 + sizeof(str_data); 138233294Sstas 13957416Smarkm if (auth_debug_mode) { 14057416Smarkm printf("%s:%d: [%d] (%d)", 14157416Smarkm str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 14257416Smarkm str_data[3], 14357416Smarkm type, c); 14457416Smarkm printd(d, c); 14557416Smarkm printf("\r\n"); 14657416Smarkm } 14757416Smarkm *p++ = ap->type; 14857416Smarkm *p++ = ap->way; 14957416Smarkm *p++ = type; 15057416Smarkm while (c-- > 0) { 15157416Smarkm if ((*p++ = *cd++) == IAC) 15257416Smarkm *p++ = IAC; 15357416Smarkm } 15457416Smarkm *p++ = IAC; 15557416Smarkm *p++ = SE; 15657416Smarkm if (str_data[3] == TELQUAL_IS) 157142403Snectar printsub('>', &p0[2], len - 2); 158142403Snectar ret = telnet_net_write(p0, len); 159142403Snectar free(p0); 160142403Snectar return ret; 16157416Smarkm} 16257416Smarkm 16357416Smarkmint 16457416Smarkmkerberos5_init(Authenticator *ap, int server) 16557416Smarkm{ 16672445Sassar krb5_error_code ret; 16772445Sassar 16872445Sassar ret = krb5_init_context(&context); 16972445Sassar if (ret) 17072445Sassar return 0; 17172445Sassar if (server) { 17272445Sassar krb5_keytab kt; 17372445Sassar krb5_kt_cursor cursor; 17472445Sassar 17572445Sassar ret = krb5_kt_default(context, &kt); 17672445Sassar if (ret) 17772445Sassar return 0; 17872445Sassar 17972445Sassar ret = krb5_kt_start_seq_get (context, kt, &cursor); 18072445Sassar if (ret) { 18172445Sassar krb5_kt_close (context, kt); 18272445Sassar return 0; 18372445Sassar } 18472445Sassar krb5_kt_end_seq_get (context, kt, &cursor); 18572445Sassar krb5_kt_close (context, kt); 18672445Sassar 18757416Smarkm str_data[3] = TELQUAL_REPLY; 18872445Sassar } else 18957416Smarkm str_data[3] = TELQUAL_IS; 19057416Smarkm return(1); 19157416Smarkm} 19257416Smarkm 19372445Sassarextern int net; 19457416Smarkmstatic int 19557416Smarkmkerberos5_send(char *name, Authenticator *ap) 19657416Smarkm{ 19757416Smarkm krb5_error_code ret; 19857416Smarkm krb5_ccache ccache; 19957416Smarkm int ap_opts; 20057416Smarkm krb5_data cksum_data; 201178825Sdfr char ap_msg[2]; 202233294Sstas 20357416Smarkm if (!UserNameRequested) { 20457416Smarkm if (auth_debug_mode) { 20557416Smarkm printf("Kerberos V5: no user name supplied\r\n"); 20657416Smarkm } 20757416Smarkm return(0); 20857416Smarkm } 209233294Sstas 21057416Smarkm ret = krb5_cc_default(context, &ccache); 21157416Smarkm if (ret) { 21257416Smarkm if (auth_debug_mode) { 21357416Smarkm printf("Kerberos V5: could not get default ccache: %s\r\n", 21457416Smarkm krb5_get_err_text (context, ret)); 21557416Smarkm } 21657416Smarkm return 0; 21757416Smarkm } 218233294Sstas 21957416Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 22057416Smarkm ap_opts = AP_OPTS_MUTUAL_REQUIRED; 22157416Smarkm else 22257416Smarkm ap_opts = 0; 223103423Snectar 224103423Snectar ap_opts |= AP_OPTS_USE_SUBKEY; 225233294Sstas 22657416Smarkm ret = krb5_auth_con_init (context, &auth_context); 22757416Smarkm if (ret) { 22857416Smarkm if (auth_debug_mode) { 22957416Smarkm printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", 23057416Smarkm krb5_get_err_text(context, ret)); 23157416Smarkm } 23257416Smarkm return(0); 23357416Smarkm } 23457416Smarkm 23557416Smarkm ret = krb5_auth_con_setaddrs_from_fd (context, 23657416Smarkm auth_context, 23757416Smarkm &net); 23857416Smarkm if (ret) { 23957416Smarkm if (auth_debug_mode) { 24057416Smarkm printf ("Kerberos V5:" 24157416Smarkm " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", 24257416Smarkm krb5_get_err_text(context, ret)); 24357416Smarkm } 24457416Smarkm return(0); 24557416Smarkm } 24657416Smarkm 247233294Sstas krb5_auth_con_setkeytype (context, auth_context, KRB5_ENCTYPE_DES_CBC_CRC); 24857416Smarkm 249178825Sdfr ap_msg[0] = ap->type; 250178825Sdfr ap_msg[1] = ap->way; 25157416Smarkm 252178825Sdfr cksum_data.length = sizeof(ap_msg); 253178825Sdfr cksum_data.data = ap_msg; 25457416Smarkm 25572445Sassar 25672445Sassar { 25772445Sassar krb5_principal service; 25872445Sassar char sname[128]; 25972445Sassar 26072445Sassar 26172445Sassar ret = krb5_sname_to_principal (context, 26272445Sassar RemoteHostName, 26372445Sassar NULL, 26472445Sassar KRB5_NT_SRV_HST, 26572445Sassar &service); 26672445Sassar if(ret) { 26772445Sassar if (auth_debug_mode) { 26872445Sassar printf ("Kerberos V5:" 26972445Sassar " krb5_sname_to_principal(%s) failed (%s)\r\n", 27072445Sassar RemoteHostName, krb5_get_err_text(context, ret)); 27172445Sassar } 27272445Sassar return 0; 27372445Sassar } 27472445Sassar ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname)); 27572445Sassar if(ret) { 27672445Sassar if (auth_debug_mode) { 27772445Sassar printf ("Kerberos V5:" 27872445Sassar " krb5_unparse_name_fixed failed (%s)\r\n", 27972445Sassar krb5_get_err_text(context, ret)); 28072445Sassar } 28172445Sassar return 0; 28272445Sassar } 28372445Sassar printf("[ Trying %s (%s)... ]\r\n", name, sname); 28472445Sassar ret = krb5_mk_req_exact(context, &auth_context, ap_opts, 285233294Sstas service, 28672445Sassar &cksum_data, ccache, &auth); 28772445Sassar krb5_free_principal (context, service); 28872445Sassar 28972445Sassar } 29057416Smarkm if (ret) { 29157416Smarkm if (1 || auth_debug_mode) { 29257416Smarkm printf("Kerberos V5: mk_req failed (%s)\r\n", 29357416Smarkm krb5_get_err_text(context, ret)); 29457416Smarkm } 29557416Smarkm return(0); 29657416Smarkm } 29757416Smarkm 29857416Smarkm if (!auth_sendname((unsigned char *)UserNameRequested, 29957416Smarkm strlen(UserNameRequested))) { 30057416Smarkm if (auth_debug_mode) 30157416Smarkm printf("Not enough room for user name\r\n"); 30257416Smarkm return(0); 30357416Smarkm } 30457416Smarkm if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 30557416Smarkm if (auth_debug_mode) 30657416Smarkm printf("Not enough room for authentication data\r\n"); 30757416Smarkm return(0); 30857416Smarkm } 30957416Smarkm if (auth_debug_mode) { 31057416Smarkm printf("Sent Kerberos V5 credentials to server\r\n"); 31157416Smarkm } 31257416Smarkm return(1); 31357416Smarkm} 31457416Smarkm 31557416Smarkmint 31657416Smarkmkerberos5_send_mutual(Authenticator *ap) 31757416Smarkm{ 31857416Smarkm return kerberos5_send("mutual KERBEROS5", ap); 31957416Smarkm} 32057416Smarkm 32157416Smarkmint 32257416Smarkmkerberos5_send_oneway(Authenticator *ap) 32357416Smarkm{ 32457416Smarkm return kerberos5_send("KERBEROS5", ap); 32557416Smarkm} 32657416Smarkm 327178825Sdfrstatic void log_message(const char *fmt, ...) 328178825Sdfr{ 329178825Sdfr va_list ap; 330178825Sdfr va_start(ap, fmt); 331178825Sdfr if (auth_debug_mode) { 332178825Sdfr va_start(ap, fmt); 333178825Sdfr vfprintf(stdout, fmt, ap); 334178825Sdfr va_end(ap); 335178825Sdfr fprintf(stdout, "\r\n"); 336178825Sdfr } 337178825Sdfr va_start(ap, fmt); 338178825Sdfr vsyslog(LOG_NOTICE, fmt, ap); 339178825Sdfr va_end(ap); 340178825Sdfr} 341178825Sdfr 34257416Smarkmvoid 34357416Smarkmkerberos5_is(Authenticator *ap, unsigned char *data, int cnt) 34457416Smarkm{ 34557416Smarkm krb5_error_code ret; 34657416Smarkm krb5_data outbuf; 34757416Smarkm krb5_keyblock *key_block; 34857416Smarkm char *name; 34957416Smarkm krb5_principal server; 35057416Smarkm int zero = 0; 35157416Smarkm 35257416Smarkm if (cnt-- < 1) 35357416Smarkm return; 35457416Smarkm switch (*data++) { 35557416Smarkm case KRB_AUTH: 35657416Smarkm auth.data = (char *)data; 35757416Smarkm auth.length = cnt; 35857416Smarkm 35957416Smarkm auth_context = NULL; 36057416Smarkm 36157416Smarkm ret = krb5_auth_con_init (context, &auth_context); 36257416Smarkm if (ret) { 36357416Smarkm Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); 36457416Smarkm auth_finished(ap, AUTH_REJECT); 365178825Sdfr log_message("Kerberos V5: krb5_auth_con_init failed (%s)", 366178825Sdfr krb5_get_err_text(context, ret)); 36757416Smarkm return; 36857416Smarkm } 36957416Smarkm 37057416Smarkm ret = krb5_auth_con_setaddrs_from_fd (context, 37157416Smarkm auth_context, 37257416Smarkm &zero); 37357416Smarkm if (ret) { 37457416Smarkm Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); 37557416Smarkm auth_finished(ap, AUTH_REJECT); 376178825Sdfr log_message("Kerberos V5: " 377178825Sdfr "krb5_auth_con_setaddrs_from_fd failed (%s)", 378178825Sdfr krb5_get_err_text(context, ret)); 37957416Smarkm return; 38057416Smarkm } 38157416Smarkm 38257416Smarkm ret = krb5_sock_to_principal (context, 38357416Smarkm 0, 38457416Smarkm "host", 38557416Smarkm KRB5_NT_SRV_HST, 38657416Smarkm &server); 38757416Smarkm if (ret) { 38857416Smarkm Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); 38957416Smarkm auth_finished(ap, AUTH_REJECT); 390178825Sdfr log_message("Kerberos V5: " 391178825Sdfr "krb5_sock_to_principal failed (%s)", 392178825Sdfr krb5_get_err_text(context, ret)); 39357416Smarkm return; 39457416Smarkm } 39557416Smarkm 39657416Smarkm ret = krb5_rd_req(context, 39757416Smarkm &auth_context, 398233294Sstas &auth, 39957416Smarkm server, 40057416Smarkm NULL, 40157416Smarkm NULL, 40257416Smarkm &ticket); 40372445Sassar 40457416Smarkm krb5_free_principal (context, server); 40557416Smarkm if (ret) { 406178825Sdfr const char *errbuf2 = "Read req failed"; 40757416Smarkm char *errbuf; 408178825Sdfr int ret2; 40957416Smarkm 410178825Sdfr ret2 = asprintf(&errbuf, 411178825Sdfr "Read req failed: %s", 412178825Sdfr krb5_get_err_text(context, ret)); 413178825Sdfr if (ret2 != -1) 414178825Sdfr errbuf2 = errbuf; 415178825Sdfr Data(ap, KRB_REJECT, errbuf2, -1); 416178825Sdfr log_message("%s", errbuf2); 417178825Sdfr if (ret2 != -1) 418178825Sdfr free (errbuf); 41957416Smarkm return; 42057416Smarkm } 421233294Sstas 42257416Smarkm { 423178825Sdfr char ap_msg[2]; 424233294Sstas 425178825Sdfr ap_msg[0] = ap->type; 426178825Sdfr ap_msg[1] = ap->way; 427233294Sstas 42857416Smarkm ret = krb5_verify_authenticator_checksum(context, 42957416Smarkm auth_context, 430233294Sstas ap_msg, 431178825Sdfr sizeof(ap_msg)); 43257416Smarkm 43357416Smarkm if (ret) { 434178825Sdfr const char *errbuf2 = "Bad checksum"; 43557416Smarkm char *errbuf; 436178825Sdfr int ret2; 437178825Sdfr 438233294Sstas ret2 = asprintf(&errbuf, "Bad checksum: %s", 439178825Sdfr krb5_get_err_text(context, ret)); 440178825Sdfr if (ret2 != -1) 441178825Sdfr errbuf2 = errbuf; 442178825Sdfr Data(ap, KRB_REJECT, errbuf2, -1); 443178825Sdfr log_message("%s", errbuf2); 444178825Sdfr if (ret2 != -1) 445178825Sdfr free(errbuf); 44657416Smarkm return; 44757416Smarkm } 44857416Smarkm } 44957416Smarkm ret = krb5_auth_con_getremotesubkey (context, 45057416Smarkm auth_context, 45157416Smarkm &key_block); 45257416Smarkm 45357416Smarkm if (ret) { 45457416Smarkm Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); 45557416Smarkm auth_finished(ap, AUTH_REJECT); 456178825Sdfr log_message("Kerberos V5: " 457178825Sdfr "krb5_auth_con_getremotesubkey failed (%s)", 458178825Sdfr krb5_get_err_text(context, ret)); 45957416Smarkm return; 46057416Smarkm } 46157416Smarkm 462107207Snectar if (key_block == NULL) { 463107207Snectar ret = krb5_auth_con_getkey(context, 464107207Snectar auth_context, 465107207Snectar &key_block); 466107207Snectar } 467107207Snectar if (ret) { 468107207Snectar Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); 469107207Snectar auth_finished(ap, AUTH_REJECT); 470178825Sdfr log_message("Kerberos V5: " 471178825Sdfr "krb5_auth_con_getkey failed (%s)", 472178825Sdfr krb5_get_err_text(context, ret)); 473107207Snectar return; 474107207Snectar } 475107207Snectar if (key_block == NULL) { 476107207Snectar Data(ap, KRB_REJECT, "no subkey received", -1); 477107207Snectar auth_finished(ap, AUTH_REJECT); 478178825Sdfr log_message("Kerberos V5: " 479178825Sdfr "krb5_auth_con_getremotesubkey returned NULL key"); 480107207Snectar return; 481107207Snectar } 482107207Snectar 48357416Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 48472445Sassar ret = krb5_mk_rep(context, auth_context, &outbuf); 48557416Smarkm if (ret) { 48657416Smarkm Data(ap, KRB_REJECT, 48757416Smarkm "krb5_mk_rep failed", -1); 48857416Smarkm auth_finished(ap, AUTH_REJECT); 489178825Sdfr log_message("Kerberos V5: " 490178825Sdfr "krb5_mk_rep failed (%s)", 491178825Sdfr krb5_get_err_text(context, ret)); 492233294Sstas krb5_free_keyblock(context, key_block); 49357416Smarkm return; 49457416Smarkm } 49557416Smarkm Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); 49657416Smarkm } 49757416Smarkm if (krb5_unparse_name(context, ticket->client, &name)) 49857416Smarkm name = 0; 49957416Smarkm 50057416Smarkm if(UserNameRequested && krb5_kuserok(context, 50157416Smarkm ticket->client, 50257416Smarkm UserNameRequested)) { 50357416Smarkm Data(ap, KRB_ACCEPT, name, name ? -1 : 0); 504178825Sdfr log_message("%s accepted as user %s from %s", 505233294Sstas name ? name : "<unknown>", 506178825Sdfr UserNameRequested ? UserNameRequested : "<unknown>", 507178825Sdfr RemoteHostName ? RemoteHostName : "<unknown>"); 50857416Smarkm 50957416Smarkm if(key_block->keytype == ETYPE_DES_CBC_MD5 || 51057416Smarkm key_block->keytype == ETYPE_DES_CBC_MD4 || 51157416Smarkm key_block->keytype == ETYPE_DES_CBC_CRC) { 51257416Smarkm Session_Key skey; 51357416Smarkm 51457416Smarkm skey.type = SK_DES; 51557416Smarkm skey.length = 8; 51657416Smarkm skey.data = key_block->keyvalue.data; 51757416Smarkm encrypt_session_key(&skey, 0); 51857416Smarkm } 51957416Smarkm 52057416Smarkm } else { 521178825Sdfr const char *msg2 = "user is not authorized to login"; 52257416Smarkm char *msg; 52357416Smarkm 524178825Sdfr ret = asprintf (&msg, "user `%s' is not authorized to " 525233294Sstas "login as `%s'", 526178825Sdfr name ? name : "<unknown>", 527178825Sdfr UserNameRequested ? UserNameRequested : "<nobody>"); 528178825Sdfr if (ret != -1) 529178825Sdfr msg2 = msg; 530178825Sdfr Data(ap, KRB_REJECT, (void *)msg2, -1); 531178825Sdfr if (ret != -1) 53257416Smarkm free(msg); 53357416Smarkm auth_finished (ap, AUTH_REJECT); 534233294Sstas krb5_free_keyblock(context, key_block); 53557416Smarkm break; 53657416Smarkm } 53757416Smarkm auth_finished(ap, AUTH_USER); 538233294Sstas krb5_free_keyblock(context, key_block); 539233294Sstas 54057416Smarkm break; 54157416Smarkm case KRB_FORWARD: { 54257416Smarkm struct passwd *pwd; 54357416Smarkm char ccname[1024]; /* XXX */ 54457416Smarkm krb5_data inbuf; 54557416Smarkm krb5_ccache ccache; 54657416Smarkm inbuf.data = (char *)data; 54757416Smarkm inbuf.length = cnt; 54857416Smarkm 54957416Smarkm pwd = getpwnam (UserNameRequested); 55057416Smarkm if (pwd == NULL) 55157416Smarkm break; 55257416Smarkm 55357416Smarkm snprintf (ccname, sizeof(ccname), 554178825Sdfr "FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid); 55557416Smarkm 55657416Smarkm ret = krb5_cc_resolve (context, ccname, &ccache); 55757416Smarkm if (ret) { 558178825Sdfr log_message("Kerberos V5: could not get ccache: %s", 55957416Smarkm krb5_get_err_text(context, ret)); 56057416Smarkm break; 56157416Smarkm } 56257416Smarkm 56357416Smarkm ret = krb5_cc_initialize (context, 56457416Smarkm ccache, 56557416Smarkm ticket->client); 56657416Smarkm if (ret) { 567178825Sdfr log_message("Kerberos V5: could not init ccache: %s", 56857416Smarkm krb5_get_err_text(context, ret)); 56957416Smarkm break; 57057416Smarkm } 57157416Smarkm 57272445Sassar#if defined(DCE) 57372445Sassar esetenv("KRB5CCNAME", ccname, 1); 57472445Sassar#endif 57572445Sassar ret = krb5_rd_cred2 (context, 57672445Sassar auth_context, 57772445Sassar ccache, 57872445Sassar &inbuf); 57957416Smarkm if(ret) { 580178825Sdfr const char *errbuf2 = "Read forwarded creds failed"; 58157416Smarkm char *errbuf; 582178825Sdfr int ret2; 58357416Smarkm 584178825Sdfr ret2 = asprintf (&errbuf, 585178825Sdfr "Read forwarded creds failed: %s", 586178825Sdfr krb5_get_err_text (context, ret)); 587178825Sdfr if (ret2 != -1) 588178825Sdfr errbuf2 = errbuf; 589178825Sdfr Data(ap, KRB_FORWARD_REJECT, errbuf, -1); 590178825Sdfr log_message("Could not read forwarded credentials: %s", errbuf); 591178825Sdfr 592178825Sdfr if (ret2 != -1) 593178825Sdfr free (errbuf); 59472445Sassar } else { 59557416Smarkm Data(ap, KRB_FORWARD_ACCEPT, 0, 0); 59672445Sassar#if defined(DCE) 59772445Sassar dfsfwd = 1; 59872445Sassar#endif 59972445Sassar } 60057416Smarkm chown (ccname + 5, pwd->pw_uid, -1); 601178825Sdfr log_message("Forwarded credentials obtained"); 60257416Smarkm break; 60357416Smarkm } 60457416Smarkm default: 605178825Sdfr log_message("Unknown Kerberos option %d", data[-1]); 60657416Smarkm Data(ap, KRB_REJECT, 0, 0); 60757416Smarkm break; 60857416Smarkm } 60957416Smarkm} 61057416Smarkm 61157416Smarkmvoid 61257416Smarkmkerberos5_reply(Authenticator *ap, unsigned char *data, int cnt) 61357416Smarkm{ 61457416Smarkm static int mutual_complete = 0; 61557416Smarkm 61657416Smarkm if (cnt-- < 1) 61757416Smarkm return; 61857416Smarkm switch (*data++) { 61957416Smarkm case KRB_REJECT: 62057416Smarkm if (cnt > 0) { 62157416Smarkm printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 62257416Smarkm cnt, data); 62357416Smarkm } else 62457416Smarkm printf("[ Kerberos V5 refuses authentication ]\r\n"); 62557416Smarkm auth_send_retry(); 62657416Smarkm return; 62757416Smarkm case KRB_ACCEPT: { 62857416Smarkm krb5_error_code ret; 62957416Smarkm Session_Key skey; 63057416Smarkm krb5_keyblock *keyblock; 631233294Sstas 63257416Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && 63357416Smarkm !mutual_complete) { 63457416Smarkm printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); 63557416Smarkm auth_send_retry(); 63657416Smarkm return; 63757416Smarkm } 63857416Smarkm if (cnt) 63957416Smarkm printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); 64057416Smarkm else 64157416Smarkm printf("[ Kerberos V5 accepts you ]\r\n"); 642233294Sstas 64357416Smarkm ret = krb5_auth_con_getlocalsubkey (context, 64457416Smarkm auth_context, 64557416Smarkm &keyblock); 64657416Smarkm if (ret) 64757416Smarkm ret = krb5_auth_con_getkey (context, 64857416Smarkm auth_context, 64957416Smarkm &keyblock); 65057416Smarkm if(ret) { 65157416Smarkm printf("[ krb5_auth_con_getkey: %s ]\r\n", 65257416Smarkm krb5_get_err_text(context, ret)); 65357416Smarkm auth_send_retry(); 65457416Smarkm return; 65557416Smarkm } 656233294Sstas 65757416Smarkm skey.type = SK_DES; 65857416Smarkm skey.length = 8; 65957416Smarkm skey.data = keyblock->keyvalue.data; 66057416Smarkm encrypt_session_key(&skey, 0); 661233294Sstas krb5_free_keyblock (context, keyblock); 66257416Smarkm auth_finished(ap, AUTH_USER); 66357416Smarkm if (forward_flags & OPTS_FORWARD_CREDS) 66457416Smarkm kerberos5_forward(ap); 66557416Smarkm break; 66657416Smarkm } 66757416Smarkm case KRB_RESPONSE: 66857416Smarkm if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 66957416Smarkm /* the rest of the reply should contain a krb_ap_rep */ 67057416Smarkm krb5_ap_rep_enc_part *reply; 67157416Smarkm krb5_data inbuf; 67257416Smarkm krb5_error_code ret; 673233294Sstas 67457416Smarkm inbuf.length = cnt; 67557416Smarkm inbuf.data = (char *)data; 67657416Smarkm 67757416Smarkm ret = krb5_rd_rep(context, auth_context, &inbuf, &reply); 67857416Smarkm if (ret) { 67957416Smarkm printf("[ Mutual authentication failed: %s ]\r\n", 68057416Smarkm krb5_get_err_text (context, ret)); 68157416Smarkm auth_send_retry(); 68257416Smarkm return; 68357416Smarkm } 68457416Smarkm krb5_free_ap_rep_enc_part(context, reply); 68557416Smarkm mutual_complete = 1; 68657416Smarkm } 68757416Smarkm return; 68857416Smarkm case KRB_FORWARD_ACCEPT: 68957416Smarkm printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); 69057416Smarkm return; 69157416Smarkm case KRB_FORWARD_REJECT: 69257416Smarkm printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", 69357416Smarkm cnt, data); 69457416Smarkm return; 69557416Smarkm default: 69657416Smarkm if (auth_debug_mode) 69757416Smarkm printf("Unknown Kerberos option %d\r\n", data[-1]); 69857416Smarkm return; 69957416Smarkm } 70057416Smarkm} 70157416Smarkm 70257416Smarkmint 70357416Smarkmkerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level) 70457416Smarkm{ 70557416Smarkm if (level < AUTH_USER) 70657416Smarkm return(level); 70757416Smarkm 70857416Smarkm if (UserNameRequested && 70957416Smarkm krb5_kuserok(context, 71057416Smarkm ticket->client, 71157416Smarkm UserNameRequested)) 71257416Smarkm { 71357416Smarkm strlcpy(name, UserNameRequested, name_sz); 71472445Sassar#if defined(DCE) 71572445Sassar dfsk5ok = 1; 71672445Sassar#endif 71757416Smarkm return(AUTH_VALID); 71857416Smarkm } else 71957416Smarkm return(AUTH_USER); 72057416Smarkm} 72157416Smarkm 72257416Smarkm#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 72357416Smarkm#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 72457416Smarkm 72557416Smarkmvoid 726233294Sstaskerberos5_printsub(unsigned char *data, size_t cnt, 727233294Sstas unsigned char *buf, size_t buflen) 72857416Smarkm{ 72957416Smarkm int i; 73057416Smarkm 731178825Sdfr buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ 73257416Smarkm buflen -= 1; 73357416Smarkm 73457416Smarkm switch(data[3]) { 73557416Smarkm case KRB_REJECT: /* Rejected (reason might follow) */ 73657416Smarkm strlcpy((char *)buf, " REJECT ", buflen); 73757416Smarkm goto common; 73857416Smarkm 73957416Smarkm case KRB_ACCEPT: /* Accepted (name might follow) */ 74057416Smarkm strlcpy((char *)buf, " ACCEPT ", buflen); 74157416Smarkm common: 74257416Smarkm BUMP(buf, buflen); 74357416Smarkm if (cnt <= 4) 74457416Smarkm break; 74557416Smarkm ADDC(buf, buflen, '"'); 74657416Smarkm for (i = 4; i < cnt; i++) 74757416Smarkm ADDC(buf, buflen, data[i]); 74857416Smarkm ADDC(buf, buflen, '"'); 74957416Smarkm ADDC(buf, buflen, '\0'); 75057416Smarkm break; 75157416Smarkm 75257416Smarkm 75357416Smarkm case KRB_AUTH: /* Authentication data follows */ 75457416Smarkm strlcpy((char *)buf, " AUTH", buflen); 75557416Smarkm goto common2; 75657416Smarkm 75757416Smarkm case KRB_RESPONSE: 75857416Smarkm strlcpy((char *)buf, " RESPONSE", buflen); 75957416Smarkm goto common2; 76057416Smarkm 76157416Smarkm case KRB_FORWARD: /* Forwarded credentials follow */ 76257416Smarkm strlcpy((char *)buf, " FORWARD", buflen); 76357416Smarkm goto common2; 76457416Smarkm 76557416Smarkm case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 76657416Smarkm strlcpy((char *)buf, " FORWARD_ACCEPT", buflen); 76757416Smarkm goto common2; 76857416Smarkm 76957416Smarkm case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 77057416Smarkm /* (reason might follow) */ 77157416Smarkm strlcpy((char *)buf, " FORWARD_REJECT", buflen); 77257416Smarkm goto common2; 77357416Smarkm 77457416Smarkm default: 77590926Snectar snprintf((char*)buf, buflen, " %d (unknown)", data[3]); 77657416Smarkm common2: 77757416Smarkm BUMP(buf, buflen); 77857416Smarkm for (i = 4; i < cnt; i++) { 77990926Snectar snprintf((char*)buf, buflen, " %d", data[i]); 78057416Smarkm BUMP(buf, buflen); 78157416Smarkm } 78257416Smarkm break; 78357416Smarkm } 78457416Smarkm} 78557416Smarkm 78657416Smarkmvoid 78757416Smarkmkerberos5_forward(Authenticator *ap) 78857416Smarkm{ 78957416Smarkm krb5_error_code ret; 79057416Smarkm krb5_ccache ccache; 79157416Smarkm krb5_creds creds; 792178825Sdfr KDCOptions flags; 79357416Smarkm krb5_data out_data; 79457416Smarkm krb5_principal principal; 79557416Smarkm 79657416Smarkm ret = krb5_cc_default (context, &ccache); 79757416Smarkm if (ret) { 79857416Smarkm if (auth_debug_mode) 79957416Smarkm printf ("KerberosV5: could not get default ccache: %s\r\n", 80057416Smarkm krb5_get_err_text (context, ret)); 80157416Smarkm return; 80257416Smarkm } 80357416Smarkm 80457416Smarkm ret = krb5_cc_get_principal (context, ccache, &principal); 80557416Smarkm if (ret) { 80657416Smarkm if (auth_debug_mode) 80757416Smarkm printf ("KerberosV5: could not get principal: %s\r\n", 80857416Smarkm krb5_get_err_text (context, ret)); 80957416Smarkm return; 81057416Smarkm } 81157416Smarkm 81257416Smarkm memset (&creds, 0, sizeof(creds)); 81357416Smarkm 81457416Smarkm creds.client = principal; 81557416Smarkm 816233294Sstas ret = krb5_make_principal(context, 817233294Sstas &creds.server, 818233294Sstas principal->realm, 819233294Sstas "krbtgt", 820233294Sstas principal->realm, 821233294Sstas NULL); 822233294Sstas 82357416Smarkm if (ret) { 82457416Smarkm if (auth_debug_mode) 82557416Smarkm printf ("KerberosV5: could not get principal: %s\r\n", 82657416Smarkm krb5_get_err_text (context, ret)); 82757416Smarkm return; 82857416Smarkm } 82957416Smarkm 83057416Smarkm creds.times.endtime = 0; 83157416Smarkm 832178825Sdfr memset(&flags, 0, sizeof(flags)); 833178825Sdfr flags.forwarded = 1; 83457416Smarkm if (forward_flags & OPTS_FORWARDABLE_CREDS) 835178825Sdfr flags.forwardable = 1; 83657416Smarkm 83757416Smarkm ret = krb5_get_forwarded_creds (context, 83857416Smarkm auth_context, 83957416Smarkm ccache, 840178825Sdfr KDCOptions2int(flags), 84157416Smarkm RemoteHostName, 84257416Smarkm &creds, 84357416Smarkm &out_data); 84457416Smarkm if (ret) { 84557416Smarkm if (auth_debug_mode) 84657416Smarkm printf ("Kerberos V5: error getting forwarded creds: %s\r\n", 84757416Smarkm krb5_get_err_text (context, ret)); 84857416Smarkm return; 84957416Smarkm } 85057416Smarkm 85157416Smarkm if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) { 85257416Smarkm if (auth_debug_mode) 85357416Smarkm printf("Not enough room for authentication data\r\n"); 85457416Smarkm } else { 85557416Smarkm if (auth_debug_mode) 85657416Smarkm printf("Forwarded local Kerberos V5 credentials to server\r\n"); 85757416Smarkm } 85857416Smarkm} 85957416Smarkm 86072445Sassar#if defined(DCE) 86172445Sassar/* if this was a K5 authentication try and join a PAG for the user. */ 86272445Sassarvoid 86372445Sassarkerberos5_dfspag(void) 86472445Sassar{ 86572445Sassar if (dfsk5ok) { 86672445Sassar dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client, 86772445Sassar UserNameRequested); 86872445Sassar } 86972445Sassar} 87072445Sassar#endif 87172445Sassar 872102644Snectarint 873102644Snectarkerberos5_set_forward(int on) 874102644Snectar{ 875102644Snectar if(on == 0) 876102644Snectar forward_flags &= ~OPTS_FORWARD_CREDS; 877102644Snectar if(on == 1) 878102644Snectar forward_flags |= OPTS_FORWARD_CREDS; 879102644Snectar if(on == -1) 880102644Snectar forward_flags ^= OPTS_FORWARD_CREDS; 881102644Snectar return 0; 882102644Snectar} 883102644Snectar 884102644Snectarint 885102644Snectarkerberos5_set_forwardable(int on) 886102644Snectar{ 887102644Snectar if(on == 0) 888102644Snectar forward_flags &= ~OPTS_FORWARDABLE_CREDS; 889102644Snectar if(on == 1) 890102644Snectar forward_flags |= OPTS_FORWARDABLE_CREDS; 891102644Snectar if(on == -1) 892102644Snectar forward_flags ^= OPTS_FORWARDABLE_CREDS; 893102644Snectar return 0; 894102644Snectar} 895102644Snectar 89657416Smarkm#endif /* KRB5 */ 897