Subject: Hesiod uid maps
To: None <tech-userlevel@netbsd.org>
From: Greg Hudson <ghudson@MIT.EDU>
List: tech-userlevel
Date: 03/06/1999 17:46:48
So, we never finished addressing the Hesiod getpwuid() problem (that
is, that Ultrix uses the "passwd" map and Athena Hesiod uses the "uid"
map).  I came up with an idea today for fixing the problem without
having to parse hesiod.conf in two places.  It adds a uid map search
just like the class search, and adds an internal function to hesiod.c
to do the resolution for uid lookups.

I do not have a good setup for testing NetBSD libc changes.  The
changes to hesiod.c are just a reindentation of changes to the Athena
hesiod code (with modified comments) which I did test, so I have good
confidence that these changes should work.

The default I chose was "uidmaps=uid".  This means people using Hesiod
against Ultrix servers will need to add "uidmaps=passwd" (or
"uidmaps=passwd,uid" or whatnot) to their hesiod.conf files before
this code will help them.  That line, as well as a "classes=" line,
will be harmless on an Ultrix box, so you can still use the same
hesiod.conf on Ultrix and NetBSD machines.

We could make the default "uidmaps=uid,passwd", but that means a
failed uid lookup using the default search paths will take four
packets.  I think that's excessive.  However, I feel less strongly
about the default in this case than I did in the classes case.

*** /mit/netbsd/src/lib/libc/net/hesiod.c	Tue Mar  2 17:48:41 1999
--- hesiod.c	Sat Mar  6 17:40:14 1999
***************
*** 75,80 ****
--- 75,81 ----
  __weak_alias(hesiod_end,_hesiod_end);
  __weak_alias(hesiod_to_bind,_hesiod_to_bind);
  __weak_alias(hesiod_resolve,_hesiod_resolve);
+ __weak_alias(hesiod__uidresolve,_hesiod__uidresolve);
  __weak_alias(hesiod_free_list,_hesiod_free_list);
  __weak_alias(hes_init,_hes_init);
  __weak_alias(hes_to_bind,_hes_to_bind);
***************
*** 83,92 ****
  __weak_alias(hes_free,_hes_free);
  #endif
  
  struct hesiod_p {
! 	char	*lhs;			/* normally ".ns" */
! 	char	*rhs;			/* AKA the default hesiod domain */
! 	int	 classes[2];		/* The class search order. */
  };
  
  #define	MAX_HESRESP	1024
--- 84,100 ----
  __weak_alias(hes_free,_hes_free);
  #endif
  
+ /* Athena uses the "uid" hesiod type for uid lookups.  Ultrix uses the
+  * "passwd" type.  Some constants for the compatibility code.
+  */
+ #define UIDMAP_UID    "uid"
+ #define UIDMAP_PASSWD "passwd"
+ 
  struct hesiod_p {
! 	char		*lhs;		/* normally ".ns" */
! 	char		*rhs;		/* AKA the default hesiod domain */
! 	int	 	classes[2];	/* The class search order */
! 	const char	*uidmaps[2];	/* The uid map search order */
  };
  
  #define	MAX_HESRESP	1024
***************
*** 259,264 ****
--- 267,285 ----
  	return retvec;
  }
  
+ /* Internal function for getpwent.c. */
+ char **hesiod__uidresolve(void *context, const char *uidstr)
+ {
+ 	struct hesiod_p *ctx = (struct hesiod_p *) context;
+ 	char **retvec;
+ 
+ 	retvec = hesiod_resolve(context, uidstr, ctx->uidmaps[0]);
+ 	if (retvec == NULL && errno == ENOENT && ctx->uidmaps[1])
+ 		retvec = hesiod_resolve(context, uidstr, ctx->uidmaps[1]);
+ 
+ 	return retvec;
+ }
+ 
  /*ARGSUSED*/
  void 
  hesiod_free_list(context, list)
***************
*** 294,299 ****
--- 315,324 ----
  	ctx->classes[0] = C_IN;
  	ctx->classes[1] = C_HS;
  
+ 		/* Set default uid maps. */
+ 	ctx->uidmaps[0] = UIDMAP_UID;
+ 	ctx->uidmaps[1] = NULL;
+ 
  		/* Try to open the configuration file. */
  	fp = fopen(filename, "r");
  	if (!fp) {
***************
*** 355,367 ****
  				}
  				while (n < 2)
  					ctx->classes[n++] = 0;
  			}
  		}
  	}
  	fclose(fp);
  
  	if (!ctx->rhs || ctx->classes[0] == 0 ||
! 	    ctx->classes[0] == ctx->classes[1]) {
  		errno = ENOEXEC;
  		return -1;
  	}
--- 380,413 ----
  				}
  				while (n < 2)
  					ctx->classes[n++] = 0;
+ 			} else if (strcasecmp(key, "uidmaps") == 0) {
+ 				n = 0;
+ 				while (*data && n < 2) {
+ 					p = data;
+ 					while (*p && *p != ',')
+ 						p++;
+ 					if (*p)
+ 						*p++ = 0;
+ 					if (strcasecmp(data, "uid") == 0)
+ 						ctx->uidmaps[n++] = UIDMAP_UID;
+ 					else if (strcasecmp(data,
+ 							    "passwd") == 0)
+ 						ctx->uidmaps[n++] =
+ 						    UIDMAP_PASSWD;
+ 					data = p;
+ 				}
+ 				while (n < 2)
+ 					ctx->uidmaps[n++] = NULL;
  			}
  		}
  	}
  	fclose(fp);
  
+ 		/* Make sure that the rhs is set and that the class search
+ 		 * order and the uidmap search order both make sense. */
  	if (!ctx->rhs || ctx->classes[0] == 0 ||
! 	    ctx->classes[0] == ctx->classes[1] || ctx->uidmaps[0] == 0 ||
! 	    ctx->uidmaps[0] == ctx->uidmaps[1]) {
  		errno = ENOEXEC;
  		return -1;
  	}
*** /mit/netbsd/src/lib/libc/gen/getpwent.c	Fri Jan 29 16:40:12 1999
--- getpwent.c	Sat Mar  6 17:35:46 1999
***************
*** 83,88 ****
--- 83,89 ----
  __weak_alias(setpwent,_setpwent);
  #endif
  
+ extern char **hesiod__uidresolve __P((void *, const char *));
  
  /*
   * The lookup techniques and data extraction code here must be kept
***************
*** 450,456 ****
  	uid_t		  uid;
  	int		  search;
  
- 	char		 *map;
  	char		**hp;
  	void		 *context;
  	int		  r;
--- 451,456 ----
***************
*** 460,476 ****
  	case _PW_KEYBYNUM:
  		snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum);
  		_pw_hesnum++;
- 		map = "passwd";
  		break;
  	case _PW_KEYBYNAME:
  		name = va_arg(ap, const char *);
  		strncpy(line, name, sizeof(line));
- 		map = "passwd";
  		break;
  	case _PW_KEYBYUID:
  		uid = va_arg(ap, uid_t);
  		snprintf(line, sizeof(line), "%u", (unsigned int)uid);
- 		map = "uid";		/* XXX this is `passwd' on ultrix */
  		break;
  	default:
  		abort();
--- 460,473 ----
***************
*** 481,487 ****
  	if (hesiod_init(&context) == -1)
  		return (r);
  
! 	hp = hesiod_resolve(context, line, map);
  	if (hp == NULL) {
  		if (errno == ENOENT) {
  			if (search == _PW_KEYBYNUM) {
--- 478,487 ----
  	if (hesiod_init(&context) == -1)
  		return (r);
  
! 	if (search == _PW_KEYBYUID)
! 		hp = hesiod__uidresolve(context, line);
! 	else
! 		hp = hesiod_resolve(context, line, "passwd");
  	if (hp == NULL) {
  		if (errno == ENOENT) {
  			if (search == _PW_KEYBYNUM) {
*** /mit/netbsd/src/lib/libc/include/namespace.h	Tue Mar  2 17:48:39 1999
--- namespace.h	Sat Mar  6 17:34:30 1999
***************
*** 221,226 ****
--- 221,227 ----
  #define hesiod_free_list	_hesiod_free_list
  #define hesiod_init		_hesiod_init
  #define hesiod_resolve		_hesiod_resolve
+ #define hesiod__uidresolve	_hesiod__uidresolve
  #define hesiod_to_bind		_hesiod_to_bind
  #define inet_aton		_inet_aton
  #define inet_lnaof		_inet_lnaof