Enable listing multiple realms in the server krb.conf file.  Up to four
realms may be treated as local in that fashion for authorization
purposes (instead of the single realm supported without this patch).

This upstream patch is in the 1.5 series but not in 1.4.  However, it
has been working in production at Stanford University for some time.

--- openafs.orig/src/audit/audit.c
+++ openafs/src/audit/audit.c
@@ -447,12 +447,43 @@
                     }
                     if ((clen = strlen(tcell))) {
 #if defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
-                        static char local_realm[AFS_REALM_SZ] = "";
-                        if (!local_realm[0]) {
-                            if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
-                                strncpy(local_realm, "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
+                        static char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
+			static int  num_lrealms = -1;
+			int i, lrealm_match;
+
+			if (num_lrealms == -1) {
+			    for (i=0; i<AFS_NUM_LREALMS; i++) {
+				if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
+				    break;
+			    }
+
+			    if (i == 0)
+				strncpy(local_realms[0], "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
+			    num_lrealms = i;
                         }
-                        if (strcasecmp(local_realm, tcell)) {
+
+			/* Check to see if the ticket cell matches one of the local realms */
+			lrealm_match = 0;
+			for ( i=0;i<num_lrealms;i++ ) {
+			    if (!strcasecmp(local_realms[i], tcell)) {
+				lrealm_match = 1;
+				break;
+			    }
+			}
+			/* If yes, then make sure that the name is not present in
+  			 * an exclusion list */
+			if (lrealm_match) {
+			    char uname[256];
+			    if (inst[0])
+				snprintf(uname,sizeof(uname),"%s.%s@%s",name,inst,tcell);
+			    else
+				snprintf(uname,sizeof(uname),"%s@%s",name,tcell);
+
+			    if (afs_krb_exclusion(uname))
+				lrealm_match = 0;
+			}
+
+			if (!lrealm_match) {
                             if (strlen(vname) + 1 + clen >= sizeof(vname))
                                 goto done;
                             strcat(vname, "@");
--- openafs.orig/src/auth/userok.c
+++ openafs/src/auth/userok.c
@@ -403,7 +403,9 @@
 
 	afs_uint32 exp;
 	static char lcell[MAXCELLCHARS] = "";
-	static char lrealm[AFS_REALM_SZ] = "";
+	static char lrealms[AFS_NUM_LREALMS][AFS_REALM_SZ];
+	static int  num_lrealms = -1;
+	int lrealm_match = 0, i;
 
 	/* get auth details from server connection */
 	code =
@@ -440,11 +442,40 @@
 	/* if running a krb environment, also get the local realm */
 	/* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */
 	/* just set it to lcell if it fails */
-	if (!lrealm[0]) {
-	    if (afs_krb_get_lrealm(lrealm, 0) != 0)	/* KSUCCESS */
-		strncpy(lrealm, lcell, AFS_REALM_SZ);
+	if (num_lrealms == -1) {
+	    for (i=0; i<AFS_NUM_LREALMS; i++) {
+		if (afs_krb_get_lrealm(lrealms[i], i) != 0 /*KSUCCESS*/)
+		    break;
+	    }
+
+	    if (i == 0) {
+		strncpy(lrealms[0], lcell, AFS_REALM_SZ);
+		num_lrealms = 1;
+	    } else {
+		num_lrealms = i;
+	    }
 	}
 
+	/* See if the ticket cell matches one of the local realms */
+	lrealm_match = 0;
+	for ( i=0;i<num_lrealms;i++ ) {
+	    if (!strcasecmp(lrealms[i], tcell)) {
+		lrealm_match = 1;
+		break;
+	    }
+	}
+
+	/* If yes, then make sure that the name is not present in
+	 * an exclusion list */
+	if (lrealm_match) {
+	    if (tinst[0])
+		snprintf(uname,sizeof(uname),"%s.%s@%s",tname,tinst,tcell);
+	    else
+		snprintf(uname,sizeof(uname),"%s@%s",tname,tcell);
+
+	    if (afs_krb_exclusion(uname))
+		lrealm_match = 0;
+	}
 
 	/* start with no uname and no authorization */
 	strcpy(uname, "");
@@ -456,8 +487,8 @@
 	    strcpy(uname, "<LocalAuth>");
 	    flag = 1;
 
-	    /* cell of connection matches local cell or krb4 realm */
-	} else if (!strcasecmp(tcell, lcell) || !strcasecmp(tcell, lrealm)) {
+	    /* cell of connection matches local cell or one of the realms */
+	} else if (!strcasecmp(tcell, lcell) || lrealm_match) {
 	    if ((tmp = CompFindUser(adir, tname, ".", tinst, NULL))) {
 		strcpy(uname, tmp);
 		flag = 1;
@@ -467,7 +498,6 @@
 		flag = 1;
 #endif
 	    }
-
 	    /* cell of conn doesn't match local cell or realm */
 	} else {
 	    if ((tmp = CompFindUser(adir, tname, ".", tinst, tcell))) {
--- openafs.orig/src/config/afs_sysnames.h
+++ openafs/src/config/afs_sysnames.h
@@ -286,4 +286,6 @@
 #ifdef	AFS_KERBREALM_ENV
 #define	AFS_REALM_SZ		64
 #endif
+/* Specifies the number of equivalent local realm names */
+#define AFS_NUM_LREALMS         4
 #endif /* __AFS_SYSNAMES_INCL_ENV_ */
--- openafs.orig/src/ptserver/ptprocs.c
+++ openafs/src/ptserver/ptprocs.c
@@ -93,6 +93,7 @@
 extern afs_int32 Initdb();
 extern int pr_noAuth;
 extern afs_int32 initd;
+extern char *pr_realmName;
 afs_int32 iNewEntry(), newEntry(), whereIsIt(), dumpEntry(), addToGroup(),
 nameToID(), Delete(), removeFromGroup();
 afs_int32 getCPS(), getCPS2(), getHostCPS(), listMax(), setMax(), listEntry();
@@ -178,22 +179,9 @@
 	if (exp < FT_ApproxTime())
 	    goto done;
 #endif
-	if (strlen(tcell)) {
-	    extern char *pr_realmName;
-#if	defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
-	    static char local_realm[AFS_REALM_SZ] = "";
-	    if (!local_realm[0]) {
-		if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
-		    strncpy(local_realm, pr_realmName, AFS_REALM_SZ);
-	    }
-#endif
-	    if (
-#if	defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
-		   strcasecmp(local_realm, tcell) &&
-#endif
-		   strcasecmp(pr_realmName, tcell))
-		foreign = 1;
-	}
+	if (tcell[0])
+	    foreign = afs_is_foreign_ticket_name(name,inst,tcell,pr_realmName);
+
 	strncpy(vname, name, sizeof(vname));
 	if (ilen = strlen(inst)) {
 	    if (strlen(vname) + 1 + ilen >= sizeof(vname))
@@ -640,7 +628,24 @@
 	ABORT_WITH(tt, code);
 
     for (i = 0; i < aname->namelist_len; i++) {
-	code = NameToID(tt, aname->namelist_val[i], &aid->idlist_val[i]);
+	char vname[256];
+	char *nameinst, *cell;
+
+	strncpy(vname, aname->namelist_val[i], sizeof(vname));
+	vname[sizeof(vname)-1] ='\0';
+
+	nameinst = vname;
+	cell = strchr(vname, '@');
+	if (cell) {
+	    *cell = '\0';
+	    cell++;
+	}
+
+	if (cell && afs_is_foreign_ticket_name(nameinst,NULL,cell,pr_realmName))
+	    code = NameToID(tt, aname->namelist_val[i], &aid->idlist_val[i]);
+	else
+	    code = NameToID(tt, nameinst, &aid->idlist_val[i]);
+
 	if (code != PRSUCCESS)
 	    aid->idlist_val[i] = ANONYMOUSID;
         osi_audit(PTS_NmToIdEvent, code, AUD_STR,
@@ -2281,7 +2286,6 @@
 }
 #endif /* IP_WILDCARDS */
 
-
 afs_int32
 WhoIsThisWithName(acall, at, aid, aname)
      struct rx_call *acall;
@@ -2309,11 +2313,12 @@
     } else if (code == 2) {	/* kad class */
 
 	int clen;
-	extern char *pr_realmName;
 
 	if ((code = rxkad_GetServerInfo(acall->conn, NULL, 0 /*was &exp */ ,
 					name, inst, tcell, NULL)))
 	    goto done;
+
+
 	strncpy(vname, name, sizeof(vname));
 	if ((ilen = strlen(inst))) {
 	    if (strlen(vname) + 1 + ilen >= sizeof(vname))
@@ -2322,19 +2327,9 @@
 	    strcat(vname, inst);
 	}
 	if ((clen = strlen(tcell))) {
+	    int foreign = afs_is_foreign_ticket_name(name,inst,tcell,pr_realmName);
 
-#if	defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
-	    static char local_realm[AFS_REALM_SZ] = "";
-	    if (!local_realm[0]) {
-		if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
-		    strncpy(local_realm, pr_realmName, AFS_REALM_SZ);
-	    }
-#endif
-	    if (
-#if	defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
-		   strcasecmp(local_realm, tcell) &&
-#endif
-		   strcasecmp(pr_realmName, tcell)) {
+	    if (foreign) {
 		if (strlen(vname) + 1 + clen >= sizeof(vname))
 		    goto done;
 		strcat(vname, "@");
--- openafs.orig/src/util/afsutil_prototypes.h
+++ openafs/src/util/afsutil_prototypes.h
@@ -74,7 +74,8 @@
 
 /* get_krbrlm.c */
 extern int afs_krb_get_lrealm(char *r, int n);
-
+extern int afs_krb_exclusion(char *name);
+extern int afs_is_foreign_ticket_name(char *tname, char *tinst, char * tcell, char *localrealm);
 /* hostparse.c */
 extern struct hostent *hostutil_GetHostByName(register char *ahost);
 extern char *hostutil_GetNameByINet(afs_uint32 addr);
--- openafs.orig/src/util/dirpath.c
+++ openafs/src/util/dirpath.c
@@ -365,6 +365,8 @@
     pathp = dirPathArray[AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID];
     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR, AFSDIR_MIGRATE_LOGNAME);
 
+    pathp = dirPathArray[AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID];
+    AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KRB_EXCL_FILE);
 
     /* client file paths */
 #ifdef AFS_NT40_ENV
--- openafs.orig/src/util/dirpath.hin
+++ openafs/src/util/dirpath.hin
@@ -144,6 +144,7 @@
 #define AFSDIR_BOSVR_FILE       "bosserver"
 #define AFSDIR_VOLSERLOG_FILE   "VolserLog"
 #define AFSDIR_AUDIT_FILE       "Audit"
+#define AFSDIR_KRB_EXCL_FILE    "krb.excl"
 
 #define AFSDIR_ROOTVOL_FILE     "RootVolume"
 #define AFSDIR_HOSTDUMP_FILE    "hosts.dump"
@@ -262,6 +263,7 @@
       AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID,
       AFSDIR_SERVER_BIN_FILE_DIRPATH_ID,
       AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID,
+      AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID,
       AFSDIR_PATHSTRING_MAX } afsdir_id_t;
 
 /* getDirPath() returns a pointer to a string from an internal array of path strings 
@@ -329,6 +331,7 @@
 #define AFSDIR_SERVER_WEIGHTING_CONSTANTS_FILEPATH getDirPath(AFSDIR_SERVER_WEIGHTING_CONSTANTS_FILEPATH_ID)
 #define AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH getDirPath(AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH_ID)
 #define AFSDIR_SERVER_MIGRATELOG_FILEPATH getDirPath(AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID)
+#define AFSDIR_SERVER_KRB_EXCL_FILEPATH getDirPath(AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID)
 
 /* client file paths */
 #define AFSDIR_CLIENT_THISCELL_FILEPATH getDirPath(AFSDIR_CLIENT_THISCELL_FILEPATH_ID)
--- openafs.orig/src/util/dirpath_nt.h
+++ openafs/src/util/dirpath_nt.h
@@ -135,6 +135,7 @@
 #define AFSDIR_BOSVR_FILE       "bosserver"
 #define AFSDIR_VOLSERLOG_FILE   "VolserLog"
 #define AFSDIR_AUDIT_FILE       "Audit"
+#define AFSDIR_KRB_EXCL_FILE    "krb.excl"
 
 #define AFSDIR_ROOTVOL_FILE     "RootVolume"
 #define AFSDIR_HOSTDUMP_FILE    "hosts.dump"
@@ -257,6 +258,7 @@
     AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID,
     AFSDIR_SERVER_BIN_FILE_DIRPATH_ID,
     AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID,
+    AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID,
     AFSDIR_PATHSTRING_MAX
 } afsdir_id_t;
 
@@ -325,6 +327,7 @@
 #define AFSDIR_SERVER_WEIGHTING_CONSTANTS_FILEPATH getDirPath(AFSDIR_SERVER_WEIGHTING_CONSTANTS_FILEPATH_ID)
 #define AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH getDirPath(AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH_ID)
 #define AFSDIR_SERVER_MIGRATELOG_FILEPATH getDirPath(AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID)
+#define AFSDIR_SERVER_KRB_EXCL_FILEPATH getDirPath(AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID)
 
 /* client file paths */
 #define AFSDIR_CLIENT_THISCELL_FILEPATH getDirPath(AFSDIR_CLIENT_THISCELL_FILEPATH_ID)
--- openafs.orig/src/util/get_krbrlm.c
+++ openafs/src/util/get_krbrlm.c
@@ -26,21 +26,148 @@
 #define	KSUCCESS	0
 #define	KFAILURE	(-1)
 
+static char *
+parse_str(char *buffer, char *result, int size)
+{
+    int n=0;
+
+    if (!buffer)
+        goto cleanup;
+
+    while (*buffer && isspace(*buffer))
+        buffer++;
+    while (*buffer && !isspace(*buffer)) {
+	if (n < size - 1) {
+	    *result++=*buffer++;
+	    n++;
+	} else {
+	    buffer++;
+	}
+    }
+
+  cleanup:
+    *result='\0';
+    return buffer;
+}
+
+
 int
 afs_krb_get_lrealm(char *r, int n)
 {
+    char linebuf[2048];
+    char tr[AFS_REALM_SZ] = "";
+    char *p;
     FILE *cnffile/*, *fopen()*/;
+    int i;
+    int rv = KFAILURE;
 
-    if (n > 1)
-	return (KFAILURE);	/* Temporary restriction */
+    *r = '\0';
 
     if ((cnffile = fopen(AFSDIR_SERVER_KCONF_FILEPATH, "r")) == NULL) {
 	return (KFAILURE);
     }
-    if (fscanf(cnffile, "%s", r) != 1) {
-	(void)fclose(cnffile);
-	return (KFAILURE);
+    if (fgets(linebuf, sizeof(linebuf)-1, cnffile) == NULL) {
+	goto cleanup;
+    }
+    linebuf[sizeof(linebuf)-1] = '\0';
+    for (i=0, p=linebuf; i<=n && *p; i++) {
+        p = parse_str(p, tr, AFS_REALM_SZ);
+    }
+
+    if (*tr) {
+	strcpy(r,tr);
+	rv = KSUCCESS;
+    }
+
+  cleanup:
+    (void)fclose(cnffile);
+    return rv;
+}
+
+int
+afs_krb_exclusion(char * name)
+{
+    char linebuf[2048];
+    char excl_name[256] = "";
+    FILE *cnffile/*, *fopen()*/;
+    int exclude = 0;
+
+    if ((cnffile = fopen(AFSDIR_SERVER_KRB_EXCL_FILEPATH, "r")) == NULL)
+	return exclude;
+
+    for (;;) {
+	if (fgets(linebuf, sizeof(linebuf)-1, cnffile) == NULL) {
+	    goto cleanup;
+	}
+	linebuf[sizeof(linebuf)-1] = '\0';
+        parse_str(linebuf, excl_name, sizeof(excl_name));
+
+	if (!strcmp(name,excl_name)) {
+	    exclude = 1;
+	    break;
+	}
     }
+
+  cleanup:
     (void)fclose(cnffile);
-    return (KSUCCESS);
+    return exclude;
+}
+
+int
+afs_is_foreign_ticket_name(char *tname, char *tinst, char * tcell, char *localrealm)
+{
+    int foreign = 0;
+
+    if (localrealm && strcasecmp(localrealm, tcell))
+	foreign = 1;
+
+#if	defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
+    if (foreign) {
+	static char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
+	static int  num_lrealms = -1;
+	int lrealm_match, i;
+	char uname[256];
+
+	if (num_lrealms == -1) {
+	    for (i=0; i<AFS_NUM_LREALMS; i++) {
+		if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
+		    break;
+	    }
+
+	    if (i==0 && localrealm) {
+		strncpy(local_realms[0], localrealm, AFS_REALM_SZ);
+		num_lrealms = 1;
+	    } else {
+		num_lrealms = i;
+	    }
+	}
+
+	/* See if the ticket cell matches one of the local realms */
+	lrealm_match = 0;
+	for ( i=0;i<num_lrealms;i++ ) {
+	    if (!strcasecmp(local_realms[i], tcell)) {
+		lrealm_match = 1;
+		break;
+	    }
+	}
+
+	/* If yes, then make sure that the name is not present in
+	 * an exclusion list */
+	if (lrealm_match) {
+	    if (tinst && tinst[0])
+		snprintf(uname,sizeof(uname),"%s.%s@%s",tname,tinst,tcell);
+	    else
+		snprintf(uname,sizeof(uname),"%s@%s",tname,tcell);
+
+	    if (afs_krb_exclusion(uname))
+		lrealm_match = 0;
+	}
+
+	foreign = !lrealm_match;
+    }
+#endif
+    return foreign;
 }
+
+
+
--- openafs.orig/src/util/test/dirpath_test.c
+++ openafs/src/util/test/dirpath_test.c
@@ -124,6 +124,8 @@
 	   AFSDIR_SERVER_FILELOG_FILEPATH);
     printf("AFSDIR_SERVER_AUDIT_FILEPATH = %s\n",
 	   AFSDIR_SERVER_AUDIT_FILEPATH);
+    printf("AFSDIR_SERVER_KRB_EXCL_FILEPATH  = %s\n",
+	   AFSDIR_SERVER_KRB_EXCL_FILEPATH);
     printf("\n");
     printf("\n");
     printf("AFSDIR_CLIENT_THISCELL_FILEPATH = %s\n",
--- openafs.orig/src/viced/host.c
+++ openafs/src/viced/host.c
@@ -1793,7 +1793,8 @@
 
 
 static char localcellname[PR_MAXNAMELEN + 1];
-char local_realm[AFS_REALM_SZ] = "";
+char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
+int  num_lrealms = -1;
 
 /* not reentrant */
 void
@@ -1801,13 +1802,26 @@
 {
     memset(&nulluuid, 0, sizeof(afsUUID));
     afsconf_GetLocalCell(confDir, localcellname, PR_MAXNAMELEN);
-    if (!local_realm[0]) {
-	if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/) {
+    if (num_lrealms == -1) {
+       int i;
+       for (i=0; i<AFS_NUM_LREALMS; i++) {
+	   if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
+	       break;
+       }
+
+       if (i == 0) {
 	    ViceLog(0,
 		    ("afs_krb_get_lrealm failed, using %s.\n",
 		     localcellname));
-	    strcpy(local_realm, localcellname);
+	    strncpy(local_realms[0], localcellname, AFS_REALM_SZ);
+	    num_lrealms = i =1;
+	} else {
+	    num_lrealms = i;
 	}
+
+	/* initialize the rest of the local realms to nullstring for debugging */
+	for (; i<AFS_NUM_LREALMS; i++)
+	    local_realms[i][0] = '\0';
     }
     rxcon_ident_key = rx_KeyCreate((rx_destructor_t) free);
     rxcon_client_key = rx_KeyCreate((rx_destructor_t) 0);
@@ -1837,11 +1851,10 @@
 
     cnamelen = strlen(acell);
     if (cnamelen) {
-	if (strcasecmp(local_realm, acell)
-	    && strcasecmp(localcellname, acell)) {
+	if (afs_is_foreign_ticket_name(aname, NULL, acell, localcellname)) {
 	    ViceLog(2,
-		    ("MapName: cell is foreign.  cell=%s, localcell=%s, localrealm=%s\n",
-		     acell, localcellname, local_realm));
+		    ("MapName: cell is foreign.  cell=%s, localcell=%s, localrealms={%s,%s,%s,%s}\n",
+		    acell, localcellname, local_realms[0],local_realms[1],local_realms[2],local_realms[3]));
 	    if ((anamelen + cnamelen + 1) >= PR_MAXNAMELEN) {
 		ViceLog(2,
 			("MapName: Name too long, using AnonymousID for %s@%s\n",
--- openafs.orig/src/viced/viced.c
+++ openafs/src/viced/viced.c
@@ -1077,7 +1077,8 @@
 		return -1;
 	    }
 	} else if (!strcmp(argv[i], "-realm")) {
-	    extern char local_realm[AFS_REALM_SZ];
+	    extern char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
+	    extern int  num_lrealms;
 	    if ((i + 1) >= argc) {
 		fprintf(stderr, "missing argument for -realm\n"); 
 		return -1; 
@@ -1088,7 +1089,15 @@
 		     AFS_REALM_SZ);
 		return -1;
 	    }
-	    strncpy(local_realm, argv[i], AFS_REALM_SZ);
+	    if (num_lrealms == -1)
+		num_lrealms = 0;
+	    if (num_lrealms >= AFS_NUM_LREALMS) {
+		printf
+		    ("a maximum of %d -realm arguments can be specified.\n",
+		     AFS_NUM_LREALMS);
+		return -1;
+	    }
+	    strncpy(local_realms[num_lrealms++], argv[i], AFS_REALM_SZ);
 	} else if (!strcmp(argv[i], "-udpsize")) {
 	    if ((i + 1) >= argc) {
 		printf("You have to specify -udpsize <integer value>\n");
