/*
* include/krb5/adm.h
*
- * Copyright 1995,2001 by the Massachusetts Institute of Technology.
+ * Copyright 1995,2001,2009 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
char * realm_kdc_ports;
char * realm_kdc_tcp_ports;
char * realm_acl_file;
+ char * realm_host_based_services;
+ char * realm_no_host_referral;
krb5_int32 realm_kadmind_port;
krb5_enctype realm_enctype;
krb5_deltat realm_max_life;
/*
* include/krb5/adm_proto.h
*
- * Copyright 1995, 2007 by the Massachusetts Institute of Technology.
+ * Copyright 1995, 2007,2008,2009 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
krb5_deltat *);
krb5_error_code krb5_aprof_get_string
(krb5_pointer, const char **, krb5_boolean, char **);
+krb5_error_code krb5_aprof_get_string_all
+ (krb5_pointer, const char **, char **);
krb5_error_code krb5_aprof_get_int32
(krb5_pointer,
const char **,
krb5_error_code krb5_os_hostaddr
(krb5_context, const char *, krb5_address ***);
+krb5_error_code krb5int_get_domain_realm_mapping
+ (krb5_context , const char *, char ***);
+
/* N.B.: You need to include fake-addrinfo.h *before* k5-int.h if you're
going to use this structure. */
struct addrlist {
#include "extern.h"
#include "adm_proto.h"
-
static void find_alternate_tgs (krb5_kdc_req *, krb5_db_entry *,
krb5_boolean *, int *);
int, krb5_principal,
krb5_data **, const char *);
+static krb5_boolean
+is_substr ( char *, krb5_data *);
+
/*ARGSUSED*/
krb5_error_code
process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
krb5_key_data *server_key;
char *cname = 0, *sname = 0, *altcname = 0;
krb5_last_req_entry *nolrarray[2], nolrentry;
-/* krb5_address *noaddrarray[1]; */
krb5_enctype useenctype;
int errcode, errcode2;
register int i;
+ size_t len;
int firstpass = 1;
const char *status = 0;
krb5_enc_tkt_part *header_enc_tkt = NULL; /* ticket granting or evidence ticket */
krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
unsigned int c_flags = 0, s_flags = 0; /* client/server KDB flags */
char *s4u_name = NULL;
- krb5_boolean is_referral;
+ krb5_boolean is_referral, db_ref_done = FALSE;
const char *emsg = NULL;
+ char **realms, **cpp, *temp_buf=NULL;
+ krb5_data *comp1 = NULL, *comp2 = NULL;
+ krb5_data *tgs_1 =NULL, *server_1 = NULL;
+ krb5_principal krbtgt_princ;
session_key.contents = NULL;
krb5_free_kdc_req(kdc_context, request);
return retval;
}
-
- if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
- status = "UNPARSING SERVER";
- goto cleanup;
- }
- limit_string(sname);
-
- /* errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat); */
errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket,
&krbtgt, &k_nprincs, &subkey);
if (header_ticket && header_ticket->enc_part2 &&
/* XXX make sure server here has the proper realm...taken from AP_REQ
header? */
- nprincs = 1;
if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
}
+ db_ref_done = FALSE;
+
+ref_tgt_again:
+ nprincs = 1;
+ if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
+ status = "UNPARSING SERVER";
+ goto cleanup;
+ }
+ limit_string(sname);
+
errcode = krb5_db_get_principal_ext(kdc_context,
request->server,
s_flags,
* might be a request for a TGT for some other realm; we
* should do our best to find such a TGS in this db
*/
- if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) {
- if (krb5_princ_size(kdc_context, request->server) == 2) {
- krb5_data *server_1 =
- krb5_princ_component(kdc_context, request->server, 1);
- krb5_data *tgs_1 =
- krb5_princ_component(kdc_context, tgs_server, 1);
-
- if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
- krb5_db_free_principal(kdc_context, &server, nprincs);
- find_alternate_tgs(request, &server, &more, &nprincs);
- firstpass = 0;
- goto tgt_again;
- }
- }
- }
+ if (firstpass ) {
+
+ if ( krb5_is_tgs_principal(request->server) == TRUE) { /* Principal is a name of krb ticket service */
+ if (krb5_princ_size(kdc_context, request->server) == 2) {
+
+ server_1 = krb5_princ_component(kdc_context, request->server, 1);
+ tgs_1 = krb5_princ_component(kdc_context, tgs_server, 1);
+
+ if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
+ krb5_db_free_principal(kdc_context, &server, nprincs);
+ find_alternate_tgs(request, &server, &more, &nprincs);
+ firstpass = 0;
+ goto tgt_again;
+ }
+ }
+ krb5_db_free_principal(kdc_context, &server, nprincs);
+ status = "UNKNOWN_SERVER";
+ errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ goto cleanup;
+
+ } else if ( db_ref_done == FALSE) {
+
+ /* By now we know that server principal name is unknown <== nprincs!=1 from get_principal
+ * If CANONICALIZE flag is set in the request (1)
+ * If req is not U2U authn. req (2)
+ * the requested server princ. has exactly two components (3)
+ * either
+ * the name type is NT-SRV-HST (4.a)
+ * or name type is NT-UNKNOWN and
+ * the 1st component is listed in conf file under host_based_services (4.b)
+ * the 1st component is not in a list in conf under "no_host_referral" (5)
+ * the 2d component looks like fully-qualified domain name (FQDN) (6)
+ * If all of these conditions are satisfied - try mapping the FQDN and
+ * re-process the request as if client had asked for cross-realm TGT.
+ */
+
+ if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE) == TRUE && /* (1) */
+ !isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY) && /* (2) */
+ krb5_princ_size(kdc_context, request->server) == 2) { /* (3) */
+
+ comp1 = krb5_princ_component(kdc_context, request->server, 0);
+ comp2 = krb5_princ_component(kdc_context, request->server, 1);
+
+ if ((krb5_princ_type(kdc_context, request->server) == KRB5_NT_SRV_HST || /* (4.a) */
+ (krb5_princ_type(kdc_context, request->server) == KRB5_NT_UNKNOWN && /* (4.b) */
+ (is_substr(kdc_active_realm->realm_host_based_services, comp1)==TRUE ||
+ strchr(kdc_active_realm->realm_host_based_services, '*')))) &&
+ (kdc_active_realm->realm_no_host_referral == NULL ||
+ (!strchr(kdc_active_realm->realm_host_based_services, '*') &&
+ is_substr(kdc_active_realm->realm_no_host_referral,comp1)==FALSE))) { /* (5) */
+
+ for ( len=0; len < comp2->length; len++) {
+ if ( comp2->data[len] == '.' ) break;
+ }
+ if ( len == comp2->length) /* (6) */
+ goto cleanup;
+
+ /* try mapping FQDN or the containing domains */
+ temp_buf = calloc(1, comp2->length+1);
+ if ( !temp_buf){
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ strncpy(temp_buf, comp2->data,comp2->length);
+ retval = krb5int_get_domain_realm_mapping(kdc_context, temp_buf, &realms);
+ free(temp_buf);
+ if (retval) {
+ /* no match found */
+ com_err("krb5_get_domain_realm_mapping", retval, 0);
+ goto cleanup;
+ }
+ if (realms == 0) {
+ printf(" (null)\n");
+ goto cleanup;
+ }
+ if (realms[0] == 0) {
+ printf(" (none)\n");
+ free(realms);
+ goto cleanup;
+ }
+ /* Modify request.
+ * Construct cross-realm tgt : krbtgt/REMOTE_REALM@LOCAL_REALM
+ * and use it as a principal in this req.
+ */
+ retval = krb5_build_principal(kdc_context, &krbtgt_princ,
+ (*request->server).realm.length,
+ (*request->server).realm.data,
+ "krbtgt", realms[0], (char *)0);
+
+ for (cpp = realms; *cpp; cpp++) free(*cpp);
+ krb5_free_principal(kdc_context, request->server);
+
+ retval = krb5_copy_principal(kdc_context, krbtgt_princ, &(request->server));
+ if ( retval == 0 ) {
+ db_ref_done = TRUE;
+ goto ref_tgt_again;
+ }
+ }
+ }
+ }
+ }
+
+
krb5_db_free_principal(kdc_context, &server, nprincs);
status = "UNKNOWN_SERVER";
errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
krb5_free_realm_tree(kdc_context, plist);
return;
}
+
+/* is_substr - verfies if d1 contains d2->data with head/trail-ing whitespaces
+ */
+static krb5_boolean
+is_substr ( char *d1, krb5_data *d2)
+{
+ krb5_boolean ret = FALSE;
+ char *new_d2 = 0, *d2_formated = 0;
+ if ( d1 && d2 && d2->data && (d2->length+2 <= strlen(d1))){
+ if ((new_d2 = calloc(1,d2->length+1))) {
+ strncpy(new_d2,d2->data,d2->length);
+ asprintf( &d2_formated, "%c%s%c", ' ', new_d2, ' ');
+ if ( d2_formated != 0 && strstr( d1, d2_formated) != NULL)
+ ret = TRUE;
+ free(new_d2);
+ free(d2_formated);
+ }
+ }
+ return ret;
+}
+
+
+
/*
* kdc/extern.h
*
- * Copyright 1990,2001,2007 by the Massachusetts Institute of Technology.
+ * Copyright 1990,2001,2007,2009 by the Massachusetts Institute of Technology.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
krb5_context realm_context; /* Context to be used for realm */
krb5_keytab realm_keytab; /* keytab to be used for this realm */
char * realm_profile; /* Profile file for this realm */
+ char * realm_host_based_services; /* do referral processing for these services
+ * If '*' - allow all referrals */
+ char * realm_no_host_referral; /* no referral for these services.
+ * If '*' - disallow all referrals and
+ * ignore realm_host_based_services */
/*
* Database per-realm data.
*/
/*
* kdc/main.c
*
- * Copyright 1990,2001,2008 by the Massachusetts Institute of Technology.
+ * Copyright 1990,2001,2008,2009 by the Massachusetts Institute of Technology.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
free(rdp->realm_tcp_ports);
if (rdp->realm_keytab)
krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
+ if (rdp->realm_host_based_services)
+ free(rdp->realm_host_based_services);
+ if (rdp->realm_no_host_referral)
+ free(rdp->realm_no_host_referral);
if (rdp->realm_context) {
if (rdp->realm_mprinc)
krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
free(rdp);
}
+static void
+handle_referrals(krb5_realm_params *rparams, char *no_refrls, char *host_based_srvcs, kdc_realm_t *rdp )
+{
+ int i = 0;
+ if ( no_refrls == NULL || ( strchr(no_refrls,'*'))==0) {
+ if ( no_refrls!=0 ){
+ if (rparams && rparams->realm_no_host_referral) {
+ asprintf(&(rdp->realm_no_host_referral), "%s%s%s%s%s",
+ " ", no_refrls," ",rparams->realm_no_host_referral, " ");
+ } else {
+ asprintf(&(rdp->realm_no_host_referral),"%s%s%s", " ", no_refrls," ");
+ }
+ } else {
+ if (rparams && rparams->realm_no_host_referral) {
+ asprintf(&(rdp->realm_no_host_referral),"%s%s%s", " ", rparams->realm_no_host_referral," ");
+ } else
+ rdp->realm_no_host_referral = 0;
+ }
+
+ if ( rdp->realm_no_host_referral &&
+ strlen(rdp->realm_no_host_referral)>1 && strchr(rdp->realm_no_host_referral, '*')!=0) {
+ rdp->realm_no_host_referral = strdup("*");
+ } else {
+ /* only if no_host_referral != "*" */
+
+ if ( (host_based_srvcs !=0 && strchr(host_based_srvcs,'*')!=0) ||
+ (rparams && rparams->realm_host_based_services && strchr(rparams->realm_host_based_services,'*')!=0)) {
+ asprintf(&(rdp->realm_host_based_services),"%s", "*");
+ } else {
+ if ( host_based_srvcs !=0) {
+ if (rparams && rparams->realm_host_based_services) {
+ asprintf(&(rdp->realm_host_based_services),"%s%s%s%s%s",
+ " ", host_based_srvcs," ",rparams->realm_host_based_services," ");
+ } else
+ asprintf(&(rdp->realm_host_based_services),"%s%s%s", " ", host_based_srvcs," ");
+ } else {
+ if (rparams && rparams->realm_host_based_services) {
+ asprintf(&(rdp->realm_host_based_services),"%s%s%s"," ", rparams->realm_host_based_services," ");
+ } else
+ rdp->realm_host_based_services = 0;
+ }
+ }
+
+ /* Walk realm_host_based_services and realm_no_host_referral and replace all ',' with whitespace */
+ i = 0;
+ while ( rdp && rdp->realm_host_based_services && (rdp->realm_host_based_services)[i] != 0){
+ if (( rdp->realm_host_based_services)[i]==',' )
+ ( rdp->realm_host_based_services)[i]=' ';
+ i++;
+ }
+ i = 0;
+ while ( rdp && rdp->realm_no_host_referral && ( rdp->realm_no_host_referral)[i] != 0){
+ if (( rdp->realm_no_host_referral)[i]==',' )
+ ( rdp->realm_no_host_referral)[i]=' ';
+ i++;
+ }
+ }
+ } else {
+ if ( no_refrls != NULL && strchr(no_refrls,'*') !=0 )
+ asprintf(&(rdp->realm_no_host_referral),"%s", "* ");
+ else
+ rdp->realm_no_host_referral = 0;
+ }
+
+ return;
+}
/*
* Initialize a realm control structure from the alternate profile or from
* the specified defaults.
static krb5_error_code
init_realm(char *progname, kdc_realm_t *rdp, char *realm,
char *def_mpname, krb5_enctype def_enctype, char *def_udp_ports,
- char *def_tcp_ports, krb5_boolean def_manual, char **db_args)
+ char *def_tcp_ports, krb5_boolean def_manual, char **db_args,
+ char *no_refrls, char *host_based_srvcs)
{
krb5_error_code kret;
krb5_boolean manual;
rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit;
else
rdp->realm_reject_bad_transit = 1;
-
+
/* Handle ticket maximum life */
rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
rparams->realm_max_life : KRB5_KDB_MAX_LIFE;
rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE;
+ /* Handle KDC referrals */
+ handle_referrals(rparams, no_refrls, host_based_srvcs, rdp );
+
if (rparams)
krb5_free_realm_params(rdp->realm_context, rparams);
krb5_pointer aprof;
const char *hierarchy[3];
char **db_args = NULL;
+ char *no_refrls = 0;
+ char *host_based_srvcs = 0;
int db_args_size = 0;
extern char *optarg;
hierarchy[1] = "kdc_max_dgram_reply_size";
if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size))
max_dgram_reply_size = MAX_DGRAM_SIZE;
+ /* The service name "*" means any service. */
+ hierarchy[1] = "no_host_referral";
+ if (krb5_aprof_get_string_all(aprof, hierarchy, &no_refrls)){
+ no_refrls = 0;
+ } else {
+ if ( strlen(no_refrls) && strchr(no_refrls, '*')) {
+ no_refrls = strdup("*");
+ }
+ }
+ if ( no_refrls == 0 || strchr(no_refrls, '*')==0) {
+ hierarchy[1] = "host_based_services";
+ if (krb5_aprof_get_string_all(aprof, hierarchy, &host_based_srvcs))
+ host_based_srvcs = 0;
+ else
+ if ( strchr( host_based_srvcs, '*')) {
+ host_based_srvcs = strdup("*");
+ }
+ }
/* aprof_init can return 0 with aprof == NULL */
if (aprof)
krb5_aprof_finish(aprof);
}
+
if (default_udp_ports == 0)
default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST);
if (default_tcp_ports == 0)
if ((retval = init_realm(argv[0], rdatap, optarg,
mkey_name, menctype,
default_udp_ports,
- default_tcp_ports, manual, db_args))) {
+ default_tcp_ports, manual, db_args,
+ no_refrls, host_based_srvcs))) {
fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
argv[0], optarg);
exit(1);
if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
if ((retval = init_realm(argv[0], rdatap, lrealm,
mkey_name, menctype, default_udp_ports,
- default_tcp_ports, manual, db_args))) {
+ default_tcp_ports, manual, db_args,
+ no_refrls, host_based_srvcs))) {
fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
argv[0], lrealm);
exit(1);
char * realm_kdc_ports;
char * realm_kdc_tcp_ports;
char * realm_acl_file;
+ char * realm_host_based_services;
+ char * realm_no_host_referral;
krb5_int32 realm_kadmind_port;
krb5_enctype realm_enctype;
krb5_deltat realm_max_life;
/*
* lib/kadm/alt_prof.c
*
- * Copyright 1995,2001,2008 by the Massachusetts Institute of Technology.
+ * Copyright 1995,2001,2008,2009 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
return(kret);
}
+/*
+ * krb5_aprof_get_string_all() - When the attr identified by "hierarchy" is specified multiple times,
+ * collect all its string values from the alternate profile.
+ *
+ * Parameters:
+ * acontext - opaque context for alternate profile.
+ * hierarchy - hierarchy of value to retrieve.
+ * stringp - Returned string value.
+ *
+ * Returns:
+ * error codes from profile_get_values() or ENOMEM
+ * Caller is responsible for deallocating stringp buffer
+ */
+krb5_error_code
+krb5_aprof_get_string_all(acontext, hierarchy, stringp)
+ krb5_pointer acontext;
+ const char **hierarchy;
+ char **stringp;
+{
+ krb5_error_code kret=0;
+ char **values;
+ int lastidx;
+ char *tmp;
+ size_t buf_size=0;
+
+ if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+ for (lastidx=0; values[lastidx]; lastidx++);
+ lastidx--;
+
+ buf_size = strlen(values[0])+2;
+ for (lastidx=1; values[lastidx]; lastidx++){
+ buf_size += strlen(values[lastidx]+1);
+ }
+ }
+ if (buf_size > 0) {
+ *stringp = calloc(1,buf_size);
+ if (stringp == NULL){
+ profile_free_list(values);
+ return ENOMEM;
+ }
+ tmp=*stringp;
+ strcpy(tmp,values[0]);
+ for (lastidx=1; values[lastidx]; lastidx++){
+ tmp = strcat(tmp, " ");
+ tmp = strcat(tmp, values[lastidx]);
+ }
+ /* Free the string storage */
+ profile_free_list(values);
+ }
+ return(kret);
+}
+
+
/*
* krb5_aprof_get_int32() - Get a 32-bit integer value from the alternate
* profile.
char *kdcprofile = 0;
char *kdcenv = 0;
+ char *no_refrls = 0;
+ char *host_based_srvcs = 0;
+
+
krb5_error_code kret;
rparams->realm_reject_bad_transit_valid = 1;
}
+ hierarchy[2] = "no_host_referral";
+ if (!krb5_aprof_get_string_all(aprofile, hierarchy, &no_refrls)) {
+
+ if (strchr(no_refrls, '*'))
+ no_refrls = strdup("*");
+ rparams->realm_no_host_referral = no_refrls;
+ } else
+ no_refrls = 0;
+
+ if (no_refrls == 0 || strlen(no_refrls) == 0 || strncmp(no_refrls, "*",1) != 0) {
+ hierarchy[2] = "host_based_services";
+ if (!krb5_aprof_get_string_all(aprofile, hierarchy, &host_based_srvcs)){
+ if (strchr(host_based_srvcs, '*'))
+ host_based_srvcs = strdup("*");
+ rparams->realm_host_based_services = host_based_srvcs;
+ } else
+ host_based_srvcs = 0;
+ }
+
+
/* Get the value for the default principal flags */
hierarchy[2] = "default_principal_flags";
if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
krb5_xfree(rparams->realm_kdc_ports);
krb5_xfree(rparams->realm_kdc_tcp_ports);
krb5_xfree(rparams->realm_acl_file);
+ krb5_xfree(rparams->realm_no_host_referral);
+ krb5_xfree(rparams->realm_host_based_services);
krb5_xfree(rparams);
}
return(0);
krb5_aprof_get_deltat
krb5_aprof_get_int32
krb5_aprof_get_string
+krb5_aprof_get_string_all
krb5_aprof_getvals
krb5_aprof_init
krb5_copy_key_data_contents
krb5_os_hostaddr
krb5_os_init_context
krb5_os_localaddr
+krb5int_get_domain_realm_mapping
krb5_overridekeyname
krb5_pac_add_buffer
krb5_pac_free
/*
* lib/krb5/os/def_realm.c
*
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991,2009 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
{
free (lrealm);
}
+krb5_error_code
+krb5int_get_domain_realm_mapping(krb5_context context, const char *host, char ***realmsp)
+{
+ char **retrealms;
+ char *realm, *cp, *temp_realm;
+ krb5_error_code retval;
+ char temp_host[MAX_DNS_NAMELEN+1];
+
+#ifdef DEBUG_REFERRALS
+ printf("krb5int_get_domain_realm_mapping(host:%s) called\n",host);
+#endif
+ /* do sanity check and lower-case */
+ retval = krb5int_clean_hostname(context, host, temp_host, sizeof temp_host);
+ if (retval)
+ return retval;
+ /*
+ Search for the best match for the host or domain.
+ Example: Given a host a.b.c.d, try to match on:
+ 1) a.b.c.d 2) .b.c.d. 3) b.c.d 4) .c.d 5) c.d 6) .d 7) d
+ */
+
+ cp = temp_host;
+ realm = (char *)NULL;
+ temp_realm = 0;
+ while (cp ) {
+#ifdef DEBUG_REFERRALS
+ printf(" trying to look up %s in the domain_realm map\n",cp);
+#endif
+ retval = profile_get_string(context->profile, "domain_realm", cp,
+ 0, (char *)NULL, &temp_realm);
+ if (retval)
+ return retval;
+ if (temp_realm != (char *)NULL)
+ break; /* Match found */
+
+ /* Setup for another test */
+ if (*cp == '.') {
+ cp++;
+ } else {
+ cp = strchr(cp, '.');
+ }
+ }
+#ifdef DEBUG_REFERRALS
+ printf(" done searching the domain_realm map\n");
+#endif
+ if (temp_realm!=(char*)NULL) {
+#ifdef DEBUG_REFERRALS
+ printf(" temp_realm is %s\n",temp_realm);
+#endif
+ realm = strdup(temp_realm);
+ profile_release_string(temp_realm);
+ if (!realm) {
+ return ENOMEM;
+ }
+ }
+ if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
+ if (realm != (char *)NULL)
+ free(realm);
+ return ENOMEM;
+ }
+
+ retrealms[0] = realm;
+ retrealms[1] = 0;
+
+ *realmsp = retrealms;
+
+ return 0;
+}
+
+