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-01-24 23:50:35 (GMT)
committer Michael Stone <michael@laptop.org>2008-01-24 23:50:35 (GMT)
commit6d62f4a9f9045b1072674e1fc1172ea5a58fad4f (patch)
tree0f565cd3dedb4b9a140eab2d736f99789478da96
parentc8e10eb4ae55f5986344ddc8c230ee9f89fc429e (diff)
Consistent style based on format_buf() and write_buf()
-rw-r--r--nss-rainbow.c198
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);
}