Permalink
Browse files

Implement getpwnam

Add getpwnam to avoid having to dynamically load glibc's NSS libraries.
When this happens when wshd runs inside a container, the version of
glibc there might not match the version of glibc it was compiled for.
  • Loading branch information...
1 parent 401735b commit 391ab5e167723a7a15844dcb91c8cbbe126c9863 Dmitriy Kalinin and Pieter Noordhuis committed Mar 15, 2013
Showing with 117 additions and 19 deletions.
  1. +2 −2 warden/src/wsh/Makefile
  2. +1 −1 warden/src/wsh/msg.c
  3. +93 −0 warden/src/wsh/pwd.c
  4. +20 −0 warden/src/wsh/pwd.h
  5. +1 −16 warden/src/wsh/wshd.c
@@ -11,10 +11,10 @@ install: all
.PHONY: all clean
-wshd: wshd.o barrier.o mount.o un.o util.o msg.o
+wshd: wshd.o barrier.o mount.o un.o util.o msg.o pwd.o
$(CC) -static -o $@ $^ -lutil
-wsh: wsh.o pump.o un.o util.o msg.o
+wsh: wsh.o pump.o un.o util.o msg.o pwd.o
$(CC) -static -o $@ $^ -lutil
%.o: %.c
@@ -2,14 +2,14 @@
#include <assert.h>
#include <errno.h>
-#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "msg.h"
+#include "pwd.h"
int msg_array_import(msg__array_t * a, int count, const char ** ptr) {
size_t off = 0;
View
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pwd.h"
+
+#define _GETPWNAM_NEXT(x, y) \
+ do { \
+ if ((y) != NULL) { \
+ (x) = (y) + 1; \
+ } \
+ \
+ (y) = strchr((x), ':'); \
+ \
+ /* Search for \n in last iteration */ \
+ if ((y) == NULL) { \
+ (y) = strchr((x), '\n'); \
+ } \
+ \
+ if ((y) == NULL) { \
+ goto done; \
+ } \
+ \
+ *(y) = '\0'; \
+ } while(0);
+
+/* Instead of using getpwnam from glibc, the following custom version is used
+ * because we need to bypass dynamically loading the nsswitch libraries.
+ * The version of glibc inside a container may be different than the version
+ * that wshd is compiled for, leading to undefined behavior. */
+struct passwd *getpwnam(const char *name) {
+ static struct passwd passwd;
+ static char buf[1024];
+ struct passwd *_passwd = NULL;
+ FILE *f;
+ char *p, *q;
+
+ f = fopen("/etc/passwd", "r");
+ if (f == NULL) {
+ goto done;
+ }
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ p = buf;
+ q = NULL;
+
+ /* Username */
+ _GETPWNAM_NEXT(p, q);
+
+ if (strcmp(p, name) != 0) {
+ continue;
+ }
+
+ passwd.pw_name = p;
+
+ /* User password */
+ _GETPWNAM_NEXT(p, q);
+ passwd.pw_passwd = p;
+
+ /* User ID */
+ _GETPWNAM_NEXT(p, q);
+ passwd.pw_uid = atoi(p);
+
+ /* Group ID */
+ _GETPWNAM_NEXT(p, q);
+ passwd.pw_gid = atoi(p);
+
+ /* User information */
+ _GETPWNAM_NEXT(p, q);
+ passwd.pw_gecos = p;
+
+ /* Home directory */
+ _GETPWNAM_NEXT(p, q);
+ passwd.pw_dir = p;
+
+ /* Shell program */
+ _GETPWNAM_NEXT(p, q);
+ passwd.pw_shell = p;
+
+ /* Done! */
+ _passwd = &passwd;
+ goto done;
+ }
+
+done:
+ if (f != NULL) {
+ fclose(f);
+ }
+
+ return _passwd;
+}
+
+#undef _GETPWNAM_NEXT
View
@@ -0,0 +1,20 @@
+#ifndef PWD_H
+#define PWD_H
+
+#include <stdint.h>
+
+#define getpwnam __wshd_getpwnam
+
+struct passwd {
+ char *pw_name; /* Username. */
+ char *pw_passwd; /* Password. */
+ uint16_t pw_uid; /* User ID. */
+ uint16_t pw_gid; /* Group ID. */
+ char *pw_gecos; /* Real name. */
+ char *pw_dir; /* Home directory. */
+ char *pw_shell; /* Shell program. */
+};
+
+struct passwd *getpwnam(const char *name);
+
+#endif
View
@@ -3,7 +3,6 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <pwd.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
@@ -24,6 +23,7 @@
#include "barrier.h"
#include "msg.h"
#include "mount.h"
+#include "pwd.h"
#include "un.h"
#include "util.h"
@@ -889,21 +889,6 @@ int main(int argc, char **argv) {
assert_directory(w->lib_path);
assert_directory(w->root_path);
- /*
- * Trigger NSS initialization.
- *
- * NSS is initialized on the first call to a function defined in <pwd.h>,
- * such as getpwnam, getpwuid, getpwent, etc.
- *
- * If this initialization step happens _after_ pivot_root(2) the shared
- * libraries that are picked up may be different from the ones that the
- * already loaded libc expects, causing inexplicable crashes.
- *
- * To prevent a shared library incompatibility, trigger initialization of the
- * NSS before modifying the environment.
- */
- getpwuid(0);
-
parent_run(w);
return 0;

0 comments on commit 391ab5e

Please sign in to comment.