Mercurial > illumos > illumos-gate
changeset 13144:9615cdbf7b70
PSARC 2010/135 Kerberos Diagnostic Enhancements (umbrella case)
6835328 Error messages generated by applications using RPCSEC_GSS are too vague
line wrap: on
line diff
--- a/usr/src/cmd/gss/gssd/gssd_proc.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/cmd/gss/gssd/gssd_proc.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,3 +1,6 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * CDDL HEADER START * @@ -18,10 +21,6 @@ * * CDDL HEADER END */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ /* * RPC server procedures for the gssapi usermode daemon gssd. @@ -35,7 +34,6 @@ #include <strings.h> #include <limits.h> #include <sys/param.h> -#include <sys/syslog.h> #include <mechglueP.h> #include "gssd.h" #include <gssapi/gssapi.h> @@ -72,6 +70,60 @@ extern void set_gssd_uid(uid_t); extern int __rpc_get_local_uid(SVCXPRT *, uid_t *); +/* + * Syslog (and output to stderr if debug set) the GSSAPI major + * and minor numbers. + */ +static void +syslog_gss_error(OM_uint32 maj_stat, OM_uint32 min_stat, char *errstr) +{ + OM_uint32 gmaj_stat, gmin_stat; + gss_buffer_desc msg; + OM_uint32 msg_ctx = 0; + + + if (gssd_debug) + fprintf(stderr, + "gssd: syslog_gss_err: called from %s: maj=%d min=%d\n", + errstr ? errstr : "<null>", maj_stat, min_stat); + + /* Print the major status error from the mech. */ + /* msg_ctx - skip the check for it as is probably unnecesary */ + gmaj_stat = gss_display_status(&gmin_stat, maj_stat, + GSS_C_GSS_CODE, + GSS_C_NULL_OID, &msg_ctx, &msg); + if ((gmaj_stat == GSS_S_COMPLETE)|| + (gmaj_stat == GSS_S_CONTINUE_NEEDED)) { + syslog(LOG_DAEMON|LOG_NOTICE, + "GSSAPI error major: %s", (char *)msg.value); + if (gssd_debug) + (void) fprintf(stderr, + "gssd: GSSAPI error major: %s\n", + (char *)msg.value); + + (void) gss_release_buffer(&gmin_stat, &msg); + } + + /* Print the minor status error from the mech. */ + msg_ctx = 0; + /* msg_ctx - skip the check for it as is probably unnecesary */ + gmaj_stat = gss_display_status(&gmin_stat, min_stat, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, &msg); + if ((gmaj_stat == GSS_S_COMPLETE)|| + (gmaj_stat == GSS_S_CONTINUE_NEEDED)) { + syslog(LOG_DAEMON|LOG_NOTICE, + "GSSAPI error minor: %s", + (char *)msg.value); + if (gssd_debug) + (void) fprintf(stderr, + "gssd: GSSAPI error minor: %s\n", + (char *)msg.value); + (void) gss_release_buffer(&gmin_stat, &msg); + } +} + void gssd_setup(char *arg) { @@ -490,7 +542,9 @@ gssd_time_verf = (OM_uint32)time(NULL); } res->gssd_cred_verifier = gssd_time_verf; - } + } else + syslog_gss_error(res->status, res->minor_status, + "acquire_cred"); /* * now release the space allocated by the underlying gssapi mechanism @@ -642,10 +696,9 @@ &res->acceptor_time_rec); if ((res->status != GSS_S_COMPLETE) && - (res->status != GSS_S_DUPLICATE_ELEMENT) && - (gssd_debug)) - fprintf(stderr, gettext("gss_add_cred failed status %d \n"), - res->status); + (res->status != GSS_S_DUPLICATE_ELEMENT)) + syslog_gss_error(res->status, res->minor_status, "add_cred"); + /* * convert the output args from the parameter given in the call to the * variable in the XDR result @@ -1014,6 +1067,8 @@ } else res->actual_mech_type.GSS_OID_len = 0; } else { + syslog_gss_error(res->status, res->minor_status, + "init_sec_context"); if (context_handle != GSS_C_NO_CONTEXT) { (void) gss_delete_sec_context(&minor_status, &context_handle, NULL); @@ -1306,6 +1361,9 @@ res->mech_type.GSS_OID_len = 0; } } else { + syslog_gss_error(res->status, res->minor_status, + "accept_sec_context"); + if (context_handle != GSS_C_NO_CONTEXT) { (void) gss_delete_sec_context(&minor_status, &context_handle, NULL); @@ -1377,6 +1435,9 @@ context_handle, &token_buffer); + if (GSS_ERROR(res->status)) + syslog_gss_error(res->status, res->minor_status, + "process_context_token"); /* return to caller */ @@ -1773,7 +1834,8 @@ if (res->status == GSS_S_COMPLETE) { res->msg_token.GSS_BUFFER_T_len = (uint_t)msg_token.length; res->msg_token.GSS_BUFFER_T_val = (char *)msg_token.value; - } + } else + syslog_gss_error(res->status, res->minor_status, "sign"); /* return to caller */ @@ -1837,8 +1899,10 @@ &token_buffer, &res->qop_state); + if (GSS_ERROR(res->status)) + syslog_gss_error(res->status, res->minor_status, "verify"); + /* return to caller */ - return (TRUE); } @@ -1918,7 +1982,8 @@ (uint_t)output_message_buffer.length; res->output_message_buffer.GSS_BUFFER_T_val = (char *)output_message_buffer.value; - } + } else + syslog_gss_error(res->status, res->minor_status, "seal"); /* return to caller */ @@ -1998,7 +2063,8 @@ (uint_t)output_message_buffer.length; res->output_message_buffer.GSS_BUFFER_T_val = (char *)output_message_buffer.value; - } + } else + syslog_gss_error(res->status, res->minor_status, "unseal"); /* return to caller */ @@ -2205,8 +2271,11 @@ &res->cred_usage, &mechanisms); - if (res->status != GSS_S_COMPLETE) + if (res->status != GSS_S_COMPLETE) { + syslog_gss_error(res->status, res->minor_status, + "inquire_cred"); return (TRUE); + } /* convert the returned name from internal to external format */
--- a/usr/src/lib/gss_mechs/mech_krb5/Makefile.com Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/Makefile.com Mon Aug 16 17:01:32 2010 -0700 @@ -171,7 +171,7 @@ util_cksum.o acquire_cred.o init_sec_context.o \ set_ccache.o acquire_cred_with_pw.o lucid_context.o \ set_allowable_enctypes.o oid_ops.o export_name.o gss_libinit.o \ - util_buffer_set.o + util_buffer_set.o util_errmap.o MECH_UTS= delete_sec_context.o gssapi_krb5.o \ import_sec_context.o k5seal.o k5sealv3.o \
--- a/usr/src/lib/gss_mechs/mech_krb5/crypto/make_random_key.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/crypto/make_random_key.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -32,6 +31,7 @@ #include "k5-int.h" #include "etypes.h" +#include <locale.h> krb5_error_code KRB5_CALLCONV krb5_c_make_random_key(krb5_context context, krb5_enctype enctype, @@ -52,7 +52,9 @@ /* Solaris Kerberos: Better error message */ if (i == krb5_enctypes_length) { krb5_set_error_message(context, KRB5_BAD_ENCTYPE, - "Unknown encryption type: %d", enctype); + dgettext(TEXT_DOMAIN, + "Unknown encryption type: %d"), + enctype); return(KRB5_BAD_ENCTYPE); }
--- a/usr/src/lib/gss_mechs/mech_krb5/et/krb5_err.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/et/krb5_err.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <locale.h> @@ -94,10 +93,10 @@ "Requested server and ticket don't match")); case 27: return (dgettext(TEXT_DOMAIN, - "KRB5 error code 27")); + "Server principal valid for user2user only")); case 28: return (dgettext(TEXT_DOMAIN, - "KRB5 error code 28")); + "KDC policy rejects transited path")); case 29: return (dgettext(TEXT_DOMAIN, "A service is not available that is required to " @@ -215,13 +214,13 @@ "Certificate mismatch")); case 67: return (dgettext(TEXT_DOMAIN, - "KRB5 error code 67")); + "No ticket granting ticket")); case 68: return (dgettext(TEXT_DOMAIN, - "KRB5 error code 68")); + "Realm not local to KDC")); case 69: return (dgettext(TEXT_DOMAIN, - "KRB5 error code 69")); + "User to user required")); case 70: return (dgettext(TEXT_DOMAIN, "Can't verify certificate"));
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/ccache/cc_file.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/ccache/cc_file.c Mon Aug 16 17:01:32 2010 -0700 @@ -82,7 +82,7 @@ #include "k5-int.h" #include <syslog.h> /* Solaris Kerberos */ #include <ctype.h> - +#include <locale.h> #include <stdio.h> #include <errno.h> @@ -2548,8 +2548,9 @@ default: retval = KRB5_CC_IO; /* XXX */ krb5_set_error_message(context, retval, - "Credentials cache I/O operation failed (%s)", - strerror(errnum)); + dgettext(TEXT_DOMAIN, + "Credentials cache I/O operation failed (%s)"), + strerror(errnum)); } return retval; }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -32,6 +31,8 @@ #include "k5-int.h" #include <stdio.h> +#include <locale.h> +#include <syslog.h> /* * Information needed by internal routines of the file-based ticket @@ -1097,10 +1098,25 @@ errno = 0; KTFILEP(id) = fopen(KTFILENAME(id), fopen_mode_rbplus); if (!KTFILEP(id)) - return errno ? errno : EMFILE; + goto report_errno; writevno = 1; - } else /* some other error */ - return errno ? errno : EMFILE; + } else { + report_errno: + switch (errno) { + case 0: + /* XXX */ + return EMFILE; + case ENOENT: + krb5_set_error_message(context, ENOENT, + /* Solaris Kerberos - added dgettext */ + dgettext(TEXT_DOMAIN, + "Key table file '%s' not found"), + KTFILENAME(id)); + return ENOENT; + default: + return errno; + } + } } if ((kerror = krb5_lock_file(context, fileno(KTFILEP(id)), mode))) { (void) fclose(KTFILEP(id));
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/fwd_tgt.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/fwd_tgt.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * lib/krb5/krb/get_in_tkt.c * @@ -34,6 +31,7 @@ #ifdef HAVE_MEMORY_H #include <memory.h> #endif +#include <locale.h> /* helper function: convert flags to necessary KDC options */ #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK) @@ -123,7 +121,22 @@ goto errout; /* tgt->client must be equal to creds.client */ - if (!krb5_principal_compare(context, tgt.client, creds.client)) { + if (!krb5_principal_compare(context, tgt.client, creds.client)) { + /* Solaris Kerberos */ + char *r_name = NULL; + char *t_name = NULL; + krb5_error_code r_err, t_err; + t_err = krb5_unparse_name(context, tgt.client, &t_name); + r_err = krb5_unparse_name(context, creds.client, &r_name); + krb5_set_error_message(context, KRB5_PRINC_NOMATCH, + dgettext(TEXT_DOMAIN, + "Requested principal and ticket don't match: Requested principal is '%s' and TGT principal is '%s'"), + r_err ? "unknown" : r_name, + t_err ? "unknown" : t_name); + if (r_name) + krb5_free_unparsed_name(context, r_name); + if (t_name) + krb5_free_unparsed_name(context, t_name); retval = KRB5_PRINC_NOMATCH; goto errout; }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/gc_frm_kdc.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/gc_frm_kdc.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright (c) 1994,2003,2005 by the Massachusetts Institute of Technology. * Copyright (c) 1994 CyberSAFE Corporation @@ -40,6 +37,7 @@ #include "k5-int.h" #include <stdio.h> #include "int-proto.h" +#include <locale.h> struct tr_state; @@ -145,12 +143,6 @@ #define HARD_CC_ERR(r) ((r) && (r) != KRB5_CC_NOTFOUND && \ (r) != KRB5_CC_NOT_KTYPE) -#define IS_TGS_PRINC(c, p) \ - ((krb5_princ_size((c), (p)) == 2) && \ - (krb5_princ_component((c), (p), 0)->length == \ - KRB5_TGS_NAME_SIZE) && \ - (!memcmp(krb5_princ_component((c), (p), 0)->data, \ - KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE))) /* * Flags for ccache lookups of cross-realm TGTs. @@ -475,9 +467,22 @@ * fetched TGT in ts->kdc_tgts. See changes in try_kdc() */ /* assert(ts->nxt_tgt == ts->kdc_tgts[ts->ntgts-1]); */ - if (krb5_princ_size(ts->ctx, ts->nxt_tgt->server) != 2) + if (krb5_princ_size(ts->ctx, ts->nxt_tgt->server) != 2) { + /* Solaris Kerberos */ + char *s_name = NULL; + int err = krb5_unparse_name(ts->ctx, ts->nxt_tgt->server, &s_name); + if (!err) { + krb5_set_error_message(ts->ctx, KRB5_KDCREP_MODIFIED, + dgettext(TEXT_DOMAIN, + "KDC reply did not match expectations: server '%s' principal size should be 2"), + s_name); + krb5_free_unparsed_name(ts->ctx, s_name); + } else + krb5_set_error_message(ts->ctx, KRB5_KDCREP_MODIFIED, + dgettext(TEXT_DOMAIN, + "KDC reply did not match expectations: server principal size should be 2")); return KRB5_KDCREP_MODIFIED; - + } r1 = krb5_princ_component(ts->ctx, ts->nxt_tgt->server, 1); for (kdcptr = ts->cur_kdc + 1; *kdcptr != NULL; kdcptr++) { @@ -507,6 +512,9 @@ ts->kdc_tgts[ts->ntgts] = NULL; } TR_DBG_RET(ts, "find_nxt_kdc", KRB5_KDCREP_MODIFIED); + krb5_set_error_message(ts->ctx, KRB5_KDCREP_MODIFIED, + dgettext(TEXT_DOMAIN, + "KDC reply did not match expectation: KDC not found. Probably got an unexpected realm referral")); return KRB5_KDCREP_MODIFIED; } ts->nxt_kdc = kdcptr; @@ -1121,6 +1129,22 @@ * in a <type>/<host> format that * krb5_get_fallback_host_realm can deal with. */ + /* Solaris Kerberos */ + char *s_name = NULL; + char *c_name = NULL; + krb5_error_code s_err, c_err; + s_err = krb5_unparse_name(context, server, &s_name); + c_err = krb5_unparse_name(context, client, &c_name); + krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, + dgettext(TEXT_DOMAIN, + "Cannot determine realm for host: Referral specified but no fallback realm available. Client is '%s' and Server is '%s'"), + c_err ? "unknown" : c_name, + s_err ? "unknown" : s_name); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + DPRINTF(("gc_from_kdc: referral specified " "but no fallback realm avaiable!\n")); return KRB5_ERR_HOST_REALM_UNKNOWN;
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/gc_via_tkt.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/gc_via_tkt.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,3 +1,6 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * lib/krb5/krb/gc_via_tgt.c * @@ -30,15 +33,8 @@ #include "k5-int.h" #include "int-proto.h" - -#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew) - -#define IS_TGS_PRINC(c, p) \ - ((krb5_princ_size((c), (p)) == 2) && \ - (krb5_princ_component((c), (p), 0)->length == \ - KRB5_TGS_NAME_SIZE) && \ - (!memcmp(krb5_princ_component((c), (p), 0)->data, \ - KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE))) +#include <locale.h> +#include <ctype.h> static krb5_error_code krb5_kdcrep2creds(krb5_context context, krb5_kdc_rep *pkdcrep, krb5_address *const *address, krb5_data *psectkt, krb5_creds **ppcreds) @@ -166,6 +162,7 @@ krb5_error *err_reply; krb5_response tgsrep; krb5_enctype *enctypes = 0; + char *hostname_used = NULL; #ifdef DEBUG_REFERRALS printf("krb5_get_cred_via_tkt starting; referral flag is %s\n", kdcoptions&KDC_OPT_CANONICALIZE?"on":"off"); @@ -174,8 +171,24 @@ #endif /* tkt->client must be equal to in_cred->client */ - if (!krb5_principal_compare(context, tkt->client, in_cred->client)) + if (!krb5_principal_compare(context, tkt->client, in_cred->client)) { + /* Solaris Kerberos */ + char *r_name = NULL; + char *t_name = NULL; + krb5_error_code r_err, t_err; + t_err = krb5_unparse_name(context, tkt->client, &t_name); + r_err = krb5_unparse_name(context, in_cred->client, &r_name); + krb5_set_error_message(context, KRB5_PRINC_NOMATCH, + dgettext(TEXT_DOMAIN, + "Requested principal and ticket don't match: Requested principal is '%s' and ticket is '%s'"), + r_err ? "unknown" : r_name, + t_err ? "unknown" : t_name); + if (r_name) + krb5_free_unparsed_name(context, r_name); + if (t_name) + krb5_free_unparsed_name(context, t_name); return KRB5_PRINC_NOMATCH; + } if (!tkt->ticket.length) return KRB5_NO_TKT_SUPPLIED; @@ -212,12 +225,12 @@ enctypes[1] = 0; } - retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, enctypes, + retval = krb5_send_tgs2(context, kdcoptions, &in_cred->times, enctypes, in_cred->server, address, in_cred->authdata, 0, /* no padata */ (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ? &in_cred->second_ticket : NULL, - tkt, &tgsrep); + tkt, &tgsrep, &hostname_used); if (enctypes) free(enctypes); if (retval) { @@ -249,9 +262,101 @@ switch (err_reply->error) { case KRB_ERR_GENERIC: krb5_set_error_message(context, retval, - "KDC returned error string: %s", - err_reply->text.data); + /* Solaris Kerberos - added dgettext */ + dgettext(TEXT_DOMAIN, + "KDC returned error string: %s"), + err_reply->text.data); break; + case KDC_ERR_S_PRINCIPAL_UNKNOWN: + { + char *s_name; + if (krb5_unparse_name(context, in_cred->server, &s_name) == +0) { + /* Solaris Kerberos - added dgettext */ + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "Server %s not found in Kerberos database"), + s_name); + krb5_free_unparsed_name(context, s_name); + } else + /* In case there's a stale S_PRINCIPAL_UNKNOWN + report already noted. */ + krb5_clear_error_message(context); + } + break; + + case KRB_AP_ERR_SKEW: + /* Solaris Kerberos */ + { + char *s_name = NULL; + char *c_name = NULL; + char stimestring[17]; + char ctimestring[17]; + char fill = ' '; + int st_err, ct_err, serr, cerr; + + st_err = krb5_timestamp_to_sfstring(err_reply->stime, + stimestring, + sizeof (stimestring), + &fill); + ct_err = krb5_timestamp_to_sfstring(err_reply->ctime, + ctimestring, + sizeof (ctimestring), + &fill); + serr = krb5_unparse_name(context, in_cred->server, &s_name); + cerr = krb5_unparse_name(context, in_cred->client, &c_name); + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "Clock skew too great: '%s' requesting ticket '%s' from KDC '%s' (%s). Skew is %dm."), + cerr == 0 ? c_name : "unknown", + serr == 0 ? s_name : "unknown", + hostname_used ? + hostname_used : "host unknown", + st_err == 0 ? stimestring : "unknown", + (ct_err||st_err) ? 0 : + abs(err_reply->stime - + err_reply->ctime) / 60); + + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + } + break; + case KRB_AP_ERR_TKT_NYV: + /* Solaris Kerberos */ + { + char *s_name = NULL; + char *c_name = NULL; + char timestring[17]; + char stimestring[17]; + char fill = ' '; + krb5_error_code t_err, st_err, cerr, serr; + + t_err = krb5_timestamp_to_sfstring(tkt->times.starttime, + timestring, + sizeof (timestring), + &fill); + st_err = krb5_timestamp_to_sfstring(err_reply->stime, + stimestring, + sizeof (stimestring), + &fill); + serr = krb5_unparse_name(context, in_cred->server, &s_name); + cerr = krb5_unparse_name(context, in_cred->client, &c_name); + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "Ticket not yet valid: '%s' requesting ticket '%s' from '%s' (%s). TGT start time is %s"), + cerr ? "unknown" : c_name, + serr ? "unknown" : s_name, + hostname_used ? hostname_used : "host unknown", + st_err ? "unknown" : stimestring, + t_err ? "unknown" : timestring); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + } + break; default: #if 0 /* We should stop the KDC from sending back this text, because if the local language doesn't match the KDC's language, we'd @@ -264,8 +369,10 @@ if (strlen (m) == err_reply->text.length-1 && !strcmp(m, err_reply->text.data)) break; + /* Solaris Kerberos - added dgettext */ krb5_set_error_message(context, retval, - "%s (KDC supplied additional data: %s)", + dgettext(TEXT_DOMAIN, + "%s (KDC supplied additional data: %s)"), m, err_reply->text.data); #endif break; @@ -336,6 +443,8 @@ krb5_free_kdc_rep(context, dec_rep); error_4:; + if (hostname_used) + free(hostname_used); free(tgsrep.response.data); #ifdef DEBUG_REFERRALS printf("krb5_get_cred_via_tkt ending; %s\n", retval?error_message(retval):"no error");
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - - + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * lib/krb5/krb/get_in_tkt.c * @@ -34,10 +30,12 @@ */ #include <string.h> - +#include <ctype.h> #include "k5-int.h" #include "int-proto.h" #include "os-proto.h" +#include <locale.h> +#include <syslog.h> /* All-purpose initial ticket routine, usually called via @@ -114,11 +112,13 @@ * unexpected response, an error is returned. */ static krb5_error_code -send_as_request(krb5_context context, +send_as_request2(krb5_context context, krb5_kdc_req *request, krb5_error ** ret_err_reply, krb5_kdc_rep ** ret_as_reply, - int *use_master) + int *use_master, + char **hostname_used) + { krb5_kdc_rep *as_reply = 0; krb5_error_code retval; @@ -143,9 +143,9 @@ k4_version = packet->data[0]; send_again: - retval = krb5_sendto_kdc(context, packet, - krb5_princ_realm(context, request->client), - &reply, use_master, tcp_only); + retval = krb5_sendto_kdc2(context, packet, + krb5_princ_realm(context, request->client), + &reply, use_master, tcp_only, hostname_used); if (retval) goto cleanup; @@ -167,8 +167,10 @@ goto send_again; } *ret_err_reply = err_reply; - } else + } else { krb5_free_error(context, err_reply); + err_reply = NULL; + } goto cleanup; } @@ -223,6 +225,21 @@ } static krb5_error_code +send_as_request(krb5_context context, + krb5_kdc_req *request, + krb5_error ** ret_err_reply, + krb5_kdc_rep ** ret_as_reply, + int *use_master) +{ + return send_as_request2(context, + request, + ret_err_reply, + ret_as_reply, + use_master, + NULL); +} + +static krb5_error_code decrypt_as_reply(krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *as_reply, @@ -520,9 +537,26 @@ int loopcount = 0; krb5_int32 do_more = 0; int use_master = 0; + char *hostname_used = NULL; - if (! krb5_realm_compare(context, creds->client, creds->server)) + if (! krb5_realm_compare(context, creds->client, creds->server)) { + /* Solaris Kerberos */ + char *s_name = NULL; + char *c_name = NULL; + krb5_error_code serr, cerr; + serr = krb5_unparse_name(context, creds->server, &s_name); + cerr = krb5_unparse_name(context, creds->client, &c_name); + krb5_set_error_message(context, KRB5_IN_TKT_REALM_MISMATCH, + dgettext(TEXT_DOMAIN, + "Client/server realm mismatch in initial ticket request: '%s' requesting ticket '%s'"), + cerr ? "unknown" : c_name, + serr ? "unknown" : s_name); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); return KRB5_IN_TKT_REALM_MISMATCH; + } if (ret_as_reply) *ret_as_reply = 0; @@ -599,6 +633,24 @@ while (1) { if (loopcount++ > MAX_IN_TKT_LOOPS) { retval = KRB5_GET_IN_TKT_LOOP; + /* Solaris Kerberos */ + { + char *s_name = NULL; + char *c_name = NULL; + krb5_error_code serr, cerr; + serr = krb5_unparse_name(context, creds->server, &s_name); + cerr = krb5_unparse_name(context, creds->client, &c_name); + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "Looping detected getting ticket: '%s' requesting ticket '%s'. Max loops is %d. Make sure a KDC is available"), + cerr ? "unknown" : c_name, + serr ? "unknown" : s_name, + MAX_IN_TKT_LOOPS); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + } goto cleanup; } @@ -621,8 +673,9 @@ */ request.nonce = (krb5_int32) time_now; - if ((retval = send_as_request(context, &request, &err_reply, - &as_reply, &use_master))) + if ((retval = send_as_request2(context, &request, &err_reply, + &as_reply, &use_master, + &hostname_used))) goto cleanup; if (err_reply) { @@ -631,6 +684,7 @@ retval = decode_krb5_padata_sequence(&err_reply->e_data, &preauth_to_use); krb5_free_error(context, err_reply); + err_reply = NULL; if (retval) goto cleanup; retval = sort_krb5_padata_sequence(context, @@ -643,6 +697,7 @@ retval = (krb5_error_code) err_reply->error + ERROR_TABLE_BASE_krb5; krb5_free_error(context, err_reply); + err_reply = NULL; goto cleanup; } } else if (!as_reply) { @@ -690,6 +745,9 @@ else krb5_free_kdc_rep(context, as_reply); } + if (hostname_used) + free(hostname_used); + return (retval); } @@ -894,6 +952,24 @@ return 0; } +/* + * Solaris Kerberos + * Return 1 if any char in string is lower-case. + */ +static int +is_lower_case(char *s) +{ + if (!s) + return 0; + + while (*s) { + if (islower((int)*s)) + return 1; + s++; + } + return 0; +} + krb5_error_code KRB5_CALLCONV krb5_get_init_creds(krb5_context context, krb5_creds *creds, @@ -920,11 +996,12 @@ krb5_data salt; krb5_data s2kparams; krb5_keyblock as_key; - krb5_error *err_reply; + krb5_error *err_reply = NULL; krb5_kdc_rep *local_as_reply; krb5_timestamp time_now; krb5_enctype etype = 0; krb5_preauth_client_rock get_data_rock; + char *hostname_used = NULL; /* initialize everything which will be freed at cleanup */ @@ -944,9 +1021,7 @@ (void) memset(&as_key, 0, sizeof(as_key)); - local_as_reply = 0; - - err_reply = NULL; + local_as_reply = 0; /* * Set up the basic request structure @@ -1221,10 +1296,11 @@ if (ret) goto cleanup; - err_reply = 0; + err_reply = NULL; local_as_reply = 0; - if ((ret = send_as_request(context, &request, &err_reply, - &local_as_reply, use_master))) + if ((ret = send_as_request2(context, &request, &err_reply, + &local_as_reply, use_master, + &hostname_used))) goto cleanup; if (err_reply) { @@ -1237,8 +1313,8 @@ } ret = decode_krb5_padata_sequence(&err_reply->e_data, &preauth_to_use); - krb5_free_error(context, err_reply); - err_reply = NULL; + krb5_free_error(context, err_reply); + err_reply = NULL; if (ret) goto cleanup; ret = sort_krb5_padata_sequence(context, @@ -1254,7 +1330,6 @@ /* error + no hints = give up */ ret = (krb5_error_code) err_reply->error + ERROR_TABLE_BASE_krb5; - krb5_free_error(context, err_reply); goto cleanup; } } @@ -1268,6 +1343,24 @@ if (loopcount == MAX_IN_TKT_LOOPS) { ret = KRB5_GET_IN_TKT_LOOP; + /* Solaris Kerberos */ + { + char *s_name = NULL; + char *c_name = NULL; + krb5_error_code serr, cerr; + serr = krb5_unparse_name(context, creds->server, &s_name); + cerr = krb5_unparse_name(context, creds->client, &c_name); + krb5_set_error_message(context, ret, + dgettext(TEXT_DOMAIN, + "Looping detected getting initial creds: '%s' requesting ticket '%s'. Max loops is %d. Make sure a KDC is available"), + cerr ? "unknown" : c_name, + serr ? "unknown" : s_name, + MAX_IN_TKT_LOOPS); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + } goto cleanup; } @@ -1340,6 +1433,95 @@ ret = 0; cleanup: + if (ret != 0) { + char *client_name = NULL; + /* See if we can produce a more detailed error message. */ + switch (ret) { + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + if (krb5_unparse_name(context, client, &client_name) == 0) { + krb5_set_error_message(context, ret, + dgettext(TEXT_DOMAIN, + "Client '%s' not found in Kerberos database"), + client_name); + free(client_name); + } + break; + /* Solaris Kerberos: spruce-up the err msg */ + case KRB5_PREAUTH_FAILED: + case KRB5KDC_ERR_PREAUTH_FAILED: + if (krb5_unparse_name(context, client, &client_name) == 0) { + krb5_set_error_message(context, ret, + dgettext(TEXT_DOMAIN, + "Client '%s' pre-authentication failed"), + client_name); + free(client_name); + } + break; + /* Solaris Kerberos: spruce-up the err msg */ + case KRB5KRB_AP_ERR_SKEW: /* KRB_AP_ERR_SKEW + ERROR_TABLE_BASE_krb5 */ + { + char *s_name = NULL; + char *c_name = NULL; + char stimestring[17]; + char fill = ' '; + krb5_error_code c_err, s_err, s_time; + + s_err = krb5_unparse_name(context, + err_reply->server, &s_name); + s_time = krb5_timestamp_to_sfstring(err_reply->stime, + stimestring, + sizeof (stimestring), + &fill); + c_err = krb5_unparse_name(context, client, &c_name); + krb5_set_error_message(context, ret, + dgettext(TEXT_DOMAIN, + "Clock skew too great: '%s' requesting ticket '%s' from KDC '%s' (%s). Skew is %dm"), + c_err == 0 ? c_name : "unknown", + s_err == 0 ? s_name : "unknown", + hostname_used ? hostname_used : "unknown", + s_time == 0 ? stimestring : "unknown", + (s_time != 0) ? 0 : + (abs(err_reply->stime - time_now) / 60)); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + } + break; + case KRB5_KDCREP_MODIFIED: + if (krb5_unparse_name(context, client, &client_name) == 0) { + /* + * Solaris Kerberos + * Extra err msg for common(?) case of + * 'kinit user@lower-case-def-realm'. + * DNS SRV recs will match (case insensitive) and trigger sendto + * KDC and result in this error (at least w/MSFT AD KDC). + */ + char *realm = strpbrk(client_name, "@"); + int set = 0; + if (realm++) { + if (realm && realm[0] && is_lower_case(realm)) { + krb5_set_error_message(context, ret, + dgettext(TEXT_DOMAIN, + "KDC reply did not match expectations for client '%s': lower-case detected in realm '%s'"), + client_name, realm); + set = 1; + } + } + if (!set) + krb5_set_error_message(context, ret, + dgettext(TEXT_DOMAIN, + "KDC reply did not match expectations for client '%s'"), + client_name); + free(client_name); + } + break; + default: + break; + } + } + if (err_reply) + krb5_free_error(context, err_reply); krb5_preauth_request_context_fini(context); if (encoded_previous_request != NULL) { krb5_free_data(context, encoded_previous_request); @@ -1374,6 +1556,7 @@ *as_reply = local_as_reply; else if (local_as_reply) krb5_free_kdc_rep(context, local_as_reply); - + if (hostname_used) + free(hostname_used); return(ret); }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/gic_pwd.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/gic_pwd.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,8 +1,5 @@ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #include "k5-int.h" #include "com_err.h" @@ -179,6 +176,7 @@ char admin_realm[1024], *cpw_service=NULL, *princ_str=NULL; kadm5_config_params params; void *server_handle; + const char *err_msg_1 = NULL; use_master = 0; as_reply = NULL; @@ -212,7 +210,6 @@ start_time, in_tkt_service, opte, krb5_get_as_key_password, (void *) &pw0, &use_master, &as_reply); - /* check for success */ if (ret == 0) @@ -224,7 +221,7 @@ if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_PREAUTH_FAILED) || (ret == KRB5_LIBOS_PWDINTR) || - (ret == KRB5_REALM_CANT_RESOLVE)) + (ret == KRB5_REALM_CANT_RESOLVE)) goto cleanup; /* if the reply did not come from the master kdc, try again with @@ -237,6 +234,9 @@ krb5_free_kdc_rep( context, as_reply); as_reply = NULL; } + + err_msg_1 = krb5_get_error_message(context, ret); + ret2 = krb5_get_init_creds(context, creds, client, prompter, data, start_time, in_tkt_service, opte, krb5_get_as_key_password, (void *) &pw0, @@ -250,12 +250,17 @@ /* if the master is unreachable, return the error from the slave we were able to contact or reset the use_master flag */ - if ((ret2 != KRB5_KDC_UNREACH) && - (ret2 != KRB5_REALM_CANT_RESOLVE) && - (ret2 != KRB5_REALM_UNKNOWN)) - ret = ret2; - else - use_master = 0; + if ((ret2 != KRB5_KDC_UNREACH) && + (ret2 != KRB5_REALM_CANT_RESOLVE) && + (ret2 != KRB5_REALM_UNKNOWN)) { + ret = ret2; + } else { + use_master = 0; + /* Solaris - if 2nd try failed, reset 1st err msg */ + if (ret2 && err_msg_1) { + krb5_set_error_message(context, ret, err_msg_1); + } + } } /* Solaris Kerberos: 163 resync */ @@ -409,6 +414,9 @@ &use_master, &as_reply); cleanup: + if (err_msg_1) + free((void *)err_msg_1); + krb5int_set_prompt_types(context, 0); /* if getting the password was successful, then check to see if the password is about to expire, and warn if so */
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/int-proto.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/int-proto.h Mon Aug 16 17:01:32 2010 -0700 @@ -54,5 +54,11 @@ const char *attr, const char *value); +#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew) + +#define IS_TGS_PRINC(c, p) \ + (krb5_princ_size((c), (p)) == 2 && \ + data_eq_string(*krb5_princ_component((c), (p), 0), KRB5_TGS_NAME)) + #endif /* KRB5_INT_FUNC_PROTO__ */
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/pac.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/pac.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * lib/krb5/krb/pac.c @@ -189,6 +188,10 @@ /* Check there isn't already a buffer of this type */ if (k5_pac_locate_buffer(context, pac, type, NULL) == 0) { + /* Solaris Kerberos */ + krb5_set_error_message(context, EINVAL, + "Duplicate PAC buffer of type %d", + type); return EINVAL; } @@ -284,20 +287,35 @@ PAC_INFO_BUFFER *buffer = NULL; size_t i; - if (pac == NULL) + if (pac == NULL) { + /* Solaris Kerberos */ + krb5_set_error_message(context, EINVAL, + "Invalid argument 'pac' is NULL"); return EINVAL; + } for (i = 0; i < pac->pac->cBuffers; i++) { if (pac->pac->Buffers[i].ulType == type) { if (buffer == NULL) buffer = &pac->pac->Buffers[i]; - else + else { + /* Solaris Kerberos */ + krb5_set_error_message(context, EINVAL, + "Invalid buffer found looping thru PAC buffers (type=%d, i=%d)", + type, i); return EINVAL; + } } } - if (buffer == NULL) + if (buffer == NULL) { + /* Solaris Kerberos */ + krb5_set_error_message(context, ENOENT, + "No PAC buffer found (type=%d)", + type); + return ENOENT; + } assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length); @@ -410,20 +428,35 @@ *ppac = NULL; - if (len < PACTYPE_LENGTH) + if (len < PACTYPE_LENGTH) { + /* Solaris Kerberos */ + krb5_set_error_message(context, ERANGE, + "PAC type length is out of range (len=%d)", + len); return ERANGE; + } cbuffers = load_32_le(p); p += 4; version = load_32_le(p); p += 4; - if (version != 0) + if (version != 0) { + /* Solaris Kerberos */ + krb5_set_error_message(context, EINVAL, + "Invalid PAC version is %d, should be 0", + version); return EINVAL; + } header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH); - if (len < header_len) + if (len < header_len) { + /* Solaris Kerberos */ + krb5_set_error_message(context, ERANGE, + "PAC header len (%d) out of range", + len); return ERANGE; + } ret = krb5_pac_init(context, &pac); if (ret != 0) @@ -451,11 +484,17 @@ if (buffer->Offset % PAC_ALIGNMENT) { krb5_pac_free(context, pac); + /* Solaris Kerberos */ + krb5_set_error_message(context, EINVAL, + "PAC buffer offset mis-aligned"); return EINVAL; } if (buffer->Offset < header_len || buffer->Offset + buffer->cbBufferSize > len) { krb5_pac_free(context, pac); + /* Solaris Kerberos */ + krb5_set_error_message(context, ERANGE, + "PAC offset is out of range"); return ERANGE; } } @@ -475,7 +514,7 @@ } static krb5_error_code -k5_time_to_seconds_since_1970(krb5_int64 ntTime, krb5_timestamp *elapsedSeconds) +k5_time_to_seconds_since_1970(krb5_context context, krb5_int64 ntTime, krb5_timestamp *elapsedSeconds) { krb5_ui_8 abstime; @@ -483,8 +522,9 @@ abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime; - if (abstime > KRB5_INT32_MAX) + if (abstime > KRB5_INT32_MAX) { return ERANGE; + } *elapsedSeconds = abstime; @@ -523,8 +563,13 @@ if (ret != 0) return ret; - if (client_info.length < PAC_CLIENT_INFO_LENGTH) + if (client_info.length < PAC_CLIENT_INFO_LENGTH) { + /* Solaris Kerberos */ + krb5_set_error_message(context, ERANGE, + "PAC client info length out of range", + client_info.length); return ERANGE; + } p = (unsigned char *)client_info.data; pac_nt_authtime = load_64_le(p); @@ -532,13 +577,17 @@ pac_princname_length = load_16_le(p); p += 2; - ret = k5_time_to_seconds_since_1970(pac_nt_authtime, &pac_authtime); + ret = k5_time_to_seconds_since_1970(context, pac_nt_authtime, &pac_authtime); if (ret != 0) return ret; if (client_info.length < PAC_CLIENT_INFO_LENGTH + pac_princname_length || - pac_princname_length % 2) + pac_princname_length % 2) { + /* Solaris Kerberos */ + krb5_set_error_message(context, ERANGE, + "PAC client info length is out of range"); return ERANGE; + } ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, &pac_princname, NULL); if (ret != 0) @@ -550,12 +599,42 @@ return ret; } - free(pac_princname); - if (pac_authtime != authtime || - krb5_principal_compare(context, pac_principal, principal) == FALSE) + if (pac_authtime != authtime) { + /* Solaris Kerberos */ + char timestring[17]; + char pac_timestring[17]; + char fill = ' '; + int err, pac_err; + /* Need better ret code here but don't see one */ ret = KRB5KRB_AP_WRONG_PRINC; + err = krb5_timestamp_to_sfstring(pac_authtime, + timestring, + sizeof (timestring), &fill); + pac_err = krb5_timestamp_to_sfstring(pac_authtime, + pac_timestring, + sizeof (pac_timestring), &fill); + if (pac_princname && !err && !pac_err) { + krb5_set_error_message(context, ret, + "PAC verify fail: PAC authtime '%s' does not match authtime '%s'. PAC principal is '%s'", + pac_timestring, timestring, pac_princname); + } + } else if (krb5_principal_compare(context, pac_principal, principal) == FALSE) { + /* Solaris Kerberos */ + char *p_name = NULL; + krb5_error_code perr; + ret = KRB5KRB_AP_WRONG_PRINC; + perr = krb5_unparse_name(context, principal, &p_name); + if (pac_princname && !perr) { + krb5_set_error_message(context, ret, + "Wrong principal in request: PAC verify: Principal in PAC is '%s' and does not match '%s'", + pac_princname, p_name); + } + if (p_name) + krb5_free_unparsed_name(context, p_name); + } + free(pac_princname); krb5_free_principal(context, pac_principal); return ret; @@ -580,14 +659,21 @@ } } - if (buffer == NULL) + if (buffer == NULL) { + /* Solaris Kerberos */ + krb5_set_error_message(context, ENOENT, + "No PAC buffer found (type=%d)", + type); return ENOENT; + } - if (buffer->Offset + buffer->cbBufferSize > pac->data.length) + if (buffer->Offset + buffer->cbBufferSize > pac->data.length) { return ERANGE; + } - if (buffer->cbBufferSize < PAC_SIGNATURE_DATA_LENGTH) + if (buffer->cbBufferSize < PAC_SIGNATURE_DATA_LENGTH) { return KRB5_BAD_MSIZE; + } /* Zero out the data portion of the checksum only */ memset(data->data + buffer->Offset + PAC_SIGNATURE_DATA_LENGTH, @@ -613,8 +699,9 @@ if (ret != 0) return ret; - if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH) + if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH) { return KRB5_BAD_MSIZE; + } p = (krb5_octet *)checksum_data.data; checksum.checksum_type = load_32_le(p); @@ -648,8 +735,12 @@ return ret; } - if (valid == FALSE) + if (valid == FALSE) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + /* Solaris Kerberos */ + krb5_set_error_message(context, ret, + "Decrypt integrity check failed for PAC"); + } free(pac_data.data); /* SUNW17PACresync - mem leak fix */ return ret; @@ -670,15 +761,17 @@ if (ret != 0) return ret; - if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH) + if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH) { return KRB5_BAD_MSIZE; + } ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_checksum); if (ret != 0) return ret; - if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH) + if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH) { return KRB5_BAD_MSIZE; + } p = (krb5_octet *)privsvr_checksum.data; checksum.checksum_type = load_32_le(p); @@ -693,8 +786,12 @@ if (ret != 0) return ret; - if (valid == FALSE) + if (valid == FALSE) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + /* Solaris Kerberos */ + krb5_set_error_message(context, ret, + "Decrypt integrity check failed for PAC"); + } return ret; } @@ -709,8 +806,9 @@ { krb5_error_code ret; - if (server == NULL) + if (server == NULL) { return EINVAL; + } ret = k5_pac_verify_server_checksum(context, pac, server); if (ret != 0) @@ -812,8 +910,9 @@ ret = k5_pac_locate_buffer(context, pac, type, &cksumdata); if (ret == 0) { /* If we're resigning PAC, make sure we can fit checksum into existing buffer */ - if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len) + if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len) { return ERANGE; + } memset(cksumdata.data, 0, cksumdata.length); } else { @@ -866,8 +965,9 @@ if (buffer->Offset % PAC_ALIGNMENT || buffer->Offset + buffer->cbBufferSize > pac->data.length || - buffer->Offset < header_len) + buffer->Offset < header_len) { return ERANGE; + } } return 0;
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,7 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - #include "k5-int.h" #include "cleanup.h" #include "auth_con.h" @@ -167,7 +165,6 @@ /*----------------------- krb5_rd_cred -----------------------*/ -#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) /* * This functions takes as input an KRB_CRED message, validates it, and @@ -195,30 +192,25 @@ return KRB5_RC_REQUIRED; -/* If decrypting with the first keyblock we try fails, perhaps the - * credentials are stored in the session key so try decrypting with + /* + * If decrypting with the first keyblock we try fails, perhaps the + * credentials are stored in the session key so try decrypting with * that. -*/ + */ if ((retval = krb5_rd_cred_basic(context, pcreddata, keyblock, &replaydata, pppcreds))) { if ((retval = krb5_rd_cred_basic(context, pcreddata, auth_context->keyblock, &replaydata, pppcreds))) { return retval; - } + } } if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_donot_replay replay; - krb5_timestamp currenttime; - if ((retval = krb5_timeofday(context, ¤ttime))) - goto error; - - if (!in_clock_skew(replaydata.timestamp)) { - retval = KRB5KRB_AP_ERR_SKEW; - goto error; - } + if ((retval = krb5int_check_clockskew(context, replaydata.timestamp))) + goto error; if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, "_forw", &replay.client)))
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_priv.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_priv.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * lib/krb5/krb/rd_priv.c * @@ -37,7 +34,6 @@ #include "cleanup.h" #include "auth_con.h" -#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) /* @@ -228,16 +224,10 @@ if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_donot_replay replay; - krb5_timestamp currenttime; - if ((retval = krb5_timeofday(context, ¤ttime))) + if ((retval = krb5int_check_clockskew(context, replaydata.timestamp))) goto error; - if (!in_clock_skew(replaydata.timestamp)) { - retval = KRB5KRB_AP_ERR_SKEW; - goto error; - } - if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, "_priv", &replay.client))) goto error;
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_req_dec.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_req_dec.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * lib/krb5/krb/rd_req_dec.c * @@ -37,6 +34,8 @@ #include "k5-int.h" #include "auth_con.h" +#include <locale.h> +#include <syslog.h> /* * essentially the same as krb_rd_req, but uses a decoded AP_REQ as @@ -69,7 +68,6 @@ (krb5_context, const krb5_ap_req *, krb5_authenticator **, int); -#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) static krb5_error_code krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, krb5_keytab keytab) @@ -77,7 +75,7 @@ krb5_error_code retval; krb5_enctype enctype; krb5_keytab_entry ktent; - + enctype = req->ticket->enc_part.enctype; /* Solaris Kerberos: */ @@ -99,10 +97,51 @@ retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket); /* Upon error, Free keytab entry first, then return */ + if (retval == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + /* Solaris Kerberos: spruce-up the err msg */ + krb5_principal princ = (krb5_principal) req->ticket->server; + char *s_name = NULL; + int kret = krb5_unparse_name(context, princ, &s_name); + if (kret == 0) { + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "AP Request ticket decrypt fail for principal '%s' (kvno=%d, enctype=%d)"), + s_name, + req->ticket->enc_part.kvno, + enctype); + krb5_free_unparsed_name(context, s_name); + } + } + (void) krb5_kt_free_entry(context, &ktent); return retval; } +/* + * Solaris Kerberos + * Same as krb5int_check_clockskew() plus return the skew in seconds. + */ +static krb5_error_code +krb5int_check_clockskew2(krb5_context context, + krb5_timestamp date, + krb5_timestamp *ret_skew) +{ + krb5_timestamp currenttime, skew; + krb5_error_code retval; + + retval = krb5_timeofday(context, ¤ttime); + if (retval) + return retval; + + skew = labs((date)-currenttime); + if (!(skew < context->clockskew)) { + *ret_skew = skew; + return KRB5KRB_AP_ERR_SKEW; + } + + return 0; +} + static krb5_error_code krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, const krb5_ap_req *req, krb5_const_principal server, @@ -110,8 +149,8 @@ krb5_ticket **ticket, int check_valid_flag) { krb5_error_code retval = 0; - krb5_timestamp currenttime; krb5_principal_data princ_data; + krb5_timestamp skew = 0; /* Solaris Kerberos */ req->ticket->enc_part2 == NULL; if (server && krb5_is_referral_realm(&server->realm)) { @@ -129,7 +168,8 @@ if (krb5_unparse_name(context, server, &wanted_name) == 0 && krb5_unparse_name(context, req->ticket->server, &found_name) == 0) krb5_set_error_message(context, KRB5KRB_AP_WRONG_PRINC, - "Wrong principal in request (found %s, wanted %s)", + dgettext(TEXT_DOMAIN, + "Wrong principal in request (found %s, wanted %s)"), found_name, wanted_name); krb5_free_unparsed_name(context, wanted_name); krb5_free_unparsed_name(context, found_name); @@ -255,6 +295,9 @@ krb5_xfree(rep.client); } + if (retval == KRB5KRB_AP_ERR_SKEW) + goto err_skew; + if (retval) goto cleanup; } @@ -263,19 +306,46 @@ if (retval != 0) goto cleanup; - if ((retval = krb5_timeofday(context, ¤ttime))) - goto cleanup; - - if (!in_clock_skew((*auth_context)->authentp->ctime)) { - retval = KRB5KRB_AP_ERR_SKEW; - goto cleanup; +err_skew: + if ((retval = krb5int_check_clockskew2(context, + (*auth_context)->authentp->ctime, + &skew))) { + /* Solaris Kerberos */ + char *s_name = NULL; + char *c_name = NULL; + krb5_error_code serr, cerr; + serr = krb5_unparse_name(context, req->ticket->server, &s_name); + cerr = krb5_unparse_name(context, req->ticket->enc_part2->client, + &c_name); + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "Clock skew too great: client '%s' AP request with ticket for '%s'. Skew is %dm (allowable %dm)."), + cerr == 0 ? c_name : "unknown", + serr == 0 ? s_name : "unknown", + skew > 0 ? skew/60 : 0, + context->clockskew > 0 ? context->clockskew/60 : 0); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + goto cleanup; } if (check_valid_flag) { - if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) { - retval = KRB5KRB_AP_ERR_TKT_INVALID; - goto cleanup; - } + if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) { + /* Solaris Kerberos */ + char *s_name = NULL; + int err = krb5_unparse_name(context, req->ticket->server, &s_name); + retval = KRB5KRB_AP_ERR_TKT_INVALID; + if (!err) { + krb5_set_error_message(context, retval, + dgettext(TEXT_DOMAIN, + "Ticket has invalid flag set for server '%s'"), + s_name); + krb5_free_unparsed_name(context, s_name); + } + goto cleanup; + } } /* check if the various etypes are permitted */ @@ -298,8 +368,9 @@ retval = KRB5_NOPERM_ETYPE; if (krb5_enctype_to_string(etype, enctype_name, sizeof(enctype_name)) == 0) krb5_set_error_message(context, retval, - "Encryption type %s not permitted", - enctype_name); + dgettext(TEXT_DOMAIN, + "Encryption type %s not permitted"), + enctype_name); goto cleanup; } } else { @@ -316,8 +387,9 @@ if (krb5_enctype_to_string(req->ticket->enc_part.enctype, enctype_name, sizeof(enctype_name)) == 0) krb5_set_error_message(context, retval, - "Encryption type %s not permitted", - enctype_name); + dgettext(TEXT_DOMAIN, + "Encryption type %s not permitted"), + enctype_name); goto cleanup; } @@ -331,8 +403,9 @@ if (krb5_enctype_to_string(req->ticket->enc_part2->session->enctype, enctype_name, sizeof(enctype_name)) == 0) krb5_set_error_message(context, retval, - "Encryption type %s not permitted", - enctype_name); + dgettext(TEXT_DOMAIN, + "Encryption type %s not permitted"), + enctype_name); goto cleanup; } @@ -348,8 +421,9 @@ enctype_name, sizeof(enctype_name)) == 0) krb5_set_error_message(context, retval, - "Encryption type %s not permitted", - enctype_name); + dgettext(TEXT_DOMAIN, + "Encryption type %s not permitted"), + enctype_name); goto cleanup; } }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c Mon Aug 16 17:01:32 2010 -0700 @@ -137,6 +137,28 @@ krb5_pa_data *const *padata, const krb5_data *second_ticket, krb5_creds *in_cred, krb5_response *rep) { + return (krb5_send_tgs2(context, kdcoptions, + timestruct, ktypes, + sname, addrs, + authorization_data, + padata, second_ticket, + in_cred, rep, + NULL)); +} + +/* + * Solaris Kerberos + * Same as krb5_send_tgs plus an extra arg to return the FQDN + * of the KDC sent the request. + */ +krb5_error_code +krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions, + const krb5_ticket_times *timestruct, const krb5_enctype *ktypes, + krb5_const_principal sname, krb5_address *const *addrs, + krb5_authdata *const *authorization_data, + krb5_pa_data *const *padata, const krb5_data *second_ticket, + krb5_creds *in_cred, krb5_response *rep, char **hostname_used) +{ krb5_error_code retval; krb5_kdc_req tgsreq; krb5_data *scratch, scratch2; @@ -271,9 +293,10 @@ /* now send request & get response from KDC */ send_again: use_master = 0; - retval = krb5_sendto_kdc(context, scratch, - krb5_princ_realm(context, sname), - &rep->response, &use_master, tcp_only); + retval = krb5_sendto_kdc2(context, scratch, + krb5_princ_realm(context, sname), + &rep->response, &use_master, tcp_only, + hostname_used); if (retval == 0) { if (krb5_is_krb_error(&rep->response)) { if (!tcp_only) {
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/valid_times.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/valid_times.c Mon Aug 16 17:01:32 2010 -0700 @@ -29,7 +29,6 @@ #include "k5-int.h" -#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) /* * This is an internal routine which validates the krb5_timestamps
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/walk_rtree.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/walk_rtree.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,4 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * lib/krb5/krb/walk_rtree.c * @@ -86,6 +88,7 @@ #define CONFIGURABLE_AUTHENTICATION_PATH #include "k5-int.h" #include "int-proto.h" +#include <locale.h> /* internal function, used by krb5_get_cred_from_kdc() */ @@ -141,8 +144,25 @@ printf(" server is %s\n",server->data); #endif - if (!(client->data &&server->data)) - return KRB5_NO_TKT_IN_RLM; + if (!(client->data && server->data)) { + /* Solaris Kerberos - enhance error message */ + if (!client->data && !server->data) { + krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, + dgettext(TEXT_DOMAIN, + "Cannot find ticket for requested realm: unknown client and server")); + } else { + if (!client->data) { + krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, + dgettext(TEXT_DOMAIN, + "Cannot find ticket for requested realm: unknown client")); + } else { + krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, + dgettext(TEXT_DOMAIN, + "Cannot find ticket for requested realm: unknown server")); + } + } + return KRB5_NO_TKT_IN_RLM; + } #ifdef CONFIGURABLE_AUTHENTICATION_PATH if ((cap_client = (char *)malloc(client->length + 1)) == NULL) return ENOMEM; @@ -198,10 +218,15 @@ /* handle case of one ran out */ if (!clen) { /* construct path from client to server, down the tree */ - if (!slen) + if (!slen) { /* in the same realm--this means there is no ticket in this realm. */ + krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, + dgettext(TEXT_DOMAIN, + "Cannot find ticket for requested realm: client is '%s', server is '%s'"), + client->data, server->data); return KRB5_NO_TKT_IN_RLM; + } if (*scp == realm_branch_char) { /* one is a subdomain of the other */ com_cdot = client->data;
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/os/hostaddr.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/os/hostaddr.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,3 +1,6 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * lib/krb5/os/hostaddr.c * @@ -28,7 +31,7 @@ */ #include "k5-int.h" - +#include <locale.h> #include "fake-addrinfo.h" krb5_error_code @@ -39,8 +42,9 @@ int i, j, r; struct addrinfo hints, *ai, *aip; - if (!name) + if (!name) { return KRB5_ERR_BAD_HOSTNAME; + } memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_NUMERICHOST; @@ -55,8 +59,13 @@ hints.ai_flags &= ~AI_NUMERICHOST; r = getaddrinfo (name, 0, &hints, &ai); } - if (r) + if (r) { + krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME, + dgettext(TEXT_DOMAIN, + "Hostname cannot be canonicalized for '%s': %s"), + name, strerror(r)); return KRB5_ERR_BAD_HOSTNAME; + } for (i = 0, aip = ai; aip; aip = aip->ai_next) { switch (aip->ai_addr->sa_family) {
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/os/locate_kdc.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/os/locate_kdc.c Mon Aug 16 17:01:32 2010 -0700 @@ -31,6 +31,26 @@ * get socket addresses for KDC. */ +/* + * Solaris Kerberos + * Re-factored the following routines to get a clear separation of locating + * KDC entries (krb5.conf/DNS-SRVrecs) versus mapping them to net addresses + * to allow us to output better error msgs: + * krb5int_locate_server + * prof_locate_server + * dns_locate_server + * krb5_locate_srv_conf_1 (removed) + * krb5_locate_srv_dns_1 (removed) + * prof_hostnames2netaddrs (new) + * hostlist2str (new) + * dns_hostnames2netaddrs (new) + * dnslist2str (new) + * Also, for the profile get_master==1 case, the algorithm has been + * simplified to just do a profile_get_values on "admin_server" and + * not try to match those against "kdc" entries (does not seem necessary + * and the DNS-SRVrecs code does not do that). + */ + #include "fake-addrinfo.h" #include "k5-int.h" #include "os-proto.h" @@ -48,6 +68,8 @@ #ifndef T_SRV #define T_SRV 33 #endif /* T_SRV */ +#include <syslog.h> +#include <locale.h> /* for old Unixes and friends ... */ #ifndef MAXHOSTNAMELEN @@ -296,261 +318,6 @@ return err; } -/* - * returns count of number of addresses found - * if master is non-NULL, it is filled in with the index of - * the master kdc - */ - -static krb5_error_code -krb5_locate_srv_conf_1(krb5_context context, const krb5_data *realm, - const char * name, struct addrlist *addrlist, - int get_masters, int socktype, - int udpport, int sec_udpport, int family) -{ - const char *realm_srv_names[4]; - char **masterlist, **hostlist, *host, *port, *cp; - krb5_error_code code; - int i, j, count, ismaster; - - Tprintf ("looking in krb5.conf for realm %s entry %s; ports %d,%d\n", - realm->data, name, ntohs (udpport), ntohs (sec_udpport)); - - if ((host = malloc(realm->length + 1)) == NULL) - return ENOMEM; - - strncpy(host, realm->data, realm->length); - host[realm->length] = '\0'; - hostlist = 0; - - masterlist = NULL; - - realm_srv_names[0] = "realms"; - realm_srv_names[1] = host; - realm_srv_names[2] = name; - realm_srv_names[3] = 0; - - code = profile_get_values(context->profile, realm_srv_names, &hostlist); - - if (code) { - Tprintf ("config file lookup failed: %s\n", - error_message(code)); - if (code == PROF_NO_SECTION || code == PROF_NO_RELATION) - code = KRB5_REALM_UNKNOWN; - krb5_xfree(host); - return code; - } - - count = 0; - while (hostlist && hostlist[count]) - count++; - Tprintf ("found %d entries under 'kdc'\n", count); - - if (count == 0) { - profile_free_list(hostlist); - krb5_xfree(host); - addrlist->naddrs = 0; - return 0; - } - - if (get_masters) { - realm_srv_names[0] = "realms"; - realm_srv_names[1] = host; - realm_srv_names[2] = "admin_server"; - realm_srv_names[3] = 0; - - code = profile_get_values(context->profile, realm_srv_names, - &masterlist); - - krb5_xfree(host); - - if (code == 0) { - for (i=0; masterlist[i]; i++) { - host = masterlist[i]; - - /* - * Strip off excess whitespace - */ - cp = strchr(host, ' '); - if (cp) - *cp = 0; - cp = strchr(host, '\t'); - if (cp) - *cp = 0; - cp = strchr(host, ':'); - if (cp) - *cp = 0; - } - } - } else { - krb5_xfree(host); - } - - /* at this point, if master is non-NULL, then either the master kdc - is required, and there is one, or the master kdc is not required, - and there may or may not be one. */ - -#ifdef HAVE_NETINET_IN_H - if (sec_udpport) - count = count * 2; -#endif - - for (i=0; hostlist[i]; i++) { - int p1, p2; - - host = hostlist[i]; - Tprintf ("entry %d is '%s'\n", i, host); - /* - * Strip off excess whitespace - */ - cp = strchr(host, ' '); - if (cp) - *cp = 0; - cp = strchr(host, '\t'); - if (cp) - *cp = 0; - port = strchr(host, ':'); - if (port) { - *port = 0; - port++; - } - - ismaster = 0; - if (masterlist) { - for (j=0; masterlist[j]; j++) { - if (strcasecmp(hostlist[i], masterlist[j]) == 0) { - ismaster = 1; - } - } - } - - if (get_masters && !ismaster) - continue; - - if (port) { - unsigned long l; -#ifdef HAVE_STROUL - char *endptr; - l = strtoul (port, &endptr, 10); - if (endptr == NULL || *endptr != 0) - return EINVAL; -#else - l = atoi (port); -#endif - /* L is unsigned, don't need to check <0. */ - if (l > 65535) - return EINVAL; - p1 = htons (l); - p2 = 0; - } else { - p1 = udpport; - p2 = sec_udpport; - } - - if (socktype != 0) - code = add_host_to_list (addrlist, hostlist[i], p1, p2, - socktype, family); - else { - code = add_host_to_list (addrlist, hostlist[i], p1, p2, - SOCK_DGRAM, family); - if (code == 0) - code = add_host_to_list (addrlist, hostlist[i], p1, p2, - SOCK_STREAM, family); - } - if (code) { - Tprintf ("error %d (%s) returned from add_host_to_list\n", code, - error_message (code)); - if (hostlist) - profile_free_list (hostlist); - if (masterlist) - profile_free_list (masterlist); - return code; - } - } - - if (hostlist) - profile_free_list(hostlist); - if (masterlist) - profile_free_list(masterlist); - - return 0; -} - -#ifdef TEST -static krb5_error_code -krb5_locate_srv_conf(krb5_context context, const krb5_data *realm, - const char *name, struct addrlist *al, int get_masters, - int udpport, int sec_udpport) -{ - krb5_error_code ret; - - ret = krb5_locate_srv_conf_1 (context, realm, name, al, - get_masters, 0, udpport, sec_udpport, 0); - if (ret) - return ret; - if (al->naddrs == 0) /* Couldn't resolve any KDC names */ - return KRB5_REALM_CANT_RESOLVE; - return 0; -} -#endif - -#ifdef KRB5_DNS_LOOKUP -static krb5_error_code -krb5_locate_srv_dns_1 (const krb5_data *realm, - const char *service, - const char *protocol, - struct addrlist *addrlist, - int family) -{ - struct srv_dns_entry *head = NULL; - struct srv_dns_entry *entry = NULL, *next; - krb5_error_code code = 0; - - code = krb5int_make_srv_query_realm(realm, service, protocol, &head); - if (code) - return 0; - - /* - * Okay! Now we've got a linked list of entries sorted by - * priority. Start looking up A records and returning - * addresses. - */ - - if (head == NULL) - return 0; - - /* Check for the "." case indicating no support. */ - if (head->next == 0 && head->host[0] == 0) { - free(head->host); - free(head); - return KRB5_ERR_NO_SERVICE; - } - - Tprintf ("walking answer list:\n"); - for (entry = head; entry != NULL; entry = next) { - Tprintf ("\tport=%d host=%s\n", entry->port, entry->host); - next = entry->next; - code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0, - (strcmp("_tcp", protocol) - ? SOCK_DGRAM - : SOCK_STREAM), family); - if (code) { - break; - } - if (entry == head) { - free(entry->host); - free(entry); - head = next; - entry = 0; - } - } - Tprintf ("[end]\n"); - - krb5int_free_srv_dns_data(head); - return code; -} -#endif - #include <locate_plugin.h> #if TARGET_OS_MAC @@ -681,56 +448,75 @@ static krb5_error_code prof_locate_server (krb5_context context, const krb5_data *realm, - struct addrlist *addrlist, - enum locate_service_type svc, int socktype, int family) + char ***hostlist, + enum locate_service_type svc) { - const char *profname; - int dflport1, dflport2 = 0; - struct servent *serv; + const char *realm_srv_names[4]; + char **hl, *host, *profname; + krb5_error_code code; + int i, j, count; + + *hostlist = NULL; /* default - indicate no KDCs found */ switch (svc) { case locate_service_kdc: profname = "kdc"; - /* We used to use /etc/services for these, but enough systems - have old, crufty, wrong settings that this is probably - better. */ - kdc_ports: - dflport1 = htons(KRB5_DEFAULT_PORT); - dflport2 = htons(KRB5_DEFAULT_SEC_PORT); break; case locate_service_master_kdc: - profname = "master_kdc"; - goto kdc_ports; + profname = "master_kdc"; + break; case locate_service_kadmin: profname = "admin_server"; - dflport1 = htons(DEFAULT_KADM5_PORT); break; case locate_service_krb524: profname = "krb524_server"; - serv = getservbyname(KRB524_SERVICE, "udp"); - dflport1 = serv ? serv->s_port : htons (KRB524_PORT); break; case locate_service_kpasswd: profname = "kpasswd_server"; - dflport1 = htons(DEFAULT_KPASSWD_PORT); break; default: - return EBUSY; /* XXX */ + return EINVAL; } - return krb5_locate_srv_conf_1 (context, realm, profname, addrlist, - 0, socktype, - dflport1, dflport2, family); + if ((host = malloc(realm->length + 1)) == NULL) + return ENOMEM; + + (void) strncpy(host, realm->data, realm->length); + host[realm->length] = '\0'; + hl = 0; + + realm_srv_names[0] = "realms"; + realm_srv_names[1] = host; + realm_srv_names[2] = profname; + realm_srv_names[3] = 0; + + code = profile_get_values(context->profile, realm_srv_names, &hl); + if (code) { + Tprintf ("config file lookup failed: %s\n", + error_message(code)); + if (code == PROF_NO_SECTION || code == PROF_NO_RELATION) + code = KRB5_REALM_UNKNOWN; + krb5_xfree(host); + return code; + } + krb5_xfree(host); + + *hostlist = hl; + + return 0; } static krb5_error_code dns_locate_server (krb5_context context, const krb5_data *realm, - struct addrlist *addrlist, - enum locate_service_type svc, int socktype, int family) + struct srv_dns_entry **dns_list_head, + enum locate_service_type svc, int socktype, int family) { const char *dnsname; int use_dns = _krb5_use_dns_kdc(context); krb5_error_code code; + struct srv_dns_entry *head = NULL; + + *dns_list_head = NULL; /* default: indicate we have found no KDCs */ if (!use_dns) return KRB5_PLUGIN_NO_HANDLE; @@ -757,15 +543,242 @@ code = 0; if (socktype == SOCK_DGRAM || socktype == 0) { - code = krb5_locate_srv_dns_1(realm, dnsname, "_udp", addrlist, family); + code = krb5int_make_srv_query_realm(realm, dnsname, "_udp", &head); if (code) Tprintf("dns udp lookup returned error %d\n", code); } if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) { - code = krb5_locate_srv_dns_1(realm, dnsname, "_tcp", addrlist, family); + code = krb5int_make_srv_query_realm(realm, dnsname, "_tcp", &head); if (code) Tprintf("dns tcp lookup returned error %d\n", code); } + + if (head == NULL) + return 0; + + /* Check for the "." case indicating no support. */ + if (head->next == 0 && head->host[0] == 0) { + free(head->host); + free(head); + return KRB5_ERR_NO_SERVICE; + } + + /* + * Okay! Now we've got a linked list of entries sorted by + * priority. Return it so later we can map hostnames to net addresses. + */ + *dns_list_head = head; + + return 0; +} + +/* + * Given the list of hostnames of KDCs found in DNS SRV recs, lets go + * thru NSS (name svc switch) to get the net addrs. + */ +static krb5_error_code +dns_hostnames2netaddrs( + struct srv_dns_entry *head, + enum locate_service_type svc, + int socktype, + int family, + struct addrlist *addrlist) +{ + struct srv_dns_entry *entry = NULL, *next; + krb5_error_code code; + + Tprintf ("walking answer list:\n"); + for (entry = head; entry != NULL; entry = entry->next) { + code = 0; + if (socktype) + code = add_host_to_list (addrlist, entry->host, + htons (entry->port), 0, + socktype, family); + else { + (void) add_host_to_list (addrlist, entry->host, + htons (entry->port), 0, + SOCK_DGRAM, family); + + code = add_host_to_list (addrlist, entry->host, + htons (entry->port), 0, + SOCK_STREAM, family); + } + if (code) { + Tprintf(" fail add_host code=%d %s\n", code, entry->host); + } + } + Tprintf ("[end]\n"); + + return code; +} + +/* + * Given the DNS SRV recs list, return a string of all the hosts like so: + * "fqdn0[,fqdn1][,fqdnN]" + */ +static char * +dnslist2str(struct srv_dns_entry *dns_list_head) +{ + struct srv_dns_entry *head = dns_list_head; + struct srv_dns_entry *entry = NULL, *next; + unsigned int size = 0, c = 0, buf_size; + char *s = NULL; + + for (entry = head; entry; entry = entry->next, c++) { + size += strlen(entry->host); + } + if (!c) + return NULL; + + /* hostnames + commas + NULL */ + buf_size = size + (c - 1) + 1; + s = malloc(buf_size); + if (!s) + return NULL; + + (void) strlcpy(s, head->host, buf_size); + for (entry = head->next; entry; entry = entry->next) { + (void) strlcat(s, ",", buf_size); + (void) strlcat(s, entry->host, buf_size); + } + + return s; +} + +/* + * Given the profile hostlist, return a string of all the hosts like so: + * "fqdn0[,fqdn1][,fqdnN]" + */ +static char * +hostlist2str(char **hostlist) +{ + unsigned int c = 0, size = 0, buf_size; + char **hl = hostlist, *s = NULL; + + while (hl && *hl) { + size += strlen(*hl); + hl++; + c++; + } + if (!c) + return NULL; + + /* hostnames + commas + NULL */ + buf_size = size + (c - 1) + 1; + s = malloc(buf_size); + if (!s) + return NULL; + + hl = hostlist; + (void) strlcpy(s, *hl, buf_size); + hl++; + while (hl && *hl) { + (void) strlcat(s, ",", buf_size); + (void) strlcat(s, *hl, buf_size); + hl++; + } + + return s; +} + +/* + * Take the profile KDC list and return a list of net addrs. + */ +static krb5_error_code +prof_hostnames2netaddrs( + char **hostlist, + enum locate_service_type svc, + int socktype, + int family, + struct addrlist *addrlist) /* output */ +{ + int udpport = 0 , sec_udpport = 0; + int code, i; + struct servent *serv; + + int count = 0; + while (hostlist && hostlist[count]) + count++; + if (count == 0) { + return 0; + } + + switch (svc) { + case locate_service_kdc: + case locate_service_master_kdc: + /* We used to use /etc/services for these, but enough systems + have old, crufty, wrong settings that this is probably + better. */ + udpport = htons(KRB5_DEFAULT_PORT); + sec_udpport = htons(KRB5_DEFAULT_SEC_PORT); + break; + case locate_service_kadmin: + udpport = htons(DEFAULT_KADM5_PORT); + break; + case locate_service_krb524: + serv = getservbyname(KRB524_SERVICE, "udp"); + udpport = serv ? serv->s_port : htons (KRB524_PORT); + break; + case locate_service_kpasswd: + udpport = htons(DEFAULT_KPASSWD_PORT); + break; + default: + return EINVAL; + } + + for (i=0; hostlist[i]; i++) { + int p1, p2; + char *cp, *port, *host; + + host = hostlist[i]; + /* + * Strip off excess whitespace + */ + cp = strchr(host, ' '); + if (cp) + *cp = 0; + cp = strchr(host, '\t'); + if (cp) + *cp = 0; + port = strchr(host, ':'); + if (port) { + *port = 0; + port++; + } + + if (port) { + unsigned long l; +#ifdef HAVE_STROUL + char *endptr; + l = strtoul (port, &endptr, 10); + if (endptr == NULL || *endptr != 0) + return EINVAL; +#else + l = atoi (port); +#endif + /* L is unsigned, don't need to check <0. */ + if (l == 0 || l > 65535) + return EINVAL; + p1 = htons (l); + p2 = 0; + } else { + p1 = udpport; + p2 = sec_udpport; + } + + + if (socktype != 0) { + code = add_host_to_list (addrlist, hostlist[i], p1, p2, + socktype, family); + } else { + code = add_host_to_list (addrlist, hostlist[i], p1, p2, + SOCK_DGRAM, family); + if (code == 0) + code = add_host_to_list (addrlist, hostlist[i], p1, p2, + SOCK_STREAM, family); + } + } + return code; } @@ -781,6 +794,8 @@ { krb5_error_code code; struct addrlist al = ADDRLIST_INIT; + char **hostlist = NULL; + struct srv_dns_entry *dns_list_head = NULL; *addrlist = al; @@ -792,19 +807,18 @@ * is no way to indicate "service not available" via the * config file. */ - - code = prof_locate_server(context, realm, &al, svc, socktype, family); + code = prof_locate_server(context, realm, &hostlist, svc); /* * Solaris Kerberos: * If kpasswd_server has not been configured and dns_lookup_kdc - * dns_fallback are not configured then admin_server should - * be inferenced, per krb5.conf(4). + * be inferred, per krb5.conf(4). */ if (code && svc == locate_service_kpasswd && !maybe_use_dns(context, "dns_lookup_kdc", 0)) { - code = krb5_locate_srv_conf_1(context, realm, "admin_server", - &al, 0, socktype, htons(DEFAULT_KPASSWD_PORT), 0, family); + code = prof_locate_server(context, realm, &hostlist, + locate_service_kadmin); } #ifdef KRB5_DNS_LOOKUP @@ -816,41 +830,8 @@ /* Try DNS for all profile errors? */ if (code && !krb5_is_referral_realm(realm)) { krb5_error_code code2; - code2 = dns_locate_server(context, realm, &al, svc, socktype, - family); - - /* - * Solaris Kerberos: - * If an entry for _kerberos-master. does not exist (checked for - * above) but _kpasswd. does then treat that as an entry for the - * master KDC (but use port 88 not the kpasswd port). MS AD creates - * kpasswd entries by default in DNS. - */ - if (code2 == 0 && svc == locate_service_master_kdc && - al.naddrs == 0) { - - /* Look for _kpasswd._tcp|udp */ - code2 = dns_locate_server(context, realm, &al, - locate_service_kpasswd, socktype, family); - - /* Set the port to 88 instead of the kpasswd port */ - if (code2 == 0 ) { - int i; - struct addrinfo *a; - - for (i = 0; i < al.naddrs; i++) { - if (al.addrs[i].ai->ai_family == AF_INET) - for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) - ((struct sockaddr_in *)a->ai_addr)->sin_port = - htons(KRB5_DEFAULT_PORT); - - if (al.addrs[i].ai->ai_family == AF_INET6) - for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) - ((struct sockaddr_in6 *)a->ai_addr)->sin6_port = - htons(KRB5_DEFAULT_PORT); - } - } - } + code2 = dns_locate_server(context, realm, &dns_list_head, + svc, socktype, family); if (code2 != KRB5_PLUGIN_NO_HANDLE) code = code2; @@ -860,26 +841,148 @@ /* We could put more heuristics here, like looking up a hostname of "kerberos."+REALM, etc. */ } - if (code == 0) - Tprintf ("krb5int_locate_server found %d addresses\n", - al.naddrs); - else - Tprintf ("krb5int_locate_server returning error code %d/%s\n", - code, error_message(code)); + if (code != 0) { if (al.space) free_list (&al); + if (hostlist) + profile_free_list(hostlist); + if (dns_list_head) + krb5int_free_srv_dns_data(dns_list_head); + return code; } - if (al.naddrs == 0) { /* No good servers */ + + /* + * At this point we have no errors, let's check to see if we have + * any KDC entries from krb5.conf or DNS. + */ + if (!hostlist && !dns_list_head) { + switch(svc) { + case locate_service_master_kdc: + krb5_set_error_message(context, + KRB5_REALM_CANT_RESOLVE, + dgettext(TEXT_DOMAIN, + "Cannot find a master KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), + realm->length, realm->data); + break; + case locate_service_kadmin: + krb5_set_error_message(context, + KRB5_REALM_CANT_RESOLVE, + dgettext(TEXT_DOMAIN, + "Cannot find a kadmin KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), + realm->length, realm->data); + break; + case locate_service_kpasswd: + krb5_set_error_message(context, + KRB5_REALM_CANT_RESOLVE, + dgettext(TEXT_DOMAIN, + "Cannot find a kpasswd KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), + realm->length, realm->data); + break; + default: /* locate_service_kdc: */ + krb5_set_error_message(context, + KRB5_REALM_CANT_RESOLVE, + dgettext(TEXT_DOMAIN, + "Cannot find any KDC entries in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), + realm->length, realm->data); + + } + return KRB5_REALM_CANT_RESOLVE; + } + + /* We have KDC entries, let see if we can get their net addrs. */ + if (hostlist) + code = prof_hostnames2netaddrs(hostlist, svc, + socktype, family, &al); + else if (dns_list_head) + code = dns_hostnames2netaddrs(dns_list_head, svc, + socktype, family, &al); + if (code) { + if (hostlist) + profile_free_list(hostlist); + if (dns_list_head) + krb5int_free_srv_dns_data(dns_list_head); + return code; + } + + /* + * Solaris Kerberos: + * If an entry for _kerberos-master. does not exist (checked for + * above) but _kpasswd. does then treat that as an entry for the + * master KDC (but use port 88 not the kpasswd port). MS AD creates + * kpasswd entries by default in DNS. + */ + if (!dns_list_head && svc == locate_service_master_kdc && + al.naddrs == 0) { + + /* Look for _kpasswd._tcp|udp */ + code = dns_locate_server(context, realm, &dns_list_head, + locate_service_kpasswd, socktype, family); + + if (code == 0 && dns_list_head) { + int i; + struct addrinfo *a; + + code = dns_hostnames2netaddrs(dns_list_head, svc, + socktype, family, &al); + + /* Set the port to 88 instead of the kpasswd port */ + if (code == 0 && al.naddrs > 0) { + for (i = 0; i < al.naddrs; i++) { + if (al.addrs[i].ai->ai_family == AF_INET) + for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) + ((struct sockaddr_in *)a->ai_addr)->sin_port = + htons(KRB5_DEFAULT_PORT); + + if (al.addrs[i].ai->ai_family == AF_INET6) + for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) + ((struct sockaddr_in6 *)a->ai_addr)->sin6_port = + htons(KRB5_DEFAULT_PORT); + } + } + } + } + + /* No errors so far, lets see if we have KDC net addrs */ + if (al.naddrs == 0) { + char *hostlist_str = NULL, *dnslist_str = NULL; if (al.space) free_list (&al); - krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, - "Cannot resolve network address for KDC in realm %.*s", - realm->length, realm->data); - + + if (hostlist) { + hostlist_str = hostlist2str(hostlist); + krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, + dgettext(TEXT_DOMAIN, + "Cannot resolve network address for KDCs '%s' specified in krb5.conf(4) for realm %.*s"), + hostlist_str ? hostlist_str : "unknown", + realm->length, realm->data); + if (hostlist_str) + free(hostlist_str); + } else if (dns_list_head) { + dnslist_str = dnslist2str(dns_list_head); + krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, + dgettext(TEXT_DOMAIN, + "Cannot resolve network address for KDCs '%s' discovered via DNS Service Location records for realm '%.*s'"), + dnslist_str ? dnslist_str : "unknown", + realm->length, realm->data); + if (dnslist_str) + free(dnslist_str); + } + + if (hostlist) + profile_free_list(hostlist); + if (dns_list_head) + krb5int_free_srv_dns_data(dns_list_head); + return KRB5_REALM_CANT_RESOLVE; } + + if (hostlist) + profile_free_list(hostlist); + if (dns_list_head) + krb5int_free_srv_dns_data(dns_list_head); + *addrlist = al; return 0; }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/os/sendto_kdc.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/os/sendto_kdc.c Mon Aug 16 17:01:32 2010 -0700 @@ -36,6 +36,7 @@ /* Solaris Kerberos */ #include <syslog.h> +#include <locale.h> #ifdef HAVE_SYS_TIME_H #include <sys/time.h> @@ -377,6 +378,21 @@ const krb5_data *realm, krb5_data *reply, int *use_master, int tcp_only) { + return (krb5_sendto_kdc2(context, message, realm, reply, use_master, + tcp_only, NULL)); +} + +/* + * Solaris Kerberos + * Same as krb5_sendto_kdc plus an extra arg to return the FQDN + * of the KDC sent the request. + * Caller (at top of stack) needs to free hostname_used. + */ +krb5_error_code +krb5_sendto_kdc2 (krb5_context context, const krb5_data *message, + const krb5_data *realm, krb5_data *reply, + int *use_master, int tcp_only, char **hostname_used) +{ krb5_error_code retval, retval2; struct addrlist addrs = ADDRLIST_INIT; /* Solaris Kerberos */ int socktype1 = 0, socktype2 = 0, addr_used; @@ -470,6 +486,24 @@ krb5int_free_addrlist (&addrs3); } } + + if (hostname_used) { + struct sockaddr *sa; + char buf[NI_MAXHOST]; + int err; + + *hostname_used = NULL; + sa = addrs.addrs[addr_used].ai->ai_addr; + err = getnameinfo (sa, socklen (sa), buf, sizeof (buf), 0, 0, + AI_CANONNAME); + if (err) + err = getnameinfo (sa, socklen (sa), buf, + sizeof (buf), 0, 0, + NI_NUMERICHOST); + if (!err) + *hostname_used = strdup(buf); + /* don't sweat strdup fail */ + } krb5int_free_addrlist (&addrs); return 0; default: @@ -480,8 +514,9 @@ retval = KRB5KDC_ERR_SVC_UNAVAILABLE; } else { krb5_set_error_message(context, retval, - "Cannot contact any KDC for realm '%.*s'", - realm->length, realm->data); + dgettext(TEXT_DOMAIN, + "Cannot contact any KDC for realm '%.*s'"), + realm->length, realm->data); } break; }
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/os/sn2princ.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/os/sn2princ.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,8 +1,6 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - /* * lib/krb5/os/sn2princ.c * @@ -40,6 +38,8 @@ #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif +#include <locale.h> +#include <syslog.h> #if !defined(DEFAULT_RDNS_LOOKUP) /* Solaris Kerberos */ @@ -94,7 +94,6 @@ printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type); printf(" name types: 0=unknown, 3=srv_host\n"); #endif - if ((type == KRB5_NT_UNKNOWN) || (type == KRB5_NT_SRV_HST)) { @@ -157,6 +156,11 @@ KRB5_LOG(KRB5_ERR, "krb5_sname_to_principal()" " can't get AF_INET or AF_INET6 addr," " err = %d", err); + + krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME, + dgettext(TEXT_DOMAIN, + "Hostname cannot be canonicalized for '%s': %s"), + hostname, strerror(err)); return KRB5_ERR_BAD_HOSTNAME; } remote_host = strdup(hp ? hp->h_name : hostname); @@ -239,6 +243,12 @@ #endif if (!hrealms[0]) { + /* Solaris Kerberos */ + krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, + dgettext(TEXT_DOMAIN, + "Cannot determine realm for host: host is '%s'"), + remote_host ? remote_host : "unknown"); + free(remote_host); krb5_xfree(hrealms); return KRB5_ERR_HOST_REALM_UNKNOWN;
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_io.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_io.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -30,6 +29,7 @@ #include <sys/types.h> #include <unistd.h> #include <syslog.h> /* SUNW */ +#include <locale.h> /* Solaris Kerberos */ #include "rc_base.h" #include "rc_file.h" #include "rc_io.h" @@ -153,16 +153,20 @@ case EEXIST: retval = KRB5_RC_IO_PERM; krb5_set_error_message(context, retval, - "Cannot create replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Cannot create replay cache %s: %s"), + d->fn ? d->fn : "<null>", + strerror(errno)); do_not_unlink = 1; goto cleanup; default: retval = KRB5_RC_IO_UNKNOWN; krb5_set_error_message(context, retval, - "Cannot create replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Cannot create replay cache %s: %s"), + d->fn ? d->fn : "<null>", + strerror(errno)); goto cleanup; } } @@ -296,14 +300,16 @@ case EROFS: retval = KRB5_RC_IO_PERM; krb5_set_error_message (context, retval, - "Cannot open replay cache %s: %s", + dgettext(TEXT_DOMAIN, + "Cannot open replay cache %s: %s"), d->fn, strerror(errno)); break; default: retval = KRB5_RC_IO_UNKNOWN; krb5_set_error_message (context, retval, - "Cannot open replay cache %s: %s", + dgettext(TEXT_DOMAIN, + "Cannot open replay cache %s: %s"), d->fn, strerror(errno)); } } @@ -416,19 +422,22 @@ case EFBIG: case ENOSPC: krb5_set_error_message (context, KRB5_RC_IO_SPACE, - "Can't write to replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't write to replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_SPACE; case EIO: krb5_set_error_message (context, KRB5_RC_IO_IO, - "Can't write to replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't write to replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_IO; case EBADF: default: krb5_set_error_message (context, KRB5_RC_IO_UNKNOWN, - "Can't write to replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't write to replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_UNKNOWN; } return 0; @@ -449,8 +458,9 @@ case EIO: return KRB5_RC_IO_IO; default: krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN, - "Cannot sync replay cache file: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Cannot sync replay cache file %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_UNKNOWN; } } @@ -470,8 +480,9 @@ case EBADF: default: krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN, - "Can't read from replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't read from replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_UNKNOWN; } if (count == 0) @@ -504,21 +515,24 @@ { case EIO: krb5_set_error_message(context, KRB5_RC_IO_IO, - "Can't destroy replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't destroy replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_IO; case EPERM: case EBUSY: case EROFS: krb5_set_error_message(context, KRB5_RC_IO_PERM, - "Can't destroy replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't destroy replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_PERM; case EBADF: default: krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN, - "Can't destroy replay cache: %s", - strerror(errno)); + dgettext(TEXT_DOMAIN, + "Can't destroy replay cache %s: %s"), + d->fn, strerror(errno)); return KRB5_RC_IO_UNKNOWN; } return 0;
--- a/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers Mon Aug 16 17:01:32 2010 -0700 @@ -211,8 +211,14 @@ encode_krb5_tgs_req; encode_krb5_ticket; error_message; + generic_gss_oid_to_str; + generic_gss_release_buffer; ggss_error_table; gss_krb5int_get_tkt_flags; + gssint_g_display_major_status; + gssint_g_make_string_buffer; + gssint_mecherrmap_map; + gssint_mecherrmap_map_errcode; gsskrb5_extract_authz_data_from_sec_context; gss_krb5_ccache_name; gss_krb5_copy_ccache; @@ -485,6 +491,7 @@ krb5_get_time_offsets; krb5_get_validated_creds; krb5_getenv; + krb5_gss_display_status2; krb5_gss_import_name; krb5_gss_oid_array; krb5_gss_userok; @@ -724,6 +731,7 @@ krb5int_get_error; krb5int_getnameinfo; krb5int_get_plugin_dir_data; + krb5int_getspecific; krb5int_gmt_mktime; krb5int_hash_sha1; krb5int_init_context_kdc; @@ -733,7 +741,9 @@ krb5int_open_plugin_dirs; krb5int_pbkdf2_hmac_sha1; krb5int_pthread_loaded; + krb5int_key_register; krb5int_sendtokdc_debug_handler; + krb5int_setspecific; krb5int_vset_error; kwarn_add_warning; kwarn_del_warning;
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,3 +1,6 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright 2000, 2004 by the Massachusetts Institute of Technology. * All Rights Reserved. @@ -70,10 +73,6 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - */ - #include "k5-int.h" #include "gssapiP_krb5.h" #ifdef HAVE_MEMORY_H @@ -81,12 +80,13 @@ #endif #include <assert.h> #include "auth_con.h" - #ifdef CFX_EXERCISE #define CFX_ACCEPTOR_SUBKEY (time(0) & 1) #else #define CFX_ACCEPTOR_SUBKEY 1 #endif +#include <syslog.h> +#include <locale.h> /* Solaris Kerberos */ /* * Decode, decrypt and store the forwarded creds in the local ccache. @@ -297,7 +297,8 @@ krb5_address addr, *paddr; krb5_authenticator *authdat = 0; krb5_checksum reqcksum; - krb5_principal name = NULL; + krb5_principal client_name = NULL; + krb5_principal server_name = NULL; krb5_ui_4 gss_flags = 0; krb5_timestamp now; gss_buffer_desc token; @@ -316,6 +317,7 @@ int cred_rcache = 0; int no_encap; OM_uint32 t_minor_status = 0; + int acquire_fail = 0; KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start"); @@ -477,7 +479,6 @@ NULL, NULL); if (major_status != GSS_S_COMPLETE){ - /* Solaris kerberos: RFC2743 indicate this should be returned if we * can't aquire a default cred. */ @@ -485,7 +486,7 @@ "krb5_gss_acquire_cred() error" "orig major_status = %d, now = GSS_S_NO_CRED\n", major_status); - + acquire_fail = 1; major_status = GSS_S_NO_CRED; goto fail; } @@ -543,6 +544,7 @@ if ((code = krb5_auth_con_init(context, &auth_context))) { major_status = GSS_S_FAILURE; + save_error_info((OM_uint32)code, context); /* Solaris Kerberos */ KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() " "krb5_auth_con_init() error code %d", code); @@ -572,9 +574,29 @@ if ((code = krb5_rd_req_decoded(context, &auth_context, request, cred->princ, cred->keytab, NULL, &ticket))) { - KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() " + KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() " "krb5_rd_req() error code %d", code); - if (code == KRB5_KT_KVNONOTFOUND || code == KRB5_KT_NOTFOUND) { + if (code == KRB5_KT_KVNONOTFOUND) { + char *s_name; + if (krb5_unparse_name(context, cred->princ, &s_name) == 0) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_BADKEYVER, + dgettext(TEXT_DOMAIN, + "Key version %d is not available for principal %s"), + request->ticket->enc_part.kvno, + s_name); + krb5_free_unparsed_name(context, s_name); + } + major_status = GSS_S_DEFECTIVE_CREDENTIAL; + code = KRB5KRB_AP_ERR_BADKEYVER; + } else if (code == KRB5_KT_NOTFOUND) { + char *s_name; + if (krb5_unparse_name(context, cred->princ, &s_name) == 0) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_NOKEY, + dgettext(TEXT_DOMAIN, + "Service key %s not available"), + s_name); + krb5_free_unparsed_name(context, s_name); + } major_status = GSS_S_DEFECTIVE_CREDENTIAL; code = KRB5KRB_AP_ERR_NOKEY; } @@ -1076,21 +1098,24 @@ /* set the return arguments */ - if (src_name) { - if ((code = krb5_copy_principal(context, ctx->there, &name))) { - major_status = GSS_S_FAILURE; - goto fail; - } - /* intern the src_name */ - if (! kg_save_name((gss_name_t) name)) { - code = G_VALIDATE_FAILED; - major_status = GSS_S_FAILURE; - goto fail; - } + /* + * Solaris Kerberos + * Regardless of src_name, get name for error msg if neeeded. + */ + if ((code = krb5_copy_principal(context, ctx->there, &client_name))) { + major_status = GSS_S_FAILURE; + goto fail; } - - if (mech_type) - *mech_type = (gss_OID) mech_used; + if ((code = krb5_copy_principal(context, ctx->here, &server_name))) { + major_status = GSS_S_FAILURE; + goto fail; + } + /* intern the src_name */ + if (! kg_save_name((gss_name_t) client_name)) { + code = G_VALIDATE_FAILED; + major_status = GSS_S_FAILURE; + goto fail; + } if (time_rec) *time_rec = ctx->endtime - now; @@ -1102,7 +1127,7 @@ *output_token = token; if (src_name) - *src_name = (gss_name_t) name; + *src_name = (gss_name_t) client_name; if (delegated_cred_handle && deleg_cred) { if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) { @@ -1123,6 +1148,21 @@ major_status = GSS_S_COMPLETE; fail: + if (mech_type) { + unsigned int min; + gss_buffer_desc oidstr; + oidstr.value = NULL; + + /* + * This needs to be set/returned even on fail so + * gss_accept_sec_context() can map_error_oid() the correct + * error/oid for later use by gss_display_status(). + * (needed in CIFS/SPNEGO case) + */ + *mech_type = (gss_OID) mech_used; + + (void) gss_oid_to_str(&min, *mech_type, &oidstr); + } if (authdat) krb5_free_authenticator(context, authdat); @@ -1169,10 +1209,6 @@ } if (token.value) xfree(token.value); - if (name) { - (void) kg_delete_name((gss_name_t) name); - krb5_free_principal(context, name); - } *minor_status = code; @@ -1219,7 +1255,7 @@ krb_error_data.e_data.length = len; } major_status = GSS_S_CONTINUE_NEEDED; - } + } code -= ERROR_TABLE_BASE_krb5; if (code < 0 || code > 128) @@ -1252,7 +1288,6 @@ } cleanup: - /* Solaris Kerberos */ if (krb_error_data.e_data.data != NULL) free(krb_error_data.e_data.data); @@ -1260,6 +1295,45 @@ if (!verifier_cred_handle && cred_handle) { krb5_gss_release_cred(&t_minor_status, &cred_handle); } + + /* + * Solaris Kerberos + * Enhance the error message. + */ + if (GSS_ERROR(major_status)) { + if (client_name && server_name && + (*minor_status == (OM_uint32)KRB5KRB_AP_ERR_BAD_INTEGRITY)) { + char *c_name = NULL; + char *s_name = NULL; + krb5_error_code cret, sret; + cret = krb5_unparse_name(context, (krb5_principal) client_name, + &c_name); + sret = krb5_unparse_name(context, (krb5_principal) server_name, + &s_name); + krb5_set_error_message(context, *minor_status, + dgettext(TEXT_DOMAIN, + "Decrypt integrity check failed for client '%s' and server '%s'"), + cret == 0 ? c_name : "unknown", + sret == 0 ? s_name : "unknown"); + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (c_name) + krb5_free_unparsed_name(context, c_name); + } + /* + * Solaris Kerberos + * krb5_gss_acquire_cred() does not take a context arg + * (and does a save_error_info() itself) so re-calling + * save_error_info() here is trouble. + */ + if (!acquire_fail) + save_error_info(*minor_status, context); + } + if (client_name) { + (void) kg_delete_name((gss_name_t) client_name); + } + if (server_name) + krb5_free_principal(context, server_name); krb5_free_context(context); /* Solaris Kerberos */
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/acquire_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/acquire_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright 2000 by the Massachusetts Institute of Technology. * All Rights Reserved. @@ -85,6 +82,9 @@ #else #include <strings.h> #endif +#include <syslog.h> +#include <locale.h> /* Solaris Kerberos */ +#include "file/ktfile.h" /* Solaris Kerberos */ #if defined(USE_LOGIN_LIBRARY) #include <Kerberos/KerberosLoginPrivate.h> @@ -184,18 +184,27 @@ return(GSS_S_NO_CRED); } - if (desired_name != GSS_C_NO_NAME) { - princ = (krb5_principal) desired_name; - if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) { - (void) krb5_kt_close(context, kt); - if (code == KRB5_KT_NOTFOUND) - *minor_status = KG_KEYTAB_NOMATCH; - else - *minor_status = code; + if (desired_name != GSS_C_NO_NAME) { + princ = (krb5_principal) desired_name; + if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) { + if (code == KRB5_KT_NOTFOUND) { + char *s_name; + if (krb5_unparse_name(context, princ, &s_name) == 0) { + krb5_set_error_message(context, KG_KEYTAB_NOMATCH, + dgettext(TEXT_DOMAIN, + "No principal in keytab ('%s') matches desired name %s"), + KTFILENAME(kt), + s_name); + krb5_free_unparsed_name(context, s_name); + } + *minor_status = KG_KEYTAB_NOMATCH; + } else + *minor_status = code; /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */ - return(GSS_S_NO_CRED); - } - krb5_kt_free_entry(context, &entry); + (void) krb5_kt_close(context, kt); + return(GSS_S_NO_CRED); + } + krb5_kt_free_entry(context, &entry); /* Open the replay cache for this principal. */ if ((code = krb5_get_server_rcache(context, @@ -205,7 +214,7 @@ return(GSS_S_FAILURE); } - } + } /* hooray. we made it */ @@ -491,9 +500,9 @@ /*SUPPRESS 29*/ if ((desired_name != (gss_name_t) NULL) && (! kg_validate_name(desired_name))) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - krb5_free_context(context); - return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + krb5_free_context(context); + return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } /* verify that the requested mechanism set is the default, or @@ -571,6 +580,7 @@ k5_mutex_destroy(&cred->lock); xfree(cred); /* minor_status set by acquire_accept_cred() */ + save_error_info(*minor_status, context); krb5_free_context(context); return(ret); } @@ -593,6 +603,7 @@ k5_mutex_destroy(&cred->lock); xfree(cred); /* minor_status set by acquire_init_cred() */ + save_error_info(*minor_status, context); krb5_free_context(context); return(ret); } @@ -613,6 +624,7 @@ k5_mutex_destroy(&cred->lock); xfree(cred); *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -637,6 +649,7 @@ k5_mutex_destroy(&cred->lock); xfree(cred); *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -686,6 +699,7 @@ k5_mutex_destroy(&cred->lock); xfree(cred); *minor_status = (OM_uint32) G_VALIDATE_FAILED; + save_error_string(*minor_status, "error saving credentials"); krb5_free_context(context); return(GSS_S_FAILURE); }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/add_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/add_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,3 +1,6 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright 2000 by the Massachusetts Institute of Technology. * All Rights Reserved. @@ -54,6 +57,7 @@ #else #include <strings.h> #endif +#include <locale.h> /* Solaris Kerberos */ /* * $Id: add_cred.c 18396 2006-07-25 20:29:43Z lxs $ @@ -122,6 +126,7 @@ major_status = krb5_gss_validate_cred_1(minor_status, input_cred_handle, context); if (GSS_ERROR(major_status)) { + save_error_info(*minor_status, context); krb5_free_context(context); return major_status; } @@ -150,6 +155,7 @@ } if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) { + save_error_info(*minor_status, context); krb5_free_context(context); return GSS_S_FAILURE; } @@ -159,7 +165,7 @@ /*SUPPRESS 29*/ if ((desired_name != (gss_name_t) NULL) && (! kg_validate_name(desired_name))) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; + *minor_status = (OM_uint32) G_VALIDATE_FAILED; krb5_free_context(context); return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } @@ -169,7 +175,24 @@ if (desired_name && !krb5_principal_compare(context, (krb5_principal) desired_name, cred->princ)) { - *minor_status = 0; + /* Solaris Kerberos: spruce-up the err msg */ + krb5_principal dname = (krb5_principal) desired_name; + char *s_name = NULL, *s_princ= NULL; + int kret = krb5_unparse_name(context, dname, &s_name); + int kret1 = krb5_unparse_name(context, cred->princ, &s_princ); + *minor_status = (OM_uint32) G_BAD_USAGE; + if (kret == 0 && kret1 == 0) { + krb5_set_error_message(context, *minor_status, + dgettext(TEXT_DOMAIN, + "Desired name principal '%s' does not match '%s'"), + s_name, s_princ); + save_error_info(*minor_status, context); + } + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (s_princ) + krb5_free_unparsed_name(context, s_princ); + krb5_free_context(context); return(GSS_S_BAD_NAME); } @@ -203,6 +226,7 @@ xfree(new_cred); *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -232,6 +256,7 @@ xfree(new_cred); *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -243,6 +268,7 @@ xfree(new_cred); *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -261,8 +287,9 @@ krb5_free_principal(context, new_cred->princ); xfree(new_cred); + *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); - *minor_status = code; return(GSS_S_FAILURE); } } else { @@ -301,9 +328,9 @@ if (new_cred->princ) krb5_free_principal(context, new_cred->princ); xfree(new_cred); + *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); - - *minor_status = code; return(GSS_S_FAILURE); } } else {
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/context_time.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/context_time.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,5 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" - +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* Copyright 1993 by OpenVision Technologies, Inc. * * Permission to use, copy, modify, distribute, and sell this software @@ -53,6 +54,7 @@ if ((code = krb5_timeofday(ctx->k5_context, &now))) { *minor_status = code; + save_error_info(*minor_status, ctx->k5_context); return(GSS_S_FAILURE); }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/copy_ccache.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/copy_ccache.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,4 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ #include "gssapiP_krb5.h" @@ -43,6 +45,7 @@ if (code) { k5_mutex_unlock(&k5creds->lock); *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -53,6 +56,7 @@ krb5_free_context(context); if (code) { *minor_status = code; + save_error_info(*minor_status, context); return(GSS_S_FAILURE); } else { *minor_status = 0;
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/disp_com_err_status.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/disp_com_err_status.c Mon Aug 16 17:01:32 2010 -0700 @@ -25,7 +25,6 @@ */ #include "gssapiP_generic.h" -#include "gss_libinit.h" #include "com_err.h" /* XXXX internationalization!! */ @@ -53,11 +52,9 @@ status_string->length = 0; status_string->value = NULL; - (void) gssint_initialize_library(); - if (! g_make_string_buffer(((status_value == 0)?no_error: - error_message(status_value)), - status_string)) { + error_message(status_value)), + status_string)) { *minor_status = ENOMEM; return(GSS_S_FAILURE); }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/disp_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/disp_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,5 +1,3 @@ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Copyright 1993 by OpenVision Technologies, Inc. * @@ -54,6 +52,7 @@ if ((code = krb5_unparse_name(context, (krb5_principal) input_name, &str))) { *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/disp_status.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/disp_status.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,10 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright 1993 by OpenVision Technologies, Inc. - * + * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appears in all copies and @@ -10,7 +14,7 @@ * without specific, written prior permission. OpenVision makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. - * + * * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR @@ -20,51 +24,210 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#pragma ident "%Z%%M% %I% %E% SMI" +#include "gssapiP_krb5.h" +#include "com_err.h" +#include <syslog.h> +/* XXXX internationalization!! */ + +static inline int +compare_OM_uint32 (OM_uint32 a, OM_uint32 b) +{ + if (a < b) + return -1; + else if (a == b) + return 0; + else + return 1; +} +static inline void +free_string (char *s) +{ + free(s); +} +#include "error_map.h" +#include <stdio.h> +/* + * AKA krb5_gss_get_error_message. See #define in gssapiP_krb5.h. + */ +char *get_error_message(OM_uint32 minor_code) +{ + gsserrmap *p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE); + char *msg = NULL; + +#ifdef DEBUG + fprintf(stderr, "%s(%lu, p=%p)", __func__, (unsigned long) minor_code, + (void *) p); +#endif + if (p) { + char **v = gsserrmap_find(p, minor_code); + if (v) { + msg = *v; +#ifdef DEBUG + fprintf(stderr, " FOUND!"); +#endif + } + } + if (msg == NULL) + msg = (char *)error_message((krb5_error_code)minor_code); +#ifdef DEBUG + fprintf(stderr, " -> %p/%s\n", (void *) msg, msg); +#endif + + return msg; +} +#define save_error_string_nocopy gss_krb5_save_error_string_nocopy +static int save_error_string_nocopy(OM_uint32 minor_code, char *msg) +{ + gsserrmap *p; + int ret; -#include "gssapiP_krb5.h" -#include "gss_libinit.h" -#include "com_err.h" +#ifdef DEBUG + fprintf(stderr, "%s(%lu, %s)", __func__, (unsigned long) minor_code, msg); +#endif + p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE); + if (!p) { + p = malloc(sizeof(*p)); + if (p == NULL) { + ret = 1; + goto fail; + } + if (gsserrmap_init(p) != 0) { + free(p); + p = NULL; + ret = 1; + goto fail; + } + if (k5_setspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE, p) != 0) { + gsserrmap_destroy(p); + free(p); + p = NULL; + ret = 1; + goto fail; + } + } + ret = gsserrmap_replace_or_insert(p, minor_code, msg); + /* Solaris Kerberos */ + if (ret) { + gsserrmap_destroy(p); + free(p); + p = NULL; + } -/* XXXX internationalization!! */ +fail: +#ifdef DEBUG + fprintf(stderr, " p=%p %s\n", (void *)p, ret ? "FAIL" : "SUCCESS"); +#endif + return ret; +} +void save_error_string(OM_uint32 minor_code, char *msg) +{ + char *s = strdup(msg); + if (s) { + if (save_error_string_nocopy(minor_code, s) != 0) + free(s); + } +} +void save_error_message(OM_uint32 minor_code, const char *format, ...) +{ + char *s; + int n; + va_list ap; + + va_start(ap, format); + n = vasprintf(&s, format, ap); + va_end(ap); + if (n >= 0) { + if (save_error_string_nocopy(minor_code, s) != 0) + free(s); + } +} +void krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx) +{ + char *s; + +#ifdef DEBUG + fprintf(stderr, "%s(%lu, ctx=%p)\n", __func__, + (unsigned long) minor_code, (void *)ctx); +#endif + s = (char *)krb5_get_error_message(ctx, (krb5_error_code)minor_code); +#ifdef DEBUG + fprintf(stderr, "%s(%lu, ctx=%p) saving: %s\n", __func__, + (unsigned long) minor_code, (void *)ctx, s); +#endif + save_error_string(minor_code, s); + /* The get_error_message call above resets the error message in + ctx. Put it back, in case we make this call again *sigh*. */ + krb5_set_error_message(ctx, (krb5_error_code)minor_code, "%s", s); + krb5_free_error_message(ctx, s); +} +void krb5_gss_delete_error_info(void *p) +{ + gsserrmap_destroy(p); +} /**/ OM_uint32 krb5_gss_display_status(minor_status, status_value, status_type, - mech_type, message_context, status_string) - OM_uint32 *minor_status; - OM_uint32 status_value; - int status_type; - gss_OID mech_type; - OM_uint32 *message_context; - gss_buffer_t status_string; + mech_type, message_context, status_string) + OM_uint32 *minor_status; + OM_uint32 status_value; + int status_type; + gss_OID mech_type; + OM_uint32 *message_context; + gss_buffer_t status_string; { - status_string->length = 0; - status_string->value = NULL; + status_string->length = 0; + status_string->value = NULL; - if ((mech_type != GSS_C_NULL_OID) && - !g_OID_equal(gss_mech_krb5, mech_type) && - !g_OID_equal(gss_mech_krb5_old, mech_type)) { - *minor_status = 0; - return(GSS_S_BAD_MECH); + if ((mech_type != GSS_C_NULL_OID) && + !g_OID_equal(gss_mech_krb5, mech_type) && + !g_OID_equal(gss_mech_krb5_old, mech_type)) { + *minor_status = 0; + return(GSS_S_BAD_MECH); } - if (status_type == GSS_C_GSS_CODE) { - return(g_display_major_status(minor_status, status_value, - message_context, status_string)); - } else if (status_type == GSS_C_MECH_CODE) { - (void) gssint_initialize_library(); + if (status_type == GSS_C_GSS_CODE) { + return(g_display_major_status(minor_status, status_value, + message_context, status_string)); + } else if (status_type == GSS_C_MECH_CODE) { + (void) gss_krb5int_initialize_library(); + + if (*message_context) { + *minor_status = (OM_uint32) G_BAD_MSG_CTX; + return(GSS_S_FAILURE); + } - if (*message_context) { - *minor_status = (OM_uint32) G_BAD_MSG_CTX; - return(GSS_S_FAILURE); - } + /* If this fails, there's not much we can do... */ + /* Solaris Kerberos - cleaned-up/fixed the return checks/values here */ + if (!g_make_string_buffer(krb5_gss_get_error_message(status_value), + status_string)) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + *minor_status = 0; + return(GSS_S_COMPLETE); + } else { + *minor_status = 0; + return(GSS_S_BAD_STATUS); + } +} - return(g_display_com_err_status(minor_status, status_value, - status_string)); - } else { - *minor_status = 0; - return(GSS_S_BAD_STATUS); - } +/* + * Solaris Kerberos + * Hack alert: workaround obfusicated func name issues for mech_spnego.so. + */ +OM_uint32 +krb5_gss_display_status2(minor_status, status_value, status_type, + mech_type, message_context, status_string) + OM_uint32 *minor_status; + OM_uint32 status_value; + int status_type; + gss_OID mech_type; + OM_uint32 *message_context; + gss_buffer_t status_string; +{ + return(krb5_gss_display_status(minor_status, status_value, + status_type, mech_type, message_context, + status_string)); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/errmap.h Mon Aug 16 17:01:32 2010 -0700 @@ -0,0 +1,276 @@ +/* + * This file is generated, please don't edit it. + * script: ./../../../util/gen.pl + * args: bimap errmap.h NAME=mecherrmap LEFT=OM_uint32 RIGHT=struct mecherror LEFTPRINT=print_OM_uint32 RIGHTPRINT=mecherror_print LEFTCMP=cmp_OM_uint32 RIGHTCMP=mecherror_cmp + * The rest of this file is copied from a template, with + * substitutions. See the template for copyright info. + */ +/* start of t_bimap header template */ +/* + * bidirectional mapping table, add-only + * + * Parameters: + * NAME + * LEFT, RIGHT - types + * LEFTCMP, RIGHTCMP - comparison functions + * + * Methods: + * int init() - nonzero is error code, if any possible + * long size() + * void foreach(int (*)(LEFT, RIGHT, void*), void*) + * int add(LEFT, RIGHT) - 0 = success, -1 = allocation failure + * const struct mecherror *findleft(OM_uint32) - null iff not found + * const OM_uint32 *findright(struct mecherror) + * void destroy() - destroys container, doesn't delete elements + * + * initial implementation: flat array of (left,right) pairs + */ + +struct mecherrmap__pair { + OM_uint32 l; + struct mecherror r; +}; +/* end of t_bimap header template */ +/* start of t_array template */ + +/* + * array type, derived from template + * + * parameters: + * NAME: mecherrmap__pairarray + * TYPE: struct mecherrmap__pair + * + * methods: + * int init() -> nonzero if fail initial allocation + * unsigned long size() -> nonnegative number of values stored + * int grow(newsize) -> negative if fail allocation, memset(,0,) new space + * struct mecherrmap__pair *getaddr(idx) -> aborts if out of range + * void set(idx, value) -> aborts if out of range + * struct mecherrmap__pair get(idx) -> value, or aborts if out of range + */ + +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <string.h> +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif + +struct mecherrmap__pairarray__header { + size_t allocated; + struct mecherrmap__pair *elts; +}; +typedef struct mecherrmap__pairarray__header mecherrmap__pairarray; + +static inline int +mecherrmap__pairarray_init(mecherrmap__pairarray *arr) +{ + arr->elts = calloc(10, sizeof(struct mecherrmap__pair)); + if (arr->elts == NULL) + return ENOMEM; + arr->allocated = 10; + return 0; +} + +static inline long +mecherrmap__pairarray_size(mecherrmap__pairarray *arr) +{ + return arr->allocated; +} + +static inline long +mecherrmap__pairarray_max_size(mecherrmap__pairarray *arr) +{ + size_t upper_bound; + + upper_bound = SIZE_MAX / sizeof(*arr->elts); + if (upper_bound > LONG_MAX) + upper_bound = LONG_MAX; + return (long) upper_bound; +} + +static inline int +mecherrmap__pairarray_grow(mecherrmap__pairarray *arr, unsigned long newcount) +{ + size_t oldsize = sizeof(*arr->elts) * arr->allocated; + size_t newsize; + void *ptr; + + if (newcount > LONG_MAX) + return -1; + if (newcount < arr->allocated) + return 0; + if (newcount > mecherrmap__pairarray_max_size(arr)) + return -1; + + newsize = sizeof(*arr->elts) * newcount; + ptr = realloc(arr->elts, newsize); + if (ptr == NULL) + return -1; + memset((char *)ptr + oldsize, 0, newsize - oldsize); + arr->elts = ptr; + arr->allocated = newcount; + return 0; +} + +static inline struct mecherrmap__pair * +mecherrmap__pairarray_getaddr (mecherrmap__pairarray *arr, long idx) +{ + if (idx < 0 || idx >= arr->allocated) + abort(); + return arr->elts + idx; +} + +static inline void +mecherrmap__pairarray_set (mecherrmap__pairarray *arr, long idx, struct mecherrmap__pair value) +{ + struct mecherrmap__pair *newvalp; + newvalp = mecherrmap__pairarray_getaddr(arr, idx); + *newvalp = value; +} + +static inline struct mecherrmap__pair +mecherrmap__pairarray_get (mecherrmap__pairarray *arr, long idx) +{ + return *mecherrmap__pairarray_getaddr(arr, idx); +} + +static inline void +mecherrmap__pairarray_destroy (mecherrmap__pairarray *arr) +{ + free(arr->elts); + arr->elts = 0; +} +/* end of t_array template */ +/* start of t_bimap body template */ + +/* for use in cases where text substitutions may not work, like putting + "const" before a type that turns out to be "char *" */ +typedef OM_uint32 mecherrmap__left_t; +typedef struct mecherror mecherrmap__right_t; + +typedef struct { + mecherrmap__pairarray a; + long nextidx; +} mecherrmap; + +static inline int +mecherrmap_init (mecherrmap *m) +{ + m->nextidx = 0; + return mecherrmap__pairarray_init (&m->a); +} + +static inline long +mecherrmap_size (mecherrmap *m) +{ + return mecherrmap__pairarray_size (&m->a); +} + +static inline void +mecherrmap_foreach (mecherrmap *m, int (*fn)(OM_uint32, struct mecherror, void *), void *p) +{ + long i, sz; + sz = m->nextidx; + for (i = 0; i < sz; i++) { + struct mecherrmap__pair *pair; + pair = mecherrmap__pairarray_getaddr (&m->a, i); + if ((*fn)(pair->l, pair->r, p) != 0) + break; + } +} + +static inline int +mecherrmap_add (mecherrmap *m, OM_uint32 l, struct mecherror r) +{ + long i, sz; + struct mecherrmap__pair newpair; + int err; + + sz = m->nextidx; + /* Make sure we're not duplicating. */ + for (i = 0; i < sz; i++) { + struct mecherrmap__pair *pair; + pair = mecherrmap__pairarray_getaddr (&m->a, i); + assert ((*cmp_OM_uint32)(l, pair->l) != 0); + if ((*cmp_OM_uint32)(l, pair->l) == 0) + abort(); + assert ((*mecherror_cmp)(r, pair->r) != 0); + if ((*mecherror_cmp)(r, pair->r) == 0) + abort(); + } + newpair.l = l; + newpair.r = r; + if (sz >= LONG_MAX - 1) + return ENOMEM; + err = mecherrmap__pairarray_grow (&m->a, sz+1); + if (err) + return err; + mecherrmap__pairarray_set (&m->a, sz, newpair); + m->nextidx++; + return 0; +} + +static inline const mecherrmap__right_t * +mecherrmap_findleft (mecherrmap *m, OM_uint32 l) +{ + long i, sz; + sz = mecherrmap_size (m); + for (i = 0; i < sz; i++) { + struct mecherrmap__pair *pair; + pair = mecherrmap__pairarray_getaddr (&m->a, i); + if ((*cmp_OM_uint32)(l, pair->l) == 0) + return &pair->r; + } + return 0; +} + +static inline const mecherrmap__left_t * +mecherrmap_findright (mecherrmap *m, struct mecherror r) +{ + long i, sz; + sz = mecherrmap_size (m); + for (i = 0; i < sz; i++) { + struct mecherrmap__pair *pair; + pair = mecherrmap__pairarray_getaddr (&m->a, i); + if ((*mecherror_cmp)(r, pair->r) == 0) + return &pair->l; + } + return 0; +} + +struct mecherrmap__printstat { + FILE *f; + int comma; +}; +static inline int +mecherrmap__printone (OM_uint32 l, struct mecherror r, void *p) +{ + struct mecherrmap__printstat *ps = p; + fprintf(ps->f, ps->comma ? ", (" : "("); + ps->comma = 1; + (*print_OM_uint32)(l, ps->f); + fprintf(ps->f, ","); + (*mecherror_print)(r, ps->f); + fprintf(ps->f, ")"); + return 0; +} + +static inline void +mecherrmap_printmap (mecherrmap *m, FILE *f) +{ + struct mecherrmap__printstat ps; + ps.comma = 0; + ps.f = f; + fprintf(f, "("); + mecherrmap_foreach (m, mecherrmap__printone, &ps); + fprintf(f, ")"); +} + +static inline void +mecherrmap_destroy (mecherrmap *m) +{ + mecherrmap__pairarray_destroy (&m->a); +} +/* end of t_bimap body template */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/error_map.h Mon Aug 16 17:01:32 2010 -0700 @@ -0,0 +1,113 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ +/* + * This file is generated, please don't edit it. + * script: ./../../../util/gen-map.pl + * args: + * -oerror_map.new + * NAME=gsserrmap + * KEY=OM_uint32 + * VALUE=char * + * COMPARE=compare_OM_uint32 + * FREEVALUE=free_string + * The rest of this file is copied from a template, with + * substitutions. See the template for copyright info. + */ +/* + * map, generated from template + * map name: gsserrmap + * key: OM_uint32 + * value: char * + * compare: compare_OM_uint32 + * copy_key: 0 + * free_key: 0 + * free_value: free_string + */ +struct gsserrmap__element { + OM_uint32 key; + char * value; + struct gsserrmap__element *next; +}; +struct gsserrmap__head { + struct gsserrmap__element *first; +}; +typedef struct gsserrmap__head gsserrmap; +static inline int gsserrmap_init (struct gsserrmap__head *head) +{ + head->first = NULL; + return 0; +} +static inline void gsserrmap_destroy (struct gsserrmap__head *head) +{ + struct gsserrmap__element *e, *e_next; + void (*free_key)(OM_uint32) = 0; + void (*free_value)(char *) = free_string; + for (e = head->first; e; e = e_next) { + e_next = e->next; + if (free_key) + (*free_key)(e->key); + if (free_value) + (*free_value)(e->value); + free(e); + } + head->first = NULL; +} +/* Returns pointer to linked-list entry, or null if key not found. */ +static inline struct gsserrmap__element * +gsserrmap__find_node (struct gsserrmap__head *head, OM_uint32 key) +{ + struct gsserrmap__element *e; + for (e = head->first; e; e = e->next) + if (compare_OM_uint32 (key, e->key) == 0) + return e; + return 0; +} +/* Returns pointer to value, or null if key not found. */ +static inline char * * +gsserrmap_find (struct gsserrmap__head *head, OM_uint32 key) +{ + struct gsserrmap__element *e = gsserrmap__find_node(head, key); + if (e) + return &e->value; + return 0; +} +/* Returns 0 or error code. */ +static inline int +gsserrmap__copy_key (OM_uint32 *out, OM_uint32 in) +{ + int (*copykey)(OM_uint32 *, OM_uint32) = 0; + if (copykey == 0) { + *out = in; + return 0; + } else + return (*copykey)(out, in); +} +/* Returns 0 or error code. */ +static inline int +gsserrmap_replace_or_insert (struct gsserrmap__head *head, + OM_uint32 key, char * new_value) +{ + struct gsserrmap__element *e = gsserrmap__find_node(head, key); + int ret; + + if (e) { + /* replace */ + void (*free_value)(char *) = free_string; + if (free_value) + (*free_value)(e->value); + e->value = new_value; + } else { + /* insert */ + e = malloc(sizeof(*e)); + if (e == NULL) + return ENOMEM; + ret = gsserrmap__copy_key (&e->key, key); + if (ret) { + free(e); + return ret; + } + e->value = new_value; + e->next = head->first; + head->first = e; + } + return 0; +}
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/export_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/export_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,5 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" - +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * lib/gssapi/krb5/export_name.c * @@ -52,16 +53,28 @@ exported_name->value = NULL; if (! kg_validate_name(input_name)) { - if (minor_status) - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - krb5_free_context(context); - return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + /* Solaris Kerberos: spruce-up the err msg */ + krb5_principal princ = (krb5_principal) input_name; + char *s_name = NULL; + int kret = krb5_unparse_name(context, princ, &s_name); + if (minor_status) + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + if (minor_status && kret == 0) { + krb5_set_error_message(context, *minor_status, + "Input name principal '%s' is invalid (kg_validate_name()) for export_name", + s_name); + save_error_info(*minor_status, context); + krb5_free_unparsed_name(context, s_name); + } + krb5_free_context(context); + return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } if ((code = krb5_unparse_name(context, (krb5_principal) input_name, &str))) { if (minor_status) *minor_status = code; + save_error_info((OM_uint32)code, context); krb5_free_context(context); return(GSS_S_FAILURE); }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/export_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/export_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -92,6 +92,9 @@ return (GSS_S_COMPLETE); error_out: + if (retval != GSS_S_COMPLETE) + if (kret != 0 && context != 0) + save_error_info((OM_uint32)kret, context); if (obuffer && bufsize) { memset(obuffer, 0, bufsize); xfree(obuffer);
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/gss_libinit.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/gss_libinit.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,7 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - #include <assert.h> #include "gssapi_err_generic.h" @@ -14,7 +12,6 @@ #include "k5-platform.h" #include "mglueP.h" - /* * Initialize the GSSAPI library. */ @@ -48,6 +45,10 @@ err = k5_key_register(K5_KEY_GSS_KRB5_CCACHE_NAME, free); if (err) return err; + err = k5_key_register(K5_KEY_GSS_KRB5_ERROR_MESSAGE, + krb5_gss_delete_error_info); + if (err) + return err; #ifndef _WIN32 err = k5_mutex_finish_init(&kg_kdc_flag_mutex); if (err)
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/import_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/import_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,5 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" - +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright 1993 by OpenVision Technologies, Inc. * @@ -38,6 +39,7 @@ #else #include <strings.h> #endif +#include <locale.h> /* * errors: @@ -103,18 +105,24 @@ xfree(tmp); } else if ((input_name_type != GSS_C_NULL_OID) && (g_OID_equal(input_name_type, gss_nt_krb5_principal))) { - krb5_principal input; + krb5_principal input; - if (input_name_buffer->length != sizeof(krb5_principal)) { - *minor_status = (OM_uint32) G_WRONG_SIZE; - krb5_free_context(context); - return(GSS_S_BAD_NAME); + if (input_name_buffer->length != sizeof(krb5_principal)) { + *minor_status = (OM_uint32) G_WRONG_SIZE; + /* Solaris Kerberos: spruce-up the err msg */ + krb5_set_error_message(context, *minor_status, + dgettext(TEXT_DOMAIN, + "The size of the specified principal is wrong")); + save_error_info(*minor_status, context); + krb5_free_context(context); + return(GSS_S_BAD_NAME); } input = *((krb5_principal *) input_name_buffer->value); if ((code = krb5_copy_principal(context, input, &princ))) { *minor_status = code; + save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } @@ -200,11 +208,18 @@ code = krb5_parse_name(context, (char *) stringrep, &princ); else { fail_name: - xfree(tmp); - if (tmp2) + xfree(tmp); + if (tmp2) xfree(tmp2); - krb5_free_context(context); - return(GSS_S_BAD_NAME); + + /* Solaris Kerberos: spruce-up (not much, sigh) the err msg */ + krb5_set_error_message(context, *minor_status, + dgettext(TEXT_DOMAIN, + "Failed to convert the specified principal to GSS-API internal format")); + save_error_info(*minor_status, context); + + krb5_free_context(context); + return(GSS_S_BAD_NAME); } if (tmp2) @@ -216,9 +231,17 @@ contains the return status */ if (code) { - *minor_status = (OM_uint32) code; - krb5_free_context(context); - return(GSS_S_BAD_NAME); + /* Solaris Kerberos: spruce-up the err msg */ + *minor_status = (OM_uint32) code; + /* krb5_sname_to_principal() sets specific err msg for bad hostname. */ + if (*minor_status != (OM_uint32)KRB5_ERR_BAD_HOSTNAME) + krb5_set_error_message(context, *minor_status, + dgettext(TEXT_DOMAIN, + "Failed to convert the specified principal to GSS-API internal format: %s"), + error_message(code)); + save_error_info(*minor_status, context); + krb5_free_context(context); + return(GSS_S_BAD_NAME); } /* save the name in the validation database */
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/init_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/init_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright 2000,2002, 2003 by the Massachusetts Institute of Technology. * All Rights Reserved. @@ -724,11 +721,28 @@ if (! krb5_principal_compare(context, ctx->there, (krb5_principal) target_name)) { - (void)krb5_gss_delete_sec_context(minor_status, + /* Solaris Kerberos: spruce-up the err msg */ + krb5_principal tname = (krb5_principal) target_name; + char *s_name = NULL, *s_princ= NULL; + int kret = krb5_unparse_name(context, tname, &s_name); + int kret1 = krb5_unparse_name(context, ctx->there, &s_princ); + code = KRB5_PRINC_NOMATCH; + if (kret == 0 && kret1 == 0) { + krb5_set_error_message(context, code, + dgettext(TEXT_DOMAIN, + "Target name principal '%s' does not match '%s'"), + s_name, s_princ); + save_error_info(code, context); + } + if (s_name) + krb5_free_unparsed_name(context, s_name); + if (s_princ) + krb5_free_unparsed_name(context, s_princ); + + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); - code = 0; - major_status = GSS_S_BAD_NAME; - goto fail; + major_status = GSS_S_BAD_NAME; + goto fail; } /* verify the token and leave the AP_REP message in ap_rep */ @@ -875,8 +889,11 @@ *minor_status = kerr; return GSS_S_FAILURE; } - if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) + if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) { + save_error_info(*minor_status, context); + krb5_free_context(context); return GSS_S_FAILURE; + } } else { context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context; } @@ -892,10 +909,23 @@ /* verify that the target_name is valid and usable */ if (! kg_validate_name(target_name)) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - if (*context_handle == GSS_C_NO_CONTEXT) - krb5_free_context(context); - return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + /* Solaris Kerberos: spruce-up the err msg */ + krb5_principal princ = (krb5_principal) target_name; + char *s_name = NULL; + int kret = krb5_unparse_name(context, princ, &s_name); + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + if (kret == 0) { + krb5_set_error_message(context, *minor_status, + dgettext(TEXT_DOMAIN, + "Target name principal '%s' is invalid"), + s_name); + krb5_free_unparsed_name(context, s_name); + save_error_info(*minor_status, context); + } + + if (*context_handle == GSS_C_NO_CONTEXT) + krb5_free_context(context); + return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } /* verify the credential, or use the default */ @@ -909,13 +939,15 @@ major_status = get_default_cred(minor_status, context, (gss_cred_id_t *)&cred); if (major_status && GSS_ERROR(major_status)) { - if (*context_handle == GSS_C_NO_CONTEXT) - krb5_free_context(context); + save_error_info(*minor_status, context); + if (*context_handle == GSS_C_NO_CONTEXT) + krb5_free_context(context); return(major_status); } } else { major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle); if (GSS_ERROR(major_status)) { + save_error_info(*minor_status, context); if (*context_handle == GSS_C_NO_CONTEXT) krb5_free_context(context); return(major_status); @@ -975,9 +1007,10 @@ output_token, ret_flags, time_rec, context, default_mech); k5_mutex_unlock(&cred->lock); - if (*context_handle == GSS_C_NO_CONTEXT) + if (*context_handle == GSS_C_NO_CONTEXT) { + save_error_info (*minor_status, context); krb5_free_context(context); - else + } else ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context; } else { /* mutual_auth doesn't care about the credentials */ @@ -1409,11 +1442,13 @@ } else { /* Try to set a useful error message */ char *princ = NULL; - krb5_unparse_name(context, me, &princ); + krb5_error_code ret; + ret = krb5_unparse_name(context, me, &princ); krb5_set_error_message(context, code, - gettext("Failed to find realm for %s in keytab"), - princ ? princ : "<unknown>"); + dgettext(TEXT_DOMAIN, + "Failed to find realm for %s in keytab"), + ret == 0 ? princ : "unknown"); if (princ) krb5_free_unparsed_name(context, princ); }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1993 by OpenVision Technologies, Inc. @@ -1391,6 +1390,7 @@ */ if ((data_set == GSS_C_NO_BUFFER_SET) || (data_set->count == 0)) { gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; return GSS_S_FAILURE; }
--- a/usr/src/lib/gss_mechs/mech_krb5/mech/rel_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/rel_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,5 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" - +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright 1993 by OpenVision Technologies, Inc. * @@ -90,7 +91,6 @@ free(cred->req_enctypes); xfree(cred); - krb5_free_context(context); *cred_handle = NULL; @@ -102,5 +102,8 @@ if (code3) *minor_status = code3; + if (*minor_status) + save_error_info(*minor_status, context); + krb5_free_context(context); return(*minor_status?GSS_S_FAILURE:GSS_S_COMPLETE); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/util_errmap.c Mon Aug 16 17:01:32 2010 -0700 @@ -0,0 +1,286 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2007, 2008 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. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * 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. + * + */ + +#include "gssapiP_generic.h" +#include "mechglueP.h" +#include <string.h> +#include <stdio.h> +#ifndef _WIN32 +#include <unistd.h> +#endif + +/* Solaris Kerberos */ +#define inline +#ifdef DEBUG +#undef DEBUG +#endif + +/* The mapping table is 0-based, but let's export codes that are + 1-based, keeping 0 for errors or unknown errors. + + The elements in the mapping table currently have separate copies of + each OID stored. This is a bit wasteful, but we are assuming the + table isn't likely to grow very large. */ + +struct mecherror { + gss_OID_desc mech; + OM_uint32 code; +}; + +static inline int +cmp_OM_uint32(OM_uint32 m1, OM_uint32 m2) +{ + if (m1 < m2) + return -1; + else if (m1 > m2) + return 1; + else + return 0; +} + +static inline int +mecherror_cmp(struct mecherror m1, struct mecherror m2) +{ + if (m1.code < m2.code) + return -1; + if (m1.code > m2.code) + return 1; + if (m1.mech.length < m2.mech.length) + return -1; + if (m1.mech.length > m2.mech.length) + return 1; + if (m1.mech.length == 0) + return 0; + return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length); +} + +static void +print_OM_uint32 (OM_uint32 value, FILE *f) +{ + fprintf(f, "%lu", (unsigned long) value); +} + +static inline int +mecherror_copy(struct mecherror *dest, struct mecherror src) +{ + *dest = src; + dest->mech.elements = malloc(src.mech.length); + if (dest->mech.elements == NULL) { + if (src.mech.length) + return ENOMEM; + else + return 0; + } + memcpy(dest->mech.elements, src.mech.elements, src.mech.length); + return 0; +} + +static void +mecherror_print(struct mecherror value, FILE *f) +{ + OM_uint32 minor; + gss_buffer_desc str; + static const struct { + const char *oidstr, *name; + } mechnames[] = { + { "{ 1 2 840 113554 1 2 2 }", "krb5-new" }, + { "{ 1 3 5 1 5 2 }", "krb5-old" }, + { "{ 1 2 840 48018 1 2 2 }", "krb5-microsoft" }, + { "{ 1 3 6 1 5 5 2 }", "spnego" }, + }; + unsigned int i; + + fprintf(f, "%lu@", (unsigned long) value.code); + + if (value.mech.length == 0) { + fprintf(f, "(com_err)"); + return; + } + fprintf(f, "%p=", value.mech.elements); + if (generic_gss_oid_to_str(&minor, &value.mech, &str)) { + fprintf(f, "(error in conversion)"); + return; + } + /* Note: generic_gss_oid_to_str returns a null-terminated string. */ + for (i = 0; i < sizeof(mechnames)/sizeof(mechnames[0]); i++) { + if (!strcmp(str.value, mechnames[i].oidstr) && mechnames[i].name != 0) { + fprintf(f, "%s", mechnames[i].name); + break; + } + } + if (i == sizeof(mechnames)/sizeof(mechnames[0])) + fprintf(f, "%s", (char *) str.value); + generic_gss_release_buffer(&minor, &str); +} + +#include "errmap.h" +#include "krb5.h" /* for KRB5KRB_AP_WRONG_PRINC */ + +static mecherrmap m; +static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER; +static OM_uint32 next_fake = 100000; + +int gssint_mecherrmap_init(void) +{ + int err; + + err = mecherrmap_init(&m); + if (err) + return err; + err = k5_mutex_finish_init(&mutex); + if (err) { + mecherrmap_destroy(&m); + return err; + } + + return 0; +} + +/* Currently the enumeration template doesn't handle freeing + element storage when destroying the collection. */ +static int free_one(OM_uint32 i, struct mecherror value, void *p) +{ + if (value.mech.length && value.mech.elements) + free(value.mech.elements); + return 0; +} + +void gssint_mecherrmap_destroy(void) +{ + mecherrmap_foreach(&m, free_one, NULL); + mecherrmap_destroy(&m); + k5_mutex_destroy(&mutex); +} + +OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid) +{ + const struct mecherror *mep; + struct mecherror me, me_copy; + const OM_uint32 *p; + int err; + OM_uint32 new_status; + +#ifdef DEBUG + FILE *f; + f = fopen("/dev/pts/9", "w+"); + if (f == NULL) + f = stderr; +#endif + + me.code = minor; + me.mech = *oid; + err = k5_mutex_lock(&mutex); + if (err) { +#ifdef DEBUG + if (f != stderr) fclose(f); +#endif + return 0; + } + + /* Is this status+oid already mapped? */ + p = mecherrmap_findright(&m, me); + if (p != NULL) { + k5_mutex_unlock(&mutex); +#ifdef DEBUG + fprintf(f, "%s: found ", __func__); + mecherror_print(me, f); + fprintf(f, " in map as %lu\n", (unsigned long) *p); + if (f != stderr) fclose(f); +#endif + return *p; + } + /* Is this status code already mapped to something else + mech-specific? */ + mep = mecherrmap_findleft(&m, minor); + if (mep == NULL) { + /* Map it to itself plus this mech-oid. */ + new_status = minor; + } else { + /* Already assigned. Pick a fake new value and map it. */ + /* There's a theoretical infinite loop risk here, if we fill + in 2**32 values. Also, returning 0 has a special + meaning. */ + do { + next_fake++; + new_status = next_fake; + if (new_status == 0) + /* ??? */; + } while (mecherrmap_findleft(&m, new_status) != NULL); + } + err = mecherror_copy(&me_copy, me); + if (err) { + k5_mutex_unlock(&mutex); + return err; + } + err = mecherrmap_add(&m, new_status, me_copy); + k5_mutex_unlock(&mutex); + if (err) { + if (me_copy.mech.length) + free(me_copy.mech.elements); + } +#ifdef DEBUG + fprintf(f, "%s: mapping ", __func__); + mecherror_print(me, f); + fprintf(f, " to %lu: err=%d\nnew map: ", (unsigned long) new_status, err); + mecherrmap_printmap(&m, f); + fprintf(f, "\n"); + if (f != stderr) fclose(f); +#endif + + if (err) + return 0; + else + return new_status; +} + +static gss_OID_desc no_oid = { 0, 0 }; +OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode) +{ + return gssint_mecherrmap_map(errcode, &no_oid); +} + +int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid, + OM_uint32 *mech_minor) +{ + const struct mecherror *p; + int err; + + if (minor == 0) { + return EINVAL; + } + err = k5_mutex_lock(&mutex); + if (err) + return err; + p = mecherrmap_findleft(&m, minor); + k5_mutex_unlock(&mutex); + if (!p) { + return EINVAL; + } + *mech_oid = p->mech; + *mech_minor = p->code; + return 0; +}
--- a/usr/src/lib/gss_mechs/mech_spnego/Makefile.com Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_spnego/Makefile.com Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # @@ -32,7 +31,7 @@ LIBRARY = mech_spnego.a VERS = .1 -OBJECTS = spnego_mech.o +OBJECTS = spnego_mech.o spnego_disp_status.o spnego_kerrs.o # include library definitions include ../../../Makefile.lib @@ -47,7 +46,7 @@ $(CLOSED)/lib/gss_mechs/mech_spnego/mapfile-vers-export MAPFILES = ../mapfile-vers $(MAPFILE_EXPORT) -CPPFLAGS += -I$(SRC)/uts/common/gssapi/include $(DEBUG) -I$(SRC)/lib/gss_mechs/mech_krb5/include -I$(SRC)/uts/common/gssapi/mechs/krb5/include +CPPFLAGS += -I$(SRC)/uts/common/gssapi/include $(DEBUG) -I$(SRC)/lib/gss_mechs/mech_krb5/include -I$(SRC)/uts/common/gssapi/mechs/krb5/include -I$(SRC)/lib/gss_mechs/mech_krb5/mech MAKEFILE_EXPORT = $(CLOSED)/lib/gss_mechs/mech_spnego/Makefile.export $(EXPORT_RELEASE_BUILD)include $(MAKEFILE_EXPORT)
--- a/usr/src/lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h Mon Aug 16 17:01:32 2010 -0700 @@ -1,13 +1,9 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - #ifndef _GSSAPIP_SPNEGO_H_ #define _GSSAPIP_SPNEGO_H_ -/* #pragma ident "@(#)gssapiP_spnego.h 1.3 03/09/18 SMI" */ - #ifdef __cplusplus extern "C" { #endif @@ -100,6 +96,7 @@ OM_uint32 ctx_flags; gss_name_t internal_name; gss_OID actual_mech; + struct errinfo err; } spnego_gss_ctx_id_rec, *spnego_gss_ctx_id_t; /* @@ -112,10 +109,6 @@ extern const gss_OID_desc * const gss_mech_spnego; extern const gss_OID_set_desc * const gss_mech_set_spnego; -/* SUNW17PACresync */ -#define TWRITE_STR(ptr, str, len) \ - memcpy((ptr), (char *)(str), (len)); \ - (ptr) += (len); #ifdef DEBUG #define dsyslog(a) syslog(LOG_DEBUG, a) @@ -282,6 +275,16 @@ gss_buffer_t /* status_string */ ); +OM_uint32 spnego_gss_display_status2 +( + OM_uint32 *, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + gss_OID, /* mech_type */ + OM_uint32 *, /* message_context */ + gss_buffer_t /* status_string */ +); + OM_uint32 glue_spnego_gss_display_status ( void *, @@ -507,13 +510,6 @@ ); -#ifdef _GSS_STATIC_LINK -int gss_spnegoint_lib_init(void); -void gss_spnegoint_lib_fini(void); -#else -gss_mechanism KRB5_CALLCONV gss_mech_initialize(void); -#endif /* _GSS_STATIC_LINK */ - #if 0 /* SUNW17PACresync - will be needed for full MIT 1.7 resync */ OM_uint32 spnego_gss_wrap_aead ( @@ -579,6 +575,26 @@ ); #endif /* 0 */ +/* + * Solaris SPNEGO + * Cloned the krb5_*_error_message and krb5_gss_*_error_info APIs + * to give similar functionality to SPNEGO mech. + * See new files in this dir: + * spnego_disp_status.c + * spnego_kerrs.c + * error_map.h + */ +typedef int spnego_error_code; +void spnego_set_error_message (spnego_gss_ctx_id_t, spnego_error_code, const char *, ...); +const char * spnego_get_error_message (spnego_gss_ctx_id_t, spnego_error_code); +void spnego_free_error_message (spnego_gss_ctx_id_t, const char *); +void spnego_clear_error_message (spnego_gss_ctx_id_t); + +void spnego_gss_save_error_info(OM_uint32 minor_code, spnego_gss_ctx_id_t ctx); +char *spnego_gss_get_error_message(OM_uint32 minor_code); +void spnego_gss_delete_error_info(void *p); + +OM_uint32 krb5_gss_display_status2(); #ifdef __cplusplus } #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_disp_status.c Mon Aug 16 17:01:32 2010 -0700 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <unistd.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <k5-int.h> +#include <krb5.h> +#include <mglueP.h> +#include "gssapiP_spnego.h" +#include "gssapiP_generic.h" +#include <gssapi_err_generic.h> + +/* X internationalization!! */ + +static inline int +compare_OM_uint32 (OM_uint32 a, OM_uint32 b) +{ + if (a < b) + return -1; + else if (a == b) + return 0; + else + return 1; +} +static inline void +free_string (char *s) +{ + free(s); +} +#include "error_map.h" +#include <stdio.h> + +#define get_error_message spnego_gss_get_error_message +char *get_error_message(OM_uint32 minor_code) +{ + gsserrmap *p = k5_getspecific(K5_KEY_GSS_SPNEGO_ERROR_MESSAGE); + char *msg = NULL; + +#ifdef DEBUG + fprintf(stderr, "%s(%lu, p=%p)", __func__, (unsigned long) minor_code, + (void *) p); +#endif + if (p) { + char **v = gsserrmap_find(p, minor_code); + if (v) { + msg = *v; +#ifdef DEBUG + fprintf(stderr, " FOUND!"); +#endif + } + } + if (msg == 0) + msg = (char *)error_message(minor_code); +#ifdef DEBUG + fprintf(stderr, " -> %p/%s\n", (void *) msg, msg); +#endif + + return msg; +} + +static int save_error_string_nocopy(OM_uint32 minor_code, char *msg) +{ + gsserrmap *p; + int ret; + +#ifdef DEBUG + fprintf(stderr, "%s(%lu, %s)", __func__, (unsigned long) minor_code, msg); +#endif + p = k5_getspecific(K5_KEY_GSS_SPNEGO_ERROR_MESSAGE); + if (!p) { + p = malloc(sizeof(*p)); + if (p == NULL) { + ret = 1; + goto fail; + } + if (gsserrmap_init(p) != 0) { + free(p); + p = NULL; + ret = 1; + goto fail; + } + if (k5_setspecific(K5_KEY_GSS_SPNEGO_ERROR_MESSAGE, p) != 0) { + gsserrmap_destroy(p); + free(p); + p = NULL; + ret = 1; + goto fail; + } + } + ret = gsserrmap_replace_or_insert(p, minor_code, msg); + /* Solaris SPNEGO */ + if (ret) { + gsserrmap_destroy(p); + free(p); + p = NULL; + } + +fail: +#ifdef DEBUG + fprintf(stderr, " p=%p %s\n", (void *)p, ret ? "FAIL" : "SUCCESS"); +#endif + return ret; +} +void save_error_string(OM_uint32 minor_code, char *msg) +{ + char *s = strdup(msg); + if (s) { + if (save_error_string_nocopy(minor_code, s) != 0) + free(s); + } +} +void save_error_message(OM_uint32 minor_code, const char *format, ...) +{ + char *s; + int n; + va_list ap; + + va_start(ap, format); + n = vasprintf(&s, format, ap); + va_end(ap); + if (n >= 0) { + if (save_error_string_nocopy(minor_code, s) != 0) + free(s); + } +} +void spnego_gss_save_error_info(OM_uint32 minor_code, spnego_gss_ctx_id_t ctx) +{ + char *s; + +#ifdef DEBUG + fprintf(stderr, "%s(%lu, ctx=%p)\n", __func__, + (unsigned long) minor_code, (void *)ctx); +#endif + s = (char *)spnego_get_error_message(ctx, minor_code); +#ifdef DEBUG + fprintf(stderr, "%s(%lu, ctx=%p) saving: %s\n", __func__, + (unsigned long) minor_code, (void *)ctx, s); +#endif + save_error_string(minor_code, s); + /* The get_error_message call above resets the error message in + ctx. Put it back, in case we make this call again *sigh*. */ + spnego_set_error_message(ctx, minor_code, "%s", s); + spnego_free_error_message(ctx, s); +} +void spnego_gss_delete_error_info(void *p) +{ + gsserrmap_destroy(p); +} + +OM_uint32 +spnego_gss_display_status2(minor_status, status_value, status_type, + mech_type, message_context, status_string) + OM_uint32 *minor_status; + OM_uint32 status_value; + int status_type; + gss_OID mech_type; + OM_uint32 *message_context; + gss_buffer_t status_string; +{ + status_string->length = 0; + status_string->value = NULL; + + if ((mech_type != GSS_C_NULL_OID) && + !g_OID_equal(gss_mech_spnego, mech_type)) { + *minor_status = 0; + return(GSS_S_BAD_MECH); + } + + if (status_type == GSS_C_GSS_CODE) { + return(g_display_major_status(minor_status, status_value, + message_context, status_string)); + } else if (status_type == GSS_C_MECH_CODE) { + /* + * Solaris SPNEGO + * This init call appears to be not needed as + * gss_spnegoint_lib_init() is called on dl open. + */ +#if 0 + (void) gss_spnegoint_initialize_library(); +#endif + + if (*message_context) { + *minor_status = (OM_uint32) G_BAD_MSG_CTX; + return(GSS_S_FAILURE); + } + + /* If this fails, there's not much we can do... */ + if (g_make_string_buffer(spnego_gss_get_error_message(status_value), + status_string) != 0) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } else + *minor_status = 0; + return(0); + } else { + *minor_status = 0; + return(GSS_S_BAD_STATUS); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_kerrs.c Mon Aug 16 17:01:32 2010 -0700 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ +/* + * lib/krb5/krb/kerrs.c + * + * Copyright 2006 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. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * 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. + * + * error-message functions + */ +#include <sys/param.h> +#include <unistd.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <k5-int.h> +#include <krb5.h> +#include <mglueP.h> +#include "gssapiP_spnego.h" +#include "gssapiP_generic.h" +#include <gssapi_err_generic.h> + +#ifdef DEBUG +static int error_message_debug = 0; +#ifndef ERROR_MESSAGE_DEBUG +#define ERROR_MESSAGE_DEBUG() (error_message_debug != 0) +#endif +#endif + +void +spnego_set_error_message (spnego_gss_ctx_id_t ctx, spnego_error_code code, + const char *fmt, ...) +{ + va_list args; + if (ctx == NULL) + return; + va_start (args, fmt); +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, + "spnego_set_error_message(ctx=%p/err=%p, code=%ld, ...)\n", + ctx, &ctx->err, (long) code); +#endif + krb5int_vset_error (&ctx->err, code, fmt, args); +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, "->%s\n", ctx->err.msg); +#endif + va_end (args); +} + +void +spnego_vset_error_message (spnego_gss_ctx_id_t ctx, spnego_error_code code, + const char *fmt, va_list args) +{ +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, "spnego_vset_error_message(ctx=%p, code=%ld, ...)\n", + ctx, (long) code); +#endif + if (ctx == NULL) + return; + krb5int_vset_error (&ctx->err, code, fmt, args); +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, "->%s\n", ctx->err.msg); +#endif +} + +const char * +spnego_get_error_message (spnego_gss_ctx_id_t ctx, spnego_error_code code) +{ +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, "spnego_get_error_message(%p, %ld)\n", ctx, (long) code); +#endif + if (ctx == NULL) + return error_message(code); + return krb5int_get_error (&ctx->err, code); +} + +void +spnego_free_error_message (spnego_gss_ctx_id_t ctx, const char *msg) +{ +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, "spnego_free_error_message(%p, %p)\n", ctx, msg); +#endif + if (ctx == NULL) + return; + krb5int_free_error (&ctx->err, msg); +} + +void +spnego_clear_error_message (spnego_gss_ctx_id_t ctx) +{ +#ifdef DEBUG + if (ERROR_MESSAGE_DEBUG()) + fprintf(stderr, "spnego_clear_error_message(%p)\n", ctx); +#endif + if (ctx == NULL) + return; + krb5int_clear_error (&ctx->err); +}
--- a/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,3 +1,6 @@ +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright (C) 2006,2008 by the Massachusetts Institute of Technology. * All rights reserved. @@ -24,9 +27,6 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * * A module that implements the spnego security mechanism. * It is used to negotiate the security mechanism between * peers using the GSS-API. @@ -72,8 +72,9 @@ #include <krb5.h> #include <mglueP.h> #include "gssapiP_spnego.h" +#include "gssapiP_generic.h" #include <gssapi_err_generic.h> - +#include <locale.h> /* * SUNW17PACresync @@ -217,6 +218,12 @@ acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, gss_cred_id_t, gss_buffer_t *, OM_uint32 *, send_token_flag *); +#ifdef _GSS_STATIC_LINK +int gss_spnegoint_lib_init(void); +void gss_spnegoint_lib_fini(void); +#else +gss_mechanism gss_mech_initialize(void); +#endif /* _GSS_STATIC_LINK */ /* * The Mech OID for SPNEGO: @@ -286,7 +293,8 @@ #ifdef _GSS_STATIC_LINK #include "mglueP.h" -static int gss_spnegomechglue_init(void) +static +int gss_spnegomechglue_init(void) { struct gss_mech_config mech_spnego; @@ -298,25 +306,48 @@ return gssint_register_mechinfo(&mech_spnego); } #else +/* Entry point for libgss */ gss_mechanism KRB5_CALLCONV gss_mech_initialize(void) { + int err; + + err = k5_key_register(K5_KEY_GSS_SPNEGO_ERROR_MESSAGE, + spnego_gss_delete_error_info); + if (err) { + syslog(LOG_NOTICE, + "SPNEGO gss_mech_initialize: error message TSD key register fail"); + return (NULL); + } + return (&spnego_mechanism); } #if 0 /* SUNW17PACresync */ MAKE_INIT_FUNCTION(gss_krb5int_lib_init); MAKE_FINI_FUNCTION(gss_krb5int_lib_fini); - int gss_krb5int_lib_init(void) +int gss_krb5int_lib_init(void) #endif #endif /* _GSS_STATIC_LINK */ -static int gss_spnegoint_lib_init(void) +static +int gss_spnegoint_lib_init(void) { #ifdef _GSS_STATIC_LINK return gss_spnegomechglue_init(); #else + int err; + + err = k5_key_register(K5_KEY_GSS_SPNEGO_ERROR_MESSAGE, + spnego_gss_delete_error_info); + if (err) { + syslog(LOG_NOTICE, + "SPNEGO gss_mech_initialize: error message TSD key register fail: err=%d", + err); + return err; + } + return 0; #endif } @@ -465,7 +496,8 @@ spnego_ctx->nego_done = 0; spnego_ctx->internal_name = GSS_C_NO_NAME; spnego_ctx->actual_mech = GSS_C_NO_OID; - + spnego_ctx->err.msg = NULL; + spnego_ctx->err.scratch_buf[0] = 0; check_spnego_options(spnego_ctx); return (spnego_ctx); @@ -679,6 +711,10 @@ } if (acc_negState == REJECT) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + /* Solaris SPNEGO */ + spnego_set_error_message(sc, *minor_status, + dgettext(TEXT_DOMAIN, + "SPNEGO failed to negotiate a mechanism: server rejected request")); map_errcode(minor_status); *tokflag = NO_TOKEN_SEND; ret = GSS_S_FAILURE; @@ -742,6 +778,10 @@ } if (acc_negState == ACCEPT_DEFECTIVE_TOKEN) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + /* Solaris SPNEGO */ + spnego_set_error_message(sc, *minor_status, + dgettext(TEXT_DOMAIN, + "SPNEGO failed to negotiate a mechanism: defective token")); map_errcode(minor_status); return GSS_S_DEFECTIVE_TOKEN; } @@ -1004,6 +1044,11 @@ } } spnego_ctx = (spnego_gss_ctx_id_t)*context_handle; + + /* Solaris SPNEGO */ + if (*minor_status == ERR_SPNEGO_NEGOTIATION_FAILED) + spnego_gss_save_error_info(*minor_status, spnego_ctx); + if (!spnego_ctx->mech_complete) { ret = init_ctx_call_init( minor_status, spnego_ctx, @@ -1339,6 +1384,76 @@ } /* + * Solaris SPNEGO + * mechoidset2str() + * Input an OID set of mechs and output a string like so: + * '{ x y z } (mechname0), { a b c } (mechname1) ...'. + * On error return NULL. + * Caller needs to free returned string. + */ +static const char *mech_no_map = "Can't map OID to mechname via /etc/gss/mech"; +static const char *oid_no_map = "Can't map OID to string"; +static char * +mechoidset2str(gss_OID_set mechset) +{ + int i, l; + char buf[256] = {0}; + char *s = NULL; + + if (!mechset) + return NULL; + + for (i = 0; i < mechset->count; i++) { + OM_uint32 maj, min; + gss_buffer_desc oidstr; + gss_buffer_t oidstrp = &oidstr; + gss_OID mech_oid = &mechset->elements[i]; + /* No need to free mech_name. */ + const char *mech_name = __gss_oid_to_mech(mech_oid); + + if (i > 0) + if (strlcat(buf, ", ", sizeof (buf)) >= sizeof (buf)) { + if (oidstrp->value) + gss_release_buffer(&min, oidstrp); + break; + } + + /* Add '{ x y x ... }'. */ + maj = gss_oid_to_str(&min, mech_oid, oidstrp); + if (strlcat(buf, maj ? oid_no_map : oidstrp->value, + sizeof (buf)) >= sizeof (buf)) { + if (oidstrp->value) + gss_release_buffer(&min, oidstrp); + break; + } + if (oidstrp->value) + gss_release_buffer(&min, oidstrp); + + /* Add '(mech name)'. */ + if (strlcat(buf, " (", sizeof (buf)) >= sizeof (buf)) + break; + if (strlcat(buf, mech_name ? mech_name : mech_no_map, + sizeof (buf)) >= sizeof (buf)) + break; + if (strlcat(buf, ") ", sizeof (buf)) >= sizeof (buf)) + break; + } + + /* Even if we have buf overflow, let's output what we got so far. */ + if (mechset->count) { + l = strlen(buf); + if (l > 0) { + s = malloc(l + 1); + if (!s) + return NULL; + (void) strlcpy(s, buf, l); + } + } + + return s ? s : NULL; +} + +/* * Set negState to REJECT if the token is defective, else * ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether initiator's * preferred mechanism is supported. @@ -1396,13 +1511,33 @@ * the acceptor will support. */ mech_wanted = negotiate_mech_type(minor_status, - supported_mechSet, - mechTypes, - negState); + supported_mechSet, + mechTypes, + negState); if (*negState == REJECT) { + /* Solaris SPNEGO: Spruce-up error msg */ + char *mechTypesStr = mechoidset2str(mechTypes); + spnego_gss_ctx_id_t tmpsc = create_spnego_ctx(); + if (tmpsc && *minor_status == ERR_SPNEGO_NEGOTIATION_FAILED) { + spnego_set_error_message(tmpsc, *minor_status, + dgettext(TEXT_DOMAIN, + "SPNEGO failed to negotiate a mechanism: client requested mech set '%s'"), + mechTypesStr ? mechTypesStr : "<null>"); + } + if (mechTypesStr) + free(mechTypesStr); + + /* + * We save error here cuz the tmp ctx goes away (very) soon. + * So callers of acc_ctx_new() should NOT call it again. + */ + spnego_gss_save_error_info(*minor_status, tmpsc); + if (tmpsc) + release_spnego_ctx(&tmpsc); ret = GSS_S_BAD_MECH; goto cleanup; } + sc = (spnego_gss_ctx_id_t)*ctx; if (sc != NULL) { gss_release_buffer(&tmpmin, &sc->DER_mechTypes); @@ -1535,6 +1670,31 @@ mech = gssint_get_mechanism(mechoid); if (mech == NULL || mech->gss_indicate_mechs == NULL) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + { + /* + * Solaris SPNEGO + * Spruce-up error msg. + */ + OM_uint32 maj, maj_sc, min; + gss_buffer_desc oidstr, oidstr_sc; + /* No need to free mnamestr. */ + const char *mnamestr = __gss_oid_to_mech( + sc->internal_mech); + maj_sc = gss_oid_to_str(&min, + sc->internal_mech, + &oidstr_sc); + maj = gss_oid_to_str(&min, mechoid, &oidstr); + spnego_set_error_message(sc, *minor_status, + dgettext(TEXT_DOMAIN, + "SPNEGO failed to negotiate a mechanism: unsupported mech OID ('%s') in the token. Negotiated mech OID is '%s' (%s)"), + maj ? oid_no_map: oidstr.value, + maj_sc ? oid_no_map: oidstr_sc.value, + mnamestr ? mnamestr : mech_no_map); + if (!maj) + (void) gss_release_buffer(&min, &oidstr); + if (!maj_sc) + (void) gss_release_buffer(&min, &oidstr_sc); + } map_errcode(minor_status); *negState = REJECT; *tokflag = ERROR_TOKEN_SEND; @@ -1551,7 +1711,30 @@ if (ret != GSS_S_COMPLETE) goto cleanup; if (!present) { - *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + { + /* + * Solaris SPNEGO + * Spruce-up error msg. + */ + OM_uint32 maj, min; + gss_buffer_desc oidstr; + char *mech_set_str = mechoidset2str(mech_set); + /* No need to free mnamestr. */ + const char *mnamestr = + __gss_oid_to_mech(sc->internal_mech); + maj = gss_oid_to_str(&min, sc->internal_mech, &oidstr); + *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + spnego_set_error_message(sc, *minor_status, + dgettext(TEXT_DOMAIN, + "SPNEGO failed to negotiate a mechanism: negotiated mech OID '%s' (%s) not found in mechset ('%s') of token mech"), + maj ? oid_no_map: oidstr.value, + mnamestr ? mnamestr : mech_no_map, + mech_set_str ? mech_set_str : "<null>"); + if (!maj) + (void) gss_release_buffer(&min, &oidstr); + if (mech_set_str) + free(mech_set_str); + } map_errcode(minor_status); *negState = REJECT; *tokflag = ERROR_TOKEN_SEND; @@ -1587,7 +1770,7 @@ return ret; } ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid, - negState, tokflag); + negState, tokflag); if (ret != GSS_S_COMPLETE) return ret; } @@ -1772,6 +1955,10 @@ mechstat = GSS_S_CONTINUE_NEEDED; } + /* Solaris SPNEGO */ + if (*minor_status == ERR_SPNEGO_NEGOTIATION_FAILED) + spnego_gss_save_error_info(*minor_status, sc); + if (!HARD_ERROR(ret) && sc->mech_complete && (sc->ctx_flags & GSS_C_INTEG_FLAG)) { @@ -1872,16 +2059,30 @@ break; case ERR_SPNEGO_NEGOTIATION_FAILED: /* CSTYLED */ - *status_string = make_err_msg("SPNEGO failed to negotiate a mechanism"); - break; + return(spnego_gss_display_status2(minor_status, + status_value, + status_type, + mech_type, + message_context, + status_string)); case ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR: /* CSTYLED */ *status_string = make_err_msg("SPNEGO acceptor did not return a valid token"); break; default: - status_string->length = 0; - status_string->value = ""; - break; + /* + * Solaris SPNEGO + * If mech_spnego calls mech_krb5 (via libgss) and an + * error occurs there, give it a shot. + */ + /* CSTYLED */ + return(krb5_gss_display_status2(minor_status, + status_value, + status_type, + (gss_OID)&gss_mech_krb5_oid, + message_context, + status_string)); + } dsyslog("Leaving display_status\n"); @@ -2593,7 +2794,7 @@ spnego_mechanism.mech_type.elements, spnego_mechanism.mech_type.length)) { /* - * Solaris Kerberos: gss_indicate_mechs is stupid as + * Solaris SPNEGO Kerberos: gss_indicate_mechs is stupid as * it never inferences any of the related OIDs of the * mechanisms configured, e.g. KRB5_OLD, KRB5_WRONG. * We add KRB5_WRONG here so that old MS clients can @@ -3108,7 +3309,7 @@ gss_OID mech_oid = &mechset->elements[i]; /* - * Solaris Kerberos: MIT compares against MS' wrong OID, but + * Solaris SPNEGO Kerberos: MIT compares against MS' wrong OID, but * we actually want to select it if the client supports, as this * will enable features on MS clients that allow credential * refresh on rekeying and caching system times from servers. @@ -3139,6 +3340,9 @@ } return (returned_mech); } + /* Solaris SPNEGO */ + *minor_status= ERR_SPNEGO_NEGOTIATION_FAILED; + *negResult = REJECT; return (NULL); }
--- a/usr/src/lib/libgss/Makefile.com Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/Makefile.com Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # LIBRARY = libgss.a @@ -70,19 +69,28 @@ GSSCREDOBJ = gsscred_utils.o gsscred_file.o # defines the duplicate sources we share with krb5 mech KRB5DIR= $(SRC)/lib/gss_mechs/mech_krb5/mech -KRB5OBJ= rel_buffer.o util_buffer_set.o +KRB5OBJ= rel_buffer.o util_buffer_set.o disp_com_err_status.o \ + util_buffer.o util_errmap.o +# defines the duplicate sources we share with krb5 mech error table +KRB5ETDIR= $(SRC)/lib/gss_mechs/mech_krb5/et +KRB5ETOBJ= error_message.o adb_err.o adm_err.o asn1_err.o \ + chpass_util_strings.o \ + gssapi_err_krb5.o gssapi_err_generic.o \ + import_err.o \ + kadm_err.o kdb5_err.o kdc5_err.o kpasswd_strings.o krb5_err.o \ + kv5m_err.o prof_err.o pty_err.o ss_err.o # defines the duplicate sources we share with kernel module UTSGSSDIR = $(SRC)/uts/common/gssapi UTSGSSOBJ = gen_oids.o SRCS += $(GSSCREDOBJ:%.o=$(GSSCRED_DIR)/%.c) \ $(KRB5OBJ:%.o=$(KRB5DIR)/%.c) \ + $(KRB5ETOBJ:%.o=$(KRB5ETDIR)/%.c) \ $(UTSGSSOBJ:%.o=$(UTSGSSDIR)/%.c) GSSLINTSRC = $(GSSOBJECTS:%.o=$(SRCDIR)/%.c) \ $(GSSCREDOBJ:%.o=$(GSSCRED_DIR)/%.c) \ - $(KRB5OBJ:%.o=$(KRB5DIR)/%.c) \ $(UTSGSSOBJ:%.o=$(UTSGSSDIR)/%.c) -OBJECTS = $(GSSOBJECTS) $(GSSCREDOBJ) $(KRB5OBJ) $(UTSGSSOBJ) +OBJECTS = $(GSSOBJECTS) $(GSSCREDOBJ) $(KRB5OBJ) $(UTSGSSOBJ) $(KRB5ETOBJ) # include library definitions include ../../Makefile.lib @@ -113,13 +121,113 @@ $(POST_PROCESS_O) # we need this in libgss so we don't have to link against mech_krb5 -pics/rel_buffer.o: $(SRC)/lib/gss_mechs/mech_krb5/mech/rel_buffer.c - $(COMPILE.c) -o $@ $(SRC)/lib/gss_mechs/mech_krb5/mech/rel_buffer.c +pics/rel_buffer.o: $(KRB5DIR)/rel_buffer.c + $(COMPILE.c) -o $@ $(KRB5DIR)/rel_buffer.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/util_buffer_set.o: $(KRB5DIR)/util_buffer_set.c + $(COMPILE.c) -o $@ $(KRB5DIR)/util_buffer_set.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/disp_com_err_status.o: $(KRB5DIR)/disp_com_err_status.c + $(COMPILE.c) -o $@ $(KRB5DIR)/disp_com_err_status.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/util_buffer.o: $(KRB5DIR)/util_buffer.c + $(COMPILE.c) -o $@ $(KRB5DIR)/util_buffer.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/util_errmap.o: $(KRB5DIR)/util_errmap.c + $(COMPILE.c) -o $@ $(KRB5DIR)/util_errmap.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/error_message.o: $(KRB5ETDIR)/error_message.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/error_message.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/adb_err.o: $(KRB5ETDIR)/adb_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/adb_err.c + $(POST_PROCESS_O) + +pics/adm_err.o: $(KRB5ETDIR)/adm_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/adm_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/asn1_err.o: $(KRB5ETDIR)/asn1_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/asn1_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/chpass_util_strings.o: $(KRB5ETDIR)/chpass_util_strings.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/chpass_util_strings.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/gssapi_err_generic.o: $(KRB5ETDIR)/gssapi_err_generic.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/gssapi_err_generic.c $(POST_PROCESS_O) # we need this in libgss so we don't have to link against mech_krb5 -pics/util_buffer_set.o: $(SRC)/lib/gss_mechs/mech_krb5/mech/util_buffer_set.c - $(COMPILE.c) -o $@ $(SRC)/lib/gss_mechs/mech_krb5/mech/util_buffer_set.c +pics/gssapi_err_krb5.o: $(KRB5ETDIR)/gssapi_err_krb5.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/gssapi_err_krb5.c + $(POST_PROCESS_O) + + +# we need this in libgss so we don't have to link against mech_krb5 +pics/import_err.o: $(KRB5ETDIR)/import_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/import_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/kadm_err.o: $(KRB5ETDIR)/kadm_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/kadm_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/kdb5_err.o: $(KRB5ETDIR)/kdb5_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/kdb5_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/kdc5_err.o: $(KRB5ETDIR)/kdc5_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/kdc5_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/kpasswd_strings.o: $(KRB5ETDIR)/kpasswd_strings.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/kpasswd_strings.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/krb5_err.o: $(KRB5ETDIR)/krb5_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/krb5_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/kv5m_err.o: $(KRB5ETDIR)/kv5m_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/kv5m_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/prof_err.o: $(KRB5ETDIR)/prof_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/prof_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/pty_err.o: $(KRB5ETDIR)/pty_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/pty_err.c + $(POST_PROCESS_O) + +# we need this in libgss so we don't have to link against mech_krb5 +pics/ss_err.o: $(KRB5ETDIR)/ss_err.c + $(COMPILE.c) -o $@ $(KRB5ETDIR)/ss_err.c $(POST_PROCESS_O) # gen_oids.c is kept in the kernel since the OIDs declared in them are
--- a/usr/src/lib/libgss/g_accept_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_accept_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,12 +27,15 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #include <string.h> #include <errno.h> +#include <syslog.h> +#ifndef LEAN_CLIENT static OM_uint32 val_acc_sec_ctx_args( OM_uint32 *minor_status, @@ -116,7 +118,6 @@ gss_name_t tmp_src_name = GSS_C_NO_NAME; gss_OID_desc token_mech_type_desc; gss_OID token_mech_type = &token_mech_type_desc; - gss_OID actual_mech = GSS_C_NO_OID; OM_uint32 flags; gss_mechanism mech; @@ -195,7 +196,7 @@ input_token_buffer, input_chan_bindings, &internal_name, - &actual_mech, + mech_type, output_token, &flags, time_rec, @@ -206,11 +207,15 @@ return (GSS_S_CONTINUE_NEEDED); /* if the call failed, return with failure */ - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + if (mech_type && (*mech_type != GSS_C_NULL_OID)) + map_error_oid(minor_status, *mech_type); + else { + map_error(minor_status, mech); + } goto error_out; + } - if (mech_type != NULL) - *mech_type = actual_mech; /* * if src_name is non-NULL, @@ -225,6 +230,7 @@ internal_name, &tmp_src_name); if (temp_status != GSS_S_COMPLETE) { *minor_status = t_minstat; + map_error(minor_status, mech); if (output_token->length) (void) gss_release_buffer( &t_minstat, @@ -253,9 +259,9 @@ * try to re-wrap it. This is for SPNEGO or other * pseudo-mechanisms. */ - if (actual_mech != GSS_C_NO_OID && + if (*mech_type != GSS_C_NO_OID && token_mech_type != GSS_C_NO_OID && - !g_OID_equal(actual_mech, token_mech_type)) { + !g_OID_equal(*mech_type, token_mech_type)) { *d_cred = tmp_d_cred; } else { gss_union_cred_t d_u_cred = NULL; @@ -272,7 +278,7 @@ status = generic_gss_copy_oid( &t_minstat, - actual_mech, + *mech_type, &d_u_cred->mechs_array); if (status != GSS_S_COMPLETE) { @@ -312,6 +318,9 @@ NULL); } + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + if (internal_name != NULL) { temp_status = __gss_convert_name_to_union_name( @@ -319,6 +328,7 @@ internal_name, &tmp_src_name); if (temp_status != GSS_S_COMPLETE) { *minor_status = t_minstat; + map_error(minor_status, mech); if (output_token->length) (void) gss_release_buffer( &t_minstat, @@ -382,3 +392,4 @@ return (status); } +#endif /* LEAN_CLIENT */
--- a/usr/src/lib/libgss/g_acquire_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_acquire_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,14 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * glue routine for gss_acquire_cred */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -76,35 +76,52 @@ static OM_uint32 val_acq_cred_args( - OM_uint32 *minor_status, - gss_cred_id_t *output_cred_handle, - gss_OID_set *actual_mechs, - OM_uint32 *time_rec) + OM_uint32 *minor_status, + /*LINTED*/ + gss_name_t desired_name, + /*LINTED*/ + OM_uint32 time_req, + /*LINTED*/ + gss_OID_set desired_mechs, + int cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) { - /* Initialize outputs. */ + /* Initialize outputs. */ - if (minor_status != NULL) - *minor_status = 0; + if (minor_status != NULL) + *minor_status = 0; + + if (output_cred_handle != NULL) + *output_cred_handle = GSS_C_NO_CREDENTIAL; - if (output_cred_handle != NULL) - *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (actual_mechs != NULL) + *actual_mechs = GSS_C_NULL_OID_SET; - if (actual_mechs != NULL) - *actual_mechs = GSS_C_NULL_OID_SET; + if (time_rec != NULL) + *time_rec = 0; + + /* Validate arguments. */ - if (time_rec != NULL) - *time_rec = 0; + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); - /* Validate arguments. */ + if (output_cred_handle == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); - if (minor_status == NULL) - return (GSS_S_CALL_INACCESSIBLE_WRITE); + if (cred_usage != GSS_C_ACCEPT + && cred_usage != GSS_C_INITIATE + && cred_usage != GSS_C_BOTH) { + if (minor_status) { + *minor_status = EINVAL; + map_errcode(minor_status); + } + return GSS_S_FAILURE; + } - if (output_cred_handle == NULL) - return (GSS_S_CALL_INACCESSIBLE_WRITE); - - return (GSS_S_COMPLETE); + return (GSS_S_COMPLETE); } OM_uint32 @@ -133,10 +150,14 @@ gss_OID_set mechs; gss_OID_desc default_OID; gss_mechanism mech; - int i; + unsigned int i; gss_union_cred_t creds; major = val_acq_cred_args(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, output_cred_handle, actual_mechs, time_rec); @@ -238,6 +259,15 @@ val_add_cred_args( OM_uint32 *minor_status, gss_cred_id_t input_cred_handle, + /*LINTED*/ + gss_name_t desired_name, + /*LINTED*/ + gss_OID desired_mech, + gss_cred_usage_t cred_usage, + /*LINTED*/ + OM_uint32 initiator_time_req, + /*LINTED*/ + OM_uint32 acceptor_time_req, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *initiator_time_rec, @@ -260,16 +290,24 @@ if (initiator_time_rec != NULL) *initiator_time_rec = 0; - /* Validate arguments. */ if (minor_status == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); if (input_cred_handle == GSS_C_NO_CREDENTIAL && - output_cred_handle == NULL) + output_cred_handle == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); - return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); + if (cred_usage != GSS_C_ACCEPT + && cred_usage != GSS_C_INITIATE + && cred_usage != GSS_C_BOTH) { + if (minor_status) { + *minor_status = EINVAL; + map_errcode(minor_status); + } + return GSS_S_FAILURE; + } return (GSS_S_COMPLETE); } @@ -305,6 +343,11 @@ status = val_add_cred_args(minor_status, input_cred_handle, + desired_name, + desired_mech, + cred_usage, + initiator_time_req, + acceptor_time_req, output_cred_handle, actual_mechs, initiator_time_rec, @@ -377,14 +420,18 @@ else if (cred_usage == GSS_C_BOTH) time_req = (acceptor_time_req > initiator_time_req) ? acceptor_time_req : initiator_time_req; + else + time_req = 0; status = mech->gss_acquire_cred(mech->context, minor_status, internal_name, time_req, GSS_C_NULL_OID_SET, cred_usage, &cred, NULL, &time_rec); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); goto errout; + } /* may need to set credential auxinfo structure */ if (union_cred->auxinfo.creation_time == 0) {
--- a/usr/src/lib/libgss/g_canon_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_canon_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -37,11 +36,13 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #include <string.h> #include <errno.h> +#include <syslog.h> static OM_uint32 val_canon_name_args( OM_uint32 *minor_status, @@ -81,6 +82,8 @@ { gss_union_name_t in_union, out_union = NULL, dest_union = NULL; OM_uint32 major_status = GSS_S_FAILURE; + /* Solaris Kerberos - need to preserve more important minor_status */ + OM_uint32 tmp_status = 0; major_status = val_canon_name_args(minor_status, input_name, @@ -119,11 +122,14 @@ goto allocation_failure; if (in_union->name_type != GSS_C_NULL_OID) { - if ((major_status = generic_gss_copy_oid(minor_status, - in_union->name_type, &out_union->name_type))) - goto allocation_failure; + major_status = generic_gss_copy_oid(minor_status, + in_union->name_type, + &out_union->name_type); + if (major_status) { + map_errcode(minor_status); + goto allocation_failure; + } } - } /* @@ -145,13 +151,15 @@ /* now let's create the new mech name */ if (major_status = generic_gss_copy_oid(minor_status, mech_type, - &dest_union->mech_type)) + &dest_union->mech_type)) { + map_errcode(minor_status); goto allocation_failure; + } if (major_status = __gss_import_internal_name(minor_status, mech_type, dest_union, - &dest_union->mech_name)) + &dest_union->mech_name)) goto allocation_failure; if (output_name) @@ -159,6 +167,7 @@ return (GSS_S_COMPLETE); +/* Solaris Kerberos - note some fails are not "allocation fails". Sigh. */ allocation_failure: /* do not delete the src name external name format */ if (output_name) { @@ -168,7 +177,7 @@ free(out_union->external_name); } if (out_union->name_type) - (void) gss_release_oid(minor_status, + (void) gss_release_oid(&tmp_status, &out_union->name_type); dest_union = out_union; @@ -181,13 +190,13 @@ */ if (dest_union->mech_name) { - (void) __gss_release_internal_name(minor_status, + (void) __gss_release_internal_name(&tmp_status, dest_union->mech_type, &dest_union->mech_name); } if (dest_union->mech_type) - (void) gss_release_oid(minor_status, &dest_union->mech_type); + (void) gss_release_oid(&tmp_status, &dest_union->mech_type); if (output_name)
--- a/usr/src/lib/libgss/g_compare_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_compare_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -29,6 +28,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif @@ -72,7 +72,7 @@ { OM_uint32 major_status, temp_minor; gss_union_name_t union_name1, union_name2; - gss_mechanism mech; + gss_mechanism mech = NULL; gss_name_t internal_name; major_status = val_comp_name_args(minor_status, @@ -116,10 +116,18 @@ (union_name2->mech_name == 0)) /* should never happen */ return (GSS_S_BAD_NAME); - return (mech->gss_compare_name(mech->context, minor_status, - union_name1->mech_name, - union_name2->mech_name, - name_equal)); + if (!mech) + return (GSS_S_BAD_MECH); + if (!mech->gss_compare_name) + return (GSS_S_UNAVAILABLE); + major_status = mech->gss_compare_name(mech->context, + minor_status, + union_name1->mech_name, + union_name2->mech_name, + name_equal); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return major_status; } /* @@ -189,10 +197,16 @@ if (major_status != GSS_S_COMPLETE) return (GSS_S_COMPLETE); /* return complete, but not equal */ + if (!mech) + return (GSS_S_BAD_MECH); + if (!mech->gss_compare_name) + return (GSS_S_UNAVAILABLE); major_status = mech->gss_compare_name(mech->context, minor_status, union_name1->mech_name, internal_name, name_equal); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); (void) __gss_release_internal_name(&temp_minor, union_name1->mech_type, &internal_name); return (major_status);
--- a/usr/src/lib/libgss/g_context_time.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_context_time.c Mon Aug 16 17:01:32 2010 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,17 +19,15 @@ * CDDL HEADER END */ /* - * Copyright (c) 1996,1997, by Sun Microsystems, Inc. - * All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * glue routines for gss_context_time */ #include <mechglueP.h> +#include "gssapiP_generic.h" OM_uint32 gss_context_time(minor_status, @@ -65,13 +62,15 @@ if (mech) { - if (mech->gss_context_time) + if (mech->gss_context_time) { status = mech->gss_context_time( mech->context, minor_status, ctx->internal_ctx_id, time_rec); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status);
--- a/usr/src/lib/libgss/g_delete_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_delete_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -73,7 +73,6 @@ { OM_uint32 status; gss_union_ctx_id_t ctx; - gss_mechanism mech; status = val_del_sec_ctx_args(minor_status, context_handle, @@ -87,26 +86,21 @@ */ ctx = (gss_union_ctx_id_t) *context_handle; - mech = __gss_get_mechanism(ctx->mech_type); - - if (mech) { - - if (mech->gss_delete_sec_context) - status = mech->gss_delete_sec_context(mech->context, - minor_status, - &ctx->internal_ctx_id, - output_token); - else - status = GSS_S_UNAVAILABLE; + if (GSSINT_CHK_LOOP(ctx)) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); - /* now free up the space for the union context structure */ - free(ctx->mech_type->elements); - free(ctx->mech_type); - free(*context_handle); - *context_handle = NULL; + status = gssint_delete_internal_sec_context(minor_status, + ctx->mech_type, + &ctx->internal_ctx_id, + output_token); + if (status) + return status; - return (status); - } + /* now free up the space for the union context structure */ + free(ctx->mech_type->elements); + free(ctx->mech_type); + free(*context_handle); + *context_handle = GSS_C_NO_CONTEXT; - return (GSS_S_BAD_MECH); + return (GSS_S_COMPLETE); }
--- a/usr/src/lib/libgss/g_dsp_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_dsp_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -29,6 +28,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -113,8 +113,10 @@ major_status = generic_gss_copy_oid(minor_status, union_name->name_type, output_name_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); return (major_status); + } } if ((output_name_buffer->value =
--- a/usr/src/lib/libgss/g_dsp_status.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_dsp_status.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -29,6 +28,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -36,7 +36,7 @@ #include <string.h> #include <libintl.h> #include <errno.h> - +#include <syslog.h> #ifndef TEXT_DOMAIN #error TEXT_DOMAIN not defined #endif @@ -60,8 +60,9 @@ OM_uint32 *message_context; gss_buffer_t status_string; { - gss_OID mech_type = (gss_OID) req_mech_type; - gss_mechanism mech; + gss_OID mech_type = (gss_OID) req_mech_type; + gss_mechanism mech; + gss_OID_desc m_oid = { 0, 0 }; if (minor_status != NULL) *minor_status = 0; @@ -75,7 +76,7 @@ message_context == NULL || status_string == GSS_C_NO_BUFFER) return (GSS_S_CALL_INACCESSIBLE_WRITE); - + /* we handle major status codes, and the mechs do the minor */ if (status_type == GSS_C_GSS_CODE) return (displayMajor(status_value, message_context, @@ -86,15 +87,63 @@ * select the appropriate underlying mechanism routine and * call it. */ + + /* In this version, we only handle status codes that have been + mapped to a flat numbering space. Look up the value we got + passed. If it's not found, complain. */ + if (status_value == 0) { + status_string->value = strdup("Unknown error"); + if (status_string->value == NULL) { + *minor_status = ENOMEM; + map_errcode(minor_status); + return GSS_S_FAILURE; + } + status_string->length = strlen(status_string->value); + *message_context = 0; + *minor_status = 0; + return GSS_S_COMPLETE; + } + { + int err; + OM_uint32 m_status = 0, status; + + err = gssint_mecherrmap_get(status_value, &m_oid, &m_status); + if (err) { + *minor_status = err; + map_errcode(minor_status); + return GSS_S_BAD_STATUS; + } + + if (m_oid.length == 0) { + /* Magic flag for com_err values. */ + status = gssint_g_display_com_err_status(minor_status, + m_status, + status_string); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; + } + mech_type = &m_oid; + status_value = m_status; + } + mech = __gss_get_mechanism(mech_type); if (mech && mech->gss_display_status) { + OM_uint32 r; + if (mech_type == GSS_C_NULL_OID) mech_type = &mech->mech_type; - return (mech->gss_display_status(mech->context, minor_status, + r = mech->gss_display_status(mech->context, minor_status, status_value, status_type, mech_type, - message_context, status_string)); + message_context, status_string); + /* How's this for weird? If we get an error returning the + mechanism-specific error code, we save away the + mechanism-specific error code describing the error. */ + if (r != GSS_S_COMPLETE) + map_error(minor_status, mech); + return r; } if (!mech) @@ -354,12 +403,11 @@ /* now copy the status code and return to caller */ outStr->length = strlen(errStr); - outStr->value = malloc((size_t)outStr->length+1); + outStr->value = strdup(errStr); if (outStr->value == NULL) { outStr->length = 0; return (GSS_S_FAILURE); } - (void) strcpy((char *)outStr->value, errStr); return (GSS_S_COMPLETE); } /* displayMajor */
--- a/usr/src/lib/libgss/g_dup_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_dup_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -31,6 +30,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif @@ -108,8 +108,10 @@ major_status = generic_gss_copy_oid(minor_status, src_union->name_type, &dest_union->name_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); goto allocation_failure; + } } /* @@ -119,8 +121,10 @@ major_status = generic_gss_copy_oid(minor_status, src_union->mech_type, &dest_union->mech_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); goto allocation_failure; + } major_status = __gss_import_internal_name(minor_status, dest_union->mech_type,
--- a/usr/src/lib/libgss/g_exp_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_exp_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,15 +19,16 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * glue routine for gss_export_sec_context */ +#ifndef LEAN_CLIENT #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #include <errno.h> #ifdef HAVE_STDLIB_H @@ -101,8 +102,10 @@ status = mech->gss_export_sec_context(mech->context, minor_status, &ctx->internal_ctx_id, &token); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); + } length = token.length + 4 + ctx->mech_type->length; interprocess_token->length = length; @@ -133,3 +136,4 @@ return (GSS_S_COMPLETE); } +#endif /*LEAN_CLIENT */
--- a/usr/src/lib/libgss/g_glue.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_glue.c Mon Aug 16 17:01:32 2010 -0700 @@ -3,7 +3,7 @@ */ #include "mglueP.h" - +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h>
--- a/usr/src/lib/libgss/g_imp_name.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_imp_name.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -29,6 +28,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -125,8 +125,10 @@ major_status = generic_gss_copy_oid(minor_status, input_name_type, &union_name->name_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); goto allocation_failure; + } } /* @@ -250,13 +252,17 @@ * have created it. */ if (mech->gss_export_name) { - if ((major = mech->gss_import_name(mech->context, minor, - &expName, (gss_OID)GSS_C_NT_EXPORT_NAME, - &unionName->mech_name)) != GSS_S_COMPLETE || - (major = generic_gss_copy_oid(minor, &mechOid, - &unionName->mech_type)) != - GSS_S_COMPLETE) { - return (major); + major = mech->gss_import_name(mech->context, minor, + &expName, + (gss_OID)GSS_C_NT_EXPORT_NAME, + &unionName->mech_name); + if (major != GSS_S_COMPLETE) + map_error(minor, mech); + else { + major = generic_gss_copy_oid(minor, &mechOid, + &unionName->mech_type); + if (major != GSS_S_COMPLETE) + map_errcode(minor); } return (major); } @@ -349,8 +355,14 @@ expName.value = nameLen ? (void *)buf : NULL; major = mech->gss_import_name(mech->context, minor, &expName, GSS_C_NULL_OID, &unionName->mech_name); - if (major != GSS_S_COMPLETE) + if (major != GSS_S_COMPLETE) { + map_error(minor, mech); return (major); + } - return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type)); + major = generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type); + if (major != GSS_S_COMPLETE) { + map_errcode(minor); + } + return (major); } /* importExportName */
--- a/usr/src/lib/libgss/g_imp_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_imp_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,15 +19,17 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * glue routine gss_export_sec_context */ +#ifndef LEAN_CLIENT + #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #include <errno.h> #include <stdlib.h> @@ -146,6 +148,7 @@ *context_handle = (gss_ctx_id_t)ctx; return (GSS_S_COMPLETE); } + map_error(minor_status, mech); error_out: if (ctx) { @@ -158,3 +161,4 @@ } return (status); } +#endif /* LEAN_CLIENT */
--- a/usr/src/lib/libgss/g_init_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_init_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,14 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * glue routine for gss_init_sec_context */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -211,6 +211,7 @@ * subsequent calls make the caller responsible for * calling gss_delete_sec_context */ + map_error(minor_status, mech); if (*context_handle == GSS_C_NO_CONTEXT) { free(union_ctx_id->mech_type->elements); free(union_ctx_id->mech_type);
--- a/usr/src/lib/libgss/g_initialize.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_initialize.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -42,6 +41,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #include <syslog.h> #include <stdlib.h> @@ -154,6 +154,7 @@ minor_status, oid); if (major == GSS_S_COMPLETE) return (GSS_S_COMPLETE); + map_error(minor_status, aMech->mech); } aMech = aMech->next; } /* while */
--- a/usr/src/lib/libgss/g_inq_context_oid.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_inq_context_oid.c Mon Aug 16 17:01:32 2010 -0700 @@ -23,8 +23,7 @@ * */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -32,6 +31,8 @@ */ #include "mglueP.h" +#include "gssapiP_generic.h" + #define gssint_get_mechanism __gss_get_mechanism /* SUNW17PACresync */ OM_uint32
--- a/usr/src/lib/libgss/g_inquire_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_inquire_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdlib.h> static OM_uint32 @@ -67,26 +67,15 @@ /* Last argument new for V2 */ OM_uint32 gss_inquire_context( - minor_status, - context_handle, - src_name, - targ_name, - lifetime_rec, - mech_type, - ctx_flags, - locally_initiated, - open) - -OM_uint32 *minor_status; -const gss_ctx_id_t context_handle; -gss_name_t *src_name; -gss_name_t *targ_name; -OM_uint32 *lifetime_rec; -gss_OID *mech_type; -OM_uint32 *ctx_flags; -int *locally_initiated; -int *open; - + OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *opened) { gss_union_ctx_id_t ctx; gss_mechanism mech; @@ -124,9 +113,10 @@ NULL, ctx_flags, locally_initiated, - open); + opened); if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); }
--- a/usr/src/lib/libgss/g_inquire_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_inquire_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -91,8 +91,10 @@ lifetime, cred_usage, mechanisms); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); + } if (name) { /* @@ -103,6 +105,7 @@ internal_name, name); if (status != GSS_S_COMPLETE) { *minor_status = temp_minor_status; + map_error(minor_status, mech); if (mechanisms && *mechanisms) { (void) gss_release_oid_set( &temp_minor_status, @@ -144,7 +147,9 @@ */ if (name != NULL) { - if ((gss_import_name(minor_status, + if (union_cred->auxinfo.name.length == 0) { + *name = GSS_C_NO_NAME; + } else if ((gss_import_name(minor_status, &union_cred->auxinfo.name, union_cred->auxinfo.name_type, name) != GSS_S_COMPLETE) || @@ -251,8 +256,10 @@ initiator_lifetime, acceptor_lifetime, cred_usage); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); + } if (name) { /* @@ -263,6 +270,7 @@ internal_name, name); if (status != GSS_S_COMPLETE) { *minor_status = temp_minor_status; + map_error(minor_status, mech); return (status); } }
--- a/usr/src/lib/libgss/g_inquire_names.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_inquire_names.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" #define MAX_MECH_OID_PAIRS 32 @@ -68,13 +68,15 @@ if (mech) { - if (mech->gss_inquire_names_for_mech) + if (mech->gss_inquire_names_for_mech) { status = mech->gss_inquire_names_for_mech( mech->context, minor_status, mechanism, name_types); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status);
--- a/usr/src/lib/libgss/g_oid_ops.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_oid_ops.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,8 +1,6 @@ /* - * Copyright (c) 1996,1997, by Sun Microsystems, Inc. - * All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * lib/gssapi/mechglue/g_oid_ops.c * @@ -32,6 +30,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" /* * gss_release_oid has been moved to g_initialize, becasue it requires access @@ -44,8 +43,11 @@ OM_uint32 *minor_status; gss_OID_set *oid_set; { - return (generic_gss_create_empty_oid_set(minor_status, - oid_set)); + OM_uint32 status; + status = generic_gss_create_empty_oid_set(minor_status, oid_set); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } OM_uint32 @@ -54,8 +56,12 @@ const gss_OID member_oid; gss_OID_set *oid_set; { - return (generic_gss_add_oid_set_member(minor_status, member_oid, - oid_set)); + OM_uint32 status; + status = generic_gss_add_oid_set_member(minor_status, member_oid, + oid_set); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } OM_uint32 @@ -75,7 +81,10 @@ const gss_OID oid; gss_buffer_t oid_str; { - return (generic_gss_oid_to_str(minor_status, oid, oid_str)); + OM_uint32 status = generic_gss_oid_to_str(minor_status, oid, oid_str); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } OM_uint32 @@ -84,5 +93,8 @@ const gss_buffer_t oid_str; gss_OID *oid; { - return (generic_gss_str_to_oid(minor_status, oid_str, oid)); + OM_uint32 status = generic_gss_str_to_oid(minor_status, oid_str, oid); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; }
--- a/usr/src/lib/libgss/g_process_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_process_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" OM_uint32 gss_process_context_token(minor_status, @@ -66,13 +66,15 @@ if (mech) { - if (mech->gss_process_context_token) + if (mech->gss_process_context_token) { status = mech->gss_process_context_token( mech->context, minor_status, ctx->internal_ctx_id, token_buffer); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status);
--- a/usr/src/lib/libgss/g_rel_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_rel_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,17 +19,15 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * glue routine for gss_release_cred */ #include <mechglueP.h> +#include "gssapiP_generic.h" #include <stdio.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -64,11 +61,14 @@ */ union_cred = (gss_union_cred_t)*cred_handle; - *cred_handle = NULL; - if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL) return (GSS_S_COMPLETE); + if (GSSINT_CHK_LOOP(union_cred)) + return (GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ); + + *cred_handle = NULL; + status = GSS_S_COMPLETE; for (j = 0; j < union_cred->count; j++) { @@ -83,8 +83,10 @@ (mech->context, minor_status, &union_cred->cred_array[j]); - if (temp_status != GSS_S_COMPLETE) + if (temp_status != GSS_S_COMPLETE) { + map_error(minor_status, mech); status = GSS_S_NO_CRED; + } } else status = GSS_S_UNAVAILABLE; } else
--- a/usr/src/lib/libgss/g_seal.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_seal.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,8 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" + static OM_uint32 val_seal_args( @@ -104,7 +105,7 @@ mech = __gss_get_mechanism(ctx->mech_type); if (mech) { - if (mech->gss_seal) + if (mech->gss_seal) { status = mech->gss_seal( mech->context, minor_status, @@ -114,7 +115,9 @@ input_message_buffer, conf_state, output_message_buffer); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status); @@ -163,6 +166,7 @@ { gss_union_ctx_id_t ctx; gss_mechanism mech; + OM_uint32 major_status; if (minor_status == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); @@ -185,10 +189,16 @@ if (!mech) return (GSS_S_BAD_MECH); - if (!mech->gss_wrap_size_limit) - return (GSS_S_UNAVAILABLE); - - return (mech->gss_wrap_size_limit(mech->context, minor_status, - ctx->internal_ctx_id, conf_req_flag, qop_req, - req_output_size, max_input_size)); + if (mech->gss_wrap_size_limit) + major_status = mech->gss_wrap_size_limit(mech->context, + minor_status, + ctx->internal_ctx_id, + conf_req_flag, qop_req, + req_output_size, + max_input_size); + else + major_status = GSS_S_UNAVAILABLE; + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return major_status; }
--- a/usr/src/lib/libgss/g_sign.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_sign.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" static OM_uint32 val_sign_args( @@ -96,7 +96,7 @@ mech = __gss_get_mechanism(ctx->mech_type); if (mech) { - if (mech->gss_sign) + if (mech->gss_sign) { status = mech->gss_sign( mech->context, minor_status, @@ -104,7 +104,9 @@ qop_req, message_buffer, msg_token); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status);
--- a/usr/src/lib/libgss/g_store_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_store_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,28 +27,50 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" +#include <errno.h> -static OM_uint32 val_store_cred_args( - OM_uint32 *minor_status, - const gss_cred_id_t input_cred_handle, - gss_OID_set *elements_stored) +static OM_uint32 +val_store_cred_args( + OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + /*LINTED*/ + const gss_OID desired_mech, + /*LINTED*/ + OM_uint32 overwrite_cred, + /*LINTED*/ + OM_uint32 default_cred, + gss_OID_set *elements_stored, + /*LINTED*/ + gss_cred_usage_t *cred_usage_stored) { - /* Initialize outputs. */ + /* Initialize outputs. */ + + if (minor_status != NULL) + *minor_status = 0; - if (minor_status != NULL) - *minor_status = 0; + if (elements_stored != NULL) + *elements_stored = GSS_C_NULL_OID_SET; - if (elements_stored != NULL) - *elements_stored = GSS_C_NULL_OID_SET; + /* Validate arguments. */ + + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); - /* Validate arguments. */ + if (input_cred_handle == GSS_C_NO_CREDENTIAL) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED); - if (minor_status == NULL) - return (GSS_S_CALL_INACCESSIBLE_WRITE); - - if (input_cred_handle == GSS_C_NO_CREDENTIAL) - return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED); + if (cred_usage != GSS_C_ACCEPT + && cred_usage != GSS_C_INITIATE + && cred_usage != GSS_C_BOTH) { + if (minor_status) { + *minor_status = EINVAL; + map_errcode(minor_status); + } + return GSS_S_FAILURE; + } return (GSS_S_COMPLETE); } @@ -80,9 +101,14 @@ gss_OID dmech; int i; - major_status = val_store_cred_args(minor_status, - input_cred_handle, - elements_stored); + major_status = val_store_cred_args(minor_status, + input_cred_handle, + cred_usage, + desired_mech, + overwrite_cred, + default_cred, + elements_stored, + cred_usage_stored); if (major_status != GSS_S_COMPLETE) return (major_status); @@ -107,7 +133,7 @@ if (mech_cred == GSS_C_NO_CREDENTIAL) return (GSS_S_NO_CRED); - return (mech->gss_store_cred(mech->context, + major_status = mech->gss_store_cred(mech->context, minor_status, (gss_cred_id_t)mech_cred, cred_usage, @@ -115,7 +141,10 @@ overwrite_cred, default_cred, elements_stored, - cred_usage_stored)); + cred_usage_stored); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return major_status; } /* desired_mech == GSS_C_NULL_OID -> store all elements */ @@ -145,8 +174,10 @@ default_cred, NULL, cred_usage_stored); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_error(minor_status, mech); continue; + } /* Succeeded for at least one mech */
--- a/usr/src/lib/libgss/g_unseal.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_unseal.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" OM_uint32 gss_unseal(minor_status, @@ -80,7 +80,7 @@ mech = __gss_get_mechanism(ctx->mech_type); if (mech) { - if (mech->gss_unseal) + if (mech->gss_unseal) { status = mech->gss_unseal( mech->context, minor_status, @@ -89,7 +89,9 @@ output_message_buffer, conf_state, qop_state); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status);
--- a/usr/src/lib/libgss/g_verify.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/lib/libgss/g_verify.c Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -28,6 +27,7 @@ */ #include <mechglueP.h> +#include "gssapiP_generic.h" OM_uint32 gss_verify(minor_status, @@ -66,7 +66,7 @@ mech = __gss_get_mechanism(ctx->mech_type); if (mech) { - if (mech->gss_verify) + if (mech->gss_verify) { status = mech->gss_verify( mech->context, minor_status, @@ -74,7 +74,9 @@ message_buffer, token_buffer, qop_state); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status);
--- a/usr/src/uts/common/gssapi/include/mechglueP.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/include/mechglueP.h Mon Aug 16 17:01:32 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -41,7 +40,9 @@ #endif #include <gssapi/gssapi_ext.h> /* SUNW15resync - mechglue.h in mit 1.5 */ -/* #include "gssapiP_generic.h" */ +#if 0 /* Solaris Kerberos */ +#include "gssapiP_generic.h" +#endif #ifdef _KERNEL #include <rpc/rpc.h> @@ -126,6 +127,18 @@ OM_uint32 * /* time_rec */ /* */); +/* + * Rudimentary pointer validation macro to check whether the + * "loopback" field of an opaque struct points back to itself. This + * field also catches some programming errors where an opaque pointer + * is passed to a function expecting the address of the opaque + * pointer. + */ +#if 0 /* Solaris Kerberos - revisit for full 1.7/next resync */ +#define GSSINT_CHK_LOOP(p) (!((p) != NULL && (p)->loopback == (p))) +#else +#define GSSINT_CHK_LOOP(p) ((p) == NULL) +#endif /********************************************************/ @@ -580,6 +593,8 @@ const gss_name_t, gss_buffer_t, gss_OID *); OM_uint32 __gss_release_internal_name(OM_uint32 *, const gss_OID, gss_name_t *); +OM_uint32 gssint_delete_internal_sec_context (OM_uint32 *, gss_OID, + gss_ctx_id_t *, gss_buffer_t); OM_uint32 __gss_convert_name_to_union_name( OM_uint32 *, /* minor_status */ gss_mechanism, /* mech */ @@ -928,16 +943,27 @@ #else /* _KERNEL */ -#include <syslog.h> +/* Use this to map an error code that was returned from a mech + operation; the mech will be asked to produce the associated error + messages. -#define map_error(MINORP, MECH) \ - (void) syslog(LOG_AUTH|LOG_DEBUG, \ - "map_error: minor status=%x", \ - (MINORP) ? *(MINORP) : 0xffffffff) + Remember that if the minor status code cannot be returned to the + caller (e.g., if it's stuffed in an automatic variable and then + ignored), then we don't care about producing a mapping. */ +#define map_error(MINORP, MECH) \ + (*(MINORP) = gssint_mecherrmap_map(*(MINORP), &(MECH)->mech_type)) +#define map_error_oid(MINORP, MECHOID) \ + (*(MINORP) = gssint_mecherrmap_map(*(MINORP), (MECHOID))) + +/* Use this to map an errno value or com_err error code being + generated within the mechglue code (e.g., by calling generic oid + ops). Any errno or com_err values produced by mech operations + should be processed with map_error. This means they'll be stored + separately even if the mech uses com_err, because we can't assume + that it will use com_err. */ #define map_errcode(MINORP) \ - (void) syslog(LOG_AUTH|LOG_DEBUG, \ - "map_errcode: minor status=%x", \ - (MINORP) ? *(MINORP) : 0xffffffff) + (*(MINORP) = gssint_mecherrmap_map_errcode(*(MINORP))) + #endif /* _KERNEL */ #endif /* _GSS_MECHGLUEP_H */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_generic.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_generic.h Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright 1993 by OpenVision Technologies, Inc. * @@ -301,4 +298,13 @@ #endif /* 0 */ +#ifndef _KERNEL +int gssint_mecherrmap_init(void); +void gssint_mecherrmap_destroy(void); +OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc *oid); +int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid, + OM_uint32 *mech_minor); +OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode); +#endif + #endif /* _GSSAPIP_GENERIC_H_ */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_krb5.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/include/gssapiP_krb5.h Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright 2000 by the Massachusetts Institute of Technology. * All Rights Reserved. @@ -843,6 +840,9 @@ gss_buffer_set_t *); #endif /* _KERNEL */ +OM_uint32 gss_krb5int_initialize_library(void); +void gss_krb5int_cleanup_library(void); + /* For error message handling. */ /* Returns a shared string, not a private copy! */ extern char * @@ -862,11 +862,12 @@ #define save_error_message krb5_gss_save_error_message -#if 0 /* SUNW17PACresync - revisit for full MIT 1.7 resync */ +/* Solaris Kerberos */ +#ifdef _KERNEL +#define save_error_info(m, ctx) +#else #define save_error_info krb5_gss_save_error_info #endif -#define save_error_info(m, ctx) - extern void krb5_gss_delete_error_info(void *p);
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/k5-int.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/include/k5-int.h Mon Aug 16 17:01:32 2010 -0700 @@ -1,8 +1,6 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - /* * Copyright (C) 1989,1990,1991,1992,1993,1994,1995,2000,2001, 2003,2006 by the Massachusetts Institute of Technology, * Cambridge, MA, USA. All Rights Reserved. @@ -317,6 +315,10 @@ /* required */ #define KDC_ERR_SERVER_NOMATCH 26 /* Requested server and */ /* ticket don't match*/ +#define KDC_ERR_MUST_USE_USER2USER 27 /* Server principal valid for */ + /* user2user only */ +#define KDC_ERR_PATH_NOT_ACCEPTED 28 /* KDC policy rejected transited */ + /* path */ #define KDC_ERR_SVC_UNAVAILABLE 29 /* A service is not * available that is * required to process the @@ -357,7 +359,12 @@ #define KDC_ERR_CLIENT_NOT_TRUSTED 62 /* client cert not trusted */ #define KDC_ERR_INVALID_SIG 64 /* client signature verify failed */ #define KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED 65 /* invalid Diffie-Hellman parameters */ -#define KDC_ERR_CANT_VERIFY_CERTIFICATE 70 /* client cert not verifiable to */ +#define KDC_ERR_CERTIFICATE_MISMATCH 66 +#define KRB_AP_ERR_NO_TGT 67 +#define KDC_ERR_WRONG_REALM 68 +#define KRB_AP_ERR_USER_TO_USER_REQUIRED 69 +#define KDC_ERR_CANT_VERIFY_CERTIFICATE 70 /* client cert not verifiable + to */ /* trusted root cert */ #define KDC_ERR_INVALID_CERTIFICATE 71 /* client cert had invalid signature */ #define KDC_ERR_REVOKED_CERTIFICATE 72 /* client cert was revoked */ @@ -658,6 +665,10 @@ krb5_error_code krb5_unlock_file (krb5_context, int); krb5_error_code krb5_sendto_kdc (krb5_context, const krb5_data *, const krb5_data *, krb5_data *, int *, int); +/* Solaris Kerberos */ +krb5_error_code krb5_sendto_kdc2 (krb5_context, const krb5_data *, + const krb5_data *, krb5_data *, int *, int, + char **); krb5_error_code krb5_get_krbhst (krb5_context, const krb5_data *, char *** ); @@ -2686,12 +2697,54 @@ extern int krb5int_crypto_init (void); extern int krb5int_prng_init(void); + /* * SUNW14resync * Hack (?) to neuter C99 "inline" which causes warnings w/our build. */ #define inline +/* Some data comparison and conversion functions. */ +#if 0 +static inline int data_cmp(krb5_data d1, krb5_data d2) +{ + if (d1.length < d2.length) return -1; + if (d1.length > d2.length) return 1; + return memcmp(d1.data, d2.data, d1.length); +} +static inline int data_eq (krb5_data d1, krb5_data d2) +{ + return data_cmp(d1, d2) == 0; +} +#else +static inline int data_eq (krb5_data d1, krb5_data d2) +{ + return (d1.length == d2.length + && !memcmp(d1.data, d2.data, d1.length)); +} +#endif +static inline krb5_data string2data (char *str) +{ + krb5_data d; + d.magic = KV5M_DATA; + d.length = strlen(str); + d.data = str; + return d; +} +/*LINTED*/ +static inline int data_eq_string (krb5_data d, char *s) +{ + return data_eq(d, string2data(s)); +} +/*LINTED*/ +static inline int authdata_eq (krb5_authdata a1, krb5_authdata a2) +{ + return (a1.ad_type == a2.ad_type + && a1.length == a2.length + && !memcmp(a1.contents, a2.contents, a1.length)); +} + + /* Solaris kerberos */ krb5_boolean KRB5_CALLCONV is_in_keytype (krb5_const krb5_enctype *keytype,
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/k5-thread.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/include/k5-thread.h Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -817,6 +816,8 @@ K5_KEY_COM_ERR, K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, K5_KEY_GSS_KRB5_CCACHE_NAME, + K5_KEY_GSS_KRB5_ERROR_MESSAGE, + K5_KEY_GSS_SPNEGO_ERROR_MESSAGE, K5_KEY_MAX } k5_key_t; /* rename shorthand symbols for export */
--- a/usr/src/uts/common/gssapi/mechs/krb5/include/krb5.h Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/include/krb5.h Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* This is the prologue to krb5.h */ @@ -2120,6 +2119,20 @@ const krb5_data *, krb5_creds *, krb5_response * ); + +krb5_error_code krb5_send_tgs2 + (krb5_context, + krb5_flags, + const krb5_ticket_times *, + const krb5_enctype *, + krb5_const_principal, + krb5_address * const *, + krb5_authdata * const *, + krb5_pa_data * const *, + const krb5_data *, + krb5_creds *, + krb5_response * , + char **); #endif #if KRB5_DEPRECATED @@ -3003,8 +3016,8 @@ #define KRB5KDC_ERR_PREAUTH_FAILED (-1765328360L) #define KRB5KDC_ERR_PREAUTH_REQUIRED (-1765328359L) #define KRB5KDC_ERR_SERVER_NOMATCH (-1765328358L) -#define KRB5PLACEHOLD_27 (-1765328357L) -#define KRB5PLACEHOLD_28 (-1765328356L) +#define KRB5KDC_ERR_MUST_USE_USER2USER (-1765328357L) +#define KRB5KDC_ERR_PATH_NOT_ACCEPTED (-1765328356L) #define KRB5KDC_ERR_SVC_UNAVAILABLE (-1765328355L) #define KRB5PLACEHOLD_30 (-1765328354L) #define KRB5KRB_AP_ERR_BAD_INTEGRITY (-1765328353L) @@ -3043,9 +3056,9 @@ #define KRB5KDC_ERR_INVALID_SIG (-1765328320L) #define KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED (-1765328319L) #define KRB5KDC_ERR_CERTIFICATE_MISMATCH (-1765328318L) -#define KRB5PLACEHOLD_67 (-1765328317L) -#define KRB5PLACEHOLD_68 (-1765328316L) -#define KRB5PLACEHOLD_69 (-1765328315L) +#define KRB5KRB_AP_ERR_NO_TGT (-1765328317L) +#define KRB5KDC_ERR_WRONG_REALM (-1765328316L) +#define KRB5KRB_AP_ERR_USER_TO_USER_REQUIRED (-1765328315L) #define KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE (-1765328314L) #define KRB5KDC_ERR_INVALID_CERTIFICATE (-1765328313L) #define KRB5KDC_ERR_REVOKED_CERTIFICATE (-1765328312L)
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/delete_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/delete_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1993 by OpenVision Technologies, Inc. @@ -153,8 +152,10 @@ if ((major = kg_seal(minor_status, *context_handle, 0, GSS_C_QOP_DEFAULT, - &empty, NULL, output_token, KG_TOK_DEL_CTX))) + &empty, NULL, output_token, KG_TOK_DEL_CTX))) { + save_error_info(*minor_status, context); return(major); + } } /* invalidate the context handle */
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/gssapi_krb5.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/gssapi_krb5.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -60,6 +59,9 @@ /* For declaration of krb5_ser_context_init */ #include "k5-int.h" #include "gssapiP_krb5.h" +#ifndef _KERNEL +#include "gss_libinit.h" +#endif /* * Solaris Kerberos @@ -245,10 +247,12 @@ if (name) { name = strdup(name); if (name == NULL) - err = errno; + err = ENOMEM; } } - if (context) + if (err && context) + save_error_info(err, context); + if (context) krb5_free_context(context); } @@ -375,4 +379,21 @@ return GSS_S_UNAVAILABLE; } + +#if 0 /* Solaris Kerberos - revisit for full 1.7/next resync */ +MAKE_INIT_FUNCTION(gss_krb5int_lib_init); +MAKE_FINI_FUNCTION(gss_krb5int_lib_fini); #endif + +OM_uint32 gss_krb5int_initialize_library (void) +{ +#if 0 /* Solaris Kerberos - revisit for full 1.7/next resync */ +#ifdef _GSS_STATIC_LINK + return gssint_mechglue_initialize_library(); +#else + return CALL_INIT_FUNCTION(gss_krb5int_lib_init); +#endif +#endif + return gssint_initialize_library(); +} +#endif /* !KERNEL */
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/import_sec_context.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/import_sec_context.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * lib/gssapi/krb5/import_sec_context.c * @@ -107,8 +104,9 @@ kret = krb5_gss_ser_init(context); if (kret) { + *minor_status = kret; + save_error_info(*minor_status, context); krb5_free_context(context); - *minor_status = kret; return GSS_S_FAILURE; } @@ -131,8 +129,9 @@ * and it will get freed by delete_sec_context. */ if (kret) { + *minor_status = (OM_uint32) kret; + save_error_info(*minor_status, context); krb5_free_context(context); - *minor_status = (OM_uint32) kret; return(GSS_S_FAILURE); }
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/k5seal.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/k5seal.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright 1993 by OpenVision Technologies, Inc. * @@ -419,6 +416,7 @@ context = ctx->k5_context; if ((code = krb5_timeofday(context, &now))) { *minor_status = code; + save_error_info(*minor_status, context); KRB5_LOG(KRB5_ERR, "kg_seal() end, krb5_timeofday() error code=%d\n", code); return (GSS_S_FAILURE); } @@ -446,6 +444,7 @@ if (code) { *minor_status = code; + save_error_info(*minor_status, context); KRB5_LOG(KRB5_ERR, "kg_seal() end, make_seal_token_v1() " "error code=%d\n", code); return (GSS_S_FAILURE);
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/k5sealv3.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/k5sealv3.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * lib/gssapi/krb5/k5sealv3.c * @@ -566,6 +563,7 @@ error: FREE(plain.data, plain.length); *minor_status = err; + save_error_info(*minor_status, context); return GSS_S_BAD_SIG; /* XXX */ } FREE(plain.data, plain.length);
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/k5unseal.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/k5unseal.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,9 +1,6 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ - - /* * Copyright 2001 by the Massachusetts Institute of Technology. * Copyright 1993 by OpenVision Technologies, Inc. @@ -729,6 +726,11 @@ *minor_status = err; +#ifndef _KERNEL + if (err != 0) + save_error_info (*minor_status, ctx->k5_context); +#endif + KRB5_LOG(KRB5_INFO, "kg_unseal() end, err = %d", err); return(err);
--- a/usr/src/uts/common/gssapi/mechs/krb5/mech/val_cred.c Mon Aug 16 16:49:45 2010 -0700 +++ b/usr/src/uts/common/gssapi/mechs/krb5/mech/val_cred.c Mon Aug 16 17:01:32 2010 -0700 @@ -1,5 +1,6 @@ -#pragma ident "%Z%%M% %I% %E% SMI" - +/* + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + */ /* * Copyright 1997 by Massachusetts Institute of Technology * All Rights Reserved. @@ -90,7 +91,8 @@ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t) cred_handle; k5_mutex_assert_locked(&cred->lock); k5_mutex_unlock(&cred->lock); - } + } else /* Solaris Kerberos - added this else */ + save_error_info(*minor_status, context); krb5_free_context(context); return maj; }