}
#endif
-#ifdef HAVE_GRP_H
-#ifndef HAVE_GETGRNAM_R
-bool fr_getgid(char const *name, gid_t *gid)
+/** Resolve a uid to a passwd entry
+ *
+ * Resolves a uid to a passwd entry. The memory to hold the
+ * passwd entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param uid to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
{
- struct group *grp;
+ static size_t len;
+ uint8_t *buff;
+ int ret;
- grp = getgrnam(name);
- if (!grp) return false;
+ *out = NULL;
- *gid = grp->gr_gid;
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+ long int sc_len;
- return true;
+#ifdef _SC_GETPW_R_SIZE_MAX
+ sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
+ talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if (ret != 0) {
+ fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct group);
+
+ return 0;
}
-#else /* getgrnam_r() exists */
-bool fr_getgid(char const *name, gid_t *gid)
+/** Resolve a username to a passwd entry
+ *
+ * Resolves a username to a passwd entry. The memory to hold the
+ * passwd entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param name to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
{
- struct group *grp, my_group;
- char *group_buffer;
- size_t group_size = 1024;
-
- grp = NULL;
- group_buffer = talloc_array(NULL, char, group_size);
- while (group_buffer) {
- int err;
-
- err = getgrnam_r(name, &my_group, group_buffer, group_size, &grp);
- if (err == ERANGE) {
- group_size *= 2;
- group_buffer = talloc_realloc(NULL, group_buffer, char, group_size);
- continue;
+ static size_t len;
+ uint8_t *buff;
+ int ret;
+
+ *out = NULL;
+
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+ long int sc_len;
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+ sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
+ talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
}
+ }
+
+ if (ret != 0) {
+ fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct group);
+
+ return 0;
+}
+
+/** Resolve a gid to a group database entry
+ *
+ * Resolves a gid to a group database entry. The memory to hold the
+ * group entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param gid to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
+{
+ static size_t len;
+ uint8_t *buff;
+ int ret;
- if (err) errno = err; /* so the caller knows what went wrong */
+ *out = NULL;
- break;
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+ long int sc_len;
+
+#ifdef _SC_GETGR_R_SIZE_MAX
+ sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+#endif
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)),
+ talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if (ret != 0) {
+ fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct group);
+
+ return 0;
+}
+
+/** Resolve a group name to a group database entry
+ *
+ * Resolves a group name to a group database entry.
+ * The memory to hold the group entry is talloced under ctx,
+ * and must be freed when no longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param name to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
+{
+ static size_t len;
+ uint8_t *buff;
+ int ret;
+
+ *out = NULL;
+
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+ long int sc_len;
+
+#ifdef _SC_GETGR_R_SIZE_MAX
+ sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+#endif
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)),
+ talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if (ret != 0) {
+ fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
}
- talloc_free(group_buffer);
+ talloc_set_type(buff, struct group);
+
+ return 0;
+}
+
+/** Resolve a group name to a GID
+ *
+ * @param ctx to allocate temporary buffers in. Useful if using talloc pools.
+ * @param name of group.
+ * @param out where to write gid.
+ * @return 0 on success, -1 on error;
+ */
+int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name)
+{
+ int ret;
+ struct group *result;
- if (!grp) return false;
+ ret = rad_getgrnam(ctx, &result, name);
+ if (ret < 0) return -1;
- *gid = grp->gr_gid;
- return true;
+ *out = result->gr_gid;
+ talloc_free(result);
+ return 0;
}
-#endif /* HAVE_GETGRNAM_R */
-#endif /* HAVE_GRP_H */
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
-
-#ifndef HAVE_GETGRNAM_R
-#define fr_getgrnam(_a, _b) getgrnam(_b)
-#else
-static struct group *fr_getgrnam(TALLOC_CTX *ctx, char const *name)
-{
- struct group *grp, *result;
- char *group_buffer;
- size_t group_size = 1024;
-
- grp = talloc(ctx, struct group);
- group_buffer = talloc_array(grp, char, group_size);
- while (group_buffer) {
- int err;
-
- err = getgrnam_r(name, grp, group_buffer, group_size, &result);
- if (err == ERANGE) {
- group_size *= 2;
- talloc_free(group_buffer);
- group_buffer = talloc_array(grp, char, group_size);
- continue;
- }
-
- if (err) errno = err; /* so the caller knows what went wrong */
- break;
- }
-
- return grp;
-}
-#endif /* HAVE_GETGRNAM_R */
-
/*
* The Group = handler.
*/
-static int groupcmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request,
+static int groupcmp(UNUSED void *instance, REQUEST *request, UNUSED VALUE_PAIR *req_vp,
VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs,
UNUSED VALUE_PAIR **reply_pairs)
{
struct group *grp;
char **member;
int retval;
-#ifdef HAVE_GETPWNAM_R
- struct passwd my_pwd;
- char pwd_buffer[1024];
-#endif
/*
- * No user name, doesn't compare.
+ * No user name, can't compare.
*/
- if (!req->username) {
- return -1;
- }
+ if (!request->username) return -1;
-#ifdef HAVE_GETPWNAM_R
- if (getpwnam_r(req->username->vp_strvalue, &my_pwd, pwd_buffer, sizeof(pwd_buffer), &pwd) != 0) {
- pwd = NULL;
- }
-#else
- pwd = getpwnam(req->username->vp_strvalue);
-#endif
- if (!pwd)
+ if (rad_getpwnam(request, &pwd, request->username->vp_strvalue) < 0) {
+ RERROR("%s", fr_strerror());
return -1;
-
- grp = fr_getgrnam(req, check->vp_strvalue);
- if (!grp)
+ }
+ if (rad_getgrnam(request, &grp, check->vp_strvalue) < 0) {
+ RERROR("%s", fr_strerror());
+ talloc_free(pwd);
return -1;
+ }
retval = (pwd->pw_gid == grp->gr_gid) ? 0 : -1;
if (retval < 0) {
for (member = grp->gr_mem; *member && retval; member++) {
- if (strcmp(*member, pwd->pw_name) == 0)
- retval = 0;
+ if (strcmp(*member, pwd->pw_name) == 0) retval = 0;
}
}
-#ifdef HAVE_GETGRNAM_R
+ /* lifo */
talloc_free(grp);
-#endif
+ talloc_free(pwd);
return retval;
}