diff options
author | Michael Stone <michael@laptop.org> | 2008-01-24 23:50:35 (GMT) |
---|---|---|
committer | Michael Stone <michael@laptop.org> | 2008-01-24 23:50:35 (GMT) |
commit | 6d62f4a9f9045b1072674e1fc1172ea5a58fad4f (patch) | |
tree | 0f565cd3dedb4b9a140eab2d736f99789478da96 | |
parent | c8e10eb4ae55f5986344ddc8c230ee9f89fc429e (diff) |
Consistent style based on format_buf() and write_buf()
-rw-r--r-- | nss-rainbow.c | 198 |
1 files changed, 122 insertions, 76 deletions
diff --git a/nss-rainbow.c b/nss-rainbow.c index f0fc376..04b6517 100644 --- a/nss-rainbow.c +++ b/nss-rainbow.c @@ -5,21 +5,22 @@ #include <stdint.h> #include <stdlib.h> #include <stdbool.h> +#include <stdarg.h> #include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> #include <errno.h> #include <unistd.h> #include <string.h> +#include <limits.h> +#include <syslog.h> /* code generators */ #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) {perror(__FILE__ "|" __XSTRING(__LINE__) "|: " msg);} -#define CHECK(RTYPE, ERR, EXPR, ERR_LABEL, MSG) {RTYPE status = EXPR; if (status == ERR) { PERROR(MSG); goto ERR_LABEL;}} -#define LET(RTYPE, RNAME, ERR, EXPR, ERR_LABEL, MSG) RTYPE RNAME = EXPR; if (RNAME == ERR) { PERROR(MSG); goto ERR_LABEL;} +#define PERROR(msg) {syslog(LOG_ERR, "%s|%d| %s: %s", __FILE__, __LINE__, __func__, 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;} /* constants */ #define SHELL "/sbin/nologin" @@ -39,19 +40,70 @@ _nss_rainbow_setpwent(void) { g_done = false; } -int write_buf(char* home, char** buf, size_t * buflen) +int write_buf(char** buf, size_t * buflen, const char* val) { - size_t homelen; - homelen = strnlen(home, *buflen); - if (homelen == *buflen) + /* write_buf will not write outside of (*buf)[0..(*buflen-1)] + * if *buflen > strlen(val), then write_buf will ensure that *buf points to a null-terminated string. + * on success, write_buf will advance *buf to the next free char, + * set *buflen to indicate the quantity of remaining space, + * and return 1. + * on error, write_buf will set errno, return 0, and will not modify *buf or *buflen. + * *buf and val should not overlap. + */ + + size_t copy_amt = strlen(val) + 1; + + if (*buflen < copy_amt) + goto out_err_range; + + memcpy(*buf, val, copy_amt); + + *buf += copy_amt; + *buflen -= copy_amt; + return 1; + +out_err_range: + errno = ERANGE; + return 0; +} + +int format_buf(char** buf, size_t* buflen, const char* fmt, ...) +{ + /* format_buf will not write outside of (*buf)[0..(*buflen-1)] + * if *buflen > 0, format_buf will ensure that *buf points to a null-terminated string. + * on success, format_buf will advance *buf to the next free char, + * set *buflen to indicate the quantity of remaining space, + * and return 1. + * on error, format_buf will set errno, return 0, and will not modify *buf or *buflen. + * *buf should know overlap with fmt or any optional arguments. + */ + if (*buflen < 1) { errno = ERANGE; - return -1; + return 0; } - strncpy(*buf, home, homelen); - (*buf)[homelen] = '\0'; - *buflen -= homelen + 1; - *buf += homelen + 1; + + size_t safe_buflen = *buflen - 1; + + va_list ap; + va_start(ap, fmt); + int status = vsnprintf(*buf, safe_buflen, fmt, ap); + SAVE_ERR(va_end(ap)); + + if (status < 0) + goto out_err; + + if (safe_buflen < (size_t) status) { + errno = ERANGE; + goto out_err; + } + + *buf += status+1; + *buflen -= status+1; + return 1; + +out_err: + (*buf)[safe_buflen] = '\0'; return 0; } @@ -63,32 +115,32 @@ _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, NULL, - getenv("HOME"), - out_error_unavail, "Unable to retrieve $HOME."); - LET(char *, user, NULL, - getenv("USER"), - out_error_unavail, "Unable to retrieve $USER."); + + 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); result->pw_dir = buf; - CHECK(int, -1, - write_buf(home, &buf, &buflen), - out_error_buffer, "Not enough buffer for $HOME."); + CHK(write_buf(&buf, &buflen, home) == 0, + "Not enough buffer for $HOME.", out_error_again); result->pw_gecos = result->pw_name = result->pw_passwd = buf; - CHECK(int, -1, - write_buf(user, &buf, &buflen), - out_error_buffer, "Not enough buffer for $USER."); - - CHECK(bool, true, - strlen(SHELL) > buflen, - out_error_buffer, "Shell string constant too long."); - strcpy(buf, SHELL); + CHK(write_buf(&buf, &buflen, user) == 0, + "Not enough buffer for $USER.", out_error_again); + result->pw_shell = buf; - // DO NOT USE BUF UNLESS YOU INCREMENT IT NOW. - // YOU ARE DONE. + CHK(write_buf(&buf, &buflen, SHELL) == 0, + "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); if (g_done) return NSS_STATUS_NOTFOUND; @@ -99,65 +151,59 @@ _nss_rainbow_getpwent_r(struct passwd *result, char* buf, size_t buflen, int *er out_error_unavail: return NSS_STATUS_UNAVAIL; -out_error_buffer: - *errnop = ERANGE; +out_error_again: + *errnop = errno; return NSS_STATUS_TRYAGAIN; } enum nss_status _nss_rainbow_getpwbyuid_r(uid_t uid, struct passwd *result, char* buf, size_t buflen, int *errnop) { if (uid < 10000) return NSS_STATUS_NOTFOUND; - int homelen = snprintf(buf, buflen, "/home/olpc/isolation/1/%d", uid); - if ((homelen <= 0) || (((unsigned int) homelen) >= buflen)) { - PERROR("Insufficient HOMEBUFLEN for the home for user uid."); - goto out_error_buffer;} - buf[homelen] = '\0'; - struct stat statbuf; - CHECK(int, -1, - stat(buf, &statbuf), - out_error_errno, "Stat failed for homebuf."); - result->pw_uid = uid; - result->pw_gid = statbuf.st_gid; + + openlog("nss-rainbow", LOG_PID, LOG_LOCAL0); + result->pw_dir = buf; - buf += homelen + 1; - buflen -= homelen + 1; - homelen = snprintf(buf, buflen, "%d", uid); - if ((homelen <= 0) || (((unsigned int ) homelen ) >= buflen)) { - PERROR("Insufficient HOMEBUFLEN for user uid as a string."); - goto out_error_buffer; - } + CHK(format_buf(&buf, &buflen, "/home/olpc/isolation/1/%d", uid) == 0, + "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; + result->pw_gecos = result->pw_name = result->pw_passwd = buf; - buf += homelen + 1; - buflen -= homelen + 1; - CHECK(bool, true, - strlen(SHELL) > buflen, - out_error_buffer, "Shell string constant too long."); - strcpy(buf, SHELL); + CHK(format_buf(&buf, &buflen, "%d", uid) == 0, + "Unable to calculate user name.", out_error_errno); + result->pw_shell = buf; - // DO NOT USE BUF UNLESS YOU INCREMENT IT NOW. - // YOU ARE DONE. + CHK(write_buf(&buf, &buflen, SHELL) == 0, + "Shell string constant too long.", out_error_errno); + + 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); return NSS_STATUS_SUCCESS; -out_error_buffer: - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; out_error_errno: + *errnop = errno; return NSS_STATUS_TRYAGAIN; } + enum nss_status _nss_rainbow_getpwbynam_r(const char * name, struct passwd *result, char* buf, size_t buflen, int *errnop) { - const char * endptr = name + strlen(name); - char * endptrt = (char *) (uintptr_t) endptr; - long uid = strtol(name, &endptrt, 10); - if (endptr != endptrt) { - PERROR("Entire name is not an integer."); - goto out_error_badname; - } + openlog("nss-rainbow", LOG_PID, LOG_LOCAL0); - // YOU ARE DONE. - return _nss_rainbow_getpwbyuid_r((uid_t)uid, result, buf, buflen, errnop); + char * endptr = (char*) (uintptr_t) (name + strlen(name)); + + errno = 0; /* To distinguish success/failure after call */ + long val = strtol(name, &endptr, 10); + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0) + || (name == endptr)) { + PERROR("Unable to parse name into a uid."); + *errnop = (errno = 0) ? EINVAL : errno; + return NSS_STATUS_NOTFOUND; + } -out_error_badname: - *errnop = EINVAL; - return NSS_STATUS_NOTFOUND; + return _nss_rainbow_getpwbyuid_r((uid_t)val, result, buf, buflen, errnop); } |