+/*
+ * A common routine for getting the Kerberos error message
+ */
+char *
+gssd_k5_err_msg(krb5_context context, krb5_error_code code)
+{
+ const char *origmsg;
+ char *msg = NULL;
+
+#if HAVE_KRB5_GET_ERROR_MESSAGE
+ if (context != NULL) {
+ origmsg = krb5_get_error_message(context, code);
+ msg = strdup(origmsg);
+ krb5_free_error_message(context, origmsg);
+ }
+#endif
+ if (msg != NULL)
+ return msg;
+#if HAVE_KRB5
+ return strdup(error_message(code));
+#else
+ if (context != NULL)
+ return strdup(krb5_get_err_text(context, code));
+ else
+ return strdup(error_message(code));
+#endif
+}
+
+/*
+ * Return default Kerberos realm
+ */
+void
+gssd_k5_get_default_realm(char **def_realm)
+{
+ krb5_context context;
+
+ if (krb5_init_context(&context))
+ return;
+
+ krb5_get_default_realm(context, def_realm);
+
+ krb5_free_context(context);
+}
+
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+/*
+ * this routine obtains a credentials handle via gss_acquire_cred()
+ * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
+ * types negotiated.
+ *
+ * XXX Should call some function to determine the enctypes supported
+ * by the kernel. (Only need to do that once!)
+ *
+ * Returns:
+ * 0 => all went well
+ * -1 => there was an error
+ */
+
+int
+limit_krb5_enctypes(struct rpc_gss_sec *sec)
+{
+ u_int maj_stat, min_stat;
+ gss_cred_id_t credh;
+ gss_OID_set_desc desired_mechs;
+ krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_MD4 };
+ int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
+ extern int num_krb5_enctypes;
+ extern krb5_enctype *krb5_enctypes;
+
+ /* We only care about getting a krb5 cred */
+ desired_mechs.count = 1;
+ desired_mechs.elements = &krb5oid;
+
+ maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
+ &desired_mechs, GSS_C_INITIATE,
+ &credh, NULL, NULL);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ if (get_verbosity() > 0)
+ pgsserr("gss_acquire_cred",
+ maj_stat, min_stat, &krb5oid);
+ return -1;
+ }
+
+ /*
+ * If we failed for any reason to produce global
+ * list of supported enctypes, use local default here.
+ */
+ if (krb5_enctypes == NULL)
+ maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
+ &krb5oid, num_enctypes, enctypes);
+ else
+ maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
+ &krb5oid, num_krb5_enctypes, krb5_enctypes);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ pgsserr("gss_set_allowable_enctypes",
+ maj_stat, min_stat, &krb5oid);
+ gss_release_cred(&min_stat, &credh);
+ return -1;
+ }
+ sec->cred = credh;
+
+ return 0;
+}
+#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */