Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Stone <michael@laptop.org>2008-07-07 03:03:12 (GMT)
committer Michael Stone <michael@laptop.org>2008-07-07 03:03:12 (GMT)
commit44e40eaad2a6eec0f64a6aee43ceaf959bfed658 (patch)
tree7c0ef4255d61db658bca60618f08243119750e8e
parent2e8cf5ba5a2236a4d75ea994f1ed84177d062509 (diff)
Craziness.
-rw-r--r--cgen.h6
-rw-r--r--nss-rainbow.c120
2 files changed, 76 insertions, 50 deletions
diff --git a/cgen.h b/cgen.h
index 38e7a71..172a404 100644
--- a/cgen.h
+++ b/cgen.h
@@ -1,7 +1,7 @@
#define STATIC_ASSERT(expr) extern char __static_assertion_failed [(expr) ? 1 : -1]
#define SAVE_ERR(EXPR) {int __errno_save = errno; EXPR; errno = __errno_save;}
#define __XSTRING(X) __STRING(X)
-#define PERROR(msg) {int __errno_cache = errno; syslog(LOG_ERR, "%s|%d| %s: %s\nError %d: %s", __FILE__, __LINE__, __func__, msg, __errno_cache, strerror(__errno_cache));}
+#define PERROR(msg) {int __errno_cache = errno; dprintf(2, "%s|%d| %s: %s\nError %d: %s\n", __FILE__, __LINE__, __func__, msg, __errno_cache, strerror(__errno_cache));}
#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 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;}}
diff --git a/nss-rainbow.c b/nss-rainbow.c
index a7bfd1f..d46e699 100644
--- a/nss-rainbow.c
+++ b/nss-rainbow.c
@@ -1,4 +1,5 @@
#define _GNU_SOURCE
+#define _SVID_SOURCE
#include <nss.h>
#include <stdio.h>
#include <pwd.h>
@@ -11,7 +12,7 @@
#include <unistd.h>
#include <string.h>
#include <limits.h>
-#include <syslog.h>
+#include <dirent.h>
/* code generators */
#include "cgen.h"
@@ -20,21 +21,43 @@
#include "nat.h"
/* constants */
-#define SHELL "/sbin/nologin"
-
-static bool g_done;
+#define SHELL "/bin/bash"
+#define SPOOL "/home/olpc/isolation/1"
+#define DEBUG "RAINBOW_NSS_DEBUG"
+
+static unsigned char g_uids[65536];
+static unsigned short g_uid = 0;
+
+/* I'm going to assume that every appropriately named dirent represents a user.
+ * We may need to revise this, e.g. by checking for the existence of home dir.
+ * We're also going to be evil and use the scandir() traversal to directly
+ * record allocated uids. <MS> */
+int
+uid_filter(const struct dirent* d) {
+ unsigned long val;
+ if(parse_nat(&val, d->d_name, strlen(d->d_name)) == 1) return 0;
+ if(val < 10000 || val > 60000) return 0;
+ g_uids[val] = 1;
+ return 0;
+}
/* implementation */
enum nss_status
_nss_rainbow_endpwent(void) {
- g_done = false;
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_rainbow_setpwent(void) {
+ for (unsigned short i = 10000; i < 60000; i++)
+ g_uids[i] = 0;
+ g_uid = 0;
+ struct dirent** uids;
+ CHK(scandir(SPOOL "/uid_pool", &uids, uid_filter, versionsort) == -1,
+ "Unable to extract uids from $RAINBOW_SPOOL.", out_error_spool);
return NSS_STATUS_SUCCESS;
- g_done = false;
+out_error_spool:
+ return NSS_STATUS_UNAVAIL;
}
enum nss_status
@@ -45,55 +68,62 @@ _nss_rainbow_getpwent_r(struct passwd *result, char* buf, size_t buflen, int *er
* once. It is undefined whether writes to the underlying storage that
* interleave with calls to getpwent() will be visible to callers. */
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
-
- result->pw_uid = getuid();
- result->pw_gid = getgid();
-
- LET(char* home = getenv("HOME"), home == NULL,
- "Unable to retrieve $HOME", out_error_unavail);
-
- LET(char * user = getenv("USER"), user == NULL,
- "Unable to retrieve $USER.", out_error_unavail);
+ char gid_path[NAME_MAX+1];
+ char gid_name[NAME_MAX+1];
+ size_t gid_path_len;
+ ssize_t gid_name_len;
+ char* gid_path_str;
+ unsigned long gid;
+
+begin:
+ gid_path_len = gid_name_len = NAME_MAX+1;
+ gid_path_str = gid_path;
+
+ /* Locate the next reserved uid. */
+ while (true){
+ g_uid++;
+ if (!g_uid) return NSS_STATUS_UNAVAIL;
+ if (g_uids[g_uid]) break;
+ }
+
+ result->pw_uid = g_uid;
+
+ CHK(format_buf(&gid_path_str, &gid_path_len, SPOOL "/uid_to_gid/%d", g_uid) == 1,
+ "Unable to calculate gid-path.", begin);
+ LET(gid_name_len = readlink(gid_path, gid_name, gid_name_len), gid_name_len == -1,
+ "Unable to read gid-path.", begin);
+ CHK(parse_nat(&gid, gid_name, gid_name_len) == 1,
+ "Unable to parse gid_buf into a gid.", begin);
+ CHK(gid < 10000 || gid > 60000,
+ "gid not in valid range.", begin);
+ result->pw_gid = gid;
result->pw_dir = buf;
- CHK(write_buf(&buf, &buflen, home) == 1,
- "Not enough buffer for $HOME.", out_error_again);
+ CHK(format_buf(&buf, &buflen, SPOOL "/uid_to_home_dir/%d", g_uid) == 1,
+ "Unable to calculate home dir.", begin);
result->pw_gecos = result->pw_name = result->pw_passwd = buf;
- CHK(write_buf(&buf, &buflen, user) == 1,
- "Not enough buffer for $USER.", out_error_again);
+ CHK(format_buf(&buf, &buflen, "%d", g_uid) == 1,
+ "Not enough buffer for $USER.", begin);
result->pw_shell = buf;
CHK(write_buf(&buf, &buflen, SHELL) == 1,
- "Shell string constant too long.", out_error_again);
-
- syslog(LOG_ERR, "%s success: %s (%d, %d) %s %s %s", __func__,
- result->pw_name, result->pw_uid, result->pw_gid, result->pw_dir,
- result->pw_shell, result->pw_passwd);
+ "Shell string constant too long.", begin);
- if (g_done)
- return NSS_STATUS_NOTFOUND;
+ 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);
- g_done = true;
return NSS_STATUS_SUCCESS;
-
-out_error_unavail:
- return NSS_STATUS_UNAVAIL;
-
-out_error_again:
- *errnop = errno;
- return NSS_STATUS_TRYAGAIN;
}
enum nss_status _nss_rainbow_getpwuid_r(uid_t uid, struct passwd *result, char* buf, size_t buflen, int *errnop) {
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
-
if (uid < 10000)
return NSS_STATUS_NOTFOUND;
result->pw_dir = buf;
- CHK(format_buf(&buf, &buflen, "/home/olpc/isolation/1/uid_to_home_dir/%d", uid) == 1,
+ CHK(format_buf(&buf, &buflen, SPOOL "/uid_to_home_dir/%d", uid) == 1,
"Unable to calculate home dir.", out_error_errno);
struct stat st;
@@ -110,7 +140,10 @@ 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);
- syslog(LOG_ERR, "%s success in uid: %s (%d, %d) %s %s %s", __func__, result->pw_name, result->pw_uid, result->pw_gid, result->pw_dir, result->pw_shell, result->pw_passwd);
+ 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;
@@ -120,8 +153,6 @@ out_error_errno:
}
enum nss_status _nss_rainbow_getpwnam_r(const char * name, struct passwd *result, char* buf, size_t buflen, int *errnop) {
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
-
unsigned long val;
CHK(parse_nat(&val, name, strlen(name)) == 1,
"Unable to parse name into a uid.", out_error_name);
@@ -139,8 +170,6 @@ out_error_name:
/*
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) {
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
-
if (uid < 10000)
return NSS_STATUS_NOTFOUND;
@@ -148,7 +177,7 @@ _nss_rainbow_initgroups_dyn(const char *user, gid_t gid, long int *start, long i
char pathdata[1024], *pathbuf = pathdata;
result->pw_dir = buf;
- CHK(format_buf(&pathbuf, &pathlen, "/home/olpc/isolation/1/uid_to_home_dir/%d", uid) == 1,
+ CHK(format_buf(&pathbuf, &pathlen, SPOOL "/uid_to_home_dir/%d", uid) == 1,
"Unable to calculate home dir.", out_error_errno);
struct stat st;
@@ -166,12 +195,10 @@ out_error_errno:
return NSS_STATUS_NOTFOUND;
}
enum nss_status _nss_rainbow_setgrent(void) {
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
return NSS_STATUS_SUCCESS;
}
enum nss_status _nss_rainbow_endgrent(void) {
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
return NSS_STATUS_SUCCESS;
}
@@ -184,7 +211,6 @@ struct group
};
enum nss_status
_nss_rainbow_getgrent_r(struct group *result, char *buf, size_t buflen, int *errnop) {
- openlog("nss-rainbow", LOG_PID, LOG_LOCAL0);
return NSS_STATUS_NOTFOUND;
}