--- /dev/null
+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");