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