diff options
author | Michael Stone <michael@laptop.org> | 2008-07-07 03:03:12 (GMT) |
---|---|---|
committer | Michael Stone <michael@laptop.org> | 2008-07-07 03:03:12 (GMT) |
commit | 44e40eaad2a6eec0f64a6aee43ceaf959bfed658 (patch) | |
tree | 7c0ef4255d61db658bca60618f08243119750e8e | |
parent | 2e8cf5ba5a2236a4d75ea994f1ed84177d062509 (diff) |
Craziness.
-rw-r--r-- | cgen.h | 6 | ||||
-rw-r--r-- | nss-rainbow.c | 120 |
2 files changed, 76 insertions, 50 deletions
@@ -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; } |