--- a/components/krb5/patches/037-root-defcred.patch Thu Sep 08 13:16:06 2016 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,578 +0,0 @@
-#
-# This patch provides support in kerberos for root acquiring a default
-# cred via either a root or host service principal keys in the keytab if
-# root doesn't have a cred already.
-#
-# This is Solaris specific behavior that MIT will not take upstream.
-# Patch source: in-house
-#
-diff --git a/src/include/k5-int.h b/src/include/k5-int.h
---- a/src/include/k5-int.h
-+++ b/src/include/k5-int.h
-@@ -2353,4 +2353,6 @@ void k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode,
- #define k5_prependmsg krb5_prepend_error_message
- #define k5_wrapmsg krb5_wrap_error_message
-
-+uid_t krb5_getuid();
-+
- #endif /* _KRB5_INT_H */
-diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
---- a/src/lib/gssapi/krb5/init_sec_context.c
-+++ b/src/lib/gssapi/krb5/init_sec_context.c
-@@ -104,6 +104,11 @@
- #endif
- #include <stdlib.h>
- #include <assert.h>
-+#include <ctype.h>
-+
-+static OM_uint32 get_default_cred(OM_uint32 *, void *, gss_cred_id_t *);
-+krb5_error_code krb5_kt_find_realm(krb5_context, krb5_keytab, krb5_principal,
-+ krb5_data *);
-
- /*
- * $Id$
-@@ -962,8 +967,11 @@ krb5_gss_init_sec_context_ext(
- /* verify the credential, or use the default */
- /*SUPPRESS 29*/
- if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
-- major_status = kg_get_defcred(minor_status, &defcred);
-+ major_status = get_default_cred(minor_status, context,
-+ (gss_cred_id_t *)&defcred);
-+
- if (major_status && GSS_ERROR(major_status)) {
-+ save_error_info(*minor_status, context);
- if (*context_handle == GSS_C_NO_CONTEXT)
- krb5_free_context(context);
- return(major_status);
-@@ -1099,3 +1107,441 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
- time_rec,
- &exts);
- }
-+
-+/* Solaris Kerberos specific routines start */
-+
-+#define ROOT_UID 0
-+#define KRB5_DEFAULT_LIFE 60*60*10
-+
-+extern int
-+safechown(const char *src, uid_t uid, gid_t gid, int mode);
-+
-+/* Solaris Kerberos */
-+static OM_uint32
-+load_root_cred_using_keytab(OM_uint32 *minor_status,
-+ krb5_context context,
-+ const char *name,
-+ krb5_int32 type)
-+{
-+ krb5_creds my_creds;
-+ krb5_principal me = NULL;
-+ krb5_principal server = NULL;
-+ krb5_error_code code;
-+ krb5_ccache ccache = NULL;
-+ krb5_keytab keytab = NULL;
-+ krb5_timestamp now;
-+ krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */
-+ krb5_get_init_creds_opt opt;
-+ krb5_data tgtname = {
-+ 0,
-+ KRB5_TGS_NAME_SIZE,
-+ KRB5_TGS_NAME
-+ };
-+ char *svcname = NULL;
-+ size_t kt_size;
-+ krb5_boolean kt_is_file;
-+
-+ if (!name)
-+ return (GSS_S_FAILURE);
-+
-+ memset((char *)&my_creds, 0, sizeof(my_creds));
-+
-+ if (code = krb5_kt_default(context, &keytab)) {
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ if (code = krb5_kt_have_content(context, keytab)) {
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ if (type == KRB5_NT_SRV_HST)
-+ code = krb5_sname_to_principal(context, NULL, name, type, &me);
-+ else
-+ code = krb5_parse_name(context, name, &me);
-+
-+ if (code == 0 && krb5_is_referral_realm(&me->realm)) {
-+ krb5_data realm;
-+ code = krb5_kt_find_realm(context, keytab, me, &realm);
-+ if (code == 0) {
-+ krb5_free_data_contents(context, &me->realm);
-+ me->realm.length = realm.length;
-+ me->realm.data = realm.data;
-+ } else {
-+ /* Try to set a useful error message */
-+ char *princ = NULL;
-+ krb5_error_code ret;
-+ ret = krb5_unparse_name(context, me, &princ);
-+
-+ krb5_set_error_message(context, code,
-+ _("Failed to find realm for %s in keytab"),
-+ ret == 0 ? princ : "unknown");
-+ if (princ)
-+ krb5_free_unparsed_name(context, princ);
-+ }
-+ }
-+
-+ if (code) {
-+ (void) krb5_kt_close(context, keytab);
-+ krb5_free_principal(context, me);
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ my_creds.client = me;
-+
-+ if ((code = krb5_build_principal_ext(context, &server,
-+ krb5_princ_realm(context, me)->length,
-+ krb5_princ_realm(context, me)->data,
-+ tgtname.length, tgtname.data,
-+ krb5_princ_realm(context, me)->length,
-+ krb5_princ_realm(context, me)->data,
-+ 0))) {
-+ *minor_status = code;
-+ krb5_free_cred_contents(context, &my_creds);
-+ (void) krb5_kt_close(context, keytab);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ my_creds.server = server;
-+ my_creds.times.starttime = 0; /* start timer
-+ * when request
-+ * gets to KDC
-+ */
-+ if ((code = krb5_timeofday(context, &now))) {
-+ *minor_status = code;
-+ krb5_free_cred_contents(context, &my_creds);
-+ (void) krb5_kt_close(context, keytab);
-+ return (GSS_S_FAILURE);
-+ }
-+ my_creds.times.endtime = now + lifetime;
-+ my_creds.times.renew_till = 0;
-+
-+ memset(&opt, 0, sizeof (opt));
-+ krb5_get_init_creds_opt_init(&opt);
-+ krb5_get_init_creds_opt_set_tkt_life(&opt, lifetime);
-+
-+ code = krb5_unparse_name(context, server, &svcname);
-+ if (code != 0) {
-+ *minor_status = code;
-+ krb5_free_cred_contents(context, &my_creds);
-+ (void) krb5_kt_close(context, keytab);
-+ return (GSS_S_FAILURE);
-+ }
-+ /*
-+ * Evidently (sigh), on success, krb5_get_init_creds_keytab
-+ * changes the my_creds princ ptrs so we need to free those
-+ * princs (me&server) as well as freeing all of my_creds contents.
-+ */
-+ code = krb5_get_init_creds_keytab(context,
-+ &my_creds, me, keytab,
-+ 0, svcname, &opt);
-+
-+ (void) krb5_kt_close(context, keytab);
-+
-+ if (svcname != NULL) {
-+ free(svcname);
-+ svcname = NULL;
-+ }
-+ if (code) {
-+ *minor_status = code;
-+ krb5_free_cred_contents(context, &my_creds);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ krb5_free_principal(context, server);
-+ server = NULL;
-+
-+ code = krb5_cc_resolve (context,
-+ krb5_cc_default_name(context),
-+ &ccache);
-+ if (code != 0) {
-+ *minor_status = code;
-+ krb5_free_cred_contents(context, &my_creds);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ code = krb5_cc_initialize (context, ccache, me);
-+ krb5_free_principal(context, me);
-+ me = NULL;
-+ if (code != 0) {
-+ *minor_status = code;
-+ krb5_free_cred_contents(context, &my_creds);
-+ (void) krb5_cc_close(context, ccache);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ code = krb5_cc_store_cred(context, ccache,
-+ &my_creds);
-+ krb5_free_cred_contents(context, &my_creds);
-+ (void) krb5_cc_close(context, ccache);
-+
-+ if (code) {
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ return (GSS_S_COMPLETE);
-+}
-+
-+static OM_uint32
-+renew_ccache(OM_uint32 *minor_status, krb5_context context, uid_t uid)
-+{
-+ krb5_principal me;
-+ krb5_principal server;
-+ krb5_creds creds;
-+ krb5_creds tmpcreds;
-+ krb5_creds *out_creds;
-+ krb5_error_code code;
-+ krb5_ccache ccache = NULL;
-+ const char *ccache_name = NULL;
-+ int options = 0;
-+ krb5_data tgtname = {
-+ 0,
-+ KRB5_TGS_NAME_SIZE,
-+ KRB5_TGS_NAME
-+ };
-+ gid_t gid = getgid();
-+
-+ memset((char *)&creds, 0, sizeof(creds));
-+ memset((char *)&tmpcreds, 0, sizeof(creds));
-+
-+ if ((code = krb5_cc_default(context, &ccache))) {
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ if ((code = krb5_cc_get_principal(context, ccache, &me)) != 0) {
-+ *minor_status = code;
-+ (void) krb5_cc_close(context, ccache);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ creds.client = me;
-+
-+ if((code = krb5_build_principal_ext(context, &server,
-+ krb5_princ_realm(context, me)->length,
-+ krb5_princ_realm(context, me)->data,
-+ tgtname.length, tgtname.data,
-+ krb5_princ_realm(context, me)->length,
-+ krb5_princ_realm(context, me)->data,
-+ 0))) {
-+ krb5_free_principal(context, me);
-+ (void) krb5_cc_close(context, ccache);
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ creds.server = server;
-+ creds.ticket_flags = TKT_FLG_RENEWABLE;
-+
-+ if ((krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_FLAGS,
-+ &creds, &tmpcreds))) {
-+ (void) krb5_cc_close(context, ccache);
-+ return (KDC_ERR_BADOPTION);
-+ }
-+
-+ creds.ticket_flags = 0;
-+ code = krb5_get_credentials_renew(context, options, ccache,
-+ &creds, &out_creds);
-+ krb5_free_cred_contents(context, &creds);
-+ krb5_free_cred_contents(context, &tmpcreds);
-+
-+ if (code) {
-+ *minor_status = code;
-+ (void) krb5_cc_close(context, ccache);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ krb5_free_creds(context, out_creds);
-+
-+ ccache_name = krb5_cc_default_name(context);
-+ if (ccache_name == NULL) {
-+ *minor_status = KRB5_FCC_INTERNAL;
-+ (void) krb5_cc_close(context, ccache);
-+ return (GSS_S_FAILURE);
-+ }
-+
-+ if (strncmp(ccache_name, "FILE:", strlen("FILE:")) == 0) {
-+ ccache_name += strlen("FILE:");
-+ code = safechown(ccache_name, uid, gid, -1);
-+ if (code == -1) {
-+ (void) krb5_cc_destroy(context, ccache);
-+ *minor_status = code;
-+ return (GSS_S_FAILURE);
-+ }
-+ }
-+
-+ (void) krb5_cc_close(context, ccache);
-+
-+ return (GSS_S_COMPLETE);
-+}
-+
-+/* Solaris Kerberos */
-+#define SAM_ACCOUNT_LEN 17 /* 15:hostname + 1:$ + 1:\0 */
-+krb5_error_code
-+get_sam_account_name(char **name)
-+{
-+ char *p, localname[SAM_ACCOUNT_LEN];
-+
-+ if (name == NULL)
-+ return (EINVAL);
-+
-+ if (gethostname(localname, SAM_ACCOUNT_LEN) != 0)
-+ return (errno);
-+
-+ localname[SAM_ACCOUNT_LEN - 2] = '\0';
-+
-+ if ((p = strchr(localname, '.')) != NULL)
-+ *p = '\0';
-+
-+ for (p = localname; *p; p++)
-+ *p = toupper(*p);
-+
-+ (void) strlcat(localname, "$", SAM_ACCOUNT_LEN);
-+
-+ *name = strdup(localname);
-+ if (*name == NULL)
-+ return (ENOMEM);
-+
-+ return (0);
-+}
-+
-+/*
-+ * Solaris Kerberos:
-+ * We enforce a minimum refresh time on the root cred. This avoids problems for
-+ * the higher level communication protocol for having valid creds and
-+ * setting up a valid context, only to have it expire before or while
-+ * it is being used. For non root users we don't care since we do not refresh
-+ * there creds, they get what they can get.
-+ */
-+#define MIN_REFRESH_TIME 300
-+#define MIN_RENEW_TIME 1500
-+
-+/* get_default_cred() must be called with the krb5_mutex lock held */
-+static OM_uint32
-+get_default_cred(OM_uint32 *minor_status, void *ct, gss_cred_id_t *cred_handle)
-+{
-+ krb5_timestamp now;
-+ krb5_gss_cred_id_t cred;
-+ OM_uint32 major;
-+ OM_uint32 mntmp;
-+ /*
-+ * Solaris Kerberos
-+ * Use krb5_getuid() to select the mechanism to obtain the uid.
-+ */
-+ uid_t uid = krb5_getuid();
-+ krb5_context context = (krb5_context)ct;
-+
-+ /* Get the default cred for user */
-+ if (((major = kg_get_defcred(minor_status, cred_handle)) != NULL) &&
-+ GSS_ERROR(major)) {
-+
-+ /* If we're not root we're done */
-+ if (uid != ROOT_UID)
-+ return (major);
-+
-+ /*
-+ * Try and get root's cred in the cache using keytab.
-+ *
-+ * First try "root", then try "host", and finally try the Security
-+ * Account Manager (SAM) for MS AD interop.
-+ */
-+ major = load_root_cred_using_keytab(minor_status,
-+ context, "root", KRB5_NT_SRV_HST);
-+
-+ if (major != GSS_S_COMPLETE)
-+ major = load_root_cred_using_keytab(minor_status,
-+ context, "host",
-+ KRB5_NT_SRV_HST);
-+
-+ if (major != GSS_S_COMPLETE) {
-+ char *name;
-+ krb5_error_code code;
-+
-+ code = get_sam_account_name(&name);
-+ if (code == 0) {
-+ major = load_root_cred_using_keytab(minor_status,
-+ context, name,
-+ KRB5_NT_PRINCIPAL);
-+ free(name);
-+ }
-+ }
-+
-+ if (major != GSS_S_COMPLETE)
-+ return (major);
-+
-+ /* We should have valid tgt now in the cache, so get it. */
-+ major = kg_get_defcred(minor_status, cred_handle);
-+
-+ return (major);
-+ }
-+
-+ /* We've got a gss cred handle that is a kerberos cred handle. */
-+ cred = (krb5_gss_cred_id_t)*cred_handle;
-+
-+ /* If we can't get the time, assume the worst. */
-+ if (krb5_timeofday(context, &now)) {
-+ (void) krb5_gss_release_cred(&mntmp, cred_handle);
-+ return (GSS_S_CREDENTIALS_EXPIRED);
-+ }
-+
-+ /*
-+ * Try and get root's cred in the cache using keytab.
-+ *
-+ * First try "root", then try "host", and finally try the Security
-+ * Account Manager (SAM) for MS AD interop.
-+ */
-+ /* If root's cred has expired re-get it */
-+ if (cred->expire && (cred->expire < now + MIN_REFRESH_TIME) &&
-+ (uid == ROOT_UID)) {
-+ (void) krb5_gss_release_cred(&mntmp, cred_handle);
-+
-+ major = load_root_cred_using_keytab(minor_status,
-+ context, "root", KRB5_NT_SRV_HST);
-+
-+ if (major != GSS_S_COMPLETE)
-+ major = load_root_cred_using_keytab(minor_status,
-+ context, "host",
-+ KRB5_NT_SRV_HST);
-+
-+ if (major != GSS_S_COMPLETE) {
-+ char *name;
-+ krb5_error_code code;
-+
-+ code = get_sam_account_name(&name);
-+ if (code == 0) {
-+ major = load_root_cred_using_keytab(minor_status,
-+ context, name,
-+ KRB5_NT_PRINCIPAL);
-+ free(name);
-+ }
-+ }
-+
-+ if (major != GSS_S_COMPLETE)
-+ return (major);
-+
-+ major = kg_get_defcred(minor_status, cred_handle);
-+ if (major != GSS_S_COMPLETE)
-+ return (major);
-+
-+ /* Any body else is SOL unless we can renew their credential cache */
-+ } else if (cred->expire && (cred->expire < now + MIN_RENEW_TIME) &&
-+ (cred->expire > now)) {
-+ (void) krb5_gss_release_cred(&mntmp, cred_handle);
-+
-+ major = renew_ccache(minor_status, context, uid);
-+ if ((major != GSS_S_COMPLETE) &&
-+ (major != KDC_ERR_BADOPTION))
-+ return (major);
-+
-+ major = kg_get_defcred(minor_status, cred_handle);
-+ if (major != GSS_S_COMPLETE)
-+ return (major);
-+
-+ }
-+
-+ /* Otherwise we got non expired creds */
-+ return (GSS_S_COMPLETE);
-+}
-diff --git a/src/lib/krb5/keytab/Makefile.in b/src/lib/krb5/keytab/Makefile.in
---- a/src/lib/krb5/keytab/Makefile.in
-+++ b/src/lib/krb5/keytab/Makefile.in
-@@ -13,6 +13,7 @@ STLIBOBJS= \
- ktremove.o \
- ktfns.o \
- kt_file.o \
-+ kt_findrealm.o \
- kt_memory.o \
- kt_srvtab.o \
- read_servi.o \
-@@ -26,6 +27,7 @@ OBJS= \
- $(OUTPRE)ktremove.$(OBJEXT) \
- $(OUTPRE)ktfns.$(OBJEXT) \
- $(OUTPRE)kt_file.$(OBJEXT) \
-+ $(OUTPRE)kt_findrealm.$(OBJEXT) \
- $(OUTPRE)kt_memory.$(OBJEXT) \
- $(OUTPRE)kt_srvtab.$(OBJEXT) \
- $(OUTPRE)read_servi.$(OBJEXT) \
-@@ -39,6 +41,7 @@ SRCS= \
- $(srcdir)/ktremove.c \
- $(srcdir)/ktfns.c \
- $(srcdir)/kt_file.c \
-+ $(srcdir)/kt_findrealm.c \
- $(srcdir)/kt_memory.c \
- $(srcdir)/kt_srvtab.c \
- $(srcdir)/read_servi.c \
-diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in
---- a/src/lib/krb5/os/Makefile.in
-+++ b/src/lib/krb5/os/Makefile.in
-@@ -24,6 +24,7 @@ STLIBOBJS= \
- gen_port.o \
- genaddrs.o \
- gen_rname.o \
-+ getuid.o \
- hostaddr.o \
- hostrealm.o \
- hostrealm_dns.o \
-@@ -49,6 +50,7 @@ STLIBOBJS= \
- read_msg.o \
- read_pwd.o \
- realm_dom.o \
-+ safechown.o \
- sendto_kdc.o \
- sn2princ.o \
- thread_safe.o \
-@@ -71,6 +73,7 @@ OBJS= \
- $(OUTPRE)gen_port.$(OBJEXT) \
- $(OUTPRE)genaddrs.$(OBJEXT) \
- $(OUTPRE)gen_rname.$(OBJEXT) \
-+ $(OUTPRE)getuid.$(OBJEXT) \
- $(OUTPRE)hostaddr.$(OBJEXT) \
- $(OUTPRE)hostrealm.$(OBJEXT) \
- $(OUTPRE)hostrealm_dns.$(OBJEXT) \
-@@ -96,6 +99,7 @@ OBJS= \
- $(OUTPRE)read_msg.$(OBJEXT) \
- $(OUTPRE)read_pwd.$(OBJEXT) \
- $(OUTPRE)realm_dom.$(OBJEXT) \
-+ $(OUTPRE)safechown.$(OBJEXT) \
- $(OUTPRE)sendto_kdc.$(OBJEXT) \
- $(OUTPRE)sn2princ.$(OBJEXT) \
- $(OUTPRE)thread_safe.$(OBJEXT) \
-@@ -118,6 +122,7 @@ SRCS= \
- $(srcdir)/gen_port.c \
- $(srcdir)/genaddrs.c \
- $(srcdir)/gen_rname.c \
-+ $(srcdir)/getuid.c \
- $(srcdir)/hostaddr.c \
- $(srcdir)/hostrealm.c \
- $(srcdir)/hostrealm_dns.c \
-@@ -143,6 +148,7 @@ SRCS= \
- $(srcdir)/read_pwd.c \
- $(srcdir)/realm_dom.c \
- $(srcdir)/port2ip.c \
-+ $(srcdir)/safechown.c \
- $(srcdir)/sendto_kdc.c \
- $(srcdir)/sn2princ.c \
- $(srcdir)/thread_safe.c \
-diff --git a/src/lib/krb5/os/expand_path.c b/src/lib/krb5/os/expand_path.c
---- a/src/lib/krb5/os/expand_path.c
-+++ b/src/lib/krb5/os/expand_path.c
-@@ -291,7 +291,7 @@ static krb5_error_code
- expand_userid(krb5_context context, PTYPE param, const char *postfix,
- char **str)
- {
-- if (asprintf(str, "%lu", (unsigned long)getuid()) < 0)
-+ if (asprintf(str, "%lu", (unsigned long)krb5_getuid()) < 0)
- return ENOMEM;
- return 0;
- }