Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Stone <michael@laptop.org>2009-09-30 02:22:48 (GMT)
committer Michael Stone <michael@laptop.org>2009-09-30 05:53:20 (GMT)
commit05156ce770ff4f7361fb0ccbbe946ac652666408 (patch)
tree3475d2821501c5cd31e59a9e5d1de0e880e81cc7
parentbb2f5070a469d96bbe2c084c27f1e808b1ef27e8 (diff)
Make nss-rainbow's return and error codes more accurate.
-rw-r--r--rainbow/nss/cgen.h2
-rw-r--r--rainbow/nss/nss-rainbow.c176
2 files changed, 86 insertions, 92 deletions
diff --git a/rainbow/nss/cgen.h b/rainbow/nss/cgen.h
index 215dda0..5ef151a 100644
--- a/rainbow/nss/cgen.h
+++ b/rainbow/nss/cgen.h
@@ -5,4 +5,4 @@
#define PERROR(msg)
#define CHK(EXPR, MSG, ERR_LABEL) {if(EXPR) { PERROR(MSG); goto ERR_LABEL;}}
#define LET(LETEXPR, CONDEXPR, MSG, ERR_LABEL) LETEXPR; if (CONDEXPR) { PERROR(MSG); goto ERR_LABEL;}
-#define TST(EXPR, ERRNO, MSG, ERR_LABEL) {if (EXPR) {errno = ERRNO; PERROR(MSG); goto ERR_LABEL;}}
+#define TST(EXPR, TRUE, MSG, ERR_LABEL) {if (EXPR) {(TRUE); PERROR(MSG); goto ERR_LABEL;}}
diff --git a/rainbow/nss/nss-rainbow.c b/rainbow/nss/nss-rainbow.c
index 21d746a..5793cde 100644
--- a/rainbow/nss/nss-rainbow.c
+++ b/rainbow/nss/nss-rainbow.c
@@ -80,7 +80,7 @@ read_gid_for_uid(unsigned long uid, unsigned long* gid) {
"Unable to read gid-path.", out_err);
CHK(parse_nat(&val, gid_name, gid_name_len) == 1,
"Unable to parse gid_buf into a gid.", out_err);
- CHK(val < 10000 || val > 60000,
+ CHK(check_gid_in_range(val) == 1,
"gid not in valid range.", out_err);
*gid = val;
@@ -91,17 +91,23 @@ out_err:
enum nss_status
_nss_rainbow_getpwent_r(struct passwd *result, char* buf, size_t buflen, int *errnop) {
- /* I'm going to interpret the reentrancy requirement on this function to mean
- * that the sequence of all results returned by all calls to this function
- * between calls to setpwent() should contain contain every entry exactly
- * once. It is undefined whether writes to the underlying storage that
- * interleave with calls to getpwent() will be visible to callers. */
+ /* Getting errno and the return code correct in this function is a pain
+ * because we need to return
+ *
+ * NSS_STATUS_TRYAGAIN + ERANGE if we run out of space in buf
+ * NSS_STATUS_NOTFOUND + ENOENT if we run out of uids
+ * NSS_STATUS_SUCCESS + _____, if we win
+ * or try another uid, if we lose
+ */
begin:
+ errno = 0;
+
/* Locate the next reserved uid. */
while (true){
g_uid++;
- if (!g_uid) return NSS_STATUS_UNAVAIL;
+ TST(!g_uid, errno = ENOENT,
+ "No more uids to check.", out_error);
if (g_uids[g_uid]) break;
}
@@ -114,22 +120,27 @@ begin:
result->pw_dir = buf;
CHK(format_buf(&buf, &buflen, SPOOL "/uid_to_home_dir/%d", g_uid) == 1,
- "Unable to calculate home dir.", begin);
+ "Unable to calculate home dir.", maybe_error);
result->pw_gecos = result->pw_name = result->pw_passwd = buf;
CHK(format_buf(&buf, &buflen, "%d", g_uid) == 1,
- "Not enough buffer for $USER.", begin);
+ "Not enough buffer for $USER.", maybe_error);
result->pw_shell = buf;
CHK(write_buf(&buf, &buflen, SHELL) == 1,
- "Shell string constant too long.", begin);
-
- if(getenv(DEBUG) != NULL)
- dprintf(2, "%s success: %s (%d, %d) %s %s %s\n", __func__,
- result->pw_name, result->pw_uid, result->pw_gid, result->pw_dir,
- result->pw_shell, result->pw_passwd);
+ "Shell string constant too long.", maybe_error);
return NSS_STATUS_SUCCESS;
+
+maybe_error:
+ if(errno == ERANGE) goto out_error;
+ goto begin;
+
+out_error:
+ *errnop = errno;
+ if (errno == ERANGE) return NSS_STATUS_TRYAGAIN;
+ if (errno == ENOENT) return NSS_STATUS_NOTFOUND;
+ return NSS_STATUS_UNAVAIL;
}
enum nss_status _nss_rainbow_getpwuid_r(uid_t uid, struct passwd *result, char* buf, size_t buflen, int *errnop) {
@@ -158,11 +169,6 @@ enum nss_status _nss_rainbow_getpwuid_r(uid_t uid, struct passwd *result, char*
CHK(write_buf(&buf, &buflen, SHELL) == 1,
"Shell string constant too long.", out_error_errno);
- if(getenv(DEBUG) != NULL)
- dprintf(2, "%s success in uid: %s (%d, %d) %s %s %s\n", __func__,
- result->pw_name, result->pw_uid, result->pw_gid,
- result->pw_dir, result->pw_shell, result->pw_passwd);
-
return NSS_STATUS_SUCCESS;
out_error_errno:
@@ -175,7 +181,7 @@ enum nss_status _nss_rainbow_getpwnam_r(const char * name, struct passwd *result
CHK(parse_nat(&val, name, strlen(name)) == 1,
"Unable to parse name into a uid.", out_error_name);
- TST(val < 10000 || val > 60000, EINVAL,
+ TST(val < 10000 || val > 60000, errno = EINVAL,
"Name specifies a uid outside [10000, 60000].", out_error_name);
return _nss_rainbow_getpwuid_r((uid_t)val, result, buf, buflen, errnop);
@@ -185,36 +191,6 @@ out_error_name:
return NSS_STATUS_NOTFOUND;
}
-#if 0
-enum nss_status
-_nss_rainbow_initgroups_dyn(const char *user, gid_t gid, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) {
- if (uid < 10000)
- return NSS_STATUS_NOTFOUND;
-
- int pathlen = 1024;
- char pathdata[1024], *pathbuf = pathdata;
-
- result->pw_dir = buf;
- CHK(format_buf(&pathbuf, &pathlen, SPOOL "/uid_to_home_dir/%d", uid) == 1,
- "Unable to calculate home dir.", out_error_errno);
-
- struct stat st;
- CHK(stat(result->pw_dir, &st) == -1,
- "Stat failed for homebuf.", out_error_errno);
- result->pw_uid = uid;
- result->pw_gid = st.st_gid;
-
- (*groupsp)[*start] =
-
- return NSS_STATUS_SUCCESS;
-
-out_error_errno:
- *ernnop = errno;
- return NSS_STATUS_NOTFOUND;
-}
-
-#endif
-
struct member_list {
struct list_head list;
char* name;
@@ -231,7 +207,7 @@ struct gid_list* g_gid;
int members_scanner(const struct dirent* d) {
size_t member_len = strlen(d->d_name);
- char* member_str = d->d_name;
+ const char* member_str = d->d_name;
CHK(member_len == 0
|| (member_len == 1 && d->d_name[0] == '.')
@@ -307,10 +283,10 @@ enum nss_status _nss_rainbow_setgrent(void) {
INIT_LIST_HEAD(&g_gids.members.list);
g_gid = &g_gids;
CHK(scandir(SPOOL "/gid_to_members", &ents, gid_to_members_scanner, versionsort) == -1,
- "Unable to extract gid->members dirs from $RAINBOW_SPOOL.", out_error_spool);
+ "Unable to extract gid->members dirs from $RAINBOW_SPOOL.", out_error);
g_gid = list_entry(g_gids.list.next, struct gid_list, list);
return NSS_STATUS_SUCCESS;
-out_error_spool:
+out_error:
return NSS_STATUS_UNAVAIL;
}
@@ -341,12 +317,12 @@ struct group
*/
int
-fill_group(struct group* result, char* buf, size_t buflen, int *errnop, struct gid_list* gid_iter) {
+fill_group(struct group* result, char* buf, size_t buflen, struct gid_list* gid_iter) {
result->gr_gid = gid_iter->gid;
result->gr_name = result->gr_passwd = buf;
- TST(format_buf(&buf, &buflen, "%d", gid_iter->gid) == 1, ENOMEM,
- "Unable to calculate group name.", out_error_errno);
+ CHK(format_buf(&buf, &buflen, "%d", gid_iter->gid) == 1,
+ "Unable to calculate group name.", out_error);
/* count the number of members */
struct member_list* member_iter;
@@ -358,9 +334,9 @@ fill_group(struct group* result, char* buf, size_t buflen, int *errnop, struct g
/* reserve space for the member-pointers */
size_t member_size = (member_count+1)* sizeof(char*);
- result->gr_mem = buf;
- TST(buflen < member_size, EINVAL,
- "Not enough space for group member pointers.", out_error_errno);
+ result->gr_mem = (char**)buf;
+ TST(buflen < member_size, errno = ERANGE,
+ "Not enough space for group member pointers.", out_error);
result->gr_mem[member_count] = 0;
buf += member_size;
buflen -= member_size;
@@ -370,23 +346,22 @@ fill_group(struct group* result, char* buf, size_t buflen, int *errnop, struct g
list_for_each_entry(member_iter, &(gid_iter->members.list), list) {
result->gr_mem[member_count] = buf;
CHK(format_buf(&buf, &buflen, "%s", member_iter->name) == 1,
- "Unable to write a group member.", out_error_errno);
+ "Unable to write a group member.", out_error);
member_count++;
}
return 0;
-out_error_errno:
- *errnop = errno;
+out_error:
return 1;
}
enum nss_status
_nss_rainbow_getgrent_r(struct group *result, char *buf, size_t buflen, int *errnop) {
if (&g_gid->list == &g_gids.list)
- return NSS_STATUS_UNAVAIL;
+ return NSS_STATUS_NOTFOUND;
- CHK(fill_group(result, buf, buflen, errnop, g_gid) == 1,
+ CHK(fill_group(result, buf, buflen, g_gid) == 1,
"Unable to fill in group struct.", out_error_errno);
g_gid = list_entry(g_gid->list.next, struct gid_list, list);
@@ -397,58 +372,77 @@ out_error_errno:
return NSS_STATUS_TRYAGAIN;
}
+int check_gid_in_range(gid_t gid)
+{
+ TST(gid < 10000 || gid > 60000, errno = ENOENT,
+ "Gid outside [10000, 60000].", out_error);
+ return 0;
+out_error:
+ return 1;
+}
enum nss_status
_nss_rainbow_getgrgid_r(gid_t gid, struct group *result, char *buf, size_t buflen, int *errnop) {
- enum nss_status ret;
- if (gid < 10000 || gid > 60000)
- return NSS_STATUS_NOTFOUND;
+ /* Getting errno and the return code exactly right is a pain.
+ * The problem is that we need
+ *
+ * NSS_STATUS_NOTFOUND + ENOENT if we can't find the result
+ * NSS_STATUS_TRYAGAIN + ERANGE if buf isn't big enough
+ * NSS_STATUS_??? + ____ if we can't setgrent()
+ * NSS_STATUS_NOTFOUND + ____ if we have bogus data
+ * NSS_SUCCESS + ____ otherwise.
+ */
- /* XXX CHECK RETURN CODE */
- _nss_rainbow_setgrent();
+ enum nss_status ret, tmp;
+
+ LET(ret = _nss_rainbow_setgrent(), ret != NSS_STATUS_SUCCESS,
+ "Unable to setgrent().", out_error);
+
+ TST(check_gid_in_range(gid) == 1, ret = NSS_STATUS_NOTFOUND,
+ "Gid outside [10000, 60000].", out_error);
/* look up group data */
struct gid_list* gid_iter = NULL;
list_for_each_entry(gid_iter, &g_gids.list, list) {
- if (gid_iter->gid == gid)
- break;
- }
- if (&gid_iter->list == &g_gids.list)
- {
- ret = NSS_STATUS_NOTFOUND;
- goto out_dealloc;
+ if (gid_iter->gid == gid) break;
}
- if(fill_group(result, buf, buflen, errnop, gid_iter) == 1)
- {
- PERROR("Unable to fill in group struct.");
- goto out_error;
- }
+ TST(&gid_iter->list == &g_gids.list, ret = NSS_STATUS_NOTFOUND,
+ "Gid not found.", out_dealloc);
- if(getenv(DEBUG) != NULL)
- dprintf(2, "%s success in gid: %s (%d) %s\n", __func__,
- result->gr_name, result->gr_gid, result->gr_passwd);
+ CHK(fill_group(result, buf, buflen, gid_iter) == 1,
+ "Unable to fill in group struct.", maybe_range);
ret = NSS_STATUS_SUCCESS;
goto out_dealloc;
+maybe_range:
+ ret = (errno == ERANGE) ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
+
out_error:
*errnop = errno;
+
out_dealloc:
- /* XXX CHECK RETURN CODE */
- _nss_rainbow_endgrent();
+ tmp = _nss_rainbow_endgrent();
+ TST(ret == NSS_STATUS_SUCCESS && tmp != NSS_STATUS_SUCCESS, ret = tmp,
+ "Unable to deallocate internal group data.", out);
+
+out:
return ret;
}
enum nss_status
_nss_rainbow_getgrnam_r(const char* name, struct group *result, char *buf, size_t buflen, int *errnop) {
unsigned long val;
+
CHK(parse_nat(&val, name, strlen(name)) == 1,
- "Unable to parse name into a gid.", out_error_name);
- TST(val < 10000 || val > 60000, EINVAL,
- "Name specifies a gid outside [10000, 60000].", out_error_name);
+ "Unable to parse name into a gid.", out_error);
+
+ CHK(check_gid_in_range(val) == 1,
+ "Name specifies a gid outside [10000, 60000].", out_error);
+
return _nss_rainbow_getgrgid_r((gid_t)val, result, buf, buflen, errnop);
-out_error_name:
+out_error:
*errnop = errno;
return NSS_STATUS_NOTFOUND;
}