char *ckathv = "Authentication, 8.0.234, 11 Jan 2007"; /* C K U A T H . C -- Authentication for C-Kermit Copyright (C) 1999, 2004, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Copyright (C) 2006, 2007 Secure Endpoints Inc. Author: Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City */ /* * Additional copyrights included with affected code. */ #ifdef HEIMDAL /* Turned off User to User support Turned off KDESTROY support Turned off KLIST support Turned off krb5_prompter() support Turned off ticket validation Turned off ticket renewal Turned off alternative cache support in k5_get_ccache() Remaining link problems: ckuath.o: In function `ck_krb5_initTGT': ckuath.o(.text+0x50c2): undefined reference to `krb5_string_to_deltat' ckuath.o(.text+0x516d): undefined reference to `krb5_string_to_deltat' ckuath.o(.text+0x51ef): undefined reference to `krb5_string_to_deltat' */ #endif /* HEIMDAL */ /* * Implements Kerberos 4/5, SRP, SSL, NTLM authentication and START_TLS */ #include "ckcsym.h" #include "ckcdeb.h" #ifdef CK_SECURITY #define CKUATH_C #include "ckcker.h" #include "ckuusr.h" #include "ckucmd.h" /* For struct keytab */ #include "ckcnet.h" #include "ckctel.h" char szUserNameRequested[UIDBUFLEN+1]; /* for incoming connections */ char szUserNameAuthenticated[UIDBUFLEN+1];/* for incoming connections */ char szHostName[UIDBUFLEN+1]; char szUserName[UIDBUFLEN+1]; static char szIP[16]; static int validUser = AUTH_REJECT; /* User starts out invalid */ int authentication_version = AUTHTYPE_NULL; int accept_complete = 0; #ifdef CK_AUTHENTICATION #ifdef CK_SSL #ifdef KRB5 #define TLS_VERIFY #endif /* KRB5 */ #endif /* CK_SSL */ #ifdef CK_DES #ifdef CK_SSL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #endif /* CK_SSL */ #endif /* CK_DES */ #ifdef CRYPT_DLL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #ifdef OS2 #ifdef NT #include #else /* NT */ #define INCL_DOSMODULEMGR #include #endif /* NT */ #endif /* OS2 */ #endif /* CRYPT_DLL */ #ifdef NT #define KRB5_AUTOCONF__ #define NTLM #endif /* NT */ #ifdef CK_KERBEROS #define KINIT #ifndef HEIMDAL #define KLIST #define KDESTROY #endif /* HEIMDAL */ #define CHECKADDRS #else /* CK_KERBEROS */ #ifdef KRB4 #undef KRB4 #endif /* KRB4 */ #ifdef KRB5 #undef KRB5 #endif /* KRB5 */ #ifdef KRB524 #undef KRB524 #endif /* KRB524 */ #endif /* CK_KERBEROS */ #include #include #include #include #include #include #ifndef malloc #ifndef VMS #ifndef FREEBSD4 #ifndef OpenBSD #ifdef MACOSX #include #else /* MACOSX */ #include #endif /* MACOSX */ #endif /* OpenBSD */ #endif /* FREEBSD4 */ #endif /* VMS */ #endif /* malloc */ #ifdef OS2 #include #endif /* OS2 */ #ifdef KRB5 #ifdef HEIMDAL #ifdef printf #define saveprintf printf #undef printf #endif /* printf */ #include "krb5.h" #include "com_err.h" #ifdef saveprintf #define printf saveprintf #endif /* saveprintf */ #else /* HEIMDAL */ #include "krb5.h" #include "profile.h" #include "com_err.h" #ifdef KRB5_GET_INIT_CREDS_OPT_TKT_LIFE #define KRB5_HAVE_GET_INIT_CREDS #else #define krb5_free_unparsed_name(con,val) krb5_xfree((char *)(val)) #endif #ifndef KRB5_HAVE_GET_INIT_CREDS #define krb5_free_data_contents(c,v) krb5_xfree((char *)(v)->data) #endif #endif /* HEIMDAL */ #ifdef HAVE_PWD_H #include #endif #endif /* KRB5 */ #ifdef KRB4 #define des_cblock Block #define const_des_cblock const Block #define des_key_schedule Schedule #ifdef KRB524 #ifdef NT #define _WINDOWS #endif /* NT */ #include "kerberosIV/krb.h" #ifndef OS2 #ifdef KRB524_CONV #include "krb524.h" #endif /* KRB524_CONV */ _PROTOTYP(const char * krb_get_err_text_entry, (int)); #endif /* OS2 */ #else /* KRB524 */ #ifdef SOLARIS #ifndef sun /* for some reason the Makefile entries for the Solaris systems have -Usun */ #define sun #endif /* sun */ #endif /* SOLARIS */ #include "krb.h" #define krb_get_err_text_entry krb_get_err_text #endif /* KRB524 */ #else /* KRB4 */ #ifdef CK_SSL #define des_cblock Block #ifdef COMMENT #define const_des_cblock const Block #endif /* COMMENT */ #define des_key_schedule Schedule #endif /* CK_SSL */ #endif /* KRB4 */ #include "ckuath.h" #ifdef CK_KERBEROS #ifndef KRB5 #define NOBLOCKDEF #else /* KRB5 */ #ifdef KRB524 #define NOBLOCKDEF #endif /* KRB524 */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #include "ckuat2.h" #ifdef CK_SSL #ifdef LIBDES #ifdef OPENSSL_097 #define OPENSSL_ENABLE_OLD_DES_SUPPORT #include #endif /* OPENSSL_097 */ #ifndef HEADER_DES_H #define HEADER_DES_H #endif /* HEADER_DES_H */ #endif /* LIBDES */ #include "ck_ssl.h" extern int ssl_finished_messages; #endif /* SSL */ #define PWD_SZ 128 #ifndef LIBDES #ifdef UNIX #define des_set_random_generator_seed(x) des_init_random_number_generator(x) #endif /* UNIX */ #else /* LIBDES */ #define des_fixup_key_parity des_set_odd_parity #endif /* LIBDES */ #ifdef OS2 #ifdef CK_ENCRYPTION #define MAP_DES #endif /* CK_ENCRYPTION */ #ifdef KRB4 #define MAP_KRB4 #endif /* KRB4 */ #ifdef SRPDLL #define MAP_SRP #endif /* SRPDLL */ #ifdef KRB5 #define MAP_KRB5 #endif /* KRB5 */ #ifdef CRYPT_DLL #define MAP_CRYPT #endif /* CRYPT_DLL */ #define MAP_NTLM #include "ckoath.h" #include "ckosyn.h" #endif /* OS2 */ /* * Globals */ int auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_AUTO, AUTHTYPE_NULL}; int auth_how=0; int auth_crypt=0; int auth_fwd=0; /* These are state completion variables */ static int mutual_complete = 0; #ifdef KRB4 #ifdef OS2 static LEASH_CREDENTIALS cred; #else /* OS2 */ static CREDENTIALS cred; #endif /* OS2 */ static KTEXT_ST k4_auth; static char k4_name[ANAME_SZ]; static AUTH_DAT k4_adat = { 0 }; static MSG_DAT k4_msg_data; #ifdef CK_ENCRYPTION static Block k4_session_key = { 0 }; static Schedule k4_sched; static Block k4_challenge = { 0 }; #ifdef MIT_CURRENT static krb5_keyblock k4_krbkey; #endif /* MIT_CURRENT */ #endif /* ENCRYPTION */ #define KRB4_SERVICE_NAME "rcmd" _PROTOTYP(static int k4_auth_send,(VOID)); _PROTOTYP(static int k4_auth_reply,(unsigned char *, int)); _PROTOTYP(static int k4_auth_is,(unsigned char *, int)); #endif /* KRB4 */ #ifdef KRB5 static krb5_data k5_auth; static krb5_auth_context auth_context; static krb5_keyblock *k5_session_key = NULL; static krb5_ticket *k5_ticket = NULL; #ifndef KRB5_SERVICE_NAME #define KRB5_SERVICE_NAME "host" #ifdef MACOSX #define MIT_CURRENT 1 #define decode_krb5_ticket krb5_decode_ticket #define krb5_read_message ck_krb5_read_message #define krb5_write_message ck_krb5_write_message #endif /* MACOSX */ #endif _PROTOTYP(static int k5_auth_send,(int,int,int)); _PROTOTYP(static int k5_auth_reply,(int, unsigned char *, int)); _PROTOTYP(static int k5_auth_is,(int,unsigned char *, int)); _PROTOTYP(static int SendK5AuthSB,(int, void *, int)); #ifdef TLS_VERIFY static int krb5_tls_verified = 0; #endif /* TLS_VERIFY */ #endif /* KRB5 */ #ifdef GSSAPI_KRB5 #include #include #include static gss_ctx_id_t gcontext; #define GSS_BUFSIZ 4096 static gss_buffer_desc gss_send_tok, gss_recv_tok, *gss_token_ptr; static char gss_stbuf[GSS_BUFSIZ]; static gss_name_t gss_target_name; static struct gss_channel_bindings_struct gss_chan; _PROTOTYP(static int gssk5_auth_send,(int,int,int)); _PROTOTYP(static int gssk5_auth_reply,(int, unsigned char *, int)); _PROTOTYP(static int gssk5_auth_is,(int,unsigned char *, int)); _PROTOTYP(static int SendGSSK5AuthSB,(int, void *, int)); #endif /* GSSAPI_KRB5 */ #ifdef CK_SRP #ifdef PRE_SRP_1_7_3 _PROTOTYP(static int srp_reply,(int, unsigned char *, int)); _PROTOTYP(static int srp_is,(int, unsigned char *, int)); #else /* PRE_SRP_1_7_3 */ _PROTOTYP(static int new_srp_reply,(int, unsigned char *, int)); _PROTOTYP(static int new_srp_is,(int, unsigned char *, int)); #endif /* PRE_SRP_1_7_3 */ #endif /* SRP */ #ifdef CK_ENCRYPTION int encrypt_flag = 1; #endif #ifdef FORWARD int forward_flag = 0; /* forward tickets? */ int forwardable_flag = 1; /* get forwardable tickets to forward? */ int forwarded_tickets = 0; /* were tickets forwarded? */ #endif static unsigned char str_data[4096] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V5, }; #define AUTHTMPBL 2048 static char strTmp[AUTHTMPBL+1]; static char szLocalHostName[UIDBUFLEN+1]; static kstream g_kstream=NULL; #ifdef KRB5 krb5_context k5_context=NULL; static krb5_creds * ret_cred=NULL; static krb5_context telnet_context=NULL; static char * telnet_krb5_realm = NULL; static krb5_principal fwd_server = NULL; #endif /* KRB5 */ #ifdef CK_SRP #ifdef PRE_SRP_1_4_4 #ifndef PRE_SRP_1_4_5 #define PRE_SRP_1_4_5 #endif /* PRE_SRP_1_4_5 */ #endif /* PRE_SRP_1_4_5 */ #ifdef PRE_SRP_1_4_5 #ifndef PRE_SRP_1_7_3 #define PRE_SRP_1_7_3 #endif /* PRE_SRP_1_7_3 */ #endif /* PRE_SRP_1_4_5 */ #include #include #include static struct t_server * ts = NULL; static struct t_client * tc = NULL; #ifdef PRE_SRP_1_4_4 static struct t_pw * tpw = NULL; static struct t_conf * tconf = NULL; #endif /* PRE_SRP_1_4_4 */ #ifndef PRE_SRP_1_7_3 #ifndef STDC_HEADERS #define STDC_HEADERS 1 #endif /* STDC_HEADERS */ #include static SRP * s_srp = NULL; static cstr * s_key = NULL; static SRP * c_srp = NULL; static cstr * c_key = NULL; #endif /* PRE_SRP_1_7_3 */ static int srp_waitresp = 0; /* Flag to indicate readiness for response */ static char srp_passwd[PWD_SZ]; #endif /* CK_SRP */ #ifdef CK_KERBEROS #ifdef RLOGCODE #define OPTS_FORWARD_CREDS 0x00000020 #define OPTS_FORWARDABLE_CREDS 0x00000010 #define KCMD_KEYUSAGE 1026 #define RLOG_BUFSIZ 5120 static int rlog_encrypt = 0; char des_inbuf[2*RLOG_BUFSIZ]; /* needs to be > largest read size */ char des_outpkt[2*RLOG_BUFSIZ+4]; /* needs to be > largest write size */ #ifdef KRB5 krb5_data desinbuf,desoutbuf; krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ static krb5_data encivec_i[2], encivec_o[2]; enum krb5_kcmd_proto { /* Old protocol: DES encryption only. No subkeys. No protection for cleartext length. No ivec supplied. OOB hacks used for rlogin. Checksum may be omitted at connection startup. */ KCMD_OLD_PROTOCOL = 1, /* New protocol: Any encryption scheme. Client-generated subkey required. Prepend cleartext-length to cleartext data (but don't include it in count). Starting ivec defined, chained. In-band signalling. Checksum required. */ KCMD_NEW_PROTOCOL, /* Hack: Get credentials, and use the old protocol iff the session key type is single-DES. */ KCMD_PROTOCOL_COMPAT_HACK, KCMD_UNKNOWN_PROTOCOL }; enum krb5_kcmd_proto krb5_rlog_ver = KCMD_PROTOCOL_COMPAT_HACK; #endif /* KRB5 */ #endif /* RLOGCODE */ static char storage[65536]; /* storage for the decryption */ static int nstored = 0; static char *store_ptr = storage; extern char * krb5_d_principal; /* Default principal */ extern char * krb5_d_instance; /* Default instance */ extern char * krb5_d_realm; /* Default realm */ extern char * krb5_d_cc; /* Default credentials cache */ extern char * krb5_d_srv; /* Default service name */ extern int krb5_d_lifetime; /* Default lifetime */ extern int krb5_d_forwardable; extern int krb5_d_proxiable; extern int krb5_d_renewable; extern int krb5_autoget; extern int krb5_checkaddrs; extern int krb5_d_getk4; extern int krb5_d_no_addresses; extern char * k5_keytab; extern int krb5_errno; extern char * krb5_errmsg; extern char * krb4_d_principal; /* Default principal */ extern char * krb4_d_realm; /* Default realm */ extern char * krb4_d_srv; /* Default service name */ extern int krb4_d_lifetime; /* Default lifetime */ extern int krb4_d_preauth; extern char * krb4_d_instance; extern int krb4_autoget; extern int krb4_checkaddrs; extern char * k4_keytab; extern int krb4_errno; extern char * krb4_errmsg; #endif /* CK_KERBEROS */ extern char tn_msg[], hexbuf[]; /* from ckcnet.c */ extern CHAR pwbuf[]; extern int pwflg, pwcrypt; extern int deblog, debses, tn_deb; extern int sstelnet, inserver; #ifdef CK_LOGIN extern int ckxanon; #endif /* CK_LOGIN */ extern int tn_auth_how; extern int tn_auth_enc; #ifdef CK_ENCRYPTION extern int cx_type; #endif /* CK_ENCRYPTION */ extern int quiet, ttyfd, ttnproto; int ck_gssapi_is_installed() { #ifdef KRB5 #ifdef OS2 return(hGSSAPI != NULL); #else /* OS2 */ return(1); #endif /* OS2 */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int ck_krb5_is_installed() { #ifdef KRB5 #ifdef OS2 return(hKRB5_32 != NULL); #else /* OS2 */ return(1); #endif /* OS2 */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int ck_krb5_is_installed_as_server() { #ifdef KRB5 #ifdef HEIMDAL krb5_error_code ret; krb5_keytab kt; krb5_kt_cursor cursor; ret = krb5_kt_default(k5_context, &kt); if ( ret ) { krb5_kt_close(k5_context, kt); return(0); } else { krb5_kt_end_seq_get(k5_context, kt, &cursor); krb5_kt_close(k5_context, kt); return(1); } #else /* HEIMDAL */ #ifndef COMMENT char ktname[CKMAXPATH]=""; if ( k5_keytab ) { ckstrncpy(ktname,k5_keytab,CKMAXPATH); } else { krb5_error_code code; if ( k5_context == NULL) if (krb5_init_context(&k5_context)) return(0); code = krb5_kt_default_name(k5_context,ktname,CKMAXPATH); debug(F101,"krb5_kt_default_name","",code); if ( code ) { /* We can't check the existence of the file since we can't */ /* determine the file name. So we return TRUE and let */ /* Krb5 be offered to the user even though it may fail later */ return(1); } } if ( !strncmp("FILE:",ktname,5) ) { if ( zchki(&ktname[5]) > 0 ) return(1); else return(0); } else { if (ktname[0]) return(1); else return(0); } #else /* COMMENT */ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; krb5_context krb5context = NULL; krb5_ccache krb5ccdef = NULL; krb5_creds krb5creds, *krb5credsp = NULL; int rc = 0; if ( !ck_krb5_is_installed() ) return(0); memset((char *)&krb5creds, 0, sizeof(krb5creds)); if ((krb5rc = krb5_init_context(&krb5context)) != 0) goto err; if ((krb5rc = krb5_sname_to_principal(krb5context, szHostName, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, KRB5_NT_SRV_HST, &krb5creds.server)) != 0) goto err; if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) goto err; if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef, &krb5creds.client)) != 0) goto err; if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef, &krb5creds, &krb5credsp)) != 0) goto err; rc = 1; err: if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client); if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server); if (krb5context) krb5_free_context(krb5context); return(rc); #endif /* COMMENT */ #endif /* HEIMDAL */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int ck_krb4_is_installed() { #ifdef KRB4 #ifdef OS2 return(hKRB4_32 != NULL); #else /* OS2 */ return(1); #endif /* OS2 */ #else /* KRB4 */ return(0); #endif /* KRB4 */ } int ck_krb4_is_installed_as_server() { if ( !ck_krb4_is_installed() ) return(0); #ifdef KRB4 if ( !k4_keytab ) { #ifdef NT char name[CKMAXPATH]=""; DWORD len = CKMAXPATH; len = GetWindowsDirectory(name,len); if ( len > 0 ) ckstrncat(name,"/srvtab",CKMAXPATH); if ( name[0] ) makestr(&k4_keytab,name); #else /* NT */ makestr(&k4_keytab,"/etc/srvtab"); #endif /* NT */ } if ( !k4_keytab ) return(0); if ( zchki(k4_keytab) > 0 ) return(1); #ifdef KRB524 else if (ck_krb5_is_installed_as_server()) return(1); #endif /* KRB524 */ else return(0); #endif /* KRB4 */ } int ck_srp_is_installed_as_server() { #ifdef CK_SRP #ifdef SRPDLL if ( hSRP == NULL ) return(0); #endif /* SRPDLL */ #ifdef COMMENT /* This is the new API as of 1.7.4. However, all it does is allocate a data structure. It can never fail. */ { SRP * s_srp = SRP_new(SRP_RFC2945_server_method()); if ( s_srp ) { SRP_free(s_srp); s_srp = NULL; return(1); } return(0); } #else /* COMMENT */ { struct t_pw * tpw = NULL; struct t_conf * tconf = NULL; if((tconf = t_openconf(NULL)) == NULL) return(0); if((tpw = t_openpw(NULL)) == NULL) { t_closeconf(tconf); return(0); } t_closeconf(tconf); t_closepw(tpw); return(1); } #endif /* COMMENT */ #else /* SRP */ return(0); #endif /* SRP */ } int ck_srp_is_installed() { #ifdef CK_SRP #ifdef SRPDLL if ( hSRP == NULL ) return(0); #endif /* SRPDLL */ return(1); #else /* CK_SRP */ return(0); #endif /* CK_SRP */ } int ck_krypto_is_installed() { #ifdef CK_SRP #ifdef OS2 if ( hLIBKRYPTO == NULL ) return(0); #endif /* OS2 */ return(1); #else /* CK_SRP */ return(0); #endif /* CK_SRP */ } int ck_crypt_is_installed() { #ifdef CK_ENCRYPTION #ifdef CRYPT_DLL return(hCRYPT != NULL); #else /* CRYPT_DLL */ return(1); #endif /* CRYPT_DLL */ #else /* ENCRYPTION */ return(0); #endif /* ENCRYPTION */ } int ck_ntlm_is_installed() { #ifdef NT return(hSSPI != NULL); #else /* NT */ return(0); #endif /* NT */ } int ck_tn_auth_valid() { return(validUser); } /* C K _ K R B _ A U T H _ I N _ P R O G R E S S * * Is an authentication negotiation still in progress? * */ int #ifdef CK_ANSIC ck_tn_auth_in_progress(void) #else ck_tn_auth_in_progress() #endif { switch (authentication_version) { case AUTHTYPE_AUTO: return(1); case AUTHTYPE_NULL: return(0); #ifdef KRB4 case AUTHTYPE_KERBEROS_V4: if (!accept_complete) { debug(F100,"ck_auth_in_progress() Kerberos 4 !accept_complete", "",0); return(1); } else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) { debug(F100,"ck_auth_in_progress() Kerberos 4 !mutual_complete", "",0); return(1); } else return(0); #endif /* KRB4 */ #ifdef KRB5 case AUTHTYPE_KERBEROS_V5: if (!accept_complete) { debug(F100,"ck_auth_in_progress() Kerberos 5 !accept_complete", "",0); return(1); } else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) { debug(F100,"ck_auth_in_progress() Kerberos 5 !mutual_complete", "",0); return(1); } else return(0); #ifdef GSSAPI_K5 case AUTHTYPE_GSSAPI_KRB5: if (!accept_complete) { debug(F100, "ck_auth_in_progress() GSSAPI Kerberos 5 !accept_complete", "", 0 ); return(1); } else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) { debug(F100, "ck_auth_in_progress() GSSAPI Kerberos 5 !mutual_complete", "", 0 ); return(1); } else return(0); break; #endif /* GSSAPI_K5 */ #endif /* KRB5 */ #ifdef CK_SRP case AUTHTYPE_SRP: if (!accept_complete || srp_waitresp) return(1); else return(0); #endif /* CK_SRP */ #ifdef NTLM case AUTHTYPE_NTLM: if (!accept_complete) { debug(F100,"ck_auth_in_progress() NTLM !accept_complete", "",0); return(1); } else return(0); #endif /* NTLM */ case AUTHTYPE_SSL: if (!accept_complete) { debug(F100,"ck_auth_in_progress() SSL !accept_complete", "",0); return(1); } else return(0); default: return(0); } return(0); } /* C K _ K R B _ T N _ A U T H _ R E Q U E S T * * Builds a Telnet Authentication Send Negotiation providing the * list of supported authentication methods. To be used only * when accepting incoming connections as only the server (DO) side of the * Telnet negotiation is allowed to send an AUTH SEND. * * Returns: 0 on success and -1 on failure */ static unsigned char str_request[64] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_SEND }; #ifdef GSSAPI_K5 static int ck_tn_auth_request_gsskrb5(int i) { if (ck_gssapi_is_installed() && ck_krb5_is_installed_as_server()) { if ( (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_EXCH) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_AFTER_EXCHANGE; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE ", TN_MSG_LEN); i++; } } } #endif /* GSSAPI_K5 */ #ifdef KRB5 static int ck_tn_auth_request_krb5(int i) { if (ck_krb5_is_installed_as_server()) { #ifdef CK_SSL if ( ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && ssl_finished_messages ) { #ifdef USE_INI_CRED_FWD if ( forward_flag && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_START_TLS; str_request[i] |= INI_CRED_FWD_ON; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS|INI_CRED_FWD_ON ", TN_MSG_LEN); i++; } #endif /* USE_INI_CRED_FWD */ if ( (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_START_TLS; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS ", TN_MSG_LEN); i++; } if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_START_TLS; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ", TN_MSG_LEN); i++; } } #ifdef CK_ENCRYPTION else { #endif /* CK_ENCRYPTION */ #endif /* CK_SSL */ #ifdef CK_ENCRYPTION #ifdef USE_INI_CRED_FWD if ( forward_flag && TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; str_request[i] |= INI_CRED_FWD_ON; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT|INI_CRED_FWD_ON ", TN_MSG_LEN); i++; } #endif /* USE_INI_CRED_FWD */ if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT ", TN_MSG_LEN); i++; } #ifdef CK_SSL } #endif /* CK_SSL */ #endif /* CK_ENCRYPTION */ if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) #ifdef CK_SSL && !(ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && tls_is_anon(0)) #endif /* CK_SSL */ ) { #ifdef CK_ENCRYPTION /* Can't perform mutual authentication without encryption */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL ", TN_MSG_LEN); i++; } #endif /* CK_ENCRYPTION */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } } return(i); } #endif /* KRB5 */ #ifdef KRB4 static int ck_tn_auth_request_krb4(int i) { if (ck_krb4_is_installed_as_server()) { #ifdef CK_ENCRYPTION if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V4; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL|ENCRYPT ", TN_MSG_LEN); i++; } #endif /* CK_ENCRYPTION */ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) ) { #ifdef CK_ENCRYPTION /* Can't perform mutual authentication without encryption */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL ) { str_request[i++] = AUTHTYPE_KERBEROS_V4; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL ", TN_MSG_LEN); i++; } #endif /* CK_ENCRYPTION */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY ) { str_request[i++] = AUTHTYPE_KERBEROS_V4; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } } return(i); } #endif /* KRB4 */ #ifdef CK_SRP static int ck_tn_auth_request_srp(int i) { if (ck_srp_is_installed_as_server()) { #ifndef PRE_SRP_1_4_5 /* Dont' do this yet. SRP when it uses the ENCRYPT_USING_TELOPT */ /* flag it must perform a checksum of the auth-type-pair but there */ /* is no mechansim to do that yet. */ #ifdef CK_SSL if ( ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && ssl_finished_messages && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT)) { str_request[i++] = AUTHTYPE_SRP; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_START_TLS; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ", TN_MSG_LEN); i++; } #ifdef CK_ENCRYPTION else { #endif /* CK_ENCRYPTION */ #endif /* CK_SSL */ #ifdef CK_ENCRYPTION if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_SRP; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT ", TN_MSG_LEN); i++; } #ifdef CK_SSL } #endif /* CK_SSL */ #endif /* CK_ENCRYPTION */ #endif /* PRE_SRP_1_4_5 */ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) #ifdef CK_SSL && !(ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && tls_is_anon(0)) #endif /* CK_SSL */ ) { str_request[i++] = AUTHTYPE_SRP; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"SRP CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } return(i); } #endif /* CK_SRP */ #ifdef CK_SSL static int ck_tn_auth_request_ssl(int i) { if (ck_ssleay_is_installed() && !tls_active_flag && !ssl_active_flag && ssl_initialized ) { if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) ) { str_request[i++] = AUTHTYPE_SSL; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"SSL CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } return(i); } #endif /* CK_SSL */ #ifdef NTLM static int ck_tn_auth_request_ntlm(int i) { /* Microsoft's Telnet client won't perform authentication if */ /* NTLM is not first. */ if ( ck_ntlm_is_valid(1) ) { if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) ) { str_request[i++] = AUTHTYPE_NTLM; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"NTLM CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } return(i); } #endif /* NTLM */ int #ifdef CK_ANSIC ck_tn_auth_request(void) #else ck_tn_auth_request() #endif { int i = 4, rc = -1; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( deblog || tn_deb || debses ) strcpy(tn_msg,"TELNET SENT SB AUTHENTICATION SEND "); /* Create a list of acceptable Authentication types to send to */ /* the client and let it choose find one that we support */ /* For those authentication methods that support Encryption or */ /* Credentials Forwarding we must send all of the appropriate */ /* combinations based upon the state of */ /* TELOPT_x_MODE(TELOPT_ENCRYPTION) and forward_flag. */ if ( auth_type_user[0] == AUTHTYPE_AUTO ) { #ifdef GSSAPI_K5 i = ck_tn_auth_request_gsskrb5(i); #endif /* GSSAPI_K5 */ #ifdef KRB5 i = ck_tn_auth_request_krb5(i); #endif /* KRB5 */ #ifdef KRB4 i = ck_tn_auth_request_krb4(i); #endif /* KRB4 */ #ifdef CK_SRP i = ck_tn_auth_request_srp(i); #endif /* SRP */ #ifdef CK_SSL i = ck_tn_auth_request_ssl(i); #endif /* CK_SSL */ #ifdef NTLM i = ck_tn_auth_request_ntlm(i); #endif /* NTLM */ } else { int j; for ( j=0; jencrypt && encrypt_is_encrypting()) { debug(F111,"ck_tn_encrypting","encrypting", g_kstream->encrypt_type); return(g_kstream->encrypt_type); } #endif /* CK_ENCRYPTION */ debug(F110,"ck_tn_encrypting","not encrypting",0); return(0); } /* C K _ K R B _ D E C R Y P T I N G * Returns 1 if we are decrypting and 0 if we are not */ int #ifdef CK_ANSIC ck_tn_decrypting(VOID) #else ck_tn_decrypting() #endif /* CK_ANSIC */ { #ifdef CK_ENCRYPTION if ( g_kstream == NULL ) return(0); if ( g_kstream->decrypt && encrypt_is_decrypting()) { debug(F111,"ck_tn_decrypting","decrypting", g_kstream->decrypt_type); return(g_kstream->decrypt_type); } #endif /* CK_ENCRYPTION */ debug(F110,"ck_tn_decrypting","not decrypting",0); return(0); } /* C K _ K R B _ A U T H E N T I C A T E D * Returns the authentication type: AUTHTYPE_NULL, AUTHTYPE_KERBEROS4, * or AUTHTYPE_KERBEROS5, AUTHTYPE_SRP, ... (see ckctel.h) */ int #ifdef CK_ANSIC ck_tn_authenticated(VOID) #else ck_tn_authenticated() #endif { return(authentication_version); } /* C K _ K R B _ E N C R Y P T * encrypts n characters in s if we are encrypting */ VOID #ifdef CK_ANSIC ck_tn_encrypt( char * s, int n ) #else ck_tn_encrypt( s,n ) char * s; int n; #endif { #ifdef CK_ENCRYPTION struct kstream_data_block i; if (g_kstream->encrypt && encrypt_is_encrypting()) { #ifdef DEBUG hexdump("from plaintext", s, n); #endif i.ptr = s; i.length = n; g_kstream->encrypt(&i, NULL); #ifdef DEBUG hexdump("to cyphertext", s, n); #endif } else debug(F101,"ck_tn_encrypt not encrypting","",n); #endif /* ENCRYPTION */ } /* C K _ K R B _ D E C R Y P T * decrypts n characters in s if we are decrypting */ VOID #ifdef CK_ANSIC ck_tn_decrypt( char * s, int n ) #else ck_tn_decrypt( s,n ) char * s; int n; #endif { #ifdef CK_ENCRYPTION struct kstream_data_block i; if (g_kstream->decrypt && encrypt_is_decrypting()) { #ifdef DEBUG hexdump("from cyphertext", s, n); #endif i.ptr = s; i.length = n; g_kstream->decrypt(&i, NULL); #ifdef DEBUG hexdump("to plaintext", s, n); #endif } else debug(F101,"ck_tn_decrypt not decrypting","",n); #endif /* ENCRYPTION */ } /* S E N D K 5 A U T H S B * Send a Kerberos 5 Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ static int #ifdef CK_ANSIC SendK5AuthSB(int type, void *data, int len) #else SendK5AuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(0); else return(1); } #endif /* CK_SSL */ if ( type < 0 || type > 7 ) /* Check for invalid values */ return(0); if (!cd) { cd = (unsigned char *)""; len = 0; } if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_KERBEROS_V5; *p = AUTH_CLIENT_TO_SERVER; *p |= auth_how; #ifdef CK_ENCRYPTION *p |= auth_crypt; #endif #ifdef USE_INI_CRED_FWD if (auth_fwd) *p |= INI_CRED_FWD_ON; #endif /* USE_INI_CRED_FWD */ p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int i; int deblen=p-str_data-2; char *s=NULL; int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt #ifdef USE_INI_CRED_FWD | (auth_fwd?INI_CRED_FWD_ON:INI_CRED_FWD_OFF) #endif /* USE_INI_CRED_FWD */ ; switch (type) { case 0: s = "AUTH"; break; case 1: s = "REJECT"; break; case 2: s = "ACCEPT"; break; case 3: s = "RESPONSE"; break; case 4: s = "FORWARD"; break; case 5: s = "FORWARD_ACCEPT"; break; case 6: s = "FORWARD_REJECT"; break; case 7: s = "TLS_VERIFY"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_IS ? "IS" : str_data[3] == TELQUAL_REPLY ? "REPLY" : "???"," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif debug(F111,"SendK5AuthSB","ttol()",rc); return(rc); } /* S E N D K 4 A U T H S B * Send a Kerberos 4 Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ static int #ifdef CK_ANSIC SendK4AuthSB(int type, void *data, int len) #else SendK4AuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; int mode = (auth_how & AUTH_HOW_MASK) | auth_crypt; if ( type < 0 || type > 4 ) /* Check for invalid values */ return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(0); else return(1); } #endif /* CK_SSL */ if (!cd) { cd = (unsigned char *)""; len = 0; } if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_KERBEROS_V4; *p = AUTH_CLIENT_TO_SERVER; *p |= mode; p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int i; int deblen=p-str_data-2; char *s=NULL; switch (type) { case 0: s = "AUTH"; break; case 1: s = "REJECT"; break; case 2: s = "ACCEPT"; break; case 3: s = "CHALLENGE"; break; case 4: s = "RESPONSE"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_IS ? "IS" : (str_data[3] == TELQUAL_REPLY ? "REPLY" : "???")," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif debug(F111,"SendK4AuthSB","ttol()",rc); return(rc); } /* S E N D S R P A U T H S B * Send a SRP Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ static int #ifdef CK_ANSIC SendSRPAuthSB(int type, void *data, int len) #else SendSRPAuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; /* Check for invalid values */ if ( type != SRP_EXP && type != SRP_RESPONSE && type != SRP_REJECT && type != SRP_ACCEPT && type != SRP_CHALLENGE && type != SRP_PARAMS && type != SRP_AUTH) return(0); if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_SRP; *p = AUTH_CLIENT_TO_SERVER; *p |= auth_how; #ifdef CK_ENCRYPTION *p |= auth_crypt; #endif p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int i; int deblen=p-str_data-2; char *s=NULL; int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt; switch (type) { case 0: s = "AUTH"; break; case 1: s = "REJECT"; break; case 2: s = "ACCEPT"; break; case 3: s = "CHALLENGE"; break; case 4: s = "RESPONSE"; break; case 5: s = "FORWARD"; break; case 6: s = "FORWARD_ACCEPT"; break; case 7: s = "FORWARD_REJECT"; break; case 8: s = "EXP"; break; case 9: s = "PARAMS"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_REPLY ? "REPLY" : str_data[3] == TELQUAL_IS ? "IS" : "???"," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif return(rc); } #ifdef CK_ENCRYPTION /* * Function: Enable or disable the encryption process. * * Parameters: * enable - TRUE to enable, FALSE to disable. */ static VOID #ifdef CK_ANSIC auth_encrypt_enable(BOOL enable) #else auth_encrypt_enable(enable) BOOL enable; #endif { encrypt_flag = enable; } #endif /* * Function: Abort the authentication process * * Parameters: */ static VOID #ifdef CK_ANSIC auth_abort(char *errmsg, long r) #else auth_abort(errmsg,r) char *errmsg; long r; #endif { char buf[9]; extern int sstelnet; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return; } #endif /* CK_SSL */ debug(F111,"auth_abort",errmsg,r); /* Construct Telnet Debugging messages */ if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION), " IS ",AUTHTYPE_NAME(AUTHTYPE_NULL)," ", AUTHTYPE_NAME(AUTHTYPE_NULL)," IAC SE", NULL,NULL,NULL,NULL,NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Construct the Abort message to send to the host */ /* Basicly we change the authentication type to NULL */ sprintf(buf, "%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, sstelnet ? TELQUAL_REPLY : TELQUAL_IS, AUTHTYPE_NULL, AUTHTYPE_NULL, IAC, SE); /* safe */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, 8); #ifdef OS2 ReleaseTelnetMutex(); #endif /* If there is an error message, and error number construct */ /* an explanation to display to the user */ if (errmsg != NULL) { ckstrncpy(strTmp, errmsg, AUTHTMPBL); } else strTmp[0] = '\0'; if (r != AUTH_SUCCESS) { ckstrncat(strTmp, "\r\n",AUTHTMPBL); #ifdef KRB4 if ( authentication_version == AUTHTYPE_KERBEROS_V4 ) { ckstrncat(strTmp, (char *)krb_get_err_text_entry(r), AUTHTMPBL); debug(F111,"auth_abort",(char *)krb_get_err_text_entry(r),r); } #endif #ifdef KRB5 if ( authentication_version == AUTHTYPE_KERBEROS_V5 ) { ckstrncat(strTmp, error_message(r),AUTHTMPBL); debug(F111,"auth_abort",error_message(r),r); } #endif } printf("Authentication failed: %s\r\n",strTmp); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { cksyslog(SYSLG_LI, 0, "Telnet authentication failure", (char *) szUserNameRequested, strTmp); } #endif /* CKSYSLOG */ authentication_version = AUTHTYPE_NULL; } /* * Function: Copy data to buffer, doubling IAC character if present. * */ int #ifdef CK_ANSIC copy_for_net(unsigned char *to, unsigned char *from, int c) #else copy_for_net(to,from,c) unsigned char *to; unsigned char *from; int c; #endif { int n; n = c; debug(F111,"copy_for_net","before",n); while (c-- > 0) { if ((*to++ = *from++) == IAC) { n++; *to++ = IAC; } } debug(F111,"copy_for_net","after",n); return n; } #ifdef CK_SSL /* S E N D S S L A U T H S B * Send a SSL Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ int #ifdef CK_ANSIC SendSSLAuthSB(int type, void *data, int len) #else SendSSLAuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; /* Check for invalid values */ if ( type != SSL_START && type != SSL_ACCEPT && type != SSL_REJECT) return(0); if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(0); else return(1); } if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_SSL; *p = AUTH_CLIENT_TO_SERVER; *p |= auth_how; #ifdef CK_ENCRYPTION *p |= auth_crypt; #endif p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int i; int deblen=p-str_data-2; char *s=NULL; int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | (auth_crypt?AUTH_ENCRYPT_USING_TELOPT:AUTH_ENCRYPT_OFF); switch (type) { case SSL_START: s = "START"; break; case SSL_ACCEPT: s = "ACCEPT"; break; case SSL_REJECT: s = "REJECT"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_REPLY ? "REPLY" : str_data[3] == TELQUAL_IS ? "IS" : "???"," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif return(rc); } #endif /* CK_SSL */ int tn_how_ok(int how) { switch ( tn_auth_how ) { case TN_AUTH_HOW_ANY: return(1); case TN_AUTH_HOW_ONE_WAY: return((how & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY); case TN_AUTH_HOW_MUTUAL: return((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL); default: return(0); } } int tn_enc_ok(int enc) { switch ( tn_auth_enc ) { case TN_AUTH_ENC_ANY: if ((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS && (!ck_ssleay_is_installed() #ifdef CK_SSL || !ssl_finished_messages || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) { #ifdef CK_SSL if (!ssl_finished_messages) debug(F100,"tn_enc_ok !ssl_finished_messages","",0); #endif /* CK_SSL */ return(0); } return(1); case TN_AUTH_ENC_NONE: return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_OFF); case TN_AUTH_ENC_TELOPT: return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT); case TN_AUTH_ENC_EXCH: return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE); case TN_AUTH_ENC_TLS: return(((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && ck_ssleay_is_installed() #ifdef CK_SSL && ssl_finished_messages && (tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ ); default: return(0); } } static int atok(int at) { int i; if ( auth_type_user[0] == AUTHTYPE_AUTO ) return(1); if ( auth_type_user[0] == AUTHTYPE_NULL ) return(0); for ( i=0; i 512 ? 512 : end_sub; memcpy(send_list,parsedat,send_len); /* Search the list of acceptable Authentication types sent from */ /* the host and find one that we support */ /* For Kerberos authentications, try to determine if we have a */ /* valid TGT, if not skip over the authentication type because */ /* we wouldn't be able to successfully login anyway. Perhaps */ /* there is another supported authentication which we could use */ #ifdef NO_FTP_AUTH /* If the userid is "ftp" or "anonymous" refuse to perform AUTH */ /* for Kerberos or SRP. */ #endif /* NO_FTP_AUTH */ if ( auth_type_user[0] == AUTHTYPE_AUTO ) { for (i = 2; i+1 <= end_sub; i += 2) { #ifdef NTLM if (parsedat[i] == AUTHTYPE_NTLM && ck_ntlm_is_valid(1) && ntlm_auth_send() == 0) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* NTLM does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_NTLM; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* NTLM */ #ifdef CK_SSL if ( parsedat[i] == AUTHTYPE_SSL && ssl_initialized && #ifdef SSLDLL ck_ssleay_is_installed() && #endif /* SSLDLL */ !tls_active_flag && !ssl_active_flag #ifndef USE_CERT_CB && tls_load_certs(ssl_ctx,ssl_con,0) #endif /* USE_CERT_CB */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* SSL does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_SSL; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SSL */ #ifdef CK_SRP if ( parsedat[i] == AUTHTYPE_SRP #ifdef SRPDLL && hSRP #endif /* SRPDLL */ #ifdef NO_FTP_AUTH && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) #endif /* NO_FTP_AUTH */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef PRE_SRP_1_4_5 if (parsedat[i+1] & AUTH_ENCRYPT_MASK) /* Do not support ENCRYPT_USING_TELOPT yet. */ continue; #endif /* PRE_SRP_1_4_5 */ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_SRP; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SRP */ #ifdef GSSAPI_KRB5 if (parsedat[i] == AUTHTYPE_GSSAPI_KRB5 && (parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE && #ifdef OS2 hGSSAPI && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_gssapi_is_installed() && !gssk5_msg) { if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } gssk5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK; authentication_version = AUTHTYPE_GSSAPI_KRB5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* GSSAPI_KRB5 */ #ifdef KRB5 if (parsedat[i] == AUTHTYPE_KERBEROS_V5 && #ifdef OS2 hKRB5_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb5_is_installed() && !krb5_msg) { /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed()) continue; /* Skip over entries that request credential forwarding */ /* if we are not forwarding. */ if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) || (forward_flag && ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY))) continue; if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } krb5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && (!ck_ssleay_is_installed() #ifdef CK_SSL || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK; authentication_version = AUTHTYPE_KERBEROS_V5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB5 */ #ifdef KRB4 if (parsedat[i] == AUTHTYPE_KERBEROS_V4 && #ifdef OS2 hKRB4_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb4_is_installed() && !krb4_msg) { int rc = 0; /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed() ) continue; if ( !k4_auth_send() ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb4_is_tgt_valid() ) { printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n"); } krb4_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ authentication_version = AUTHTYPE_KERBEROS_V4; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB4 */ } } else { for (i = 2; i+1 <= end_sub; i += 2) { #ifdef CK_SSL if ( atok(AUTHTYPE_SSL) && parsedat[i] == AUTHTYPE_SSL && #ifdef SSLDLL ck_ssleay_is_installed() && #endif /* SSLDLL */ !tls_active_flag && !ssl_active_flag && ssl_initialized #ifndef USE_CERT_CB && tls_load_certs(ssl_ctx,ssl_con,0) #endif /* USE_CERT_CB */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* SSL does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_SSL; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SSL */ #ifdef CK_SRP if ( atok(AUTHTYPE_SRP) && parsedat[i] == AUTHTYPE_SRP #ifdef SRPDLL && hSRP #endif /* SRPDLL */ #ifdef NO_FTP_AUTH && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) #endif /* NO_FTP_AUTH */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef PRE_SRP_1_4_5 if (parsedat[i+1] & AUTH_ENCRYPT_MASK) /* Do not support ENCRYPT_USING_TELOPT yet. */ continue; #endif /* PRE_SRP_1_4_5 */ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && (!ck_ssleay_is_installed() #ifdef CK_SSL || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_SRP; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SRP */ #ifdef GSSAPI_KRB5 if (atok(AUTHTYPE_GSSAPI_KRB5) && parsedat[i] == AUTHTYPE_GSSAPI_KRB5 && (parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE && #ifdef OS2 hGSSAPI && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_gssapi_is_installed() && !gssk5_msg) { if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } gssk5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK; authentication_version = AUTHTYPE_GSSAPI_KRB5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* GSSAPI_KRB5 */ #ifdef KRB5 if ( atok(AUTHTYPE_KERBEROS_V5) && parsedat[i] == AUTHTYPE_KERBEROS_V5 && #ifdef OS2 hKRB5_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb5_is_installed() && !krb5_msg) { /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed()) continue; /* Skip over entries that request credential forwarding */ /* if we are not forwarding. */ if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) || (forward_flag && ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY))) continue; if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf( "Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } krb5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && (!ck_ssleay_is_installed() #ifdef CK_SSL || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if (auth_crypt) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_KERBEROS_V5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB5 */ #ifdef KRB4 if ( atok(AUTHTYPE_KERBEROS_V4) && parsedat[i] == AUTHTYPE_KERBEROS_V4 && #ifdef OS2 hKRB4_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb4_is_installed() && !krb4_msg) { int rc = 0; /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed()) continue; if ( !k4_auth_send() ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb4_is_tgt_valid() ) { printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n"); } krb4_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; if (auth_crypt) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ authentication_version = AUTHTYPE_KERBEROS_V4; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB4 */ #ifdef NTLM if ( atok(AUTHTYPE_NTLM) && parsedat[i] == AUTHTYPE_NTLM && ck_ntlm_is_valid(1) && ntlm_auth_send() == 0) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* NTLM does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_NTLM; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* NTLM */ } } if (auth_how == -1) { /* Did we find one? */ switch ( auth_type_user[0] ) { /* If not, abort the negotiation */ case AUTHTYPE_NULL: auth_abort("User refused to accept any authentication method",0); break; case AUTHTYPE_AUTO: auth_abort("No authentication method available", 0); break; default: { char msg[80]; ckmakmsg(msg,80,AUTHTYPE_NAME(auth_type_user[0]), " could not be negotiated",NULL,NULL ); auth_abort(msg, 0); } } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } printf("Authenticating with %s\r\n", AUTHTYPE_NAME(authentication_version)); /* Send Telnet Auth Name message (if necessary) */ switch ( authentication_version ) { case AUTHTYPE_SRP: case AUTHTYPE_KERBEROS_V4: case AUTHTYPE_KERBEROS_V5: case AUTHTYPE_GSSAPI_KRB5: /* if we do not have a name to login with get one now. */ while ( szUserName[0] == '\0' ) { extern char * tn_pr_uid; int ok = uq_txt(NULL, tn_pr_uid && tn_pr_uid[0] ? tn_pr_uid : "Host Userid: ", 1, NULL, szUserName, 63, NULL,DEFAULT_UQ_TIMEOUT); if ( !ok ) return AUTH_FAILURE; } plen = strlen(szUserName); pname = (unsigned char *) szUserName; /* Construct Telnet Debugging Message */ if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION), " NAME ",(char *)pname," IAC SE",NULL, NULL,NULL,NULL,NULL,NULL,NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Construct and send Authentication Name subnegotiation */ if ( plen < sizeof(buf) - 6 ) { sprintf((char *)buf, "%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME); memcpy(&buf[4], pname, plen); /* safe */ sprintf((char *)&buf[plen + 4], "%c%c", IAC, SE); /* safe */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, plen+6); #ifdef OS2 ReleaseTelnetMutex(); #endif } else { sprintf((char *)buf, "%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, IAC, SE); /* safe */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, 6); #ifdef OS2 ReleaseTelnetMutex(); #endif } } /* Construct Authentication Mode subnegotiation message (if necessary) */ switch ( authentication_version ) { case AUTHTYPE_SRP: case AUTHTYPE_KERBEROS_V4: case AUTHTYPE_KERBEROS_V5: case AUTHTYPE_GSSAPI_KRB5: case AUTHTYPE_NTLM: mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt #ifdef USE_INI_CRED_FWD | (((authentication_version == AUTHTYPE_KERBEROS_V5) && auth_fwd)?INI_CRED_FWD_ON:INI_CRED_FWD_OFF) #endif /* USE_INI_CRED_FWD */ ; sprintf((char *)buf, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_IS, authentication_version, mode, KRB_AUTH); /* safe */ break; } /* Send initial authentication data */ switch ( authentication_version ) { #ifdef CK_SSL case AUTHTYPE_SSL: SendSSLAuthSB(SSL_START,NULL,0); break; #endif /* SSL */ #ifdef CK_SRP case AUTHTYPE_SRP: sprintf(&buf[7], "%c%c", IAC, SE); /* safe */ if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION), " IS ",AUTHTYPE_NAME(authentication_version), " AUTH ",AUTHMODE_NAME(mode)," IAC SE", NULL,NULL,NULL,NULL,NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, 9); #ifdef OS2 ReleaseTelnetMutex(); #endif break; #endif /* SRP */ #ifdef NTLM case AUTHTYPE_NTLM: { int length = 0; for ( i=0 ; i= 0; --i) { register int x; x = (unsigned int)k4_challenge[i] + 1; k4_challenge[i] = x; /* ignore overflow */ if (x < 256) /* if no overflow, all done */ break; } hexdump("auth_send k4_challenge+1",k4_challenge,8); #ifdef MIT_CURRENT data.data = k4_challenge; data.length = 8; encdata.ciphertext.data = k4_challenge; encdata.ciphertext.length = 8; encdata.enctype = ENCTYPE_UNKNOWN; if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &data, &encdata)) { com_err("libtelnet", code, "while encrypting random key"); return(0); } #else /* MIT_CURRENT */ #ifdef NT des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1); #else /* NT */ des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1); #endif /* NT */ hexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,1)", k4_challenge,8); #endif /* MIT_CURRENT */ } #endif /* ENCRYPTION */ #endif /* REMOVE_FOR_EXPORT */ break; #endif /* KRB4 */ #ifdef GSSAPI_KRB5 case AUTHTYPE_GSSAPI_KRB5: for ( i=0 ; i 63 ? 63 : (end_sub-2); if ( len > 0 && (len + 1) < sizeof(szUserNameRequested)) { memcpy(szUserNameRequested,&parsedat[2],len); /* safe */ szUserNameRequested[len] = '\0'; } else szUserNameRequested[0] = '\0'; debug(F111,"auth_name szUserNameRequested",szUserNameRequested,len); return(AUTH_SUCCESS); } /* * Function: Parse the athorization sub-options and reply. * * Parameters: * parsedat - sub-option string to parse. * * end_sub - last charcter position in parsedat. */ int auth_parse(unsigned char *parsedat, int end_sub) { int rc = AUTH_FAILURE; switch (parsedat[1]) { case TELQUAL_SEND: rc = auth_send(parsedat, end_sub); break; case TELQUAL_REPLY: rc= auth_reply(parsedat, end_sub); break; case TELQUAL_IS: rc = auth_is(parsedat, end_sub); break; case TELQUAL_NAME: rc = auth_name(parsedat, end_sub); break; } debug(F111,"auth_parse","rc",rc); return(rc); } /* * Function: Initialization routine called kstream encryption system. * * Parameters: * data - user data. */ int #ifdef CK_ANSIC auth_init(kstream ks) #else auth_init(ks) kstream_ptr ks; #endif { #ifdef FORWARD forwarded_tickets = 0; /* were tickets forwarded? */ #endif /* FORWARD */ #ifdef CK_ENCRYPTION encrypt_init(ks,cx_type); #endif return 0; } /* * Function: Destroy routine called kstream encryption system. * * Parameters: * data - user data. */ VOID #ifdef CK_ANSIC auth_destroy(void) #else auth_destroy() #endif { } /* * Function: Callback to encrypt a block of characters * * Parameters: * out - return as pointer to converted buffer. * * in - the buffer to convert * * Returns: number of characters converted. */ int #ifdef CK_ANSIC auth_encrypt(struct kstream_data_block *out, struct kstream_data_block *in) #else auth_encrypt(out,in) struct kstream_data_block *out; struct kstream_data_block *in; #endif { out->ptr = in->ptr; out->length = in->length; return(out->length); } /* * Function: Callback to decrypt a block of characters * * Parameters: * out - return as pointer to converted buffer. * * in - the buffer to convert * * Returns: number of characters converted. */ int #ifdef CK_ANSIC auth_decrypt(struct kstream_data_block *out, struct kstream_data_block *in) #else auth_decrypt(out,in) struct kstream_data_block *out; struct kstream_data_block *in; #endif { out->ptr = in->ptr; out->length = in->length; return(out->length); } #ifdef KRB4 #ifdef NT void ck_krb4_debug(int x) { set_krb_debug(x); set_krb_ap_req_debug(x); } #endif /* NT */ int ck_krb4_autoget_TGT(char * realm) { extern struct krb_op_data krb_op; extern struct krb4_init_data krb4_init; char passwd[PWD_SZ]; char prompt[256]; char * saverealm=NULL; int rc = -1; extern char * k4prprompt; extern char * k4pwprompt; ini_kerb(); /* Place defaults in above structs */ passwd[0] = '\0'; if ( krb4_init.principal == NULL || krb4_init.principal[0] == '\0') { int ok = uq_txt(NULL, k4prprompt && k4prprompt[0] ? k4prprompt : "Kerberos 4 Principal: ", 2, NULL, passwd,PWD_SZ-1, NULL, DEFAULT_UQ_TIMEOUT); if ( ok && passwd[0] ) makestr(&krb4_init.principal,passwd); else return(0); } /* Save realm in init structure so it can be restored */ if ( realm ) { saverealm = krb4_init.realm; krb4_init.realm = realm; } if ( passwd[0] || !(pwbuf[0] && pwflg) ) { int ok; if ( k4pwprompt && k4pwprompt[0] && (strlen(k4pwprompt) + strlen(krb4_init.principal) + strlen(krb4_init.realm) - 4) < sizeof(prompt)) { sprintf(prompt,k4pwprompt,krb4_init.principal,krb4_init.realm); } else ckmakxmsg(prompt,sizeof(prompt), "Kerberos 4 Password for ",krb4_init.principal,"@", krb4_init.realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) passwd[0] = '\0'; } else { ckstrncpy(passwd,pwbuf,sizeof(passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)passwd); #endif /* OS2 */ } if ( passwd[0] ) { makestr(&krb4_init.password,passwd); rc = ck_krb4_initTGT(&krb_op, &krb4_init); free(krb4_init.password); krb4_init.password = NULL; } krb4_init.password = NULL; memset(passwd,0,PWD_SZ); /* restore realm to init structure if needed */ if ( saverealm ) krb4_init.realm = saverealm; return(rc == 0); } char * ck_krb4_realmofhost(char *host) { return (char *)krb_realmofhost(host); } /* * * K4_auth_send - gets authentication bits we need to send to KDC. * * Result is left in auth * * Returns: 0 on failure, 1 on success */ static int #ifdef CK_ANSIC k4_auth_send(void) #else k4_auth_send() #endif { int r=0; /* Return value */ char instance[INST_SZ+1]=""; char *realm=NULL; char tgt[4*REALM_SZ+1]; memset(instance, 0, sizeof(instance)); #ifdef COMMENT /* we only need to call krb_get_phost if the hostname */ /* is not fully qualified. But we have already done */ /* this in netopen() call. This will save a round of */ /* DNS queries. */ debug(F110,"k4_auth_send","krb_get_phost",0); if (realm = (char *)krb_get_phost(szHostName)) { ckstrncpy(instance, realm, INST_SZ); } #else /* COMMENT */ { char *p; ckstrncpy(instance, szHostName, INST_SZ); for ( p=instance; *p && *p != '.' ; p++ ); *p = '\0'; } #endif /* COMMENT */ debug(F110,"k4_auth_send","krb_get_realmofhost",0); realm = (char *)krb_realmofhost(szHostName); if (!realm) { strcpy(strTmp, "Can't find realm for host \""); ckstrncat(strTmp, szHostName,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 4 error: %s\r\n",strTmp); krb4_errno = r; makestr(&krb4_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm); r = ck_krb4_tkt_isvalid(tgt); if ( r <= 0 && krb4_autoget ) ck_krb4_autoget_TGT(realm); debug(F110,"k4_auth_send","krb_mk_req",0); r = krb_mk_req(&k4_auth, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME, instance, realm, 0); if (r == 0) { debug(F110,"k4_auth_send","krb_get_cred",0); r = krb_get_cred(krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME, instance, realm, &cred); if (r) debug(F111,"k4_auth_send","krb_get_cred() failed",r); } else debug(F111,"k4_auth_send","krb_mk_req() failed",r); if (r) { strcpy(strTmp, "Can't get \""); ckstrncat(strTmp, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,AUTHTMPBL); if (instance[0] != 0) { ckstrncat(strTmp, ".",AUTHTMPBL); ckstrncat(strTmp, instance,AUTHTMPBL); } ckstrncat(strTmp, "@",AUTHTMPBL); ckstrncat(strTmp, realm,AUTHTMPBL); ckstrncat(strTmp, "\" ticket\r\n ",AUTHTMPBL); ckstrncat(strTmp, (char *)krb_get_err_text_entry(r),AUTHTMPBL); debug(F111,"k4_auth_send",(char *)krb_get_err_text_entry(r),r); printf("?Kerberos 4 error: %s\r\n",strTmp); krb4_errno = r; makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno)); return(0); } #ifdef OS2 if ( !szUserName[0] || !stricmp(szUserName,cred.pname) ) { ckstrncpy(szUserName, cred.pname, UIDBUFLEN); } #endif /* OS2 */ krb4_errno = r; makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno)); debug(F110,"k4_auth_send",krb4_errmsg,0); return(1); } /* * Function: K4 parse authentication reply command * * Parameters: * parsedat - the sub-command data. * * end_sub - index of the character in the 'parsedat' array which * is the last byte in a sub-negotiation * * Returns: Kerberos error code. */ static int #ifdef CK_ANSIC k4_auth_reply(unsigned char *parsedat, int end_sub) #else k4_auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub; #endif { #ifdef CK_ENCRYPTION Session_Key skey; #ifdef MIT_CURRENT krb5_data kdata; krb5_enc_data encdata; krb5_error_code code; #endif /* MIT_CURRENT */ #endif time_t t; int x; int i; if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (parsedat[4] == KRB_REJECT) { strTmp[0] = 0; for (i = 5; i <= end_sub; i++) { if (parsedat[i] == IAC) break; strTmp[i-5] = parsedat[i]; strTmp[i-4] = 0; } if (!strTmp[0]) strcpy(strTmp, "Authentication rejected by remote machine!"); printf("Kerberos V4 authentication failed!\r\n%s\r\n",strTmp); krb4_errno = -1; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (parsedat[4] == KRB_ACCEPT) { int net_len; if ((parsedat[3] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) { ckmakmsg(strTmp,sizeof(strTmp),"Kerberos V4 accepts you as ", szUserName,NULL,NULL); printf("%s\r\n",strTmp); accept_complete = 1; krb4_errno = 0; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; } if ((parsedat[3] & AUTH_HOW_MASK) != AUTH_HOW_MUTUAL) { printf("Kerberos V4 authentication failed!\r\n"); ckstrncpy(strTmp, "Kerberos V4 accepted you, but didn't provide mutual authentication", sizeof(strTmp)); printf("%s\r\n",strTmp); krb4_errno = -1; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifndef REMOVE_FOR_EXPORT #ifdef CK_ENCRYPTION SendK4AuthSB(KRB4_CHALLENGE,k4_session_key,sizeof(k4_session_key)); /* We have sent the decrypted session key to the host as a challenge */ /* now encrypt it to restore it to its original valid DES key value */ #ifdef MIT_CURRENT kdata.data = k4_session_key; kdata.length = 8; encdata.ciphertext.data = k4_session_key; encdata.ciphertext.length = 8; encdata.enctype = ENCTYPE_UNKNOWN; if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &kdata, &encdata)) { com_err("k4_auth_reply", code, "while encrypting session_key"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #else /* MIT_CURRENT */ #ifdef NT des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 1); #else /* NT */ des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 1); #endif /* NT */ hexdump( "k4_auth_reply des_ecb_encrypt(k4_session_key,k4_session_key,1)", k4_session_key, 8 ); #endif /* MIT_CURRENT */ #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ { /* And then use it to configure the encryption state machine. */ skey.type = SK_DES; skey.length = 8; skey.data = k4_session_key; encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* ENCRYPTION */ #endif /* REMOVE_FOR_EXPORT */ accept_complete = 1; ckmakmsg(strTmp,sizeof(strTmp), "Kerberos V4 accepts you as ",szUserName,NULL,NULL); printf("%s\r\n",strTmp); krb4_errno = 0; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; } if (parsedat[4] == KRB4_RESPONSE) { if (end_sub < 12) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } hexdump("KRB4_RESPONSE &parsedat[5]",&parsedat[5],8); #ifdef CK_ENCRYPTION hexdump("KRB4_RESPONSE k4_challenge",k4_challenge,8); /* The datablock returned from the host should match the value */ /* we stored in k4_challenge. */ if (memcmp(&parsedat[5], k4_challenge, sizeof(k4_challenge)) != 0) { printf("Kerberos V4 authentication failed!\r\n%s\r\n", "Remote machine is being impersonated!"); krb4_errno = -1; makestr(&krb4_errmsg,"Remote machine is being impersonated!"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #else /* ENCRYPTION */ makestr(&krb4_errmsg,"Kermit built without support for encryption."); return AUTH_FAILURE; #endif /* ENCRYPTION */ mutual_complete = 1; ckstrncpy(strTmp,"Remote machine has been mutually authenticated", sizeof(strTmp)); printf("%s\r\n",strTmp); krb4_errno = 0; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } /* * Function: K4 parse authentication IS command * * Parameters: * parsedat - the sub-command data. * * end_sub - index of the character in the 'parsedat' array which * is the last byte in a sub-negotiation * * Returns: Kerberos error code. */ static int #ifdef CK_ANSIC k4_auth_is(unsigned char *parsedat, int end_sub) #else k4_auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub; #endif { #ifdef CK_ENCRYPTION Session_Key skey; #ifdef MIT_CURRENT Block datablock, tmpkey; krb5_data kdata; krb5_enc_data encdata; krb5_error_code code; #else /* MIT_CURRENT */ Block datablock; #endif /* MIT_CURRENT */ #endif /* ENCRYPTION */ char realm[REALM_SZ+1]; char instance[INST_SZ]; int r = 0; char * data = &parsedat[5]; int cnt = end_sub - 5; extern char myipaddr[]; struct hostent *host; struct in_addr inaddr; int i; if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) { debug(F110,"k4_auth_is","Not kerberos v4",0); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch (parsedat[4]) { case KRB_AUTH: debug(F110,"k4_auth_is","KRB_AUTH",0); ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ+1); if (realm[0] == '\0') { SendK4AuthSB(KRB_REJECT, (void *)"No local V4 Realm.", -1); printf("\r\n? Kerberos 4 - No Local Realm\r\n"); debug(F110,"k4_auth_is","No local realm",0); krb4_errno = -1; makestr(&krb4_errmsg,"No local realm"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } debug(F110,"k4_auth_is",realm,0); if ( cnt < sizeof(k4_auth.dat) ) { k4_auth.length = cnt; memcpy((void *)k4_auth.dat, (void *)data, k4_auth.length); } else k4_auth.length = 0; hexdump("k4_auth.dat",k4_auth.dat, k4_auth.length); /* Get Instance */ inaddr.s_addr = inet_addr(myipaddr); host = gethostbyaddr((unsigned char *)&inaddr,4,PF_INET); if ( host ) { #ifdef HADDRLIST host = ck_copyhostent(host); #endif /* HADDRLIST */ ckstrncpy(instance,host->h_name,INST_SZ); for ( i=0;i= 0; r--) { register int t; t = (unsigned int)k4_challenge[r] + 1; k4_challenge[r] = t; /* ignore overflow */ if (t < 256) /* if no overflow, all done */ break; } hexdump("auth_is k4_challenge+1",k4_challenge,8); #ifdef MIT_CURRENT kdata.data = k4_challenge; kdata.length = 8; encdata.ciphertext.data = k4_challenge; encdata.ciphertext.length = 8; encdata.enctype = ENCTYPE_UNKNOWN; if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &kdata, &encdata)) { com_err("k4_auth_is", code, "while decrypting challenge"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #else /* MIT_CURRENT */ #ifdef NT des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1); #else /* NT */ des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1); #endif /* NT */ hexdump("auth_is des_ecb_encrypt(k4_challenge_key,k4_challenge,1)", k4_challenge,8); #endif /* MIT_CURRENT */ SendK4AuthSB(KRB4_RESPONSE,(void *)k4_challenge,sizeof(k4_challenge)); #endif /* ENCRYPTION */ mutual_complete = 1; break; default: if (1) printf("Unknown Kerberos option %d\r\n", data[-1]); SendK4AuthSB(KRB_REJECT, 0, 0); return(AUTH_FAILURE); } krb4_errno = r; makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno)); return(AUTH_SUCCESS); } #endif /* KRB4 */ #ifdef KRB5 int ck_krb5_autoget_TGT(char * realm) { extern struct krb_op_data krb_op; extern struct krb5_init_data krb5_init; char passwd[PWD_SZ]; char prompt[64]; char * saverealm=NULL; int rc = -1; extern char * k5prprompt; extern char * k5pwprompt; ini_kerb(); /* Place defaults in above structs */ passwd[0] = '\0'; if ( krb5_init.principal == NULL || krb5_init.principal[0] == '\0') { int ok = uq_txt(NULL,k5prprompt && k5prprompt[0] ? k5prprompt : "Kerberos 5 Principal: ",2,NULL,passwd,PWD_SZ-1,NULL, DEFAULT_UQ_TIMEOUT); if ( ok && passwd[0] ) makestr(&krb5_init.principal,passwd); else return(0); } /* Save realm in init structure so it can be restored */ if ( realm ) { saverealm = krb5_init.realm; krb5_init.realm = realm; } if ( passwd[0] || !(pwbuf[0] && pwflg) ) { int ok; if ( k5pwprompt && k5pwprompt[0] && (strlen(k5pwprompt) + strlen(krb5_init.principal) + strlen(krb5_init.realm) - 4) < sizeof(prompt)) { sprintf(prompt,k5pwprompt,krb5_init.principal,krb5_init.realm); } else ckmakxmsg(prompt,sizeof(prompt), k5pwprompt && k5pwprompt[0] ? k5pwprompt : "Kerberos 5 Password for ", krb5_init.principal,"@",krb5_init.realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) passwd[0] = '\0'; } else { ckstrncpy(passwd,pwbuf,sizeof(passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)passwd); #endif /* OS2 */ } if ( passwd[0] ) { extern struct krb4_init_data krb4_init; char * savek4realm=NULL; makestr(&krb5_init.password,passwd); if ( krb5_d_getk4 ) { krb5_init.getk4 = 1; makestr(&krb4_init.principal,krb5_init.principal); makestr(&krb4_init.password,passwd); if ( realm ) { savek4realm = krb4_init.realm; krb4_init.realm = realm; } rc = ck_krb5_initTGT(&krb_op, &krb5_init,&krb4_init); if ( savek4realm ) krb4_init.realm = savek4realm; free(krb4_init.password); krb4_init.password = NULL; } else { rc = ck_krb5_initTGT(&krb_op, &krb5_init,NULL); } free(krb5_init.password); krb5_init.password = NULL; memset(passwd,0,PWD_SZ); } /* restore realm to init structure if needed */ if ( saverealm ) krb5_init.realm = saverealm; return(rc == 0); } static krb5_error_code #ifdef CK_ANSIC k5_get_ccache( krb5_context k5_context, krb5_ccache * p_ccache, char * cc_name ) #else /* CK_ANSIC */ k5_get_ccache(k5_context, p_ccache, cc_name) krb5_context k5_context; krb5_ccache * p_ccache; char * cc_name; #endif /* CK_ANSIC */ { krb5_error_code r=0; char cc_tmp[CKMAXPATH+1]; const char * def_name = NULL; #ifndef HEIMDAL if ( cc_name ) { if ( strncmp("FILE:",cc_name,5) && strncmp("MEMORY:",cc_name,7) && strncmp("API:",cc_name,4) && strncmp("STDIO:",cc_name,6) && strncmp("MSLSA:",cc_name,6)) #ifdef NT ckmakmsg(cc_tmp,CKMAXPATH,"API:",cc_name,NULL,NULL); #else /* NT */ ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",cc_name,NULL,NULL); #endif /* NT */ else { ckstrncpy(cc_tmp,cc_name,CKMAXPATH); } r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache); if (r != 0) { com_err("k5_get_ccache resolving ccache",r, cc_tmp); } else { /* Make sure GSSAPI sees the same cache we are using */ char buf[128]; ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL); putenv(buf); } } else if ( krb5_d_cc ) { if ( strncmp("FILE:",krb5_d_cc,5) && strncmp("MEMORY:",krb5_d_cc,7) && strncmp("API:",krb5_d_cc,4) && strncmp("STDIO:",krb5_d_cc,6) && strncmp("MSLSA:", krb5_d_cc,6)) #ifdef NT ckmakmsg(cc_tmp,CKMAXPATH,"API:",krb5_d_cc,NULL,NULL); #else /* NT */ ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",krb5_d_cc,NULL,NULL); #endif /* NT */ else { ckstrncpy(cc_tmp,krb5_d_cc,CKMAXPATH); } r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache); if (r != 0) { com_err("k5_get_ccache resolving ccache",r, krb5_d_cc); } else { /* Make sure GSSAPI sees the same cache we are using */ char buf[128]; ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL); putenv(buf); } } else #endif /* HEIMDAL */ { if ((r = krb5_cc_default(k5_context, p_ccache))) { com_err("k5_get_ccache",r,"while getting default ccache"); } } /* do not set krb5_errno/krb5_errmsg here since the value returned */ /* is being passed internally within the krb5 functions. */ return(r); } char * ck_krb5_realmofhost(char *host) { char ** realmlist=NULL; krb5_context private_context=NULL; static char * realm = NULL; if ( !host ) return NULL; if ( realm ) { free(realm); realm = NULL; } /* create private_context */ if (krb5_init_context(&private_context)) { debug(F110,"ck_krb5_realmofhost()","unable to init_context",0); return(NULL); } if (!krb5_get_host_realm(private_context,host,&realmlist)) { if (realmlist[0]) makestr(&realm,realmlist[0]); krb5_free_host_realm(private_context,realmlist); realmlist = NULL; } if ( private_context ) { krb5_free_context(private_context); private_context = NULL; } if (realm == NULL || ckstrchr(realm,'.') == NULL) { int n = 0; char * p = host; while ( (p = ckstrchr(p,'.')) != NULL ) { n++; p++; } if (n == 1) { makestr(&realm,host); ckupper(realm); } else { free(realm); realm = NULL; } } return(realm); } /* * * K5_auth_send - gets authentication bits we need to send to KDC. * * Code lifted from telnet sample code in the appl directory. * * Result is left in k5_auth * * Returns: 0 on failure, 1 on success * */ static int #ifdef CK_ANSIC k5_auth_send(int how, int encrypt, int forward) #else k5_auth_send(how,encrypt,forward) int how; int encrypt; int forward; #endif { krb5_error_code r=0; krb5_ccache ccache=NULL; #ifndef HEIMDAL krb5_creds creds; #endif /* HEIMDAL */ krb5_creds * new_creds=NULL; #ifdef CK_ENCRYPTION krb5_keyblock *newkey = 0; #endif /* CK_ENCRYPTION */ krb5_flags ap_opts, auth_flags; char type_check[32]; krb5_data checksum; int len=0; char * realm = NULL; char tgt[256]; realm = ck_krb5_realmofhost(szHostName); if (!realm) { ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL); ckstrncat(strTmp, szHostName,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 5 error: %s\r\n",strTmp); krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN; makestr(&krb5_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"k5_auth_send TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); r = k5_get_ccache(k5_context,&ccache,NULL); if ( r ) { com_err(NULL, r, "while authorizing (0)."); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } #ifndef HEIMDAL memset((char *)&creds, 0, sizeof(creds)); if (r = krb5_sname_to_principal(k5_context, szHostName, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, KRB5_NT_SRV_HST, &creds.server)) { com_err(NULL, r, "while authorizing (1)."); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } if (forward_flag) { if (fwd_server) { krb5_free_principal(k5_context,fwd_server); fwd_server = NULL; } krb5_copy_principal(k5_context,creds.server,&fwd_server); } r = krb5_cc_get_principal(k5_context, ccache, &creds.client); if (r) { com_err(NULL, r, "while authorizing (2)."); krb5_free_cred_contents(k5_context, &creds); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } if (szUserName[0] == '\0') { /* Get user name now */ len = krb5_princ_component(k5_context, creds.client, 0)->length; if ( len < sizeof(szUserName) ) { memcpy(szUserName, krb5_princ_component(k5_context, creds.client, 0)->data, len); /* safe */ } else len = 0; szUserName[len] = '\0'; } else { char * name = NULL; len = krb5_princ_component(k5_context, creds.client, 0)->length; if ( len == strlen(szUserName) ) { name = krb5_princ_component(k5_context, creds.client, 0)->data; #ifdef OS2 if ( !strnicmp(szUserName,name,len) ) memcpy(szUserName,name,len); /* safe */ #endif /* OS2 */ } } if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */ /* Not sure if this is necessary anymore. What impact does it have * on Win2000 TGTs that use DES_CBC_MD5 or RC4_HMAC? * * This prevents using 3DES Service Tickets. */ creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC; } if (r = krb5_get_credentials(k5_context, 0, ccache, &creds, &new_creds)) { com_err(NULL, r, "while authorizing (3)."); krb5_free_cred_contents(k5_context, &creds); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } #endif /* HEIMDAL */ if (auth_context) { krb5_auth_con_free(k5_context, auth_context); auth_context = 0; } if (r = krb5_auth_con_init(k5_context, &auth_context)) { com_err(NULL, r, "while initializing auth context"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */ /* client and then server finished messages. */ type_check[0] = AUTHTYPE_KERBEROS_V5; type_check[1] = AUTH_CLIENT_TO_SERVER | (how ? AUTH_HOW_MUTUAL : AUTH_HOW_ONE_WAY) | (encrypt) | (forward ? INI_CRED_FWD_ON : INI_CRED_FWD_OFF); #ifdef CK_SSL if (encrypt == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); } #endif /* CK_SSL */ #ifndef HEIMDAL checksum.magic = KV5M_DATA; #endif /* HEIMDAL */ checksum.length = #ifdef CK_SSL (encrypt == AUTH_ENCRYPT_START_TLS) ? 26 : #endif /* CK_SSL */ 2; checksum.data = (char *)&type_check; ap_opts = 0; if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ap_opts |= AP_OPTS_MUTUAL_REQUIRED; #ifdef HEIMDAL r = krb5_auth_setkeytype(k5_context, auth_context, KEYTYPE_DES); if (r) com_err(NULL, r, "while setting auth keytype"); r = krb5_auth_con_setaddrs_from_fd(k5_context,auth_context, &ttyfd); if (r) com_err(NULL, r, "while setting auth addrs"); r = krb5_mk_req(k5_context, &auth_context, ap_opts, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, szHostName, &checksum, ccache, &k5_auth); if (r) com_err(NULL, r, "while making request"); #else /* HEIMDAL */ auth_flags = KRB5_AUTH_CONTEXT_RET_TIME; #ifdef CK_ENCRYPTION ap_opts |= AP_OPTS_USE_SUBKEY; #endif /* CK_ENCRYPTION */ #ifdef TLS_VERIFY if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { auth_flags |= KRB5_AUTH_CONTEXT_DO_SEQUENCE; if (!krb5_d_no_addresses) r = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR); } #endif /* CK_SSL */ krb5_auth_con_setflags(k5_context, auth_context, auth_flags); r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts, &checksum, new_creds, &k5_auth); #endif /* HEIMDAL */ #ifdef CK_ENCRYPTION if (!r) { r = krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey); if (r) r = krb5_auth_con_getkey(k5_context, auth_context, &newkey); if (k5_session_key) { krb5_free_keyblock(k5_context, k5_session_key); k5_session_key = 0; } } if (newkey) { /* * keep the key in our private storage, but don't use it * yet---see kerberos5_reply() below */ #ifdef HEIMDAL if ((newkey->keytype == ETYPE_DES_CBC_CRC) || (newkey->keytype == ETYPE_DES_CBC_MD5) || (newkey->keytype == ETYPE_DES_CBC_MD4)) { debug(F111,"k5_auth_send()","newkey->keytype",newkey->keytype); krb5_copy_keyblock(k5_context, newkey, &k5_session_key); } #else /* HEIMDAL */ /* look for all possible DES keys first - just for compatibility */ /* other key types are much less likely to be available */ if ((newkey->enctype == ENCTYPE_DES_CBC_CRC) || (newkey->enctype == ENCTYPE_DES_CBC_MD5) || (newkey->enctype == ENCTYPE_DES_CBC_MD4)) { debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype); krb5_copy_keyblock(k5_context, newkey, &k5_session_key); } else if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) || (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5)) { /* use the session key in credentials instead */ debug(F111,"k5_auth_send()","new_creds->keyblock.enctype", new_creds->keyblock.enctype); krb5_copy_keyblock(k5_context, &new_creds->keyblock, &k5_session_key); } else if (newkey->enctype != 0) { debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype); krb5_copy_keyblock(k5_context, newkey, &k5_session_key); } else if (new_creds->keyblock.enctype != 0) { /* use the session key in credentials instead */ debug(F111,"k5_auth_send()","new_creds->keyblock.enctype", new_creds->keyblock.enctype); krb5_copy_keyblock(k5_context, &new_creds->keyblock, &k5_session_key); } else { debug(F110,"k5_auth_send()","NO KEY in newkey",0); } #endif /* HEIMDAL */ krb5_free_keyblock(k5_context, newkey); } #endif /* CK_ENCRYPTION */ #ifndef HEIMDAL krb5_free_cred_contents(k5_context, &creds); krb5_free_creds(k5_context, new_creds); #endif /* HEIMDAL */ krb5_cc_close(k5_context,ccache); if (r) { com_err(NULL, r, "while authorizing (4)."); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); return(1); } /* * K5_auth_reply -- checks the reply for mutual authentication. */ static int #ifdef CK_ANSIC k5_auth_reply(int how, unsigned char *data, int cnt) #else k5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { #ifdef CK_ENCRYPTION Session_Key skey; #endif /* CK_ENCRYPTION */ data += 4; /* Point to status byte */ cnt -=5; switch (*data++) { case KRB_REJECT: if (cnt > 0) { char *s; int len; ckstrncpy(strTmp,"Kerberos V5 refuses authentication because\r\n", sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s, data, cnt); /* safe */ s[cnt] = 0; } } else ckstrncpy(strTmp,"Kerberos V5 refuses authentication", sizeof(strTmp)); krb5_errno = -1; makestr(&krb5_errmsg,strTmp); printf("Kerberos authentication failed!\r\n%s\r\n",strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; case KRB_ACCEPT: if (!mutual_complete) { if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !mutual_complete) { ckstrncpy(strTmp, "Kerberos V5 accepted you, but didn't provide" " mutual authentication",sizeof(strTmp)); printf("Kerberos authentication failed!\r\n%s\r\n",strTmp); krb5_errno = -1; makestr(&krb5_errmsg,strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifdef CK_ENCRYPTION if (k5_session_key) { if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */ skey.type = SK_DES; skey.length = 8; #ifdef HEIMDAL skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } else { #ifdef HEIMDAL switch ( k5_session_key->keytype ) { case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD5: case ETYPE_DES_CBC_MD4: skey.type = SK_DES; skey.length = 8; break; default: skey.type = SK_GENERIC; skey.length = k5_session_key->length; encrypt_dont_support(ENCTYPE_DES_CFB64); encrypt_dont_support(ENCTYPE_DES_OFB64); } skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ switch ( k5_session_key->enctype ) { case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_MD4: skey.type = SK_DES; skey.length = 8; default: skey.type = SK_GENERIC; skey.length = k5_session_key->length; encrypt_dont_support(ENCTYPE_DES_CFB64); encrypt_dont_support(ENCTYPE_DES_OFB64); } skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* CK_ENCRYPTION */ } if ( cnt > 0 ) { char *s; int len; ckstrncpy(strTmp,"Kerberos V5 accepts you as ",sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s,data,cnt); s[cnt] = 0; } } accept_complete = 1; printf("%s\r\n",strTmp); #ifdef FORWARD if (forward_flag #ifdef COMMENT /* Marc Horowitz has successfully argued that it is indeed safe to send Forwarded credentials to an untrusted host. */ && (auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL #endif /* COMMENT */ ) kerberos5_forward(); #endif /* FORWARD */ krb5_errno = 0; makestr(&krb5_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; case KRB5_RESPONSE: #ifdef TLS_VERIFY if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS && !krb5_tls_verified) { printf( "Man in the middle attack detected. Session terminated.\r\n"); #ifndef BETATEST netclos(); #endif /* BETATEST */ krb5_errno = -1; makestr(&krb5_errmsg,"TLS not verified"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if((ssl_active_flag || tls_active_flag) && (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { printf("TLS session parameters verified by Kerberos 5\r\n"); } #endif /* TLS_VERIFY */ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* the rest of the reply should contain a krb_ap_rep */ krb5_ap_rep_enc_part *reply; krb5_data inbuf; krb5_error_code r; inbuf.length = cnt; inbuf.data = (char *)data; if (r = krb5_rd_rep(k5_context, auth_context, &inbuf, &reply)) { com_err(NULL, r, "while authorizing. (5)"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } krb5_free_ap_rep_enc_part(k5_context, reply); #ifdef CK_ENCRYPTION if (encrypt_flag && k5_session_key) { if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */ skey.type = SK_DES; skey.length = 8; #ifdef HEIMDAL skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } else { #ifdef HEIMDAL switch ( k5_session_key->keytype ) { case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD5: case ETYPE_DES_CBC_MD4: skey.type = SK_DES; skey.length = 8; default: skey.type = SK_GENERIC; skey.length = k5_session_key->length; } skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ switch ( k5_session_key->enctype ) { case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_MD4: skey.type = SK_DES; skey.length = 8; break; default: skey.type = SK_GENERIC; skey.length = k5_session_key->length; } skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* ENCRYPTION */ mutual_complete = 1; } ckstrncpy(strTmp,"Remote machine has been mutually authenticated", sizeof(strTmp)); krb5_errno = 0; makestr(&krb5_errmsg,strTmp); printf("%s\r\n",strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; #ifdef FORWARD case KRB5_FORWARD_ACCEPT: forwarded_tickets = 1; ckstrncpy(strTmp,"Remote machine has accepted forwarded credentials", sizeof(strTmp)); krb5_errno = 0; makestr(&krb5_errmsg,strTmp); printf("%s\r\n",strTmp); return AUTH_SUCCESS; case KRB5_FORWARD_REJECT: forwarded_tickets = 0; if (cnt > 0) { char *s; int len; len = ckstrncpy(strTmp, "Kerberos V5 refuses forwarded credentials because ", sizeof(strTmp)); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s, data, cnt); s[cnt] = 0; } } else ckstrncpy(strTmp, "Kerberos V5 refuses forwarded credentials", sizeof(strTmp)); printf("%s\r\n",strTmp); krb5_errno = -1; makestr(&krb5_errmsg,strTmp); return AUTH_SUCCESS; #endif /* FORWARD */ #ifdef TLS_VERIFY case KRB5_TLS_VERIFY: if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { krb5_data reply, msg; char tls_verify[24]; krb5_replay_data repdata; krb5_error_code r; ssl_get_server_finished(&tls_verify[0],12); ssl_get_client_finished(&tls_verify[12],12); reply.data = data; reply.length = cnt; krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR); if (r = krb5_rd_safe(k5_context,auth_context,&reply,&msg,&repdata)) { com_err("", r, "decoding tls verifier"); krb5_errno = r; makestr(&krb5_errmsg,"TLS verify failure"); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } if ( msg.length == 24 && !memcmp(msg.data,tls_verify,24) ) krb5_tls_verified = 1; krb5_free_data_contents(k5_context,&msg); if (krb5_tls_verified) return(AUTH_SUCCESS); } printf("Man in the middle attack detected. Session terminated.\r\n"); netclos(); krb5_errno = -1; makestr(&krb5_errmsg,"TLS verify failure"); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); #endif /* CK_SSL */ default: krb5_errno = -1; makestr(&krb5_errmsg,"Unknown reply type"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; /* Unknown reply type */ } } #ifdef FORWARD /* Decode, decrypt and store the forwarded creds in the local ccache. */ /* Needed for KRB5_FORWARD */ static krb5_error_code rd_and_store_for_creds(context, auth_context, inbuf, client) krb5_context context; krb5_auth_context auth_context; krb5_data *inbuf; krb5_const_principal client; { krb5_creds ** creds=NULL; krb5_error_code retval; krb5_ccache ccache=NULL; #ifdef HEIMDAL /* Heimdal Telnetd creates the cache file at this point and sets the KRB5CCNAME environment variable. struct passwd *pwd; char ccname[1024]; pwd = getpwnam(szUserNameRequested); if (pwd == NULL) break; snprintf(ccname, sizeof(ccname)-1, "FILE:/tmp/krb5cc_%u",pwd->pw_uid); retval = krb5_cc_resolve(context,ccname,&ccache); chown(ccname + 5, pwd->pw_uid, -1); */ #endif /* HEIMDAL */ if (retval = k5_get_ccache(context,&ccache,NULL)) return(retval); #ifdef HEIMDAL if ((retval = krb5_cc_initialize(context, ccache, client))) return(retval); if ((retval = krb5_rd_cred(context, auth_context, ccache, inbuf))) return(retval); #else /* HEIMDAL */ if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) return(retval); if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client))) goto cleanup; if ((retval = krb5_cc_store_cred(context, ccache, creds[0]))) goto cleanup; if ((retval = krb5_cc_close(context, ccache))) goto cleanup; cleanup: krb5_free_tgt_creds(context, creds); #endif /* HEIMDAL */ return retval; } #endif /* FORWARD */ /* * * K5_auth_is. * */ static int #ifdef CK_ANSIC k5_auth_is(int how, unsigned char *data, int cnt) #else k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { int r = 0; krb5_principal server; krb5_keyblock *newkey = NULL; krb5_data outbuf; char errbuf[128]=""; char *getenv(); #ifndef HEIMDAL krb5_authenticator *authenticator; krb5_keytab keytabid = 0; #endif /* HEIMDAL */ krb5_data inbuf; #ifdef CK_ENCRYPTION Session_Key skey; #endif /* CK_ENCRYPTION */ char princ[256]=""; int len; data += 4; /* Point to status byte */ cnt -= 4; hexdump("k5_auth_is data",data,cnt); debug(F111,"k5_auth_is","how",how); if (cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch (*data++) { case KRB_AUTH: k5_auth.data = (char *)data; k5_auth.length = cnt; debug(F110,"k5_auth_is","KRB_AUTH",0); debug(F111,"k5_auth_is","auth_context",auth_context); if (!r && !auth_context) { r = krb5_auth_con_init(k5_context, &auth_context); debug(F111,"k5_auth_is","krb5_auth_con_init",r); } #ifdef HEIMDAL if (!r) r = krb5_auth_con_setaddrs_from_fd(k5_context,auth_context,&ttyfd); if (!r) r = krb5_sock_to_principal(k5_context,0,"host", KRB5_NT_SRV_HST,&server); if (!r) #else /* HEIMDAL */ if (!r) { krb5_rcache rcache = NULL; r = krb5_auth_con_getrcache(k5_context, auth_context, &rcache); debug(F111,"k5_auth_is","krb5_auth_con_getrcache",r); if (!r && !rcache) { /* Do not resolve server's principal name, we will check */ /* for validity after the krb5_rd_req() call. */ r = krb5_sname_to_principal(k5_context, 0, 0, KRB5_NT_SRV_HST, &server); debug(F111,"k5_auth_is","krb5_sname_to_principal",r); if (!r) { r = krb5_get_server_rcache(k5_context, krb5_princ_component(k5_context, server, 0), &rcache); debug(F111,"k5_auth_is","krb5_get_server_rcache",r); krb5_free_principal(k5_context, server); } } if (!r) { r = krb5_auth_con_setrcache(k5_context, auth_context, rcache); debug(F111,"k5_auth_is","krb5_auth_con_setrcache",r); } } if (!r && k5_keytab) { r = krb5_kt_resolve(k5_context, k5_keytab, &keytabid); debug(F111,"k5_auth_is","krb5_kt_resolve",r); } #endif /* HEIMDAL */ if (!r) { r = krb5_rd_req(k5_context, &auth_context, &k5_auth, #ifdef HEIMDAL server, NULL, NULL, #else /* HEIMDAL */ NULL, keytabid, NULL, #endif /* HEIMDAL */ &k5_ticket); debug(F111,"k5_auth_is","krb5_rd_req",r); } if (r) { (void) ckstrncpy(errbuf, "krb5_rd_req failed: ",sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } #ifdef HEIMDAL krb5_free_principal(k5_context, server); { char type_check[26]; /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */ /* client and then server finished messages. */ type_check[0] = AUTHTYPE_KERBEROS_V5; type_check[1] = how; /* not broken into parts */ #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); hexdump("k5_auth_is type_check",type_check,26); } #endif /* CK_SSL */ r = krb5_verify_authenticator_checksum(k5_context, auth_context, type_check, #ifdef CK_SSL ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 : #endif /* CK_SSL */ 2); } #else /* HEIMDAL */ len = krb5_princ_component(k5_context,k5_ticket->server,0)->length; if (len < 256) { memcpy(princ, krb5_princ_component(k5_context,k5_ticket->server,0)->data, len); princ[len] = '\0'; } if ( strcmp((krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME), princ) ) { debug(F110,"k5_auth_is incorrect service name",princ,0); ckstrncpy(errbuf,"incorrect service name: ",sizeof(errbuf)); ckstrncat(errbuf,krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, sizeof(errbuf)); ckstrncat(errbuf," != ",sizeof(errbuf)); ckstrncat(errbuf,princ,sizeof(errbuf)); goto errout; } r = krb5_auth_con_getauthenticator(k5_context, auth_context, &authenticator); debug(F111,"k5_auth_is","krb5_auth_con_getauthenticator",r); if (r) { (void) ckstrncpy(errbuf, "krb5_auth_con_getauthenticator failed: ", sizeof(errbuf) ); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } if (authenticator->checksum) { char type_check[26]; krb5_checksum *cksum = authenticator->checksum; krb5_keyblock *key; /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */ /* client and then server finished messages. */ type_check[0] = AUTHTYPE_KERBEROS_V5; type_check[1] = how; /* not broken into parts */ #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); hexdump("k5_auth_is type_check",type_check,26); } #endif /* CK_SSL */ r = krb5_auth_con_getkey(k5_context, auth_context, &key); debug(F111,"k5_auth_is","krb5_auth_con_getkey",r); if (r) { (void) ckstrncpy(errbuf, "krb5_auth_con_getkey failed: ", sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } r = krb5_verify_checksum(k5_context, cksum->checksum_type, cksum, &type_check, ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 : 2, key->contents, key->length ); debug(F111,"k5_auth_is","krb5_verify_checksum",r); if (r) { (void) ckstrncpy(errbuf, "checksum verification failed: ", sizeof(errbuf) ); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } krb5_free_keyblock(k5_context, key); } else { if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) { (void) strcpy(errbuf, "authenticator is missing required checksum"); goto errout; } } krb5_free_authenticator(k5_context, authenticator); #endif /* HEIMDAL */ #ifdef TLS_VERIFY if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { krb5_data in, msg; char tls_verify[24]; krb5_replay_data repdata; ssl_get_server_finished(&tls_verify[0],12); ssl_get_client_finished(&tls_verify[12],12); in.data = tls_verify; in.length = 24; krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR); if (r = krb5_mk_safe(k5_context,auth_context,&in,&msg,&repdata)) { com_err("", r, "encoding tls verifier"); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } SendK5AuthSB(KRB5_TLS_VERIFY, msg.data, msg.length); krb5_free_data_contents(k5_context,&msg); } #endif /* CK_SSL */ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* do ap_rep stuff here */ if ((r = krb5_mk_rep(k5_context, #ifdef HEIMDAL &auth_context, #else /* HEIMDAL */ auth_context, #endif /* HEIMDAL */ &outbuf))) { debug(F111,"k5_auth_is","krb5_mk_rep",r); (void) ckstrncpy(errbuf, "Make reply failed: ",sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } debug(F111,"k5_auth_is","krb5_mk_rep",r); SendK5AuthSB(KRB5_RESPONSE, outbuf.data, outbuf.length); mutual_complete = 1; } #ifdef HEIMDAL { char * name = NULL; if (krb5_unparse_name(k5_context, k5_ticket->client, &name)) { szUserNameAuthenticated[0] = '\0'; } else { ckstrncpy(szUserNameAuthenticated,UIDBUFLEN,name); free(name); } } #else /* HEIMDAL */ if ( krb5_aname_to_localname(k5_context, k5_ticket->enc_part2->client, UIDBUFLEN,szUserNameAuthenticated) ) szUserNameAuthenticated[0] = '\0'; #endif /* HEIMDAL */ SendK5AuthSB(KRB_ACCEPT, szUserNameAuthenticated, szUserNameAuthenticated[0] ? -1 : 0); accept_complete = 1; ckmakmsg(strTmp,sizeof(strTmp), "Kerberos5 identifies him as ``", szUserNameAuthenticated,"''",NULL); printf("%s\r\n",strTmp); if (szUserNameRequested[0] && krb5_kuserok(k5_context, #ifdef HEIMDAL k5_ticket->client, #else /* HEIMDAL */ k5_ticket->enc_part2->client, #endif /* HEIMDAL */ szUserNameRequested)) auth_finished(AUTH_VALID); else auth_finished(AUTH_USER); krb5_auth_con_getremotesubkey(k5_context, auth_context, &newkey); if (k5_session_key) { krb5_free_keyblock(k5_context, k5_session_key); k5_session_key = 0; } if (newkey) { krb5_copy_keyblock(k5_context, newkey, &k5_session_key); krb5_free_keyblock(k5_context, newkey); } else { krb5_copy_keyblock(k5_context, #ifdef HEIMDAL &k5_ticket->ticket.key, #else /* HEIMDAL */ k5_ticket->enc_part2->session, #endif /* HEIMDAL */ &k5_session_key); } #ifdef CK_ENCRYPTION #ifdef HEIMDAL skey.type = k5_session_key->keyvalue.length == 8 ? SK_DES : SK_GENERIC; skey.length = k5_session_key->keyvalue.length; skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.type = k5_session_key->length == 8 ? SK_DES : SK_GENERIC; skey.length = k5_session_key->length; skey.data = k5_session_key->contents; #endif /* HEIMDAL */ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT); #endif /* CK_ENCRYPTION */ debug(F100,"k5_auth_is AUTH_SUCCESS","",0); krb5_errno = r; if ( krb5_errno ) makestr(&krb5_errmsg,error_message(krb5_errno)); else makestr(&krb5_errmsg,strTmp); return AUTH_SUCCESS; #ifdef FORWARD case KRB5_FORWARD: if ( !forward_flag ) { SendK5AuthSB(KRB5_FORWARD_REJECT, "forwarded credentials are being refused.", -1); return(AUTH_SUCCESS); } inbuf.length = cnt; inbuf.data = (char *)data; if ( #ifndef HEIMDAL (!krb5_d_no_addresses && (r = krb5_auth_con_genaddrs(k5_context,auth_context,g_kstream->fd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) || #endif /* HEIMDAL */ (r = rd_and_store_for_creds(k5_context, auth_context,&inbuf, #ifdef HEIMDAL k5_ticket->client #else /* HEIMDAL */ k5_ticket->enc_part2->client #endif /* HEIMDAL */ ))) { (void) ckstrncpy(errbuf, "Read forwarded creds failed: ", sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); SendK5AuthSB(KRB5_FORWARD_REJECT, errbuf, -1); printf("Could not read forwarded credentials\r\n"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); } else { SendK5AuthSB(KRB5_FORWARD_ACCEPT, 0, 0); ckstrncpy(strTmp,"Forwarded credentials obtained",sizeof(strTmp)); printf("%s\r\n",strTmp); krb5_errno = 0; makestr(&krb5_errmsg,strTmp); } /* A failure to accept forwarded credentials is not an */ /* authentication failure. */ return AUTH_SUCCESS; #endif /* FORWARD */ default: printf("Unknown Kerberos option %d\r\n", data[-1]); SendK5AuthSB(KRB_REJECT, 0, 0); break; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; errout: SendK5AuthSB(KRB_REJECT, errbuf, -1); krb5_errno = r; makestr(&krb5_errmsg,errbuf); printf("%s\r\n", errbuf); if (auth_context) { krb5_auth_con_free(k5_context, auth_context); auth_context = 0; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifdef FORWARD int #ifdef CK_ANSIC kerberos5_forward(void) #else kerberos5_forward() #endif { krb5_error_code r; krb5_ccache ccache=NULL; krb5_principal client = 0; krb5_principal server = 0; krb5_data forw_creds; #ifdef HEIMDAL krb5_creds creds; #endif /* HEIMDAL */ forw_creds.data = 0; r = k5_get_ccache(k5_context,&ccache,NULL); if ( r ) { com_err(NULL, r, "Kerberos V5: could not get default ccache"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(AUTH_FAILURE); } if ((r = krb5_cc_get_principal(k5_context, ccache, &client))) { com_err(NULL, r, "Kerberos V5: could not get default principal"); goto cleanup; } #ifdef HEIMDAL memset(&creds, 0, sizeof(creds)); creds.client = client; if (r = krb5_build_principal(k5_context, &creds.server, strlen(client->realm), client->realm, "krbtgt", client->realm, NULL)) { com_err(NULL, r, "Kerberos V5: could not get principal"); goto cleanup; } creds.times.endtime = 0; if (r = krb5_get_forwarded_creds(k5_context, auth_context, ccache, 0, szHostName, &creds, &forw_creds)) { com_err(NULL, r, "Kerberos V5: error getting forwarded creds"); goto cleanup; } #else /* HEIMDAL */ /* we should not need to make this call since we are storing the */ /* server's principal in fwd_server from our call to */ /* krb5_sname_to_principal() in k5_auth_send() */ if (fwd_server == NULL) { if ((r = krb5_sname_to_principal(k5_context, szHostName, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, KRB5_NT_SRV_HST, &server))) { com_err(NULL, r, "Kerberos V5: could not make server principal"); goto cleanup; } } if (!krb5_d_no_addresses && (r = krb5_auth_con_genaddrs(k5_context, auth_context, g_kstream->fd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) { com_err(NULL, r, "Kerberos V5: could not gen local full address"); goto cleanup; } if (r = krb5_fwd_tgt_creds(k5_context, auth_context, 0, client, fwd_server ? fwd_server : server, ccache, forwardable_flag, &forw_creds)) { com_err(NULL, r, "Kerberos V5: error getting forwardable credentials"); goto cleanup; } #endif /* HEIMDAL */ /* Send forwarded credentials */ if (!SendK5AuthSB(KRB5_FORWARD, forw_creds.data, forw_creds.length)) { printf("Kerberos V5 forwarding error!\r\n%s\r\n", "Not enough room for authentication data"); } cleanup: if (client) krb5_free_principal(k5_context, client); if (server) krb5_free_principal(k5_context, server); #ifdef HEIMDAL krb5_data_free(&forw_creds); #else /* HEIMDAL */ krb5_free_data_contents(k5_context,&forw_creds); #endif /* HEIMDAL */ krb5_cc_close(k5_context, ccache); krb5_errno = r; makestr(&krb5_errmsg,krb5_errno?error_message(krb5_errno):"OK"); return(r?AUTH_FAILURE:AUTH_SUCCESS); } #endif /* FORWARD */ #else /* KRB5 */ int ck_krb5_autoget_TGT(char * dummy) { return(0); } #ifdef CK_KERBEROS int #ifdef CK_ANSIC ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init, struct krb4_init_data * k4_init) #else ck_krb5_initTGT(op,init,k4_init) krb_op_data * op; struct krb5_init_data * init; struct krb4_init_data * k4_init; #endif /* CK_ANSIC*/ { return(-1); } int #ifdef CK_ANSIC ck_krb5_destroy(struct krb_op_data * op) #else ck_krb5_destroy(op) struct krb_op_data * op; #endif { return(-1); } int #ifdef CK_ANSIC ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc) #else ck_krb5_list_creds(op,lc) struct krb_op_data * op; struct krb5_list_cred_data * lc; #endif { return(-1); } #else /* CK_KERBEROS */ int #ifdef CK_ANSIC ck_krb5_initTGT(void * op, void * init, void * k4_init ) #else ck_krb5_initTGT(op,init,k4_init) void * op; void * init; void * k4_init; #endif /* CK_ANSIC*/ { return(-1); } int #ifdef CK_ANSIC ck_krb5_destroy(void * op) #else ck_krb5_destroy(op) void * op; #endif { return(-1); } int #ifdef CK_ANSIC ck_krb5_list_creds(void * op, void * lc) #else ck_krb5_list_creds(op,lc) void * op; void * lc; #endif { return(-1); } #endif /* CK_KERBEROS */ #endif /* KRB5 */ #ifdef GSSAPI_KRB5 /* * * gssk5_auth_send - gets authentication bits we need to send to KDC. * * Result is left in k5_auth * * Returns: 0 on failure, 1 on success * */ static int #ifdef CK_ANSIC gssk5_auth_send(int how, int encrypt, int forward) #else gssk5_auth_send(how,encrypt,forward) int how; int encrypt; int forward; #endif { OM_uint32 maj_stat, min_stat; #ifdef KRB5 char * realm = NULL; char tgt[256]; #endif /* KRB5 */ gss_chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */ gss_chan.initiator_address.length = 4; gss_chan.initiator_address.value = &myctladdr.sin_addr.s_addr; gss_chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */ gss_chan.acceptor_address.length = 4; gss_chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr; gss_chan.application_data.length = 0; gss_chan.application_data.value = 0; #ifdef KRB5 realm = ck_krb5_realmofhost(ftp_host); if (realm) { ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); } #endif /* KRB5 */ /* Blob from gss-client */ /* host@hostname */ /* the V5 GSSAPI binding canonicalizes this for us... */ ckmakmsg(gss_stbuf,GSS_BUFSIZ, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, "@", szHostName, NULL ); fprintf(stderr, "Authenticating to <%s>...\n", gss_stbuf); gss_send_tok.value = gss_stbuf; gss_send_tok.length = strlen(gss_stbuf); maj_stat = gss_import_name(&min_stat, &gss_send_tok, gss_nt_service_name, &gss_target_name ); if (maj_stat != GSS_S_COMPLETE) { user_gss_error(maj_stat, min_stat, "parsing name"); secure_error("name parsed <%s>\n", gss_stbuf); return(0); } token_ptr = GSS_C_NO_BUFFER; gcontext = GSS_C_NO_CONTEXT; /* structure copy */ fprintf(stderr, "calling gss_init_sec_context\n"); maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &gcontext, gss_target_name, gss_mech_krb5, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | ((forward && forward_flag) ? GSS_C_DELEG_FLAG : 0), 0, (krb5_d_no_addresses ? /* channel bindings */ GSS_C_NO_CHANNEL_BINDINGS : &gss_chan), gss_token_ptr, NULL, /* ignore mech type */ &gss_send_tok, NULL, /* ignore ret_flags */ NULL ); /* ignore time_rec */ if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { user_gss_error(maj_stat, min_stat, "initializing context" ); gss_release_name(&min_stat, &gss_target_name); return(0); } return(1); } /* * gssk5_auth_reply -- checks the reply for mutual authentication. */ static int #ifdef CK_ANSIC gssk5_auth_reply(int how, unsigned char *data, int cnt) #else gssk5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { data += 4; /* Point to status byte */ cnt -=5; switch (*data++) { case GSS_REJECT: if (cnt > 0) { char *s; int len; ckstrncpy(strTmp,"GSSAPI refuses authentication because\r\n", sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s, data, cnt); /* safe */ s[cnt] = 0; } } else ckstrncpy(strTmp,"GSSAPI refuses authentication", sizeof(strTmp)); printf("GSSAPI authentication failed!\r\n%s\r\n",strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; case GSS_ACCEPT: if ( cnt > 0 ) { char *s; int len; ckstrncpy(strTmp,"GSSAPI accepts you as ",sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s,data,cnt); s[cnt] = 0; } } accept_complete = 1; printf("%s\r\n",strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; case GSS_RESPONSE: gss_token_ptr = &gss_recv_tok; gss_recv_tok.value = data; gss_recv_tok.length = cnt; maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &gcontext, gss_target_name, gss_krb5_mech, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | (forward_flag ? GSS_C_DELEG_FLAG : 0), 0, (krb5_d_no_addresses ? /* channel bindings */ GSS_C_NO_CHANNEL_BINDINGS : &gss_chan), gss_token_ptr, NULL, /* ignore mech type */ &gss_send_tok, NULL, /* ignore ret_flags */ NULL ); /* ignore time_rec */ if ( maj_stat == GSS_S_COMPLETE ) { } else if ( maj_stat == CSS_S_CONTINUE_NEEDED ) { } else { } ckstrncpy(strTmp,"Remote machine has been mutually authenticated", sizeof(strTmp)); printf("%s\r\n",strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; default: auth_finished(AUTH_REJECT); return AUTH_FAILURE; /* Unknown reply type */ } } /* * * gssk5_auth_is. * */ static int #ifdef CK_ANSIC k5_auth_is(int how, unsigned char *data, int cnt) #else k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { int replied = 0; gss_cred_id_t server_creds, deleg_creds; gss_name_t client; int ret_flags; gss_buffer_desc name_buf; gss_name_t server_name; OM_uint32 acquire_maj, acquire_min, accept_maj, accept_min, stat_maj, stat_min; gss_OID mechid; gss_buffer_desc tok, out_tok; char gbuf[GSS_BUFSIZ]; u_char gout_buf[GSS_BUFSIZ]; char localname[MAXHOSTNAMELEN]; char service_name[MAXHOSTNAMELEN+10]; char **service; struct hostent *hp; data += 4; /* Point to status byte */ cnt -= 4; hexdump("gssk5_auth_is data",data,cnt); debug(F111,"gssk5_auth_is","how",how); if (cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch (*data++) { case GSS_AUTH: gss_chan.initiator_addrtype = GSS_C_AF_INET; gss_chan.initiator_address.length = 4; gss_chan.initiator_address.value = &his_addr.sin_addr.s_addr; gss_chan.acceptor_addrtype = GSS_C_AF_INET; gss_chan.acceptor_address.length = 4; gss_chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr; gss_chan.application_data.length = 0; gss_chan.application_data.value = 0; tok.value = data; tok.length = cnt; if (gethostname(localname, MAXHOSTNAMELEN)) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (!(hp = gethostbyname(localname))) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifdef HADDRLIST hp = ck_copyhostent(hp); #endif /* HADDRLIST */ strncpy(localname, hp->h_name, sizeof(localname) - 1); localname[sizeof(localname) - 1] = '\0'; sprintf(service_name, "%s@%s", *service, localname); name_buf.value = service_name; name_buf.length = strlen(name_buf.value) + 1; stat_maj = gss_import_name(&stat_min, &name_buf, gss_nt_service_name, &server_name); if (stat_maj != GSS_S_COMPLETE) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } acquire_maj = gss_acquire_cred(&acquire_min, server_name, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL); (void) gss_release_name(&stat_min, &server_name); if (acquire_maj != GSS_S_COMPLETE) { reply_gss_error(535, accept_maj, accept_min, "accepting context"); syslog(LOG_ERR, "failed accepting context"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return 0; } gcontext = GSS_C_NO_CONTEXT; accept_maj = gss_accept_sec_context(&accept_min, &gcontext, /* context_handle */ /* verifier_cred_handle */ server_creds, &tok, /* input_token */ (krb5_d_no_addresses ? /* channel bindings */ GSS_C_NO_CHANNEL_BINDINGS : &gss_chan), &client, /* src_name */ &mechid, /* mech_type */ &out_tok, /* output_token */ &ret_flags, NULL, /* ignore time_rec */ /* forwarded credentials */ &deleg_creds ); if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED) { reply_gss_error(535, accept_maj, accept_min, "accepting context"); syslog(LOG_ERR, "failed accepting context"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return 0; } if (out_tok.length) { if (kerror = radix_encode(out_tok.value,gbuf,&out_tok.length, 0)) { secure_error("Couldn't encode ADAT reply (%s)", radix_error(kerror)); syslog(LOG_ERR, "couldn't encode ADAT reply"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return(0); } if (stat_maj == GSS_S_COMPLETE) { reply(235, "ADAT=%s", gbuf); replied = 1; } else { /* If the server accepts the security data, and requires additional data, it should respond with reply code 335. */ reply(335, "ADAT=%s", gbuf); } (void) gss_release_buffer(&stat_min, &out_tok); } if (stat_maj == GSS_S_COMPLETE) { /* GSSAPI authentication succeeded */ stat_maj = gss_display_name(&stat_min, client, &client_name, &mechid); if (stat_maj != GSS_S_COMPLETE) { /* "If the server rejects the security data (if a checksum fails, for instance), it should respond with reply code 535." */ reply_gss_error(535, stat_maj, stat_min, "extracting GSSAPI identity name"); syslog(LOG_ERR, "gssapi error extracting identity"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return 0; } auth_type = temp_auth_type; temp_auth_type = NULL; (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) { if (want_creds) ftpd_gss_convert_creds(client_name.value, deleg_creds); (void) gss_release_cred(&stat_min, &deleg_creds); } /* If the server accepts the security data, but does not require any additional data (i.e., the security data exchange has completed successfully), it must respond with reply code 235. */ if (!replied) { if (ret_flags & GSS_C_DELEG_FLAG && !have_creds) reply(235, "GSSAPI Authentication succeeded, but could not accept forwarded credentials" ); else reply(235, "GSSAPI Authentication succeeded"); } return(1); } else if (stat_maj == GSS_S_CONTINUE_NEEDED) { /* If the server accepts the security data, and requires additional data, it should respond with reply code 335. */ reply(335, "more data needed"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return(0); } else { /* "If the server rejects the security data (if a checksum fails, for instance), it should respond with reply code 535." */ reply_gss_error(535, stat_maj, stat_min, "GSSAPI failed processing ADAT"); syslog(LOG_ERR, "GSSAPI failed processing ADAT"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return(0); } debug(F100,"gssk5_auth_is AUTH_SUCCESS","",0); krb5_errno = r; if ( krb5_errno ) makestr(&krb5_errmsg,error_message(krb5_errno)); else makestr(&krb5_errmsg,strTmp); return AUTH_SUCCESS; default: printf("Unknown Kerberos option %d\r\n", data[-1]); SendGSSK5AuthSB(GSS_REJECT, 0, 0); break; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #endif /* GSSAPI_KRB5 */ #ifdef CK_SRP /* * Copyright (c) 1997 Stanford University * * The use of this software for revenue-generating purposes may require a * license from the owners of the underlying intellectual property. * Specifically, the SRP-3 protocol may not be used for revenue-generating * purposes without a license. * * NOTE: Columbia University has a license. * * Within that constraint, permission to use, copy, modify, and distribute * this software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notices and this permission * notice appear in all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ static void srp_encode_length(data, num) unsigned char * data; int num; { *data = (num >> 8) & 0xff; *++data = num & 0xff; } static int srp_decode_length(data) unsigned char * data; { return (((int) *data & 0xff) << 8) | (*(data + 1) & 0xff); } #ifdef PRE_SRP_1_7_3 static int #ifdef CK_ANSIC srp_reply(int how, unsigned char *data, int cnt) #else srp_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { struct t_num n; struct t_num g; struct t_num s; struct t_num B; struct t_num * A; char type_check[26]; int pflag; #ifdef CK_ENCRYPTION Session_Key skey; #endif /* ENCRYPTION */ char * str=NULL; data += 4; /* Point to status byte */ cnt -= 4; if(cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch(*data++) { case SRP_REJECT: ckmakmsg(strTmp,sizeof(strTmp), "SRP refuses authentication for '",szUserName, "'\r\n",NULL); if (cnt > 0) { int len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { str = strTmp + strlen(strTmp); memcpy(str,data,cnt); str[cnt] = 0; } } printf("SRP authentication failed!\r\n%s\r\n",strTmp); if (tc != NULL) { t_clientclose(tc); tc = NULL; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; case SRP_ACCEPT: if(cnt < RESPONSE_LEN || !srp_waitresp || tc == NULL ) { printf("SRP Protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } srp_waitresp = 0; if(t_clientverify(tc, data) == 0) { printf("SRP accepts you as %s\r\n",szUserName); #ifdef CK_SSL if((ssl_active_flag || tls_active_flag) && (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { printf("TLS session parameters verified by SRP\r\n"); } else #endif /* CK_SSL */ #ifdef CK_ENCRYPTION { skey.type = SK_GENERIC; skey.length = SESSION_KEY_LEN; skey.data = tc->session_key; encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* ENCRYPTION */ t_clientclose(tc); tc = NULL; accept_complete = 1; auth_finished(AUTH_VALID); return AUTH_SUCCESS; } else { printf("SRP server authentication failed!\r\n"); t_clientclose(tc); tc = NULL; return(auth_resend(AUTHTYPE_SRP)); } break; case SRP_PARAMS: if(!szUserName) { printf("No username available\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.len = srp_decode_length(data); data += 2; cnt -= 2; if(n.len > cnt) { printf("n too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.data = data; data += n.len; cnt -= n.len; g.len = srp_decode_length(data); data += 2; cnt -= 2; if(g.len > cnt) { printf("g too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } g.data = data; data += g.len; cnt -= g.len; s.len = srp_decode_length(data); data += 2; cnt -= 2; if(s.len > cnt) { printf("salt too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } s.data = data; data += s.len; cnt -= s.len; /* If the parameters provided by the server cannot be * validated the following function will fail. */ tc = t_clientopen(szUserName, &n, &g, &s); if (tc == NULL) { printf("SRP parameter initialization error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } A = t_clientgenexp(tc); if(A == NULL) { printf("SRP protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } SendSRPAuthSB(SRP_EXP, A->data, A->len); if ( pwbuf[0] && pwflg ) { printf("SRP using %d-bit modulus for '%s'\r\n", 8 * n.len, szUserName ); ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)srp_passwd); #endif /* OS2 */ } else { extern char * srppwprompt; char preface[128]; int ok; if (srppwprompt && srppwprompt[0] && (strlen(srppwprompt) + strlen(szUserName) - 2) < sizeof(preface)) { sprintf(preface,srppwprompt,szUserName); } else { ckmakxmsg( preface,sizeof(preface), "SRP using ",ckitoa(8*n.len),"-bit modulus for '", szUserName, "'", NULL, NULL, NULL, NULL, NULL, NULL, NULL); } ok = uq_txt( preface,"Password: ",2,NULL, srp_passwd,sizeof(srp_passwd)-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) srp_passwd[0] = '\0'; } t_clientpasswd(tc, srp_passwd); memset(srp_passwd, 0, sizeof(srp_passwd)); return AUTH_SUCCESS; case SRP_CHALLENGE: if(tc == NULL) { printf("SRP protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } #ifndef PRE_SRP_1_4_5 /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); t_clientaddexdata(tc,type_check,26); } else #endif /* CK_SSL */ t_clientaddexdata(tc,type_check,2); } #endif /* PRE_SRP_1_4_5 */ B.data = data; B.len = cnt; t_clientgetkey(tc, &B); SendSRPAuthSB(SRP_RESPONSE, t_clientresponse(tc), RESPONSE_LEN); srp_waitresp = 1; return AUTH_SUCCESS; default: return(auth_resend(AUTHTYPE_SRP)); } return AUTH_FAILURE; } static int #ifdef CK_ANSIC srp_is(int how, unsigned char *data, int cnt) #else srp_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { char * pbuf = NULL; char * ptr; #ifdef CK_ENCRYPTION Session_Key skey; #endif struct t_num A; struct t_pw * tpw = NULL; struct t_conf * tconf = NULL; struct passwd * pass; static struct t_num * B = NULL; /* Holder for B */ #ifdef CK_SSL char type_check[26]; #else char type_check[2]; #endif /* CK_SSL */ if ((cnt -= 4) < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } data += 4; cnt -= 1; switch(*data++) { case SRP_AUTH: /* Send parameters back to client */ if(ts != NULL) { t_serverclose(ts); ts = NULL; } if(!szUserNameRequested[0]) { if (1) printf("No username available\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #ifdef IKSD #ifdef CK_LOGIN if (inserver && ckxanon && !strcmp(szUserNameRequested,"anonymous")) { SendSRPAuthSB(SRP_REJECT, (void *) "anonymous login cannot be performed with Secure Remote Password", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #endif /* CK_LOGIN */ #endif /* IKSD */ #ifndef PRE_SRP_1_4_4 if(tpw == NULL) { if((tpw = t_openpw(NULL)) == NULL) { if (1) printf("Unable to open password file\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "No password file", -1); return(AUTH_FAILURE); } } if(tconf == NULL) { if((tconf = t_openconf(NULL)) == NULL) { if (1) printf("Unable to open configuration file\r\n"); SendSRPAuthSB(SRP_REJECT, (void *)"No configuration file", -1); return(AUTH_FAILURE); } } ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf); t_closepw(tpw); tpw = NULL; t_closeconf(tconf); tconf = NULL; #else /* PRE_SRP_1_4_4 */ #ifdef COMMENT /* the code in this block should no longer be necessary on OS/2 or Windows because I have added functionality to libsrp.lib to find the srp files. 4/22/2000 */ /* On Windows and OS/2 there is no well defined place for the */ /* ETC directory. So we look for either an SRP_ETC or ETC */ /* environment variable in that order. If we find one we */ /* attempt to open the files manually. */ /* We will reuse the strTmp[] for the file names. */ ptr = getenv("SRP_ETC"); if ( !ptr ) ptr = getenv("ETC"); #ifdef NT if ( !ptr ) { DWORD len; len = AUTHTMPBL; len = GetWindowsDirectory(strTmp,len); if ( len > 0 && len < AUTHTMPBL) { if ( !isWin95() ) { if ( len == 1 ) ckstrncat(strTmp,"SYSTEM32/DRIVERS/ETC",sizeof(strTmp)); else ckstrncat(strTmp,"/SYSTEM32/DRIVERS/ETC",sizeof(strTmp)); } } ptr = strTmp; } #endif /* NT */ if ( ptr ) { int len = strlen(ptr); int i; if (ptr != strTmp) strcpy(strTmp,ptr); for ( i=0;in.len + ts->g.len + ts->s.len + 7); ptr = pbuf; srp_encode_length(ptr, ts->n.len); ptr += 2; memcpy(ptr, ts->n.data, ts->n.len); /* safe */ ptr += ts->n.len; srp_encode_length(ptr, ts->g.len); ptr += 2; memcpy(ptr, ts->g.data, ts->g.len); /* safe */ ptr += ts->g.len; srp_encode_length(ptr, ts->s.len); ptr += 2; memcpy(ptr, ts->s.data, ts->s.len); /* safe */ ptr += ts->s.len; SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf); free(pbuf); pbuf = NULL; B = t_servergenexp(ts); ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN); return AUTH_SUCCESS; case SRP_EXP: /* Client is sending A to us, compute challenge & expected response. */ if (ts == NULL || B == NULL) { printf("Protocol error: SRP_EXP unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: unexpected EXP", -1 ); return(AUTH_FAILURE); } /* Wait until now to send B, since it contains the key to "u" */ SendSRPAuthSB(SRP_CHALLENGE, B->data, B->len); B = NULL; #ifndef PRE_SRP_1_4_5 /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); } #endif /* CK_SSL */ t_serveraddexdata(ts,type_check, #ifdef CK_SSL ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 : #endif /* CK_SSL */ 2); } #endif /* PRE_SRP_1_4_5 */ A.data = data; A.len = cnt; ptr = t_servergetkey(ts, &A); if(ptr == NULL) { if (1) printf("Security alert: Trivial session key attempted\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Trivial session key detected", -1 ); return(AUTH_FAILURE); } srp_waitresp = 1; return AUTH_SUCCESS; case SRP_RESPONSE: /* Got the response; see if it's correct */ if (!srp_waitresp || ts == NULL ) { if (1) printf("Protocol error: SRP_RESPONSE unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: unexpected RESPONSE", -1 ); return(AUTH_FAILURE); } srp_waitresp = 0; /* we got a response */ if (cnt < RESPONSE_LEN) { if (1) printf("Protocol error: malformed response\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: malformed response", -1 ); return(AUTH_FAILURE); } if (t_serververify(ts, data) == 0) { SendSRPAuthSB(SRP_ACCEPT, t_serverresponse(ts), RESPONSE_LEN); accept_complete = 1; #ifdef CK_ENCRYPTION #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ { hexdump("SRP_RESPONSE ts",ts,sizeof(ts)); hexdump("SRP_RESPONSE session_key", ts->session_key, SESSION_KEY_LEN ); skey.type = SK_GENERIC; skey.length = SESSION_KEY_LEN; skey.data = ts->session_key; encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT); } #endif /* CK_ENCRYPTION */ auth_finished(AUTH_VALID); } else { SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } return AUTH_SUCCESS; default: printf("Unknown SRP option %d\r\n", data[-1]); SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1); return(AUTH_FAILURE); } } #else /* PRE_SRP_1_7_3 */ static int #ifdef CK_ANSIC new_srp_reply(int how, unsigned char *data, int cnt) #else new_srp_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { data += 4; /* Point to status byte */ cnt -= 4; if(cnt-- < 1) { /* Matches with data++ */ auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch(*data++) { case SRP_PARAMS: { struct t_num n; struct t_num g; struct t_num s; cstr * A; if(!szUserName) { printf("No username available\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.len = srp_decode_length(data); data += 2; cnt -= 2; if(n.len > cnt) { printf("n too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.data = data; data += n.len; cnt -= n.len; g.len = srp_decode_length(data); data += 2; cnt -= 2; if(g.len > cnt) { printf("g too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } g.data = data; data += g.len; cnt -= g.len; s.len = srp_decode_length(data); data += 2; cnt -= 2; if(s.len != cnt) { printf("invalid salt\r\n"); return(auth_resend(AUTHTYPE_SRP)); } s.data = data; data += s.len; cnt -= s.len; /* If the parameters provided by the server cannot be * validated the following function will fail. */ c_srp = SRP_new(SRP_RFC2945_client_method()); if (c_srp == NULL || SRP_set_username(c_srp, szUserName) != SRP_SUCCESS || SRP_set_params(c_srp,n.data,n.len,g.data,g.len,s.data,s.len) != SRP_SUCCESS) { printf("SRP Parameter initialization error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } A = cstr_new(); if(SRP_gen_pub(c_srp, &A) != SRP_SUCCESS) { printf("SRP Error generating key exchange\r\n"); return(auth_resend(AUTHTYPE_SRP)); } SendSRPAuthSB(SRP_EXP, A->data, A->length); cstr_free(A); if ( pwbuf[0] && pwflg ) { printf("SRP using %d-bit modulus for '%s'\r\n", 8 * n.len, szUserName ); ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)srp_passwd); #endif /* OS2 */ } else { extern char * srppwprompt; char preface[128]; int ok; if (srppwprompt && srppwprompt[0] && (strlen(srppwprompt) + strlen(szUserName) - 2) < sizeof(preface)) { sprintf(preface,srppwprompt,szUserName); } else { ckmakxmsg( preface,sizeof(preface), "SRP using ",ckitoa(8*n.len),"-bit modulus for '", szUserName, "'", NULL, NULL, NULL, NULL, NULL, NULL, NULL); } ok = uq_txt(preface,"Password: ",2,NULL, srp_passwd,sizeof(srp_passwd)-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) srp_passwd[0] = '\0'; } if(SRP_set_auth_password(c_srp, srp_passwd) != SRP_SUCCESS) { memset(srp_passwd, 0, sizeof(srp_passwd)); printf("SRP Error setting client password\r\n"); return(auth_resend(AUTHTYPE_SRP)); } memset(srp_passwd, 0, sizeof(srp_passwd)); return AUTH_SUCCESS; } case SRP_CHALLENGE: { char type_check[26]; cstr * resp = NULL; if(c_srp == NULL) { printf("SRP protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); SRP_add_ex_data(c_srp, type_check, 26); } else #endif /* CK_SSL */ SRP_add_ex_data(c_srp, type_check, 2); } if(SRP_compute_key(c_srp, &c_key, data, cnt) != SRP_SUCCESS) { printf("SRP ERROR: unable to compute client key\r\n"); return(auth_resend(AUTHTYPE_SRP)); } resp = cstr_new(); if(SRP_respond(c_srp, &resp) != SRP_SUCCESS) { printf("SRP ERROR: unable to compute client response\r\n"); return(auth_resend(AUTHTYPE_SRP)); } SendSRPAuthSB(SRP_RESPONSE, resp->data, resp->length); cstr_free(resp); srp_waitresp = 1; return AUTH_SUCCESS; } case SRP_ACCEPT: { #ifdef CK_ENCRYPTION Session_Key skey; #endif /* ENCRYPTION */ if(cnt < RESPONSE_LEN || !srp_waitresp || c_srp == NULL) { printf("SRP Protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } srp_waitresp = 0; if(SRP_verify(c_srp, data, cnt) == SRP_SUCCESS) { printf("SRP accepts you as %s\r\n",szUserName); #ifdef CK_SSL if((ssl_active_flag || tls_active_flag) && (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { printf("TLS session parameters verified by SRP\r\n"); } else #endif /* CK_SSL */ #ifdef CK_ENCRYPTION { skey.type = SK_GENERIC; skey.length = c_key->length; skey.data = c_key->data; encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); cstr_clear_free(c_key); c_key = NULL; } #endif /* CK_ENCRYPTION */ accept_complete = 1; auth_finished(AUTH_VALID); SRP_free(c_srp); c_srp = NULL; return AUTH_SUCCESS; } else { printf("[ Error: SRP server authentication failed ]\r\n"); return(auth_resend(AUTHTYPE_SRP)); } } case SRP_REJECT: { char * str=NULL; ckmakmsg(strTmp,sizeof(strTmp), "SRP refuses authentication for '",szUserName, "'\r\n",NULL); if (cnt > 0) { int len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { str = strTmp + strlen(strTmp); memcpy(str,data,cnt); str[cnt] = 0; } } printf("SRP authentication failed!\r\n%s\r\n",strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } default: printf("Unknown SRP option %d\r\n", data[-1]); return(auth_resend(AUTHTYPE_SRP)); } /* NEVER REACHED */ } static int #ifdef CK_ANSIC new_srp_is(int how, unsigned char *data, int cnt) #else new_srp_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { char * pbuf = NULL; char * ptr; #ifdef CK_ENCRYPTION Session_Key skey; #endif static cstr * B = NULL; /* Holder for B */ struct t_passwd * pass; cstr * resp; char type_check[26]; if ((cnt -= 4) < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } data += 4; cnt -= 1; switch(*data++) { case SRP_AUTH: /* Send parameters back to client */ if(s_srp != NULL) { SRP_free(s_srp); s_srp = NULL; } if (B != NULL) { cstr_free(B); B = NULL; } if(!szUserNameRequested[0]) { if (1) printf("No username available\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #ifdef IKSD #ifdef CK_LOGIN if (inserver && ckxanon && !strcmp(szUserNameRequested,"anonymous")) { SendSRPAuthSB(SRP_REJECT, (void *) "anonymous login cannot be performed with Secure Remote Password", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #endif /* CK_LOGIN */ #endif /* IKSD */ s_srp = SRP_new(SRP_RFC2945_server_method()); if(s_srp == NULL) { printf("Error initializing SRP server\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "SRP server init failed", -1 ); return(AUTH_FAILURE); } pass = gettpnam(szUserNameRequested); if(pass == NULL) { printf("User %s not found\r\n", szUserNameRequested); SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1); return(AUTH_FAILURE); } if(SRP_set_username(s_srp, szUserNameRequested) != SRP_SUCCESS || SRP_set_params(s_srp, pass->tc.modulus.data, pass->tc.modulus.len, pass->tc.generator.data, pass->tc.generator.len, pass->tp.salt.data, pass->tp.salt.len) != SRP_SUCCESS || SRP_set_authenticator(s_srp, pass->tp.password.data, pass->tp.password.len) != SRP_SUCCESS) { printf("Error initializing SRP parameters\r\n"); SendSRPAuthSB(SRP_REJECT,(void *)"SRP parameter init failed", -1); return(AUTH_FAILURE); } pbuf = (char *)malloc(pass->tc.modulus.len + pass->tc.generator.len + pass->tp.salt.len + 7); ptr = pbuf; srp_encode_length(ptr, pass->tc.modulus.len); ptr += 2; memcpy(ptr, pass->tc.modulus.data, pass->tc.modulus.len); ptr += pass->tc.modulus.len; srp_encode_length(ptr, pass->tc.generator.len); ptr += 2; memcpy(ptr, pass->tc.generator.data, pass->tc.generator.len); ptr += pass->tc.generator.len; srp_encode_length(ptr, pass->tp.salt.len); ptr += 2; memcpy(ptr, pass->tp.salt.data, pass->tp.salt.len); ptr += pass->tp.salt.len; SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf); free(pbuf); pbuf = NULL; if(SRP_gen_pub(s_srp, &B) != SRP_SUCCESS) { printf("Error generating SRP public value\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "SRP_gen_pub failed", -1); return(AUTH_FAILURE); } ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN); return AUTH_SUCCESS; case SRP_EXP: /* Client is sending A to us, compute challenge and expected response. */ if (s_srp == NULL || B == NULL) { printf("Protocol error: SRP_EXP unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *)"Protocol error: unexpected EXP", -1); return(AUTH_FAILURE); } /* Wait until now to send B, since it contains the key to "u" */ SendSRPAuthSB(SRP_CHALLENGE, B->data, B->length); cstr_free(B); B = NULL; /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); SRP_add_ex_data(s_srp, type_check, 26); } else #endif /* CK_SSL */ SRP_add_ex_data(s_srp, type_check, 2); } if(SRP_compute_key(s_srp, &s_key, data, cnt) != SRP_SUCCESS) { printf("Security alert: Trivial session key attempted\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Trivial session key detected", -1); return(AUTH_FAILURE); } srp_waitresp = 1; return AUTH_SUCCESS; case SRP_RESPONSE: /* Got the response; see if it's correct */ if (!srp_waitresp || s_srp == NULL) { if (1) printf("Protocol error: SRP_RESPONSE unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: unexpected RESPONSE", -1 ); return(AUTH_FAILURE); } srp_waitresp = 0; /* we got a response */ if (cnt < RESPONSE_LEN) { if (1) printf("Protocol error: malformed response\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: malformed response", -1 ); return(AUTH_FAILURE); } if(SRP_verify(s_srp, data, cnt) == SRP_SUCCESS) { resp = cstr_new(); if(SRP_respond(s_srp, &resp) != SRP_SUCCESS) { printf("Error computing response\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Error computing response", -1); return(AUTH_FAILURE); } SendSRPAuthSB(SRP_ACCEPT, resp->data, resp->length); accept_complete = 1; cstr_free(resp); #ifdef CK_ENCRYPTION #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ { skey.type = SK_GENERIC; skey.length = s_key->length; skey.data = s_key->data; encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT); cstr_clear_free(s_key); s_key = NULL; } #endif /* CK_ENCRYPTION */ auth_finished(AUTH_VALID); } else { SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } return AUTH_SUCCESS; default: printf("Unknown SRP option %d\r\n", data[-1]); SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1); return(AUTH_FAILURE); } } #endif /* PRE_SRP_1_7_3 */ #endif /* SRP */ #ifdef KRB5 #ifdef KINIT /* * clients/kinit/kinit.c * * Copyright 1990 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * * Initialize a credentials cache. */ #define KRB5_DEFAULT_OPTIONS 0 #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ static krb5_data tgtname = { #ifndef HEIMDAL 0, #endif /* HEIMDAL */ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; /* Internal prototypes */ _PROTOTYP(static krb5_error_code krb5_validate_tgt, (krb5_context, krb5_ccache,krb5_principal, krb5_data *)); _PROTOTYP(static krb5_error_code krb5_renew_tgt, (krb5_context, krb5_ccache, krb5_principal, krb5_data *)); _PROTOTYP(static krb5_error_code krb5_tgt_gen, (krb5_context, krb5_ccache, krb5_principal, krb5_data *, int opt)); #ifdef KRB5_HAVE_GET_INIT_CREDS static krb5_error_code KRB5_CALLCONV ck_krb5_prompter( krb5_context context, void *data, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]) { krb5_error_code errcode = 0; int i; #ifdef KUI struct txtbox * tb = NULL; #else /* KUI */ char * prompt = NULL; #endif /* KUI */ int len = 0, blen=0, nlen=0; debug(F110,"ck_krb5_prompter name",name,0); debug(F110,"ck_krb5_prompter banner",banner,0); debug(F101,"ck_krb5_prompter num_prompts","",num_prompts); if (name) nlen = strlen(name)+2; if (banner) blen = strlen(banner)+2; #ifdef KUI tb = (struct txtbox *) malloc(sizeof(struct txtbox) * num_prompts); if ( tb != NULL ) { int ok; memset(tb,0,sizeof(struct txtbox) * num_prompts); for ( i=0; i < num_prompts; i++ ) { tb[i].t_buf = prompts[i].reply->data; tb[i].t_len = prompts[i].reply->length; tb[i].t_lbl = prompts[i].prompt; tb[i].t_dflt = NULL; tb[i].t_echo = (prompts[i].hidden ? 2 : 1); } ok = uq_mtxt((char *)banner,NULL,num_prompts,tb); if ( ok ) { for ( i=0; i < num_prompts; i++ ) prompts[i].reply->length = strlen(prompts[i].reply->data); } else errcode = -2; } #else /* KUI */ for (i = 0; i < num_prompts; i++) { debug(F111,"ck_krb5_prompter prompt",prompts[i].prompt,i); if ( prompt && len < (nlen + blen + strlen(prompts[i].prompt)+2) ) { free(prompt); prompt = NULL; } if ( !prompt ) prompt = (char *)malloc(nlen + blen + strlen(prompts[i].prompt)+2); if ( !prompt ) { errcode = KRB5_RC_MALLOC; goto cleanup; } len = nlen + blen + strlen(prompts[i].prompt)+2; ckmakxmsg(prompt,len, (char *) (name?name:""), name?"\r\n":"", (char *) (banner?banner:""), banner?"\r\n":"", (char *)prompts[i].prompt, ": ",NULL,NULL,NULL,NULL,NULL,NULL); memset(prompts[i].reply->data, 0, prompts[i].reply->length); if (prompts[i].hidden) { readpass(prompt, prompts[i].reply->data, prompts[i].reply->length); } else { readtext(prompt, prompts[i].reply->data, prompts[i].reply->length); } prompts[i].reply->length = strlen(prompts[i].reply->data); } #endif /* KUI */ cleanup: #ifdef KUI if ( tb ) free(tb); #else /* KUI */ if ( prompt ) free(prompt); #endif /* KUI */ if (errcode) { for (i = 0; i < num_prompts; i++) { memset(prompts[i].reply->data, 0, prompts[i].reply->length); } } return errcode; } /* * I'm not really sure what to do with this. The NRL DLLs use a * different interface for the krb5_prompter callback. It has * one less parameter. This is going to be ugly. */ static krb5_error_code KRB5_CALLCONV ck_NRL_krb5_prompter( krb5_context context, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]) { return(ck_krb5_prompter(context,NULL,name,banner,num_prompts,prompts)); } #endif /* KRB5_HAVE_GET_INIT_CREDS */ #ifdef KRB524_CONV long try_convert524(krb5_context ctx, krb5_principal me, krb5_ccache cc) { char * progname = "convert524"; krb5_error_code code = 0; int icode = 0; krb5_principal kpcserver = 0; krb5_creds *v5creds = 0; krb5_creds increds; #ifdef OS2 LEASH_CREDENTIALS v4creds; #else /* OS2 */ CREDENTIALS v4creds; #endif /* OS2 */ memset((char *) &increds, 0, sizeof(increds)); /* From this point on, we can goto cleanup because increds is initialized. */ if ((code = krb5_build_principal(ctx, &kpcserver, krb5_princ_realm(ctx, me)->length, krb5_princ_realm(ctx, me)->data, "krbtgt", krb5_princ_realm(ctx, me)->data, NULL))) { com_err(progname, code, "while creating service principal name"); goto cleanup; } memset((char*) &increds, 0, sizeof(increds)); increds.client = me; increds.server = kpcserver; /* Prevent duplicate free calls. */ kpcserver = 0; increds.times.endtime = 0; increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; if ((code = krb5_get_credentials(ctx, 0, cc, &increds, &v5creds))) { com_err(progname, code, "getting V5 credentials"); goto cleanup; } if ((icode = krb524_convert_creds_kdc(ctx, v5creds, &v4creds))) { com_err(progname, icode, "converting to V4 credentials"); goto cleanup; } /* this is stolen from the v4 kinit */ /* initialize ticket cache */ if ((icode = krb_in_tkt(v4creds.pname, v4creds.pinst, v4creds.realm) != KSUCCESS)) { com_err(progname, icode, "trying to create the V4 ticket file"); goto cleanup; } /* stash ticket, session key, etc. for future use */ if ((icode = krb_save_credentials(v4creds.service, v4creds.instance, v4creds.realm, v4creds.session, v4creds.lifetime, v4creds.kvno, &(v4creds.ticket_st), v4creds.issue_date))) { com_err(progname, icode, "trying to save the V4 ticket"); goto cleanup; } cleanup: memset(&v4creds, 0, sizeof(v4creds)); if (v5creds) krb5_free_creds(ctx, v5creds); increds.client = 0; krb5_free_cred_contents(ctx, &increds); if (kpcserver) krb5_free_principal(ctx, kpcserver); return !(code || icode); } #endif /* KRB524_CONV */ #define NO_KEYTAB int #ifdef CK_ANSIC ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init, struct krb4_init_data * k4_init) #else ck_krb5_initTGT(op,init,k4_init) krb_op_data * op; struct krb5_init_data * init; struct krb4_init_data * k4_init; #endif /* CK_ANSIC*/ { krb5_context kcontext; krb5_ccache ccache = NULL; krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */ krb5_timestamp starttime = 0; krb5_deltat rlife = 0; int options = KRB5_DEFAULT_OPTIONS; int option; int errflg = 0; krb5_error_code code; krb5_principal me=NULL; krb5_principal server=NULL; krb5_creds my_creds; krb5_timestamp now; #ifndef HEIMDAL krb5_address **addrs = (krb5_address **)0; #endif /* HEIMDAL */ int addr_count=0; int i,j; #ifndef NO_KEYTAB int use_keytab = 0; /* -k option */ krb5_keytab keytab = NULL; #endif /* NO_KEYTAB */ struct passwd *pw = 0; int pwsize; char *client_name=NULL, principal[256]="", realm[256]="", numstr[40]=""; char *password=NULL, passwd[80]=""; #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt opts; #endif char * name; int len; if ( !ck_krb5_is_installed() ) return(-1); #ifdef COMMENT printf("Kerberos V initialization\r\n"); #endif /* COMMENT */ code = krb5_init_context(&kcontext); if (code) { com_err("krb5_kinit",code,"while init_context"); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } debug(F110,"krb5_init","krb5_init_context",0); if ((code = krb5_timeofday(kcontext, &now))) { com_err("krb5_kinit",code,"while getting time of day"); goto exit_k5_init; } #ifdef KRB5_HAVE_GET_INIT_CREDS memset(&opts, 0, sizeof(opts)); krb5_get_init_creds_opt_init(&opts); debug(F110,"krb5_init","krb5_get_init_creds_opt_init",0); #endif if ( init->renewable ) { options |= KDC_OPT_RENEWABLE; ckmakmsg(numstr,sizeof(numstr),ckitoa(init->renewable),"m",NULL,NULL); #ifdef HEIMDAL code = -1; #else /* HEIMDAL */ code = krb5_string_to_deltat(numstr, &rlife); #endif /* HEIMDAL */ if (code != 0 || rlife == 0) { printf("Bad renewable time value %s\r\n", numstr); errflg++; } #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_renew_life(&opts, rlife); #endif } if ( init->renew ) { /* renew the ticket */ options |= KDC_OPT_RENEW; } if ( init->validate ) { /* validate the ticket */ options |= KDC_OPT_VALIDATE; } if ( init->proxiable ) { options |= KDC_OPT_PROXIABLE; #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_proxiable(&opts, 1); #endif } if ( init->forwardable ) { options |= KDC_OPT_FORWARDABLE; #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_forwardable(&opts, 1); #endif } #ifndef NO_KEYTAB if ( ) { use_keytab = 1; } if ( ) { if (keytab == NULL && keytab_name != NULL) { code = krb5_kt_resolve(kcontext, keytab_name, &keytab); if (code != 0) { debug(F111,"krb5_init resolving keytab", keytab_name,code); errflg++; } } } #endif /* NO_KEYTAB */ if ( init->lifetime ) { ckmakmsg(numstr,sizeof(numstr),ckitoa(init->lifetime),"m",NULL,NULL); #ifdef HEIMDAL code = -1; #else /* HEIMDAL */ code = krb5_string_to_deltat(numstr, &lifetime); #endif /* HEIMDAL */ if (code != 0 || lifetime == 0) { printf("Bad lifetime value %s\r\n", numstr); errflg++; } #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime); #endif } if ( init->postdate ) { /* Convert cmdate() to a time_t value */ struct tm * time_tm; struct tm * cmdate2tm(char *,int); time_tm = cmdate2tm(init->postdate,0); if ( time_tm ) starttime = (krb5_timestamp) mktime(time_tm); if (code != 0 || starttime == 0 || starttime == -1) { krb5_deltat ktmp; #ifdef HEIMDAL code = -1; #else /* HEIMDAL */ code = krb5_string_to_deltat(init->postdate, &ktmp); #endif /* HEIMDAL */ if (code == 0 && ktmp != 0) { starttime = now + ktmp; options |= KDC_OPT_POSTDATED; } else { printf("Bad postdate start time value %s\r\n", init->postdate); errflg++; } } else { options |= KDC_OPT_POSTDATED; } } debug(F110,"krb5_init searching for ccache",op->cache,0); code = k5_get_ccache(kcontext,&ccache,op->cache); if (code != 0) { com_err("krb5_kinit",code,"while getting default ccache"); goto exit_k5_init; } /* This is our realm unless it is changed */ ckstrncpy(realm,init->realm ? init->realm : krb5_d_realm, 256); #ifdef BETATEST /* This code is going to take the realm and attempt to correct */ /* the case. */ { profile_t profile; code = krb5_get_profile(kcontext, &profile); if ( !code ) { const char *names[4]; char ** realms; int found = 0; names[0] = "realms"; names[1] = NULL; code = profile_get_subsection_names(profile,names,&realms); if ( code == 0 ) { int i=0; while ( realms[i] ) { if (ckstrcmp(realm,realms[i],-1,0) == 0) { strcpy(realm,realms[i]); found = 1; break; } i++; } } #ifdef CK_DNS_SRV if ( !found ) { char * dns_realm = NULL; /* We did not find the realm in the profile so let's try DNS */ locate_txt_rr("_kerberos",realm,&dns_realm); if ( dns_realm && ckstrcmp(realm,dns_realm,-1,0) == 0 && ckstrcmp(realm,dns_realm,-1,1) != 0 ) { ckstrncpy(realm,dns_realm,256); free(dns_realm); } } #endif /* CK_DNS_SRV */ } if (init->realm && ckstrcmp(realm,init->realm,-1,0) == 0 && ckstrcmp(realm,init->realm,-1,1) != 0) strcpy(init->realm,realm); if (ckstrcmp(realm,krb5_d_realm,-1,0) == 0 && ckstrcmp(realm,krb5_d_realm,-1,1) != 0) strcpy(krb5_d_realm,realm); } #endif /* BETATEST */ if (init->principal == NULL) { /* No principal name specified */ #ifndef NO_KEYTAB if (use_keytab) { /* Use the default host/service name */ code = krb5_sname_to_principal(kcontext, NULL, NULL, KRB5_NT_SRV_HST, &me); if (code == 0 && krb5_princ_realm(kcontext, me)->length < sizeof(realm)) { /* Save the realm */ memcpy(realm,krb5_princ_realm(kcontext, me)->data, krb5_princ_realm(kcontext, me)->length); /* safe */ realm[krb5_princ_realm(kcontext, me)->length]='\0'; } else { com_err("krb5_kinit", code, "when creating default server principal name"); goto exit_k5_init; } } else #endif /* NO_KEYTAB */ { int len; char * name; /* Get default principal from cache if one exists */ code = krb5_cc_get_principal(kcontext, ccache, &me); #ifdef HEIMDAL name = me->realm; len = strlen(name); #else /* HEIMDAL */ len = krb5_princ_realm(kcontext, me)->length; name = krb5_princ_realm(kcontext, me)->data; #endif /* HEIMDAL */ if (code == 0 && len < sizeof(realm)) { /* Save the realm */ memcpy(realm,name,len); /* safe */ realm[len]='\0'; } else { #ifdef HAVE_PWD_H /* Else search passwd file for client */ pw = getpwuid((int) getuid()); if (pw) { char princ_realm[256]; if ( (strlen(pw->pw_name) + strlen(realm) + 1) > 255 ) goto exit_k5_init; ckstrncpy(principal,pw->pw_name,256); ckstrncpy(princ_realm,pw->pw_name,256); ckstrncat(princ_realm,"@",256); ckstrncat(princ_realm,realm,256); if ((code = krb5_parse_name(kcontext,princ_realm,&me))) { krb5_errno = code; com_err("krb5_kinit",code,"when parsing name", princ_realm); goto exit_k5_init; } } else { printf( "Unable to identify user from password file\r\n"); goto exit_k5_init; } #else /* HAVE_PWD_H */ printf("Unable to identify user\r\n"); goto exit_k5_init; #endif /* HAVE_PWD_H */ } } #ifdef HEIMDAL len = me->name.name_string.len; name = *me->name.name_string.val; #else /* HEIMDAL */ len = krb5_princ_name(kcontext, me)->length; name = krb5_princ_name(kcontext, me)->data; #endif /* HEIMDAL */ if ( len < sizeof(principal) ) { memcpy(principal,name,len); /* safe */ principal[len]='\0'; } } /* Use specified name */ else { char princ_realm[256]; if ( (strlen(init->principal) + (init->instance ? strlen(init->instance)+1 : 0) + strlen(realm) + 2) > 255 ) goto exit_k5_init; ckstrncpy(principal,init->principal,256); ckstrncpy(princ_realm,init->principal,256); if (init->instance) { ckstrncat(princ_realm,"/",256); ckstrncat(princ_realm,init->instance,256); } if (realm[0]) { ckstrncat(princ_realm,"@",256); ckstrncat(princ_realm,realm,256); } if ((code = krb5_parse_name (kcontext, princ_realm, &me))) { com_err("krb5_kinit",code,"when parsing name",princ_realm); goto exit_k5_init; } } if ((code = krb5_unparse_name(kcontext, me, &client_name))) { com_err("krb5_kinit",code,"when unparsing name"); goto exit_k5_init; } debug(F110,"krb5_init client_name",client_name,0); memset((char *)&my_creds, 0, sizeof(my_creds)); my_creds.client = me; if (init->service == NULL) { if ((code = krb5_build_principal_ext(kcontext, &server, strlen(realm),realm, tgtname.length, tgtname.data, strlen(realm),realm, 0))) { com_err("krb5_kinit",code,"while building server name"); goto exit_k5_init; } } else { if (code = krb5_parse_name(kcontext, init->service, &server)) { com_err("krb5_kinit",code,"while parsing service name", init->service); goto exit_k5_init; } } my_creds.server = server; if (options & KDC_OPT_POSTDATED) { my_creds.times.starttime = starttime; my_creds.times.endtime = starttime + lifetime; } else { my_creds.times.starttime = 0; /* start timer when request gets to KDC */ my_creds.times.endtime = now + lifetime; } if (options & KDC_OPT_RENEWABLE) { my_creds.times.renew_till = now + rlife; } else my_creds.times.renew_till = 0; if (options & KDC_OPT_VALIDATE) { krb5_data outbuf; #ifdef KRB5_HAVE_GET_INIT_CREDS code = krb5_get_validated_creds(kcontext, &my_creds, me, ccache, init->service); if ( code == -1 ) #endif { #ifdef HEIMDAL printf("?validate not implemented\r\n"); code = -1; goto exit_k5_init; #else /* HEIMDAL */ code = krb5_validate_tgt(kcontext, ccache, server, &outbuf); #endif /* HEIMDAL */ } if (code) { com_err("krb5_kinit",code,"validating tgt"); goto exit_k5_init; } /* should be done... */ goto exit_k5_init; } if (options & KDC_OPT_RENEW) { krb5_data outbuf; #ifdef KRB5_HAVE_GET_INIT_CREDS code = krb5_get_renewed_creds(kcontext, &my_creds, me, ccache, init->service); if ( code == -1 ) #endif { #ifdef HEIMDAL printf("?renew not implemented\r\n"); code = -1; goto exit_k5_init; #else /* HEIMDAL */ code = krb5_renew_tgt(kcontext, ccache, server, &outbuf); #endif /* HEIMDAL */ } if (code) { com_err("krb5_kinit",code,"while renewing tgt"); goto exit_k5_init; } /* should be done... */ goto store_cred; } #ifndef HEIMDAL if ( init->addrs && !init->no_addresses ) { /* construct an array of krb5_address structs to pass to get_in_tkt */ /* include both the local ip addresses as well as any other that */ /* are specified. */ unsigned long ipaddr; for ( addr_count=0;addr_countaddrs[addr_count] == NULL ) break; if (addr_count > 0) { krb5_address ** local_addrs=NULL; krb5_os_localaddr(kcontext, &local_addrs); i = 0; while ( local_addrs[i] ) i++; addr_count += i; addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); if ( !addrs ) { krb5_free_addresses(kcontext, local_addrs); goto exit_k5_init; } memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); i = 0; while ( local_addrs[i] ) { addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); if (addrs[i] == NULL) { krb5_free_addresses(kcontext, local_addrs); goto exit_k5_init; } addrs[i]->magic = local_addrs[i]->magic; addrs[i]->addrtype = local_addrs[i]->addrtype; addrs[i]->length = local_addrs[i]->length; addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); if (!addrs[i]->contents) { krb5_free_addresses(kcontext, local_addrs); goto exit_k5_init; } memcpy(addrs[i]->contents,local_addrs[i]->contents, local_addrs[i]->length); /* safe */ i++; } krb5_free_addresses(kcontext, local_addrs); for ( j=0;imagic = KV5M_ADDRESS; addrs[i]->addrtype = AF_INET; addrs[i]->length = 4; addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); if (!addrs[i]->contents) goto exit_k5_init; ipaddr = inet_addr(init->addrs[j]); memcpy(addrs[i]->contents,&ipaddr,4); /* safe */ } #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_address_list(&opts,addrs); #endif } } #endif /* !HEIMDAL */ #ifdef KRB5_HAVE_GET_INIT_CREDS if ( init->no_addresses ) krb5_get_init_creds_opt_set_address_list(&opts,NULL); #endif #ifndef NO_KEYTAB if (!use_keytab) #endif { if ( init->password ) { pwsize = strlen(init->password); if ( pwsize ) password = init->password; } else if (init->getk4 && k4_init) { /* When we are requesting that K4 tickets be automatically */ /* acquired when K5 tickets are acquired, we must get the */ /* password up front. */ char prmpt[256]; extern char * k5prprompt; extern char * k5pwprompt; int ok = 0; if ( k5pwprompt && k5pwprompt[0] && (strlen(k5pwprompt) + strlen(principal) + strlen(realm) - 4) < sizeof(prmpt)) { sprintf(prmpt,k5pwprompt,principal,realm); } else ckmakxmsg(prmpt,sizeof(prmpt), k5pwprompt && k5pwprompt[0] ? k5pwprompt : "Kerberos 5 Password for ", principal,"@",realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; if ( k4_init->password == NULL ) makestr(&k4_init->password,passwd); } #ifdef KRB5_HAVE_GET_INIT_CREDS debug(F100,"krb5_init calling krb5_get_init_creds_password()","",0); #ifdef OS2 if ( is_NRL_KRB5() ) code = krb5_get_init_creds_password(kcontext, &my_creds, me, password, (void *)ck_NRL_krb5_prompter, NULL, starttime, init->service, &opts); else #endif /* OS2 */ code = krb5_get_init_creds_password(kcontext, &my_creds, me, password, ck_krb5_prompter, NULL, starttime, init->service, &opts); debug(F111,"krb5_init","krb5_get_init_creds_password()",code); if ( code == -1 ) { if (!password) { char prmpt[256]; int ok; ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ", client_name,": ",NULL); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL, DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; else { code = -2; goto exit_k5_init; } } if ( !password ) password = ""; code = krb5_get_in_tkt_with_password(kcontext, options, #ifdef HEIMDAL NULL, #else /* HEIMDAL */ init->no_addresses ? NULL :addrs, #endif /* HEIMDAL */ NULL, NULL, password, NULL, &my_creds, NULL); if ( code ) debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code); } #else /* KRB5_HAVE_GET_INIT_CREDS */ if (!password) { char prmpt[256]; int ok; ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ", client_name,": ",NULL); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; else { code = -2; goto exit_k5_init; } } if ( !password ) password = ""; code = krb5_get_in_tkt_with_password(kcontext, options, #ifdef HEIMDAL NULL, #else /* HEIMDAL */ init->no_addresses ? NULL :addrs, #endif /* HEIMDAL */ NULL, NULL, password, NULL, &my_creds, NULL); if ( code ) debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code); #endif /* KRB5_HAVE_GET_INIT_CREDS */ if ( init->password && pwsize > 0 ) memset(init->password, 0, pwsize); memset(passwd,0,80); } #ifndef NO_KEYTAB else { #ifdef KRB5_HAVE_GET_INIT_CREDS code = krb5_get_init_creds_keytab(kcontext, &my_creds, me, keytab, starttime, init->service, &opts); #ifdef OS2 if ( code == -1) code = krb5_get_in_tkt_with_keytab(kcontext, options, init->no_addresses ? NULL :addrs, NULL, NULL, keytab, NULL, &my_creds, 0); #endif /* OS2 */ #else /* KRB5_HAVE_GET_INIT_CREDS */ code = krb5_get_in_tkt_with_keytab(kcontext, options, #ifdef HEIMDAL NULL, #else /* HEIMDAL */ init->no_addresses ? NULL :addrs, #endif /* HEIMDAL */ NULL, NULL, keytab, NULL, &my_creds, 0); #endif /* KRB5_HAVE_GET_INIT_CREDS */ } #endif if (code) { switch (code) { case KRB5KRB_AP_ERR_BAD_INTEGRITY: printf("Password incorrect\r\n"); goto exit_k5_init; case KRB5KRB_AP_ERR_V4_REPLY: if (init->getk4 && k4_init) { printf("Kerberos 5 Tickets not support by server. "); printf("A version 4 Ticket will be requested.\r\n"); } goto exit_k5_init; default: goto exit_k5_init; } } store_cred: debug(F100,"krb5_init calling krb5_cc_initialize()","",0); code = krb5_cc_initialize (kcontext, ccache, me); if ( code == KRB5_CC_BADNAME ) { /* This is a really ugly hack that should not have to be here. * krb5_cc_initialize should not fail with an error if the * cache already exists. The reason the problem is occuring * is that the krb5 library is no longer calling cc_destroy() * when cc_initialize() is called and the CCAPI implementation * on Windows has not yet been corrected to handle it. To * ensure that K95 will continue to work with both we will call * cc_destroy() if the cc_initialize() call fails with a BADNAME * error. If the cc_destroy() is successful, we will try again. */ debug(F100,"krb5_init calling krb5_cc_destroy()","",0); code = krb5_cc_destroy (kcontext, ccache); if ( !code ) { debug(F100,"krb5_init calling k5_get_ccache()","",0); code = k5_get_ccache(kcontext,&ccache,op->cache); debug(F100,"krb5_init calling krb5_cc_initialize()","",0); code = krb5_cc_initialize (kcontext, ccache, me); } else code = KRB5_CC_BADNAME; } if (code) { com_err("krb5_kinit",code,"when initializing cache",op->cache); goto exit_k5_init; } debug(F100,"krb5_init calling krb5_cc_store_cred()","",0); code = krb5_cc_store_cred(kcontext, ccache, &my_creds); if (code) { com_err("krb5_kinit",code,"while storing credentials"); goto exit_k5_init; } if ( init->getk4 && #ifdef KRB524_CONV !try_convert524(kcontext,me,ccache) && #endif /* KRB524_CONV */ k4_init ) { int k4rc = ck_krb4_initTGT(op,k4_init); if (k4rc < 0) code = -3; } exit_k5_init: debug(F100,"krb5_init exit_k5_init","",0); #ifndef HEIMDAL /* Free krb5_address structures if we created them */ if ( addrs ) { for ( i=0;icontents ) free(addrs[i]->contents); free(addrs[i]); } } } #endif /* HEIMDAL */ krb5_errno = code; makestr(&krb5_errmsg,krb5_errno ? error_message(krb5_errno) : "OK"); if (client_name) krb5_free_unparsed_name(kcontext, client_name); /* my_creds is pointing at server */ debug(F100,"krb5_init calling krb5_free_principal()","",0); krb5_free_principal(kcontext, server); debug(F100,"krb5_init calling krb5_cc_close()","",0); krb5_cc_close(kcontext,ccache); debug(F100,"krb5_init calling krb5_free_context()","",0); krb5_free_context(kcontext); if (code != -2) printf("Result from realm %s: %s\r\n",realm, code==-3?"Unable to retrieve Kerberos IV credentials": code?error_message(code):"OK"); return(code?-1:0); } #ifndef HEIMDAL #define VALIDATE 0 #define RENEW 1 /* stripped down version of krb5_mk_req */ static krb5_error_code #ifdef CK_ANSIC krb5_validate_tgt( krb5_context context, krb5_ccache ccache, krb5_principal server, /* tgtname */ krb5_data *outbuf ) #else krb5_validate_tgt(context, ccache, server, outbuf) krb5_context context; krb5_ccache ccache; krb5_principal server; /* tgtname */ krb5_data *outbuf; #endif { return krb5_tgt_gen(context, ccache, server, outbuf, VALIDATE); } /* stripped down version of krb5_mk_req */ static krb5_error_code #ifdef CK_ANSIC krb5_renew_tgt(krb5_context context, krb5_ccache ccache, krb5_principal server, /* tgtname */ krb5_data *outbuf) #else krb5_renew_tgt(context, ccache, server, outbuf) krb5_context context; krb5_ccache ccache; krb5_principal server; /* tgtname */ krb5_data *outbuf; #endif { return krb5_tgt_gen(context, ccache, server, outbuf, RENEW); } /* stripped down version of krb5_mk_req */ static krb5_error_code #ifdef CK_ANSIC krb5_tgt_gen(krb5_context context, krb5_ccache ccache, krb5_principal server, /* tgtname */ krb5_data *outbuf, int opt) #else krb5_tgt_gen(context, ccache, server, outbuf, opt) krb5_context context; krb5_ccache ccache; krb5_principal server; /* tgtname */ krb5_data *outbuf; int opt; #endif { krb5_error_code retval; krb5_creds * credsp; krb5_creds creds; /* obtain ticket & session key */ memset((char *)&creds, 0, sizeof(creds)); if ((retval = krb5_copy_principal(context, server, &creds.server))) goto cleanup; if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) goto cleanup_creds; if (opt == VALIDATE) { if ((retval = krb5_get_credentials_validate(context, 0, ccache, &creds, &credsp))) goto cleanup_creds; } else { if ((retval = krb5_get_credentials_renew(context, 0, ccache, &creds, &credsp))) goto cleanup_creds; } /* we don't actually need to do the mk_req, just get the creds. */ cleanup_creds: krb5_free_cred_contents(context, &creds); cleanup: return retval; } #endif /* HEIMDAL */ #endif /* KINIT */ #ifdef KDESTROY int #ifdef CK_ANSIC ck_krb5_destroy(struct krb_op_data * op) #else ck_krb5_destroy(op) struct krb_op_data * op; #endif { krb5_context kcontext; krb5_error_code retval; int c; krb5_ccache ccache = NULL; char *cache_name = NULL; int code; int errflg=0; int quiet = 0; if ( !ck_krb5_is_installed() ) return(-1); code = krb5_init_context(&kcontext); if (code) { debug(F101,"ck_krb5_destroy while initializing krb5","",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } code = k5_get_ccache(kcontext,&ccache,op->cache); if (code != 0) { debug(F101,"ck_krb5_destroy while getting ccache", "",code); krb5_free_context(kcontext); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } code = krb5_cc_destroy (kcontext, ccache); if (code != 0) { debug(F101,"ck_krb5_destroy while destroying cache","",code); if ( code == KRB5_FCC_NOFILE ) printf("No ticket cache to destroy.\r\n"); else printf("Ticket cache NOT destroyed!\r\n"); krb5_cc_close(kcontext,ccache); krb5_free_context(kcontext); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } printf("Tickets destroyed.\r\n"); /* Do not call krb5_cc_close() because cache has been destroyed */ krb5_free_context(kcontext); krb5_errno = 0; makestr(&krb5_errmsg,"OK"); return (0); } #else /* KDESTROY */ #ifdef KRB5 int #ifdef CK_ANSIC ck_krb5_destroy(struct krb_op_data * op) #else ck_krb5_destroy(op) struct krb_op_data * op; #endif { printf("?Not implemented.\r\n"); return(-1); } #endif /* KRB5 */ #endif /* KDESTROY */ #ifndef KLIST #ifdef KRB5 int #ifdef CK_ANSIC ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc) #else ck_krb5_list_creds(op,lc) struct krb_op_data * op; struct krb5_list_cred_data * lc; #endif { printf("?Not implemented.\r\n"); return(-1); } #endif /* KRB5 */ #else /* KLIST */ static int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0; static int show_etype = 0, show_addr = 0; static char *defname; static char *progname; static krb5_int32 now; static int timestamp_width; _PROTOTYP(static char * etype_string, (krb5_enctype )); _PROTOTYP(static void show_credential,(krb5_context,krb5_creds *)); _PROTOTYP(static int do_ccache, (krb5_context,char *)); _PROTOTYP(static int do_keytab, (krb5_context,char *)); _PROTOTYP(static void printtime, (time_t)); _PROTOTYP(static void fillit, (int, int)); #define DEFAULT 0 #define CCACHE 1 #define KEYTAB 2 int #ifdef CK_ANSIC ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc) #else ck_krb5_list_creds(op,lc) struct krb_op_data * op; struct krb5_list_cred_data * lc; #endif { krb5_context kcontext; krb5_error_code retval; int code; char *name = op->cache; int mode; if ( !ck_krb5_is_installed() ) return(-1); code = krb5_init_context(&kcontext); if (code) { debug(F101,"ck_krb5_list_creds while initializing krb5","",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } name = op->cache; mode = DEFAULT; show_flags = 0; show_time = 0; status_only = 0; show_keys = 0; show_etype = 0; show_addr = 0; show_flags = lc->flags; show_etype = lc->encryption; show_addr = lc->addr; show_time = 1; show_keys = 1; mode = CCACHE; if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_list_creds while getting time of day.", "",code); krb5_free_context(kcontext); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } else { char tmp[BUFSIZ]; if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) || !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), (char *) NULL)) timestamp_width = (int) strlen(tmp); else timestamp_width = 15; } if (mode == DEFAULT || mode == CCACHE) retval = do_ccache(kcontext,name); else retval = do_keytab(kcontext,name); krb5_free_context(kcontext); return(retval); } static int #ifdef CK_ANSIC do_keytab(krb5_context kcontext, char * name) #else do_keytab(kcontext,name) krb5_context kcontext; char * name; #endif { krb5_keytab kt; krb5_keytab_entry entry; krb5_kt_cursor cursor; char buf[BUFSIZ]; /* hopefully large enough for any type */ char *pname; int code = 0; if (name == NULL) { if ((code = krb5_kt_default(kcontext, &kt))) { debug(F101,"ck_krb5_list_creds while getting default keytab", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } } else { if ((code = krb5_kt_resolve(kcontext, name, &kt))) { debug(F111,"ck_krb5_list_creds while resolving keytab", name,code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } } if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) { debug(F101,"ck_krb5_list_creds while getting keytab name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } printf("Keytab name: %s\r\n", buf); if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) { debug(F101,"ck_krb5_list_creds while starting keytab scan", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } if (show_time) { printf("KVNO Timestamp"); fillit(timestamp_width - sizeof("Timestamp") + 2, (int) ' '); printf("Principal\r\n"); printf("---- "); fillit(timestamp_width, (int) '-'); printf(" "); fillit(78 - timestamp_width - sizeof("KVNO"), (int) '-'); printf("\r\n"); } else { printf("KVNO Principal\r\n"); printf( "---- --------------------------------------------------------------------\ ------\r\n"); } while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) { if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) { debug(F101,"ck_krb5_list_creds while unparsing principal name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } printf("%4d ", entry.vno); if (show_time) { printtime(entry.timestamp); printf(" "); } printf("%s", pname); if (show_etype) printf(" (%s) " , #ifdef HEIMDAL etype_string(entry.key.keytype) #else /* HEIMDAL */ etype_string(entry.key.enctype) #endif /* HEIMDAL */ ); if (show_keys) { printf(" (0x"); { int i; for (i = 0; i < entry.key.length; i++) printf("%02x", #ifdef HEIMDAL entry.key.keyvalue[i] #else /* HEIMDAL */ entry.key.contents[i] #endif /* HEIMDAL */ ); } printf(")"); } printf("\r\n"); krb5_free_unparsed_name(kcontext,pname); } if (code && code != KRB5_KT_END) { debug(F101,"ck_krb5_list_creds while scanning keytab", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) { debug(F101,"ck_krb5_list_creds while ending keytab scan", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); return(0); } static int #ifdef CK_ANSIC do_ccache(krb5_context kcontext, char * cc_name) #else do_ccache(kcontext,name) krb5_context kcontext; char * cc_name; #endif { krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code = 0; int exit_status = 0; if (status_only) /* exit_status is set back to 0 if a valid tgt is found */ exit_status = 1; code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"do_ccache while getting ccache", error_message(code),code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_list_creds (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_list_creds while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } printf("No ticket File.\r\n"); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_list_creds while retrieving principal name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_list_creds while unparsing principal name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } if (!status_only) { printf("Ticket cache: %s:%s\r\nDefault principal: %s\r\n\r\n", krb5_cc_get_type(kcontext, cache), krb5_cc_get_name(kcontext, cache), defname); printf("Valid starting"); fillit(timestamp_width - sizeof("Valid starting") + 3, (int) ' '); printf("Expires"); fillit(timestamp_width - sizeof("Expires") + 3, (int) ' '); printf("Service principal\r\n"); } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while starting to retrieve tickets", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { if (status_only) { if (exit_status && creds.server->length == 2 && strcmp(creds.server->realm.data, princ->realm.data) == 0 && strcmp((char *)creds.server->data[0].data, "krbtgt") == 0 && strcmp((char *)creds.server->data[1].data, princ->realm.data) == 0 && creds.times.endtime > now) exit_status = 0; } else { show_credential(kcontext, &creds); } krb5_free_cred_contents(kcontext, &creds); } printf("\r\n"); if (code == KRB5_CC_END || code == KRB5_CC_NOTFOUND) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while finishing ticket retrieval", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_list_creds while closing ccache", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); krb5_cc_close(kcontext,cache); return(0); } else { debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); krb5_cc_close(kcontext,cache); return(0); } static char * #ifdef CK_ANSIC #ifdef HEIMDAL etype_string(krb5_keytype enctype) #else /* HEIMDAL */ etype_string(krb5_enctype enctype) #endif /* HEIMDAL */ #else #ifdef HEIMDAL etype_string(enctype) krb5_keytype enctype; #else /* HEIMDAL */ etype_string(enctype) krb5_enctype enctype; #endif /* HEIMDAL */ #endif { static char buf[12]; switch (enctype) { case ENCTYPE_NULL: return "NULL"; case ENCTYPE_DES_CBC_CRC: return "DES-CBC-CRC"; case ENCTYPE_DES_CBC_MD4: return "DES-CBC-MD4"; case ENCTYPE_DES_CBC_MD5: return "DES-CBC-MD5"; case ENCTYPE_DES_CBC_RAW: return "DES-CBC-RAW"; case ENCTYPE_DES3_CBC_SHA: return "DES3-CBC-SHA"; case ENCTYPE_DES3_CBC_RAW: return "DES3-CBC-RAW"; case ENCTYPE_DES_HMAC_SHA1: return "DES-HMAC-SHA1"; case ENCTYPE_DES3_CBC_SHA1: return "DES3-CBC-SHA1"; case ENCTYPE_AES128_CTS_HMAC_SHA1_96: return "AES128_CTS-HMAC-SHA1_96"; case ENCTYPE_AES256_CTS_HMAC_SHA1_96: return "AES256_CTS-HMAC-SHA1_96"; case ENCTYPE_ARCFOUR_HMAC: return "RC4-HMAC-NT"; case ENCTYPE_ARCFOUR_HMAC_EXP: return "RC4-HMAC-NT-EXP"; case ENCTYPE_UNKNOWN: return "UNKNOWN"; case ENCTYPE_LOCAL_DES3_HMAC_SHA1: return "LOCAL-DES3-HMAC-SHA1"; case ENCTYPE_LOCAL_RC4_MD4: return "LOCAL-RC4-MD4"; default: ckmakmsg(buf, sizeof(buf),"etype ", ckitoa(enctype),NULL,NULL); return buf; break; } } static char * #ifdef CK_ANSIC flags_string(register krb5_creds *cred) #else flags_string(cred) register krb5_creds *cred; #endif { static char buf[32]; int i = 0; if (cred->ticket_flags & TKT_FLG_FORWARDABLE) buf[i++] = 'F'; if (cred->ticket_flags & TKT_FLG_FORWARDED) buf[i++] = 'f'; if (cred->ticket_flags & TKT_FLG_PROXIABLE) buf[i++] = 'P'; if (cred->ticket_flags & TKT_FLG_PROXY) buf[i++] = 'p'; if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE) buf[i++] = 'D'; if (cred->ticket_flags & TKT_FLG_POSTDATED) buf[i++] = 'd'; if (cred->ticket_flags & TKT_FLG_INVALID) buf[i++] = 'i'; if (cred->ticket_flags & TKT_FLG_RENEWABLE) buf[i++] = 'R'; if (cred->ticket_flags & TKT_FLG_INITIAL) buf[i++] = 'I'; if (cred->ticket_flags & TKT_FLG_HW_AUTH) buf[i++] = 'H'; if (cred->ticket_flags & TKT_FLG_PRE_AUTH) buf[i++] = 'A'; buf[i] = '\0'; return(buf); } static char * #ifdef CK_ANSIC short_date(long *dp) #else short_date(dp) long *dp; #endif { register char *cp; #ifndef ctime extern char *ctime(); #endif /* ctime */ cp = ctime(dp) + 4; cp[15] = '\0'; return (cp); } static VOID #ifdef CK_ANSIC printtime(time_t tv) #else printtime(tv) time_t tv; #endif { char timestring[BUFSIZ]; char format[12]; char fill; fill = ' '; sprintf(format,"%%-%ds",timestamp_width); /* safe */ if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv, timestring, timestamp_width+1, &fill)) { printf(format,timestring); } else { printf(format,short_date(&tv)); } } static void #ifdef CK_ANSIC one_addr(krb5_address *a) #else one_addr(a) krb5_address *a; #endif { struct hostent *h; extern tcp_rdns; if ((a->addrtype == ADDRTYPE_INET) && (a->length == 4)) { if (tcp_rdns != SET_OFF) { h = gethostbyaddr(a->contents, 4, AF_INET); if (h) { #ifdef HADDRLIST h = ck_copyhostent(h); #endif /* HADDRLIST */ printf("%s (%d.%d.%d.%d)", h->h_name, a->contents[0], a->contents[1], a->contents[2], a->contents[3]); } } if (tcp_rdns == SET_OFF || !h) { printf("%d.%d.%d.%d", a->contents[0], a->contents[1], a->contents[2], a->contents[3]); } } else { printf("unknown addr type %d", a->addrtype); } } static VOID #ifdef CK_ANSIC show_credential(krb5_context kcontext, register krb5_creds * cred) #else show_credential(kcontext, cred) krb5_context kcontext; register krb5_creds * cred; #endif { krb5_error_code retval=0; krb5_ticket *tkt=NULL; char *name=NULL, *sname=NULL, *flags=NULL; int extra_field = 0; retval = krb5_unparse_name(kcontext, cred->client, &name); if (retval) { debug(F101,"ck_krb5_list_creds while unparsing client name","",retval); krb5_errno = retval; makestr(&krb5_errmsg,error_message(krb5_errno)); return; } retval = krb5_unparse_name(kcontext, cred->server, &sname); if (retval) { debug(F101,"ck_krb5_list_creds while unparsing server name","",retval); free(name); krb5_errno = retval; makestr(&krb5_errmsg,error_message(krb5_errno)); return; } if (!cred->times.starttime) cred->times.starttime = cred->times.authtime; printtime(cred->times.starttime); printf(" "); if ( time(0) < cred->times.endtime ) printtime(cred->times.endtime); else printf("** expired ** "); printf(" %s\r\n", sname); if (strcmp(name, defname)) { printf(" for client %s", name); extra_field++; } if (cred->times.renew_till) { if (!extra_field) printf(" "); else printf(", "); printf("renew until "); printtime(cred->times.renew_till); extra_field += 2; } if (extra_field > 3) { printf("\r\n"); extra_field = 0; } if (show_flags) { flags = flags_string(cred); if (flags && *flags) { if (!extra_field) printf(" "); else printf(", "); printf("Flags: %s", flags); extra_field++; } } if (extra_field > 2) { printf("\r\n"); extra_field = 0; } if (show_etype) { retval = decode_krb5_ticket(&cred->ticket, &tkt); if (!extra_field) printf(" "); else printf(", "); #ifdef HEIMDAL printf("Etype (skey, tkt): %s, %s ", etype_string(cred->session.keytype), etype_string(tkt->enc_part.keytype)); #else /* HEIMDAL */ printf("Etype (skey, tkt): %s, %s ", etype_string(cred->keyblock.enctype), etype_string(tkt->enc_part.enctype)); #endif /* HEIMDAL */ krb5_free_ticket(kcontext, tkt); extra_field++; } /* if any additional info was printed, extra_field is non-zero */ if (extra_field) printf("\r\n"); if ( show_addr ) { if (!cred->addresses || !cred->addresses[0]) { printf("\tAddresses: (none)\r\n"); } else { int i; for (i=0; cred->addresses[i]; i++) { if (i) printf(" "); else printf(" Addresses: "); one_addr(cred->addresses[i]); printf("\r\n"); } } } krb5_free_unparsed_name(kcontext,name); krb5_free_unparsed_name(kcontext,sname); krb5_errno = 0; makestr(&krb5_errmsg,"OK"); } static VOID #ifdef CK_ANSIC fillit(int num, int c) #else fillit(num, c) int num; int c; #endif { int i; for (i=0; i= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10; return -1; } /* returns: NULL for ok, pointer to error string for bad input */ static char* #ifdef CK_ANSIC hex_scan_four_bytes(char *out, char *in) #else hex_scan_four_bytes(out, in) char *out; char *in; #endif { int i; int c; char c1; for (i=0; i<8; i++) { if(!in[i]) return "not enough input"; c = hex_scan_nybble(in[i]); if(c<0) return "invalid digit"; c1 = c; i++; if(!in[i]) return "not enough input"; c = hex_scan_nybble(in[i]); if(c<0) return "invalid digit"; *out++ = (c1 << 4) + c; } switch(in[i]) { case 0: case '\r': case '\n': return NULL; default: return "extra characters at end of input"; } } #endif /* COMMENT */ /* ck_krb4_initTGT() returns 0 on success */ int #ifdef CK_ANSIC ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init) #else ck_krb4_initTGT(op,init) struct krb_op_data * op, struct krb4_init_data * init #endif { char aname[ANAME_SZ+1]; char inst[INST_SZ+1]; char realm[REALM_SZ+1]; char *password=NULL; char passwd[80]=""; char *username = NULL; char *usernameptr=NULL; int iflag, /* Instance */ rflag, /* Realm */ vflag, /* Verbose */ lflag, /* Lifetime */ pflag, /* Preauth */ lifetime=KRB_DEFAULT_LIFE, /* Life Time */ k_errno; register char *cp; register i; if ( !ck_krb4_is_installed() ) return(-1); *inst = *realm = '\0'; iflag = rflag = vflag = lflag = pflag = 0; vflag = init->verbose; pflag = init->preauth; if ( init->lifetime ) { lifetime = init->lifetime<5?1:init->lifetime/5; if ( lifetime > 255 ) lifetime = 255; } else lifetime = KRB_DEFAULT_LIFE; username = init->principal; if (username && username[0] && (k_errno = kname_parse(aname, inst, realm, username)) != AUTH_SUCCESS) { krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); printf("%s\r\n", krb_get_err_text_entry(k_errno)); iflag = rflag = 1; username = NULL; } if ( init->realm ) { ckstrncpy(realm,init->realm,REALM_SZ); } if ( init->instance ) { ckstrncpy(inst,init->instance, INST_SZ); } #ifdef COMMENT if ( vflag ) printf("Kerberos IV initialization\r\n"); #endif /* COMMENT */ if (!username || !username[0]) { debug(F100,"ck_krb4_initTGT no username specified","",0); printf("?Invalid principal specified.\r\n"); krb4_errno = -1; makestr(&krb4_errmsg,"No principal specified"); return(-1); } if (!*realm) { ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ); } if ( init->password ) password = init->password; else { char prmpt[80]; int ok; ckmakxmsg(prmpt,sizeof(prmpt), "Kerberos 4 Password for ",username,"@",realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; } if (pflag) { k_errno = krb_get_pw_in_tkt_preauth( aname, inst, realm, "krbtgt", realm, lifetime, password); if (k_errno == -1) { /* preauth method not available */ k_errno = krb_get_pw_in_tkt(aname, inst, realm, "krbtgt", realm, lifetime, password); } } else { k_errno = krb_get_pw_in_tkt(aname, inst, realm, "krbtgt", realm, lifetime, password); } memset(passwd,0,sizeof(passwd)); if (k_errno) { printf("%s for principal %s%s%s@%s\r\n", krb_get_err_text_entry(k_errno), aname, inst[0]?".":"", inst, realm); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } else if (vflag) { printf("Result from realm %s: ", realm); printf("%s\r\n", krb_get_err_text_entry(k_errno)); } krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(0); } #endif /* KINIT */ #ifdef KDESTROY int #ifdef CK_ANSIC ck_krb4_destroy(struct krb_op_data * op) #else ck_krb4_destroy(op) struct krb_op_data * op; #endif { int k_errno=0; if ( !ck_krb4_is_installed() ) return(-1); k_errno = dest_tkt(); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); if (k_errno == 0) printf("Tickets destroyed.\r\n"); else if (k_errno == RET_TKFIL) printf("No tickets to destroy.\r\n"); else { printf("Tickets MAY NOT be destroyed.\r\n"); return(-1); } return(0); } #endif /* KDESTROY */ #ifdef KLIST _PROTOTYP(static int display_tktfile,(char *, int, int, int)); int #ifdef CK_ANSIC ck_krb4_list_creds(struct krb_op_data * op) #else ck_krb4_list_creds(op) struct krb_op_data * op; #endif { int long_form = 1; int tgt_test = 0; int do_srvtab = 0; int show_kvnos = 0; char *tkt_file = NULL; if ( !ck_krb4_is_installed() ) return(-1); if ( op->cache ) tkt_file = op->cache; if ( k4debug ) { show_kvnos = 1; } if (do_srvtab) return(display_srvtab(tkt_file)); else return(display_tktfile(tkt_file, tgt_test, long_form, show_kvnos)); } #ifndef KRB5 static int timestamp_width=0; static char * #ifdef CK_ANSIC short_date(long *dp) #else short_date(dp) long *dp; #endif { register char *cp; extern char *ctime(); cp = ctime(dp) + 4; cp[15] = '\0'; return (cp); } static VOID #ifdef CK_ANSIC printtime(time_t tv) #else printtime(tv) time_t tv; #endif { char timestring[BUFSIZ]; char format[12]; char fill; fill = ' '; sprintf(format,"%%-%ds",timestamp_width); /* safe */ printf(format,short_date(&tv)); } #endif /* KRB5 */ static int #ifdef CK_ANSIC display_tktfile(char *file, int tgt_test, int long_form, int show_kvnos) #else display_tktfile(file,tgt_test,long_form,show_kvnos) char *file; int tgt_test; int long_form; int show_kvnos; #endif { char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ int header = 1; file = tkt_string(); if (long_form) { printf("Ticket cache: %s\r\n", file); } /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { if (!tgt_test) printf("%s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* Close ticket file */ (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { if (!tgt_test) printf("can't find realm of ticket file: %s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { if (!tgt_test) printf("%s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* Get principal name and instance */ if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { (void) tf_close(); if (!tgt_test) printf("%s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ if (!tgt_test && long_form) printf("Default principal: %s%s%s%s%s\r\n\r\n", pname, (pinst[0] ? "." : ""), pinst, (prealm[0] ? "@" : ""), prealm); while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { if (!tgt_test && long_form && header) { printf("%-17s %-17s %s\r\n", "Valid starting", "Expires", "Service principal"); header = 0; } if (tgt_test) { creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60; if (!strcmp(creds.service, "krbtgt") && !strcmp(creds.instance, prealm)) { krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); (void) tf_close(); if (time(0) < creds.issue_date) { return(0); /* tgt hasn't expired */ } else { return(-1); /* has expired */ } } continue; /* not a tgt */ } if (long_form) { timestamp_width = 17; /* for k5 display function */ /* if available */ printtime(creds.issue_date); printf(" "); creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60; if ( time(0) < creds.issue_date ) printtime(creds.issue_date); else printf("*** expired *** "); printf(" "); } if (show_kvnos) printf("%s%s%s%s%s (%d)\r\n", creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, creds.kvno); else printf("%s%s%s%s%s\r\n", creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm); #ifdef OS2 if ( creds.address[0] ) printf(" Address: %s\r\n",creds.address); #endif /* OS2 */ } (void) tf_close(); if (tgt_test) { return(-1); }/* no tgt found */ if (header && long_form && k_errno == EOF) { printf("No tickets in file.\r\n"); } krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(0); } #ifdef COMMENT /* Just so we remember what the command line interface looked like */ usage() { printf( "Usage: [ -s | -t ] [ -file filename ] [ -srvtab ] [ -version ]\r\n"); return(-1); } #endif /* COMMENT */ /* adapted from getst() in librkb */ /* * ok_getst() takes a file descriptor, a string and a count. It reads * from the file until either it has read "count" characters, or until * it reads a null byte. When finished, what has been read exists in * the given string "s". If "count" characters were actually read, the * last is changed to a null, so the returned string is always null- * terminated. ok_getst() returns the number of characters read, including * the null terminator. * * If there is a read error, it returns -1 (like the read(2) system call) */ static int #ifdef CK_ANSIC ok_getst(int fd, register char *s, int n) #else ok_getst(fd, s, n) int fd; register char *s; int n; #endif { register int count = n; int err; while ((err = read(fd, s, 1)) > 0 && --count) if (*s++ == '\0') return (n - count); if (err < 0) return(-1); *s = '\0'; return (n - count); } int #ifdef CK_ANSIC display_srvtab(char *file) #else display_srvtab(file) char *file; #endif { int stab; char serv[SNAME_SZ]; char inst[INST_SZ]; char rlm[REALM_SZ]; unsigned char key[8]; unsigned char vno; int count; printf("Server key file: %s\r\n", file); #ifdef NT #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #endif /* O_RDONLY */ #endif /* NT */ if ((stab = open(file, O_RDONLY, 0400)) < 0) { perror(file); return(-1); } printf("%-15s %-15s %-10s %s\r\n","Service","Instance","Realm", "Key Version"); printf("------------------------------------------------------\r\n"); /* argh. getst doesn't return error codes, it silently fails */ while (((count = ok_getst(stab, serv, SNAME_SZ)) > 0) && ((count = ok_getst(stab, inst, INST_SZ)) > 0) && ((count = ok_getst(stab, rlm, REALM_SZ)) > 0)) { if (((count = read(stab,(char *) &vno,1)) != 1) || ((count = read(stab,(char *) key,8)) != 8)) { if (count < 0) perror("reading from key file"); else printf("key file truncated\r\n"); return(-1); } printf("%-15s %-15s %-15s %d\r\n",serv,inst,rlm,vno); } if (count < 0) perror(file); (void) close(stab); return(0); } #endif /* KLIST */ #else /* KRB4 */ int ck_krb4_autoget_TGT(char * dummy) { return(-1); } #ifdef CK_KERBEROS int #ifdef CK_ANSIC ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init) #else ck_krb4_initTGT(op,init) struct krb_op_data * op, struct krb4_init_data * init #endif { return(-1); } #ifdef CK_ANSIC ck_krb4_destroy(struct krb_op_data * op) #else ck_krb4_destroy(op) struct krb_op_data * op; #endif { return(-1); } int #ifdef CK_ANSIC ck_krb4_list_creds(struct krb_op_data * op) #else ck_krb4_list_creds(op) struct krb_op_data * op; #endif { return(-1); } #else /* CK_KERBEROS */ int ck_krb4_initTGT(void * a, void *b) { return(-1); } int ck_krb4_destroy(void *a) { return(-1); } int ck_krb4_list_creds(void *a) { return(-1); } #endif /* CK_KERBEROS */ #endif /* KRB4 */ /* The following functions are used to implement the Kermit Script Language */ /* functions */ struct tkt_list_item { char * name; struct tkt_list_item * next; }; static struct tkt_list_item * k4_tkt_list = NULL; int #ifdef CK_ANSIC ck_krb4_get_tkts(VOID) #else ck_krb4_get_tkts() #endif { #ifdef KRB4 char *file=NULL; char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ int tkt_count=0; struct tkt_list_item ** list = &k4_tkt_list; while ( k4_tkt_list ) { struct tkt_list_item * next; next = k4_tkt_list->next; free(k4_tkt_list->name); free(k4_tkt_list); k4_tkt_list = next; } if ( !ck_krb4_is_installed() ) return(-1); file = tkt_string(); /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Close ticket file */ (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { return(-1); } /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Get principal name and instance */ if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { char tkt_buf[256]; ckmakxmsg(tkt_buf,sizeof(tkt_buf), creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, NULL,NULL,NULL,NULL,NULL,NULL,NULL); *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item)); (*list)->name = strdup(tkt_buf); (*list)->next = NULL; list = &((*list)->next); tkt_count++; } tf_close(); return(tkt_count); #else /* KRB4 */ return(0); #endif /* KRB4 */ } char * #ifdef CK_ANSIC ck_krb4_get_next_tkt(VOID) #else ck_krb4_get_next_tkt() #endif { #ifdef KRB4 static char * s=NULL; struct tkt_list_item * next=NULL; if ( s ) { free(s); s = NULL; } if ( k4_tkt_list == NULL ) return(NULL); next = k4_tkt_list->next; s = k4_tkt_list->name; free(k4_tkt_list); k4_tkt_list = next; return(s); #else /* KRB4 */ return(NULL); #endif /* KRB4 */ } int #ifdef CK_ANSIC ck_krb4_tkt_isvalid(char * tktname) #else ck_krb4_tkt_isvalid(tktname) char * tktname; #endif { #ifdef KRB4 char *file=NULL; char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; time_t issue_t, expire_t, now_t; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ if ( !ck_krb4_is_installed() ) return(-1); debug(F110,"ck_krb4_tkt_isvalid","tkt_string",0); file = tkt_string(); /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_init",0); if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ debug(F110,"ck_krb4_tkt_isvalid","krb_get_tf_realm",0); if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { return(-1); } /* Open ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_init",0); if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Get principal name and instance */ debug(F110,"ck_krb4_tkt_isvalid","tf_get_name/tf_get_pinst",0); if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ debug(F110,"ck_krb4_tkt_isvalid","tf_get_cred",0); while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { char tkt_buf[256]; ckmakxmsg(tkt_buf,sizeof(tkt_buf), creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, NULL,NULL,NULL,NULL,NULL,NULL,NULL); if ( !strcmp(tktname,tkt_buf) ) { /* we found the ticket we are looking for */ issue_t = creds.issue_date; expire_t = creds.issue_date + ((unsigned char) creds.lifetime) * 5 * 60; now_t = time(0); /* We add a 5 minutes fudge factor to compensate for potential */ /* clock skew errors between the KDC and K95's host OS */ if ( now_t >= (issue_t-300) && now_t < expire_t) { #ifdef OS2 #ifdef CHECKADDRS if ( krb4_checkaddrs ) { extern char myipaddr[20]; /* From ckcnet.c */ if ( !myipaddr[0] ) { int i; char buf[60]; for ( i=0;i<64;i++ ) { if ( getlocalipaddrs(buf,60,i) < 0 ) break; if ( !strcmp(buf,creds.address) ) { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* They're the same */ } } /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* They're different */ } else if ( strcmp(myipaddr,creds.address) ) { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* They're different */ } else { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* They're the same */ } } else { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* They're the same */ } #else /* CHECKADDRS */ /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* valid but no ip address check */ #endif /* CHECKADDRS */ #else /* OS2 */ /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* Valid but no ip address check */ #endif /* OS2 */ } else { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* expired or otherwise invalid */ } } } /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* could not find the desired ticket */ #else /* KRB4 */ return(-1); #endif /* KRB4 */ } int #ifdef CK_ANSIC ck_krb4_is_tgt_valid(VOID) #else ck_krb4_is_tgt_valid() #endif { #ifdef KRB4 char tgt[256]; char * s; int rc = 0; s = krb4_d_realm ? krb4_d_realm : ck_krb4_getrealm(); ckmakmsg(tgt,sizeof(tgt),"krbtgt.",s,"@",s); rc = ck_krb4_tkt_isvalid(tgt); debug(F111,"ck_krb4_is_tgt_valid",tgt,rc); return(rc > 0); #else /* KRB4 */ return(0); #endif /* KRB4 */ } int #ifdef CK_ANSIC ck_krb4_tkt_time(char * tktname) #else ck_krb4_tkt_time(tktname) char * tktname; #endif { #ifdef KRB4 char *file=NULL; char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ if ( !ck_krb4_is_installed() ) return(-1); file = tkt_string(); /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Close ticket file */ (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { return(-1); } /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Get principal name and instance */ if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { tf_close(); return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { char tkt_buf[256]; ckmakxmsg(tkt_buf,sizeof(tkt_buf), creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, NULL,NULL,NULL,NULL,NULL,NULL,NULL); if ( !strcmp(tktname,tkt_buf) ) { /* we found the ticket we are looking for */ int n = (creds.issue_date + (((unsigned char) creds.lifetime) * 5 * 60)) - time(0); tf_close(); return(n <= 0 ? 0 : n); } } tf_close(); return(0); /* could not find the desired ticket */ #else /* KRB4 */ return(-1); #endif /* KRB4 */ } char * #ifdef CK_ANSIC ck_krb4_getrealm(void) #else ck_krb4_getrealm() #endif { #ifdef KRB4 char *file=NULL; int k_errno; static char realm[256]=""; realm[0]='\0'; if ( !ck_krb4_is_installed() ) return(realm); /* Try to get realm from ticket file */ /* If failure get the local realm */ /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. */ /* Open ticket file */ file = tkt_string(); if (file == NULL || !file[0]) return(realm); if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) { /* Close ticket file */ (void) tf_close(); k_errno = krb_get_tf_realm(file, realm); } if (k_errno != KSUCCESS) { k_errno = krb_get_lrealm(realm, 1); } return(realm); #else /* KRB4 */ return(""); #endif /* KRB4 */ } char * #ifdef CK_ANSIC ck_krb4_getprincipal(void) #else ck_krb4_getprincipal() #endif { #ifdef KRB4 char *file=NULL; int k_errno; static char principal[256]=""; char instance[256]=""; char realm[256]=""; principal[0]='\0'; if ( !ck_krb4_is_installed() ) return(principal); /* Try to get realm from ticket file */ /* If failure get the local realm */ /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. */ /* Open ticket file */ file = tkt_string(); if (file == NULL || !file[0]) return(principal); if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) { /* Close ticket file */ (void) tf_close(); k_errno = krb_get_tf_fullname(file, principal, instance, realm); } return(principal); #else /* KRB4 */ return(""); #endif /* KRB4 */ } static struct tkt_list_item * k5_tkt_list = NULL; int #ifdef CK_ANSIC ck_krb5_get_tkts(char * cc_name) #else ck_krb5_get_tkts(cc_name) char * cc_name; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; int exit_status = 0; int tkt_count=0; struct tkt_list_item ** list = &k5_tkt_list; while ( k5_tkt_list ) { struct tkt_list_item * next; next = k5_tkt_list->next; free(k5_tkt_list->name); free(k5_tkt_list); k5_tkt_list = next; } if ( !ck_krb5_is_installed() ) return(-1); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_get_tkts while initializing krb5","",retval); return(-1); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_get_tkts while getting ccache", error_message(code),code); tkt_count = -1; goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_get_tkts (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_get_tkts while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } tkt_count = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_get_tkts while retrieving principal name", "",code); tkt_count = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_get_tkts while unparsing principal name", "",code); tkt_count = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_get_tkts while starting to retrieve tickets", "",code); tkt_count = -1; goto exit_k5_get_tkt; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_get_tkts while unparsing server name","",retval); tkt_count = -1; goto exit_k5_get_tkt; } *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item)); (*list)->name = sname; (*list)->next = NULL; list = &((*list)->next); krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); tkt_count++; } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_get_tkts while finishing ticket retrieval", "",code); tkt_count = -1; goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_get_tkts while closing ccache", "",code); tkt_count = -1; goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_get_tkts while retrieving a ticket","",code); tkt_count = -1; goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(tkt_count); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_get_next_tkt(VOID) #else ck_krb5_get_next_tkt() #endif { #ifdef KRB5 #ifndef HEIMDAL static char * s=NULL; struct tkt_list_item * next=NULL; if ( s ) { free(s); s = NULL; } if ( k5_tkt_list == NULL ) return(NULL); next = k5_tkt_list->next; s = k5_tkt_list->name; free(k5_tkt_list); k5_tkt_list = next; return(s); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(NULL); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_tkt_flags(char * cc_name, char * tktname) #else ck_krb5_tkt_flags(cc_name,tktname) char * cc_name; char * tktname; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; char * flag_str = ""; if ( !ck_krb5_is_installed() ) return(""); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_tkt_flags while initializing krb5","",retval); return(""); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_tkt_isvalid while getting ccache", error_message(code),code); goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_tkt_flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_tkt_flags while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_tkt_flags while retrieving principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_tkt_flags while unparsing principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_flags while starting to retrieve tickets", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_tkt_flags while getting time of day.", "",code); retval = -1; goto exit_k5_get_tkt; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_tkt_flags while unparsing server name","",retval); retval = -1; krb5_free_cred_contents(kcontext, &creds); goto exit_k5_get_tkt; } if ( !strcmp(sname,tktname) ) { /* we found the ticket we are looking for */ flag_str = flags_string(&creds); krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; break; } krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_flags while finishing ticket retrieval", "",code); goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_tkt_flags while closing ccache", "",code); goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_tkt_flags while retrieving a ticket","",code); goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(flag_str); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } int #ifdef CK_ANSIC ck_krb5_tkt_isvalid(char * cc_name, char * tktname) #else ck_krb5_tkt_isvalid(cc_name,tktname) char * cc_name; char * tktname; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext=NULL; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; #ifdef CHECKADDRS krb5_address ** myAddrs=NULL; krb5_address ** p=NULL; BOOL Addrfound = FALSE; #endif /*CHECKADDRS*/ if ( !ck_krb5_is_installed() ) return(-1); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_tkt_isvalid while initializing krb5","",retval); return(-1); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_tkt_isvalid while getting ccache", error_message(code),code); goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_tkt_isvalid (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_tkt_isvalid while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_tkt_isvalid while retrieving principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_tkt_isvalid while unparsing principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_isvalid while starting to retrieve tickets", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_tkt_isvalid while getting time of day.", "",code); retval = -1; goto exit_k5_get_tkt; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_tkt_isvalid while unparsing server name","",retval); retval = -1; krb5_free_cred_contents(kcontext, &creds); goto exit_k5_get_tkt; } if ( !strcmp(sname,tktname) ) { /* we found the ticket we are looking for */ /* We add a 5 minutes fudge factor to compensate for potential */ /* clock skew errors between the KDC and K95's host OS */ retval = ((creds.times.starttime > 0) && now >= (creds.times.starttime - 300) && now < (creds.times.endtime + 300) && !(creds.ticket_flags & TKT_FLG_INVALID)); #ifdef CHECKADDRS if ( retval && krb5_checkaddrs && creds.addresses && creds.addresses[0] ) { /* if we think it is valid, then lets check the IP Addresses */ /* to make sure it is valid for our current connection. */ /* Also make sure it's for the correct IP address */ retval = krb5_os_localaddr(kcontext, &myAddrs); if (retval) { com_err(NULL, retval, "retrieving my IP address"); krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; retval = -1; break; } /* See if any of our addresses match any in cached credentials */ for (Addrfound=FALSE, p=myAddrs; (Addrfound==FALSE) && (*p); p++ ) { if (krb5_address_search(kcontext, *p, creds.addresses)) { Addrfound = TRUE; } } krb5_free_addresses(k5_context, myAddrs); if (Addrfound) { krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; retval = 1; break; } else { krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; retval = 0; break; } } #endif /* CHECKADDRS */ krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; break; } krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_isvalid while finishing ticket retrieval", "",code); retval = -1; goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_tkt_isvalid while closing ccache", "",code); retval = -1; goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_tkt_isvalid while retrieving a ticket","",code); retval = -1; goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(retval); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(-1); #endif /* KRB5 */ } int #ifdef CK_ANSIC ck_krb5_is_tgt_valid(VOID) #else ck_krb5_is_tgt_valid() #endif { #ifdef KRB5 #ifndef HEIMDAL char tgt[256]; char * s; int rc = 0; s = ck_krb5_getrealm(krb5_d_cc); ckmakmsg(tgt,sizeof(tgt),"krbtgt/",s,"@",s); rc = ck_krb5_tkt_isvalid(krb5_d_cc,tgt); debug(F111,"ck_krb5_is_tgt_valid",tgt,rc); return(rc>0); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int #ifdef CK_ANSIC ck_krb5_tkt_time(char * cc_name, char * tktname) #else ck_krb5_tkt_time(cc_name, tktname) char * cc_name; char * tktname; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; if ( !ck_krb5_is_installed() ) return(-1); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_list_creds while initializing krb5","",retval); return(-1); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_tkt_time while getting ccache", error_message(code),code); retval = -1; goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_list_creds (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_list_creds while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_list_creds while retrieving principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_list_creds while unparsing principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while starting to retrieve tickets", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_list_creds while getting time of day.", "",code); krb5_free_context(kcontext); return(-1); } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_list_creds while unparsing server name","",retval); retval = -1; krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); goto exit_k5_get_tkt; } if ( !strcmp(sname,tktname) ) { /* we found the ticket we are looking for */ int valid = (creds.times.starttime && now > creds.times.starttime && now < creds.times.endtime && !(creds.ticket_flags & TKT_FLG_INVALID)); if ( valid ) { retval = creds.times.endtime - now; } else retval = 0; krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; break; } krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while finishing ticket retrieval", "",code); retval = -1; goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_list_creds while closing ccache", "",code); retval = -1; goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code); retval = -1; goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(retval); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(-1); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_get_cc_name(void) #else ck_krb5_get_cc_name() #endif { #ifdef KRB5 #ifndef HEIMDAL static char cc_name[CKMAXPATH+1]=""; krb5_context kcontext = NULL; krb5_ccache ccache = NULL; krb5_error_code code; char * p=NULL; cc_name[0] = '\0'; if ( !ck_krb5_is_installed() ) return(cc_name); p = getenv("KRB5CCNAME"); if ( !p ) { code = krb5_init_context(&kcontext); if (code) { com_err("ck_krb5_get_cc_name",code,"while init_context"); return(cc_name); } if ((code = krb5_cc_default(kcontext, &ccache))) { com_err("ck_krb5_get_cc_name",code,"while getting default ccache"); goto exit_k5_get_cc; } ckmakmsg(cc_name,sizeof(cc_name), (char *)krb5_cc_get_type(kcontext,ccache),":", (char *)krb5_cc_get_name(kcontext,ccache),NULL); } else { ckstrncpy(cc_name,p,CKMAXPATH); } if ( !strncmp("FILE:",cc_name,5) ) { for ( p=cc_name; *p ; p++ ) if ( *p == '\\' ) *p = '/'; } exit_k5_get_cc: if ( ccache ) krb5_cc_close(kcontext,ccache); if ( kcontext ) krb5_free_context(kcontext); return(cc_name); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_getrealm(char * cc_name) #else ck_krb5_getrealm(cc_name) char * cc_name; #endif { #ifdef KRB5 #ifndef HEIMDAL static char realm[256]=""; krb5_context kcontext; krb5_ccache ccache = NULL; krb5_error_code code; krb5_principal me=NULL; realm[0] = '\0'; if ( !ck_krb5_is_installed() ) return(realm); code = krb5_init_context(&kcontext); if (code) { return(realm); } code = k5_get_ccache(kcontext,&ccache,cc_name); if (code != 0) { goto exit_k5_getrealm; } code = krb5_cc_get_principal(kcontext, ccache, &me); if (code) code = krb5_parse_name(kcontext, "foo", &me); if (code) { goto exit_k5_getrealm; } if ( krb5_princ_realm(kcontext, me)->length < sizeof(realm) ) { memcpy(realm,krb5_princ_realm(kcontext, me)->data, krb5_princ_realm(kcontext, me)->length); /* safe */ realm[krb5_princ_realm(kcontext, me)->length]='\0'; } exit_k5_getrealm: if ( me ) krb5_free_principal(kcontext,me); if ( ccache ) krb5_cc_close(kcontext,ccache); if (kcontext) krb5_free_context(kcontext); return(realm); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_getprincipal(char * cc_name) #else ck_krb5_getprincipal(cc_name) char * cc_name; #endif { #ifdef KRB5 #ifndef HEIMDAL static char principal[UIDBUFLEN+1]=""; krb5_context kcontext; krb5_ccache ccache = NULL; krb5_error_code code; krb5_principal me; char * p=NULL; int i; principal[0] = '\0'; if ( !ck_krb5_is_installed() ) return(principal); code = krb5_init_context(&kcontext); if (code) { return(principal); } code = k5_get_ccache(kcontext,&ccache,cc_name); if (code != 0) { goto exit_k5_getprincipal; } if ((code = krb5_cc_get_principal(kcontext, ccache, &me))) { goto exit_k5_getprincipal; } if ((code = krb5_unparse_name (kcontext, me, &p))) { krb5_free_principal(kcontext,me); goto exit_k5_getprincipal; } ckstrncpy(principal,p,UIDBUFLEN); i = ckindex("@",principal,0,0,0); if (i) principal[i-1] = '\0'; krb5_free_unparsed_name(kcontext,p); exit_k5_getprincipal: if ( ccache ) krb5_cc_close(kcontext,ccache); if (kcontext) krb5_free_context(kcontext); return(principal); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } #ifndef CRYPT_DLL int ck_get_crypt_table(struct keytab ** pTable, int * pN) { #ifdef CK_ENCRYPTION return(get_crypt_table(pTable, pN)); #else /* ENCRYPTION */ int i=0; #ifndef OS2 char * tmpstring = NULL; #endif /* OS2 */ if ( *pTable ) { for ( i=0 ; i < *pN ; i++ ) free( (*pTable)[i].kwd ) ; free ( *pTable ) ; } *pTable = NULL; *pN = 0; *pTable = malloc( sizeof(struct keytab) * 2 ) ; if ( !(*pTable) ) return(0); #ifdef OS2 (*pTable)[0].kwd =strdup("automatic"); #else /* OS2 */ makestr(&tmpstring,"automatic"); (*pTable)[0].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[0].kwval = ENCTYPE_ANY; (*pTable)[0].flgs = 0; #ifdef OS2 (*pTable)[1].kwd =strdup("none"); #else /* OS2 */ makestr(&tmpstring,"none"); (*pTable)[1].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[1].kwval = 999; (*pTable)[1].flgs = 0; (*pN) = 2; return(2); #endif /* ENCRYPTION */ } VOID ck_encrypt_send_support() { #ifdef CK_ENCRYPTION encrypt_send_support(); #endif /* ENCRYPTION */ } #endif /* CRYPT_DLL */ /* * * Kstream * * Emulates the kstream package in Kerberos 4 * */ int kstream_destroy() { if (g_kstream != NULL) { auth_destroy(); /* Destroy authorizing */ free(g_kstream); g_kstream=NULL; } return 0; } VOID #ifdef CK_ANSIC kstream_set_buffer_mode(int mode) #else kstream_set_buffer_mode(mode) int mode; #endif { } int #ifdef CK_ANSIC kstream_create_from_fd(int fd, kstream_ptr data) #else kstream_create_from_fd(fd,data) int fd; kstream_ptr data; #endif { int n; g_kstream = malloc(sizeof(struct kstream_int)); if (g_kstream == NULL) return 0; g_kstream->fd = fd; n = auth_init(g_kstream); /* Initialize authorizing */ if (n) { free(g_kstream); g_kstream = NULL; return 0; } g_kstream->encrypt = NULL; g_kstream->decrypt = NULL; g_kstream->encrypt_type = ENCTYPE_ANY; g_kstream->decrypt_type = ENCTYPE_ANY; return 1; } #ifdef CK_KERBEROS #ifdef RLOGCODE static int do_lencheck, use_ivecs; extern int rlog_inband; #ifdef KRB5 void rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck, am_client, protonum) krb5_keyblock *in_keyblock; int encrypt_flag; int lencheck; int am_client; enum krb5_kcmd_proto protonum; { krb5_error_code status; size_t blocksize; if (!encrypt_flag) return; desinbuf.data = des_inbuf; desoutbuf.data = des_outpkt+4; /* Set up des buffers */ k5_session_key = in_keyblock; do_lencheck = lencheck; if ( protonum == KCMD_OLD_PROTOCOL ) { use_ivecs = 0; return; } use_ivecs = 1; if (status = krb5_c_block_size(k5_context, k5_session_key->enctype, &blocksize)) { /* XXX what do I do? */ printf("fatal kerberos 5 crypto library error\n"); ttclos(0); return; } encivec_i[0].length = encivec_i[1].length = encivec_o[0].length = encivec_o[1].length = blocksize; if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) == NULL) { /* XXX what do I do? */ printf("fatal malloc failed\n"); ttclos(0); return; } encivec_i[1].data = encivec_i[0].data + encivec_i[0].length; encivec_o[0].data = encivec_i[1].data + encivec_i[1].length; encivec_o[1].data = encivec_o[0].data + encivec_o[0].length; /* is there a better way to initialize this? */ memset(encivec_i[0].data, am_client, blocksize); memset(encivec_o[0].data, 1 - am_client, blocksize); memset(encivec_i[1].data, 2 | am_client, blocksize); memset(encivec_o[1].data, 2 | (1 - am_client), blocksize); } #endif /* KRB5 */ int #ifdef CK_ANSIC ck_krb_rlogin(CHAR * hostname, int port, CHAR * localuser, CHAR * remoteuser, CHAR * term_speed, struct sockaddr_in * l_addr, struct sockaddr_in * r_addr, int kversion, int encrypt_flag) #else /* CK_ANSIC */ ck_krb_rlogin(hostname, port, localuser, remoteuser, term_speed, l_addr, r_addr, encrypt_flag) CHAR * hostname; int port; CHAR * localuser; CHAR * remoteuser; CHAR * term_speed; struct sockaddr_in * l_addr; struct sockaddr_in * r_addr; int kversion; int encrypt_flag; #endif /* CK_ANSIC */ { unsigned long status; char * realm=NULL; extern int ttyfd; int c; long msglen; debug(F111,"ck_krb_rlogin",hostname,port); if ( kversion == 4 && !ck_krb4_is_installed() ) { printf("?Kerberos 4 is not installed\r\n"); return(-1); } else if ( kversion == 5 && !ck_krb5_is_installed() ) { printf("?Kerberos 5 is not installed\r\n"); return(-1); } if ( encrypt_flag && !ck_crypt_is_installed() ) { printf("?Encryption is not installed\r\n"); return(-1); } if ( kversion == 5 ) { #ifdef KRB5 krb5_flags authopts=0; krb5_ccache ccache=NULL; char *cksumbuf=NULL; char *service=NULL; char * kcmd_version=NULL; enum krb5_kcmd_proto use_proto; krb5_data cksumdat; krb5_creds *get_cred = 0; krb5_error_code status; krb5_error *error = 0; krb5_ap_rep_enc_part *rep_ret = NULL; krb5_data outbuf; int rc; krb5_int32 seqno=0; krb5_int32 server_seqno=0; char ** realmlist=NULL; int buflen; char tgt[256]; debug(F100,"ck_krb_rlogin version 5","",0); realm = ck_krb5_realmofhost(hostname); if (!realm) { ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL); ckstrncat(strTmp, hostname,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 5 error: %s\r\n",strTmp); krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN; makestr(&krb5_errmsg,strTmp); return(-1); } ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"ck_rlog_rlogin TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); buflen = strlen(term_speed)+strlen(remoteuser)+64; if ((cksumbuf = malloc(buflen)) == 0) { printf("Unable to allocate memory for checksum buffer.\r\n"); return(-1); } ckmakmsg(cksumbuf,buflen,ckuitoa((unsigned short) ntohs(port)),":", term_speed,remoteuser); cksumdat.data = cksumbuf; cksumdat.length = strlen(cksumbuf); status = krb5_init_context(&k5_context); if (status) { debug(F110,"ck_krb_rlogin()","unable to init_context",0); return(-1); } desinbuf.data = des_inbuf; desoutbuf.data = des_outpkt+4; /* Set up des buffers */ rc = k5_get_ccache(k5_context,&ccache,NULL); if (rc != 0) { com_err(NULL, rc, "while getting ccache."); return(0); } service = krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME; if (!(get_cred = (krb5_creds *)calloc(1, sizeof(krb5_creds)))) { printf("ck_krb_rlogin: no memory\r\n"); return(-1); } memset(get_cred,0,sizeof(krb5_creds)); status = krb5_sname_to_principal(k5_context, hostname, service, KRB5_NT_SRV_HST, &get_cred->server); if (status) { printf("ck_krb_rlogin: krb5_sname_to_principal failed: %s\r\n", error_message(status)); return(-1); } ttoc(0); if (status = krb5_cc_get_principal(k5_context, ccache, &get_cred->client) ) { (void) krb5_cc_close(k5_context, ccache); krb5_free_creds(k5_context, get_cred); goto bad; } if (krb5_rlog_ver == KCMD_OLD_PROTOCOL) get_cred->keyblock.enctype=ENCTYPE_DES_CBC_CRC; /* Get ticket from credentials cache or kdc */ status = krb5_get_credentials(k5_context, 0, ccache, get_cred, &ret_cred ); krb5_free_creds(k5_context, get_cred); get_cred = NULL; (void) krb5_cc_close(k5_context, ccache); if (status) goto bad; /* Reset internal flags; these should not be set. */ authopts &= (~OPTS_FORWARD_CREDS); authopts &= (~OPTS_FORWARDABLE_CREDS); if (krb5_auth_con_init(k5_context, &auth_context)) goto bad; if (krb5_auth_con_setflags(k5_context, auth_context, KRB5_AUTH_CONTEXT_RET_TIME)) goto bad; /* Only need local address for mk_cred() to send to krlogind */ if (!krb5_d_no_addresses) if (status = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR )) goto bad; /* Here is where we start to handle the new protocol in earnest */ if ( krb5_rlog_ver == KCMD_PROTOCOL_COMPAT_HACK ) { krb5_boolean is_des; if (status = krb5_c_enctype_compare( k5_context, ENCTYPE_DES_CBC_CRC, #ifdef HEIMDAL ret_cred->session.keytype, #else /* HEIMDAL */ ret_cred->keyblock.enctype, #endif /* HEIMDAL */ &is_des)) { krb5_free_creds(k5_context, ret_cred); ret_cred = NULL; goto bad; } if ( is_des ) { kcmd_version = "KCMDV0.1"; use_proto = KCMD_OLD_PROTOCOL; } else { authopts = AP_OPTS_USE_SUBKEY; kcmd_version = "KCMDV0.2"; use_proto = KCMD_NEW_PROTOCOL; } } else { use_proto = krb5_rlog_ver; switch ( krb5_rlog_ver ) { case KCMD_NEW_PROTOCOL: authopts = AP_OPTS_USE_SUBKEY; kcmd_version = "KCMDV0.2"; break; case KCMD_OLD_PROTOCOL: kcmd_version = "KCMDV0.1"; break; default: goto bad; } } /* call Kerberos library routine to obtain an authenticator, pass it over the socket to the server, and obtain mutual authentication. */ status = krb5_sendauth(k5_context, &auth_context, (krb5_pointer) &ttyfd, kcmd_version, ret_cred->client, ret_cred->server, authopts, &cksumdat, ret_cred, 0, &error, &rep_ret, NULL ); krb5_free_data_contents(k5_context,&cksumdat); if (status) { if ( !quiet ) printf("Couldn't authenticate to server: %s\r\n", error_message(status)); if (error) { if ( !quiet ) { printf("Server returned error code %d (%s)\r\n", error->error, error_message(ERROR_TABLE_BASE_krb5 + error->error)); if (error->text.length) { printf("Error text sent from server: %s\r\n", error->text.data); } } krb5_free_error(k5_context, error); error = 0; } goto bad; } if (rep_ret) { server_seqno = rep_ret->seq_number; krb5_free_ap_rep_enc_part(k5_context, rep_ret); } (void) ttol(remoteuser, strlen(remoteuser)+1); (void) ttol(term_speed, strlen(term_speed)+1); (void) ttol(localuser, strlen(localuser)+1); if (forward_flag) { /* Forward credentials (global) */ if (status = krb5_fwd_tgt_creds( k5_context, auth_context, hostname, ret_cred->client, ret_cred->server, 0, (forwardable_flag ? OPTS_FORWARDABLE_CREDS : 0), &outbuf ) ) { printf("Error forwarding credentials: %s\r\n", error_message(status)); goto bad2; } /* Send forwarded credentials */ status = krb5_write_message(k5_context, (krb5_pointer)&ttyfd, &outbuf ); } else { /* Dummy write to signal no forwarding */ bad2: outbuf.length = 0; status = krb5_write_message(k5_context, (krb5_pointer)&ttyfd, &outbuf); } if ((c = ttinc(0)) < 0) { if (c==-1) { perror(hostname); } else { printf("ck_krb_rlogin: bad connection with remote host\r\n"); } status = -1; goto bad; } if (c != 0) { while ((c = ttinc(1)) >= 0) { (void) printf("%c",c); if (c == '\n') break; } status = -1; goto bad; } if ( status == 0 ) { /* success */ krb5_keyblock * key = 0; if ( use_proto == KCMD_NEW_PROTOCOL ) { int on = 1; rlog_inband = 1; setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof on); status = krb5_auth_con_getlocalsubkey( k5_context, auth_context, &key); if ((status || !key) && encrypt_flag ) goto bad2; } if ( key == 0 ) { #ifdef HEIMDAL key = &ret_cred->session; #else /* HEIMDAL */ key = &ret_cred->keyblock; #endif /* HEIMDAL */ } rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, use_proto); if ( encrypt_flag ) rlog_encrypt = 1; } return (0); /* success */ bad: if ( status && !quiet ) { printf("Kerberos authentication error: %s\r\n", error_message(status)); } if (ret_cred) { krb5_free_creds(k5_context, ret_cred); ret_cred = NULL; } return (status); #else /* KRB5 */ return(-1); #endif /* KRB5 */ } else if (kversion == 4) { #ifdef KRB4 char tgt[4*REALM_SZ+1]; debug(F100,"ck_krb_rlogin version 4","",0); realm = (char *)krb_realmofhost(hostname); if (!realm) { strcpy(strTmp, "Can't find realm for host \""); ckstrncat(strTmp, hostname,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 4 error: %s\r\n",strTmp); krb4_errno = 0; makestr(&krb4_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm); status = ck_krb4_tkt_isvalid(tgt); if ( status <= 0 && krb4_autoget ) ck_krb4_autoget_TGT(realm); ttoc(0); /* write a NUL */ status = krb_sendauth(encrypt_flag?KOPT_DO_MUTUAL:0, ttyfd, &k4_auth, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME, hostname, realm, (unsigned long) getpid(), &k4_msg_data, &cred, #ifdef CK_ENCRYPTION &k4_sched, #else /* ENCRYPTION */ NULL, #endif /* ENCRYPTION */ l_addr, r_addr, "KCMDV0.1"); debug(F111,"ck_krb_rlogin","krb_sendauth",status); if (status != KSUCCESS) { printf( "krb_sendauth failed: %s\r\n", krb_get_err_text_entry(status) ); return(-1); } ttol(remoteuser,strlen(remoteuser)+1); ttol(term_speed,strlen(term_speed)+1); reread: if ((c = ttinc(0)) < 0) { printf("rcmd: bad connection with remote host\r\n"); return(-1); } debug(F111,"ck_krb_rlogin","first byte",c); if (c != 0) { char *check = "ld.so: warning:"; /* If rlogind was compiled on SunOS4, and it somehow got the shared library version numbers wrong, it may give an ld.so warning about an old version of a shared library. Just ignore any such warning. Note that the warning is a characteristic of the server; we may not ourselves be running under SunOS4. */ if (c == 'l') { char *p; char cc; p = &check[1]; while ((c = ttinc(0)) >= 0) { if (*p == '\0') { if (c == '\n') break; } else { if (c != *p) break; ++p; } } if (*p == '\0') goto reread; } printf(check); while ((c = ttinc(1)) >= 0) { printf("%c",c); if (c == '\n') break; } debug(F110,"ck_krb_rlogin","fatal error 1",0); return(-1); } #ifdef CK_ENCRYPTION if ( encrypt_flag ) { /* if we are encrypting we need to setup the encryption */ /* routines. */ des_key_sched(cred.session, k4_sched); rlog_encrypt = 1; } #endif /* ENCRYPTION */ #else /* KRB4 */ return(-1); #endif /* KRB4 */ } return(0); /* success */ } #define SRAND srand #define RAND rand #define RAND_TYPE int static long random_confounder(size, fillin) size_t size; char * fillin; { static int seeded = 0; register unsigned char *real_fill; RAND_TYPE rval; if (!seeded) { /* time() defined in 4.12.2.4, but returns a time_t, which is an "arithmetic type" (4.12.1) */ rval = (RAND_TYPE) time(0); SRAND(rval); rval = RAND(); rval ^= getpid(); SRAND(rval); seeded = 1; } real_fill = (unsigned char *)fillin; while (size > 0) { rval = RAND(); *real_fill = rval & 0xff; real_fill++; size--; if (size) { *real_fill = (rval >> 8) & 0xff; real_fill++; size--; } } return 0; } #ifdef KRB5 int krb5_des_avail(fd) int fd; { return(nstored); } int krb5_des_read(fd, buf, len, secondary) int fd; register char *buf; int len; int secondary; { int nreturned = 0; long net_len,rd_len; int cc; krb5_error_code status; unsigned char c; krb5_data plain; krb5_enc_data cipher; debug(F111,"krb5_des_read","len",len); debug(F111,"krb5_des_read","rlog_encrypt",rlog_encrypt); if ( !rlog_encrypt ) { cc = net_read(fd, buf, len); debug(F111,"krb5_des_read","chars read",cc); if ( cc < 0 ) netclos(); return(cc); } if (nstored >= len) { if ( buf ) { memcpy(buf, store_ptr, len); /* safe */ store_ptr += len; nstored -= len; return(len); } else return(0); } else if (nstored) { if ( buf ) { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; buf += nstored; len -= nstored; nstored = 0; } else return(0); } /* See the comment in v4_des_read. */ while (1) { cc = net_read(fd, &c, 1); /* we should check for non-blocking here, but we'd have to make it save partial reads as well. */ if (cc <= 0) { return cc; /* read error */ } if (cc == 1) { if (c == 0 || !do_lencheck) break; } } rd_len = c; if ((cc = net_read(fd, &c, 1)) != 1) return 0; rd_len = (rd_len << 8) | c; if ((cc = net_read(fd, &c, 1)) != 1) return 0; rd_len = (rd_len << 8) | c; if ((cc = net_read(fd, &c, 1)) != 1) return 0; rd_len = (rd_len << 8) | c; if (status = krb5_c_encrypt_length(k5_context, k5_session_key->enctype, use_ivecs ? rd_len + 4 : rd_len, &net_len)) { errno = status; return(-1); } if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) { /* preposterous length; assume out-of-sync; only recourse is to close connection, so return 0 */ printf("Read size problem.\r\n"); return(0); } if ((cc = net_read(fd, desinbuf.data, net_len)) != net_len ) { /* pipe must have closed, return 0 */ printf( "Read error: length received %d != expected %d.\r\n", cc, net_len ); return(cc); } /* decrypt info */ cipher.enctype = ENCTYPE_UNKNOWN; cipher.ciphertext.length = net_len; cipher.ciphertext.data = desinbuf.data; plain.length = sizeof(storage); plain.data = storage; if ( status = krb5_c_decrypt(k5_context, k5_session_key, KCMD_KEYUSAGE, use_ivecs ? encivec_i + secondary : 0, &cipher,&plain) ) { /* probably out of sync */ printf("Cannot decrypt data from network: %s\r\n", error_message(status)); errno = EIO; return(-1); } store_ptr = storage; nstored = rd_len; if ( use_ivecs ) { int rd_len2; rd_len2 = storage[0] & 0xff; rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff; rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff; rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff; if (rd_len2 != rd_len) { /* cleartext length trashed? */ errno = EIO; return -1; } store_ptr += 4; } if ( !buf ) return(0); #ifdef RLOGCODE /* blah */ if (rlog_inband && (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN)) { int i, left, n; for (i = 0; i < nstored; i++) { if (store_ptr[i] == '\377' && store_ptr[i+1] == '\377') { left = nstored - i; n = rlog_ctrl(&store_ptr[i], left); if (n < 0) { left -= (-n); nstored = left; /* flush before, and (-n) bytes */ if (left > 0) memmove(store_ptr, &store_ptr[i-n], left); } else if (n) { left -= n; nstored -= n; if (left > 0) memmove(store_ptr, &store_ptr[n], left); } } } } #endif /* RLOGCODE */ if (nstored > len) { memcpy(buf, store_ptr, len); /* safe */ nreturned += len; store_ptr += len; nstored -= len; } else { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; nstored = 0; } return(nreturned); } int krb5_des_write(fd, buf, len, secondary) int fd; char *buf; int len; int secondary; { char tmpbuf[2*RLOG_BUFSIZ+8]; unsigned char *len_buf = (unsigned char *) tmpbuf; krb5_error_code status; krb5_data plain; krb5_enc_data cipher; debug(F111,"krb5_des_write","rlog_encrypt",rlog_encrypt); if ( !rlog_encrypt ) { int cc = net_write(fd, buf, len); debug(F111,"net_write","chars written",cc); return(cc != len ? -1 : len); } if (use_ivecs) { unsigned char *lenbuf2 = (unsigned char *) tmpbuf; if (len + 4 > sizeof(tmpbuf)) abort (); lenbuf2[0] = (len & 0xff000000) >> 24; lenbuf2[1] = (len & 0xff0000) >> 16; lenbuf2[2] = (len & 0xff00) >> 8; lenbuf2[3] = (len & 0xff); memcpy (tmpbuf + 4, buf, len); plain.data = tmpbuf; plain.length = len + 4; } else { plain.data = buf; plain.length = len; } cipher.ciphertext.length = sizeof(des_outpkt)-4; cipher.ciphertext.data = desoutbuf.data; if ( status = krb5_c_encrypt(k5_context, k5_session_key, KCMD_KEYUSAGE, use_ivecs ? encivec_o + secondary : 0, &plain, &cipher)) { printf("Write encrypt problem: %s.\r\n", error_message(status)); errno = EIO; return(-1); } desoutbuf.length = cipher.ciphertext.length; len_buf = (unsigned char *) des_outpkt; len_buf[0] = (len & 0xff000000) >> 24; len_buf[1] = (len & 0xff0000) >> 16; len_buf[2] = (len & 0xff00) >> 8; len_buf[3] = (len & 0xff); if (net_write(fd, des_outpkt,desoutbuf.length+4) != desoutbuf.length+4){ printf("Could not write out all data\r\n"); return(-1); } else return(len); } #endif /* KRB5 */ #ifdef KRB4 /* * Note that the encrypted rlogin packets take the form of a four-byte * length followed by encrypted data. On writing the data out, a significant * performance penalty is suffered (at least one RTT per character, two if we * are waiting for a shell to echo) by writing the data separately from the * length. So, unlike the input buffer, which just contains the output * data, the output buffer represents the entire packet. */ int krb4_des_avail(fd) int fd; { return(nstored); } int krb4_des_read(fd, buf, len) int fd; register char *buf; int len; { int nreturned = 0; unsigned long net_len, rd_len; int cc; unsigned char c; int gotzero = 0; debug(F111,"krb4_des_read","rlog_encrypt",rlog_encrypt); debug(F111,"krb4_des_read","len",len); if ( !rlog_encrypt ) { cc = net_read(fd, buf, len); debug(F111,"krb4_des_read","chars read",cc); if ( cc < 0 ) netclos(); return(cc); } if (nstored >= len) { if ( buf ) { debug(F111,"krb4_des_read (nstored >= len)","nstored",nstored); memcpy(buf, store_ptr, len); /* safe */ store_ptr += len; nstored -= len; return(len); } else return(0); } else if (nstored) { if ( buf ) { debug(F111,"krb4_des_read (nstored)","nstored",nstored); memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; buf += nstored; len -= nstored; nstored = 0; } else return(0); } /* We're fetching the length which is MSB first, and the MSB has to be zero unless the client is sending more than 2^24 (16M) bytes in a single write (which is why this code is in rlogin but not rcp or rsh.) The only reasons we'd get something other than zero are: -- corruption of the tcp stream (which will show up when everything else is out of sync too) -- un-caught Berkeley-style "pseudo out-of-band data" which happens any time the user hits ^C twice. The latter is *very* common, as shown by an 'rlogin -x -d' using the CNS V4 rlogin. Mark EIchin 1/95 */ debug(F110,"krb4_des_read", "about to call net_read() this will block", 0 ); do { cc = net_read(fd, &c, 1); debug(F111,"net_read","chars read",cc); if (cc <= 0) { netclos(); return(-1); } if (cc != 1) return 0; /* read error */ if (cc == 1) { if (c == 0) gotzero = 1; } } while (!gotzero); debug(F110,"krb4_des_read","gotzero",0); cc = net_read(fd, &c, 1); debug(F111,"net_read","chars read",cc); if (cc < 0) { netclos(); return(-1); } else if ( cc != 1 ) return(0); net_len = c; cc = net_read(fd, &c, 1); debug(F111,"net_read","chars read",cc); if (cc < 0) { netclos(); return(-1); } else if ( cc != 1 ) return(0); net_len = (net_len << 8) | c; debug(F111,"net_read","chars read",cc); cc = net_read(fd, &c, 1); if (cc < 0) { netclos(); return(-1); } else if ( cc != 1 ) return(0); net_len = (net_len << 8) | c; debug(F111,"krb4_des_read","net_len",net_len); /* Note: net_len is unsigned */ if (net_len > sizeof(des_inbuf)) { /* XXX preposterous length, probably out of sync. act as if pipe closed */ return(0); } /* the writer tells us how much real data we are getting, but we need to read the pad bytes (8-byte boundary) */ #ifndef roundup #define roundup(x,y) ((((x)+(y)-1)/(y))*(y)) #endif /* roundup */ rd_len = roundup(net_len, 8); debug(F111,"krb4_des_read","rd_len",rd_len); cc = net_read(fd, des_inbuf, rd_len); debug(F111,"net_read","chars read",cc); if (cc < 0) { netclos(); return(-1); } else if ( cc != rd_len ) return(0); hexdump("krb4_des_read des_inbuf",des_inbuf,8); #ifdef CK_ENCRYPTION #ifdef KRB524 (void) des_pcbc_encrypt(des_inbuf, storage, (net_len < 8) ? 8 : net_len, k4_sched, cred.session, DECRYPT); #else /* KRB524 */ (void) des_pcbc_encrypt((Block *)des_inbuf, (Block *)storage, (net_len < 8) ? 8 : net_len, k4_sched, &cred.session, DECRYPT); #endif /* KRB524 */ #endif /* ENCRYPTION */ hexdump("krb4_des_read storage",storage,8); /* * when the cleartext block is < 8 bytes, it is "right-justified" * in the block, so we need to adjust the pointer to the data */ if (net_len < 8) store_ptr = storage + 8 - net_len; else store_ptr = storage; nstored = net_len; if ( !buf ) return(0); if (nstored > len) { memcpy(buf, store_ptr, len); /* safe */ nreturned += len; store_ptr += len; nstored -= len; } else { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; nstored = 0; } debug(F111,"net_read","nreturned",nreturned); return(nreturned); } int krb4_des_write(fd, buf, len) int fd; char *buf; int len; { static char garbage_buf[8]; unsigned char *len_buf = (unsigned char *) des_outpkt; int cc; debug(F111,"krb4_des_write","rlog_encrypt",rlog_encrypt); if ( !rlog_encrypt ) { cc = net_write(fd, buf, len); debug(F111,"net_write","chars written",cc); return(cc); } /* * pcbc_encrypt outputs in 8-byte (64 bit) increments * * it zero-fills the cleartext to 8-byte padding, * so if we have cleartext of < 8 bytes, we want * to insert random garbage before it so that the ciphertext * differs for each transmission of the same cleartext. * if len < 8 - sizeof(long), sizeof(long) bytes of random * garbage should be sufficient; leave the rest as-is in the buffer. * if len > 8 - sizeof(long), just garbage fill the rest. */ if (len < 8) { random_confounder(8 - len, garbage_buf); /* this "right-justifies" the data in the buffer */ (void) memcpy(garbage_buf + 8 - len, buf, len); /* safe */ hexdump("krb4_des_write garbage_buf",garbage_buf,8); } else hexdump("krb4_des_write buf",buf,8); #ifdef CK_ENCRYPTION #ifdef KRB524 (void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf, des_outpkt+4, (len < 8) ? 8 : len, k4_sched, cred.session, ENCRYPT); #else /* KRB524 */ (void) des_pcbc_encrypt((Block *)((len < 8) ? garbage_buf : buf), (Block *)(des_outpkt+4), (len < 8) ? 8 : len, k4_sched, &cred.session, ENCRYPT); #endif /* KRB524 */ #endif /* ENCRYPTION */ if ( len < 8 ) hexdump("krb4_des_write (post pcbc) garbage_buf",garbage_buf,8); else hexdump("krb4_des_write (post pcbc) buf",buf,8); hexdump("krb4_des_write (des_outpkt+4)",(des_outpkt+4),8); /* tell the other end the real amount, but send an 8-byte padded packet */ len_buf[0] = (len & 0xff000000) >> 24; len_buf[1] = (len & 0xff0000) >> 16; len_buf[2] = (len & 0xff00) >> 8; len_buf[3] = (len & 0xff); hexdump("krb4_des_write des_outpkt len",des_outpkt,12); cc = net_write(fd, des_outpkt, roundup(len,8)+4); debug(F111,"net_write","chars written",cc); return(len); } #endif /* KRB4 */ #endif /* RLOGCODE */ #ifdef KRB524 #ifndef OS2 /* The following functions are missing from the compatibility library */ const char * krb_get_err_text_entry(r) int r; { extern char krb_err_text[]; return(krb_err_txt[r]); } #endif /* OS2 */ #endif /* KRB524 */ #endif /* CK_KERBEROS */ #ifdef CK_KERBEROS #ifdef KRB5_U2U /* Kerberos 5 User to User Client */ int k5_user_to_user_client_auth() { extern int ttyfd; register int retval, i; char **srealms; /* realm(s) of server */ char *princ; /* principal in credentials cache */ krb5_ccache cc; krb5_creds creds, *new_creds; krb5_data reply, msg, msgtext, princ_data; krb5_ticket * ticket = NULL; if (retval = k5_get_ccache(k5_context,&cc,NULL)) { com_err("uu-client", retval, "getting credentials cache"); return(-1); } memset ((char*)&creds, 0, sizeof(creds)); if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client)) { com_err("uu-client", retval, "getting principal name"); return(-1); } if (retval = krb5_get_host_realm(k5_context, szHostName, &srealms)) { com_err("uu-client", retval, "getting realms for \"%s\"", szHostName); return(-1); } if (retval = krb5_build_principal_ext(k5_context, &creds.server, krb5_princ_realm(k5_context, creds.client)->length, krb5_princ_realm(k5_context, creds.client)->data, 6, "krbtgt", krb5_princ_realm(k5_context, creds.client)->length, krb5_princ_realm(k5_context, creds.client)->data, 0)) { com_err("uu-client", retval, "setting up tgt server name"); return(-1); } /* Get TGT from credentials cache */ if (retval = krb5_get_credentials(k5_context, KRB5_GC_CACHED, cc, &creds, &new_creds)) { com_err("uu-client", retval, "getting TGT"); return(-1); } if (retval = krb5_unparse_name(k5_context, creds.client, &princ)) { com_err("uu-client", retval, "printing principal name"); return(-1); } i = strlen(princ) + 1; princ_data.data = princ; princ_data.length = i; /* include null terminator for server's convenience */ retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &princ_data); if (retval) { com_err("uu-client", retval, "sending principal name to server"); return(-1); } krb5_free_unparsed_name(k5_context,princ); retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &new_creds->ticket); if (retval) { com_err("uu-client", retval, "sending ticket to server"); return(-1); } retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &reply); if (retval) { com_err("uu-client", retval, "reading reply from server"); return(-1); } if (retval = krb5_auth_con_init(k5_context, &auth_context)) { com_err("uu-client", retval, "initializing the auth_context"); return(-1); } if (!krb5_d_no_addresses) { if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) { com_err("uu-client", retval, "generating addrs for auth_context"); return(-1); } } if (retval = krb5_auth_con_setflags(k5_context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { com_err("uu-client", retval, "initializing the auth_context flags"); return(-1); } if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context, &new_creds->keyblock)) { com_err("uu-client", retval, "setting useruserkey for authcontext"); return(-1); } /* read the ap_req to get the session key */ retval = krb5_rd_req(k5_context, &auth_context, &reply, NULL, NULL, NULL, &ticket); if (retval) { com_err("uu-client", retval, "reading AP_REQ from server"); return(-1); } if (k5_u2u_read_msg(k5_context,&msg) < 0) return(-1); if ( strcmp("Kermit implements Kerberos 5 User to User",msg.data) ) return(-1); krb5_free_data_contents(k5_context,&msg); msgtext.data = "As do I! :-)"; msgtext.length = strlen(msgtext.data)+1; if (k5_u2u_write_msg(k5_context,&msgtext) < 0) return(-1); if (retval = krb5_unparse_name(k5_context, #ifdef HEIMDAL ticket->client, #else /* HEIMDAL */ ticket->enc_part2->client, #endif /* HEIMDAL */ &princ)) com_err("uu-client", retval, "while unparsing client name"); else { ckstrncpy(szUserNameAuthenticated,princ,UIDBUFLEN); validUser = AUTH_VALID; authentication_version = AUTHTYPE_KERBEROS_V5; if ( !quiet ) printf("Peer name is \"%s\"\n", princ); krb5_free_unparsed_name(k5_context,princ); } return 0; } /* Kerberos 5 User to User Server */ int k5_user_to_user_server_auth() { krb5_data pname_data, tkt_data; int retval; krb5_creds creds, *new_creds; krb5_ccache cc; krb5_data msg, msgtext; extern int ttyfd; if (retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &pname_data)) { com_err ("uu-server", retval, "reading pname"); return(-1); } /* client sends it already null-terminated. */ if ( !quiet ) printf ("Peer name is \"%s\".\n", pname_data.data); ckstrncpy(szUserNameAuthenticated,pname_data.data,UIDBUFLEN); validUser = AUTH_VALID; authentication_version = AUTHTYPE_KERBEROS_V5; if (retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &tkt_data)) { com_err ("uu-server", retval, "reading ticket data"); return(-1); } if (retval = k5_get_ccache(k5_context,&cc,NULL)) { com_err("uu-server", retval, "getting credentials cache"); return(-1); } memset ((char*)&creds, 0, sizeof(creds)); if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client)) { com_err("uu-server", retval, "getting principal name"); return(-1); } if (retval = krb5_parse_name(k5_context, pname_data.data, &creds.server)) { com_err("uu-server", retval, "parsing client name"); return(-1); } creds.second_ticket = tkt_data; if (retval = krb5_get_credentials(k5_context, KRB5_GC_USER_USER, cc, &creds, &new_creds)) { com_err("uu-server", retval, "getting user-user ticket"); return(-1); } /* send a ticket/authenticator to the other side, so it can get the key we're using for the krb_safe below. */ if (retval = krb5_auth_con_init(k5_context, &auth_context)) { com_err("uu-server", retval, "making auth_context"); return(-1); } if (retval = krb5_auth_con_setflags(k5_context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { com_err("uu-server", retval, "initializing the auth_context flags"); return(-1); } if (!krb5_d_no_addresses) { if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) { com_err("uu-server", retval, "generating addrs for auth_context"); return(-1); } } if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context, &new_creds->keyblock)) { com_err("uu-server", retval, "setting useruserkey for authcontext"); return(-1); } if (retval = krb5_mk_req_extended(k5_context, &auth_context, AP_OPTS_USE_SESSION_KEY | AP_OPTS_MUTUAL_REQUIRED, NULL, new_creds, &msg)) { com_err("uu-server", retval, "making AP_REQ"); return(-1); } retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &msg); if (retval) { com_err("uu-server", retval, "writing message to client"); return(-1); } krb5_free_data_contents(k5_context,&msg); msgtext.data = "Kermit implements Kerberos 5 User to User"; msgtext.length = strlen(msgtext.data)+1; if (k5_u2u_write_msg(k5_context,&msgtext) < 0) return(-1); if (k5_u2u_read_msg(k5_context,&msg) < 0) return(-1); if ( strcmp("As do I! :-)",msg.data) ) return(-1); krb5_free_data_contents(k5_context,&msg); return(0); } int k5_u2u_read_msg(krb5_context context, int fd, krb5_data * msg) { int retval; krb5_data reply; retval = krb5_read_message(context, (krb5_pointer) &fd, &reply); if (retval) { com_err("uu-client", retval, "reading reply"); return(-1); } if (retval = krb5_rd_priv(context, auth_context, &reply, msg, NULL)) { com_err("uu-client", retval, "decoding reply"); return(-1); } return(0); } int k5_u2u_write_msg(krb5_context context, int fd, krb5_data * msgtext) { int retval; krb5_data msg; if (retval = krb5_mk_priv(k5_context, auth_context, msgtext, &msg, NULL)) { com_err("uu-server", retval, "encoding message"); return(-1); } retval = krb5_write_message(k5_context, (krb5_pointer) &fd, &msg); krb5_free_data_contents(k5_context,&msg); if (retval) { com_err("uu-server", retval, "writing message"); return(-1); } return(0); } int krb5_u2u_avail(fd) int fd; { return(nstored); } int krb5_u2u_read(fd, buf, len) int fd; register char *buf; int len; { int nreturned = 0; krb5_data msg; debug(F111,"krb5_u2u_read","len",len); if ( !buf ) return(0); if (nstored >= len) { memcpy(buf, store_ptr, len); /* safe */ store_ptr += len; nstored -= len; return(len); } else if (nstored) { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; buf += nstored; len -= nstored; nstored = 0; } if (k5_u2u_read_msg(k5_context, fd, &msg) < 0) return(-1); if ( msg.length <= len ) { memcpy(buf, msg.data, msg.length); nreturned += msg.length; nstored = 0; } else { memcpy(buf, msg.data, len); nreturned += len; if ( msg.length - len < sizeof(storage) ) { store_ptr = storage; nstored = msg.length - len; memcpy(storage,msg.data+len,nstored); } else { nstored = 0; return(-1); } } return(nreturned); } int krb5_u2u_write(fd, buf, len) int fd; char *buf; int len; { krb5_data msg; msg.length = len; msg.data = buf; if ( k5_u2u_write_msg(k5_context, fd, &msg) < 0 ) return(-1); else return(len); } #endif /* KRB5_U2U */ #endif /* CK_KERBEROS */ #ifdef CK_FORWARD_X /* Copyright (c) 1988 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* Modified for stand-alone compiling by * Peter 'Luna' Runestig */ #include #include #include #include #include #define Time_t time_t void XauDisposeAuth (auth) Xauth *auth; { if (auth) { if (auth->address) (void) free (auth->address); if (auth->number) (void) free (auth->number); if (auth->name) (void) free (auth->name); if (auth->data) { (void) bzero (auth->data, auth->data_length); (void) free (auth->data); } free ((char *) auth); } return; } char * XauFileName () { char *slashDotXauthority = "/.Xauthority"; char *name; static char *buf=NULL; static int bsize=0; int size, namelen; extern char * tn_fwdx_xauthority; if ( tn_fwdx_xauthority ) return(tn_fwdx_xauthority); if (name = getenv ("XAUTHORITY")) return(name); name = zhome(); if ( !name ) return(NULL); namelen = strlen (name); size = namelen + strlen(slashDotXauthority) + 1; if (size > bsize) { if (buf) free (buf); buf = malloc ((unsigned) size); if (!buf) return 0; bsize = size; } ckstrncpy (buf, name, bsize); if ( name[namelen-1] != '/' #ifdef OS2 && name[namelen-1] != '\\' #endif /* OS2 */ ) ckstrncat (buf, slashDotXauthority, bsize); else ckstrncat (buf, &slashDotXauthority[1], bsize); return(buf); } static int binaryEqual (a, b, len) register char *a, *b; register int len; { while (len--) if (*a++ != *b++) return 0; return 1; } #ifndef R_OK #define R_OK 04 #endif /* R_OK */ Xauth * XauGetAuthByAddr (family, address_length, address, number_length, number, name_length, name) unsigned int family; unsigned int address_length; const char *address; unsigned int number_length; const char *number; unsigned int name_length; const char *name; { FILE *auth_file; char *auth_name; Xauth *entry; auth_name = XauFileName(); if (!auth_name) return 0; if (access (auth_name, R_OK) != 0) /* checks REAL id */ return 0; auth_file = fopen (auth_name, "rb"); if (!auth_file) return 0; for (;;) { entry = XauReadAuth (auth_file); if (!entry) break; /* * Match when: * either family or entry->family are FamilyWild or * family and entry->family are the same * and * either address or entry->address are empty or * address and entry->address are the same * and * either number or entry->number are empty or * number and entry->number are the same * and * either name or entry->name are empty or * name and entry->name are the same */ /* if ((family == FamilyWild || entry->family == FamilyWild || (entry->family == family && address_length == entry->address_length && binaryEqual (entry->address, address, (int)address_length))) && (number_length == 0 || entry->number_length == 0 || (number_length == entry->number_length && binaryEqual (entry->number, number, (int)number_length))) && (name_length == 0 || entry->name_length == 0 || (entry->name_length == name_length && binaryEqual (entry->name, name, (int)name_length)))) */ /* the original matching code above doesn't seem to meet the matching * algorithm, it doesn't check if "address_length == 0 || * entry->address_length == 0". / Luna 2000-02-09 */ if ((family == FamilyWild || entry->family == FamilyWild || entry->family == family) && (address_length == 0 || entry->address_length == 0 || (address_length == entry->address_length && binaryEqual (entry->address, address, (int)address_length))) && (number_length == 0 || entry->number_length == 0 || (number_length == entry->number_length && binaryEqual (entry->number, number, (int)number_length))) && (name_length == 0 || entry->name_length == 0 || (entry->name_length == name_length && binaryEqual (entry->name, name, (int)name_length)))) break; XauDisposeAuth (entry); } (void) fclose (auth_file); return entry; } static int read_short (shortp, file) unsigned short *shortp; FILE *file; { unsigned char file_short[2]; if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; *shortp = file_short[0] * 256 + file_short[1]; return 1; } static int read_counted_string (countp, stringp, file) unsigned short *countp; char **stringp; FILE *file; { unsigned short len; char *data; if (read_short (&len, file) == 0) return 0; if (len == 0) { data = 0; } else { data = malloc ((unsigned) len); if (!data) return 0; if (fread (data, (int) sizeof (char), (int) len, file) != len) { bzero (data, len); free (data); return 0; } } *stringp = data; *countp = len; return 1; } Xauth * XauReadAuth (auth_file) FILE *auth_file; { Xauth local; Xauth *ret; if (read_short (&local.family, auth_file) == 0) return 0; if (read_counted_string (&local.address_length, &local.address, auth_file) == 0) return 0; if (read_counted_string (&local.number_length, &local.number, auth_file) == 0) { if (local.address) free (local.address); return 0; } if (read_counted_string (&local.name_length, &local.name, auth_file) == 0) { if (local.address) free (local.address); if (local.number) free (local.number); return 0; } if (read_counted_string (&local.data_length, &local.data, auth_file) == 0) { if (local.address) free (local.address); if (local.number) free (local.number); if (local.name) free (local.name); return 0; } ret = (Xauth *) malloc (sizeof (Xauth)); if (!ret) { if (local.address) free (local.address); if (local.number) free (local.number); if (local.name) free (local.name); if (local.data) { bzero (local.data, local.data_length); free (local.data); } return 0; } *ret = local; return ret; } static int write_short (s, file) unsigned short s; FILE *file; { unsigned char file_short[2]; file_short[0] = (s & (unsigned)0xff00) >> 8; file_short[1] = s & 0xff; if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; return 1; } static int write_counted_string (count, string, file) unsigned short count; char *string; FILE *file; { if (write_short (count, file) == 0) return 0; if (fwrite (string, (int) sizeof (char), (int) count, file) != count) return 0; return 1; } int XauWriteAuth (auth_file, auth) FILE *auth_file; Xauth *auth; { if (write_short (auth->family, auth_file) == 0) return 0; if (write_counted_string (auth->address_length, auth->address, auth_file) == 0) return 0; if (write_counted_string (auth->number_length, auth->number, auth_file) == 0) return 0; if (write_counted_string (auth->name_length, auth->name, auth_file) == 0) return 0; if (write_counted_string (auth->data_length, auth->data, auth_file) == 0) return 0; return 1; } #ifdef KRB5 #ifdef K5_XAUTH /* * functions to encode/decode Kerberos V5 principals * into something that can be reasonable spewed over * the wire * * Author: Tom Yu * * Still needs to be fixed up wrt signed/unsigned lengths, but we'll worry * about that later. */ /* * XauKrb5Encode * * this function encodes the principal passed to it in a format that can * easily be dealt with by stuffing it into an X packet. Encoding is as * follows: * length count of the realm name * realm * component count * length of component * actual principal component * etc.... * * Note that this function allocates a hunk of memory, which must be * freed to avoid nasty memory leak type things. All counts are * byte-swapped if needed. (except for the total length returned) * * nevermind.... stuffing the encoded packet in net byte order just to * always do the right thing. Don't have to frob with alignment that way. */ int XauKrb5Encode(princ, outbuf) krb5_principal princ; /* principal to encode */ krb5_data *outbuf; /* output buffer */ { CARD16 i, numparts, totlen = 0, plen, rlen; char *cp, *pdata; rlen = krb5_princ_realm(princ)->length; numparts = krb5_princ_size(princ); totlen = 2 + rlen + 2; /* include room for realm length and component count */ for (i = 0; i < numparts; i++) totlen += krb5_princ_component(princ, i)->length + 2; /* add 2 bytes each time for length */ if ((outbuf->data = (char *)malloc(totlen)) == NULL) return -1; cp = outbuf->data; *cp++ = (char)((int)(0xff00 & rlen) >> 8); *cp++ = (char)(0x00ff & rlen); memcpy(cp, krb5_princ_realm(princ)->data, rlen); /* safe */ cp += rlen; *cp++ = (char)((int)(0xff00 & numparts) >> 8); *cp++ = (char)(0x00ff & numparts); for (i = 0; i < numparts; i++) { plen = krb5_princ_component(princ, i)->length; pdata = krb5_princ_component(princ, i)->data; *cp++ = (char)((int)(0xff00 & plen) >> 8); *cp++ = (char)(0x00ff & plen); memcpy(cp, pdata, plen); /* safe */ cp += plen; } outbuf->length = totlen; return 0; } /* * XauKrb5Decode * * This function essentially reverses what XauKrb5Encode does. * return value: 0 if okay, -1 if malloc fails, -2 if inbuf format bad */ int XauKrb5Decode(inbuf, princ) krb5_data inbuf; krb5_principal *princ; { CARD16 i, numparts, plen, rlen; CARD8 *cp, *pdata; if (inbuf.length < 4) { return -2; } *princ = (krb5_principal)malloc(sizeof (krb5_principal_data)); if (*princ == NULL) return -1; bzero(*princ, sizeof (krb5_principal_data)); cp = (CARD8 *)inbuf.data; rlen = *cp++ << 8; rlen |= *cp++; if (inbuf.length < 4 + (int)rlen + 2) { krb5_free_principal(*princ); return -2; } krb5_princ_realm(*princ)->data = (char *)malloc(rlen); if (krb5_princ_realm(*princ)->data == NULL) { krb5_free_principal(*princ); return -1; } krb5_princ_realm(*princ)->length = rlen; memcpy(krb5_princ_realm(*princ)->data, cp, rlen); /* safe */ cp += rlen; numparts = *cp++ << 8; numparts |= *cp++; krb5_princ_name(*princ) = (krb5_data *)malloc(numparts * sizeof (krb5_data)); if (krb5_princ_name(*princ) == NULL) { krb5_free_principal(*princ); return -1; } krb5_princ_size(*princ) = 0; for (i = 0; i < numparts; i++) { if (cp + 2 > (CARD8 *)inbuf.data + inbuf.length) { krb5_free_principal(*princ); return -2; } plen = *cp++ << 8; plen |= *cp++; if (cp + plen > (CARD8 *)inbuf.data + inbuf.length) { krb5_free_principal(*princ); return -2; } pdata = (CARD8 *)malloc(plen); if (pdata == NULL) { krb5_free_principal(*princ); return -1; } krb5_princ_component(*princ, i)->data = (char *)pdata; krb5_princ_component(*princ, i)->length = plen; memcpy(pdata, cp, plen); /* safe */ cp += plen; krb5_princ_size(*princ)++; } return 0; } #endif /* K5_XAUTH */ #endif /* KRB5 */ #endif /* CK_FORWARD_X */ #endif /* CK_AUTHENTICATION */ /* C K _ A U T H _ I N I T * Initialize the Kerberos system for a pending connection * hostname - a reverse DNS lookup of the hostname when possible * ipaddr - the ip address of the host * username - the name the user wants to connect under not necessarily * the same as principal * socket - the socket handle (ttyfd in Kermit speak) * * Returns: 1 on success and 0 on failure */ int #ifdef CK_ANSIC ck_auth_init( char * hostname, char * ipaddr, char * username, int socket ) #else /* CK_ANSIC */ ck_auth_init( hostname, ipaddr, username, socket ) char * hostname; char * ipaddr; char *username; int socket; #endif /* CK_ANSIC */ { #ifdef CK_AUTHENTICATION #ifdef OS2 if ( !ck_security_loaddll() ) { TELOPT_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; return(0); } #endif /* OS2 */ #endif /* CK_AUTHENTICAITON */ #ifdef CK_ENCRYPTION if ( !!ck_crypt_is_installed() ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ if (!hostname) hostname = ""; if (!ipaddr) ipaddr = ""; if (!username) username = ""; debug(F110,"ck_auth_init Username",username,0); debug(F110,"ck_auth_init Hostname",hostname,0); debug(F110,"ck_auth_init Ipaddr",ipaddr,0); ckstrncpy( szUserName, username, UIDBUFLEN ); ckstrncpy( szHostName, hostname, UIDBUFLEN ); ckstrncpy( szIP, ipaddr, 16 ); szUserNameRequested[0] = '\0'; szUserNameAuthenticated[0] = '\0'; validUser = AUTH_REJECT; accept_complete = 0; authentication_version = AUTHTYPE_NULL; #ifdef CK_AUTHENTICATION auth_how = 0; auth_crypt = 0; auth_fwd = 0; mutual_complete = 0; if ( sstelnet ) str_data[3] = TELQUAL_REPLY; else str_data[3] = TELQUAL_IS; #endif /* CK_AUTHENTICATION */ #ifdef CK_SRP srp_waitresp = 0; #endif /* SRP */ #ifdef CK_KERBEROS #ifdef KRB5 /* free previous ret_cred */ if ( ret_cred ) { #ifdef CK_ENCRYPTION #ifdef HEIMDAL if ( k5_session_key == &ret_cred->session) k5_session_key = NULL; #else /* HEIMDAL */ if ( k5_session_key == &ret_cred->keyblock) k5_session_key = NULL; #endif /* HEIMDAL */ #endif /* CK_ENCRYPTION */ krb5_free_creds(k5_context, ret_cred); ret_cred = NULL; } if (k5_ticket) { krb5_free_ticket(k5_context, k5_ticket); k5_ticket = NULL; } /* and context */ if ( k5_context ) { krb5_free_context(k5_context); k5_context = NULL; } /* create k5_context */ krb5_init_context(&k5_context); #ifndef MIT_CURRENT if (k5_context) krb5_init_ets(k5_context); #endif /* MIT_CURRENT */ #ifdef KRB524_CONV krb524_init_ets(k5_context); #endif /* KRB524_CONV */ memset(&k5_auth,0,sizeof(k5_auth)); if (auth_context) { krb5_auth_con_free(k5_context, auth_context); auth_context = 0; } #ifdef CK_ENCRYPTION if (k5_session_key) { krb5_free_keyblock(k5_context, k5_session_key); k5_session_key = 0; } #endif /* ENCRYPTION */ #ifdef TLS_VERIFY krb5_tls_verified = 0; #endif /* TLS_VERIFY */ #endif /* KRB5 */ #ifdef KRB4 #ifdef CK_ENCRYPTION /* Initialize buffers used for authentication */ memset(&k4_session_key, 0, sizeof(k4_session_key)); memset(&k4_challenge, 0, sizeof(k4_challenge)); #endif /* CK_ENCRYPTION */ #endif /* KRB4 */ #ifdef RLOGCODE rlog_encrypt = 0; #endif /* RLOGCODE */ nstored = 0; store_ptr = storage; memset(storage,0,sizeof(storage)); #endif /* CK_KERBEROS */ #ifdef CK_ENCRYPTION kstream_destroy(); if (!kstream_create_from_fd(socket, NULL)) return(0); #endif /* CK_ENCRYPTION */ return(1); } void auth_finished(result) int result; { extern char uidbuf[]; extern int sstelnet; validUser = result; switch (result) { case AUTH_REJECT: /* Rejected */ if (sstelnet) uidbuf[0] = '\0'; authentication_version = AUTHTYPE_NULL; break; case AUTH_UNKNOWN: /* We don't know who he is, but he's okay */ if (sstelnet) strcpy(uidbuf,"(unknown)"); break; case AUTH_OTHER: /* We know him, but not his name */ if (sstelnet) strcpy(uidbuf,"(other)"); break; case AUTH_USER: /* We know he name */ case AUTH_VALID: /* We know him, and he needs no password */ if (sstelnet) strcpy(uidbuf,szUserNameRequested); break; } } #ifdef MACOSX #ifdef KRB5 krb5_error_code ck_krb5_write_message(krb5_context con, krb5_pointer ptr, krb5_data *data) { int fd = *((int *)ptr); long msglen; msglen = htonl(data->length); if (net_write(fd,(CHAR *)&msglen,4) != 4) { return(-1); } if ( data->length ) { if (net_write(fd,data->data,data->length) != data->length) { return(-1); } } return(0); } krb5_error_code ck_krb5_read_message( krb5_context context, krb5_pointer ptr, krb5_data * data) { extern int ttyfd; int fd = *((int *)ptr); long msglen; char *p; int i, rc; if (net_read(fd,&msglen,4) < 0) return(-1); data->length = ntohl(msglen); if ( data->length ) { data->data = malloc(data->length); i = 0; while ( i < data->length ) { if ((rc = net_read(fd,&data->data[i],(data->length - i))) < 0) return(-1); i += rc; } } return(0); } #endif /* KRB5 */ #endif /* MACOSX */ #endif /* CK_SECURITY */