about summary refs log tree commit diff
path: root/src/passwd
diff options
context:
space:
mode:
Diffstat (limited to 'src/passwd')
-rw-r--r--src/passwd/getgr_r.c53
-rw-r--r--src/passwd/getgrent.c39
-rw-r--r--src/passwd/getgrent_a.c46
-rw-r--r--src/passwd/getpw_r.c46
-rw-r--r--src/passwd/getpwent.c39
-rw-r--r--src/passwd/getpwent_a.c37
-rw-r--r--src/passwd/getspent.c14
-rw-r--r--src/passwd/getspnam.c17
-rw-r--r--src/passwd/getspnam_r.c89
-rw-r--r--src/passwd/lckpwdf.c11
-rw-r--r--src/passwd/pwf.h13
11 files changed, 404 insertions, 0 deletions
diff --git a/src/passwd/getgr_r.c b/src/passwd/getgr_r.c
new file mode 100644
index 00000000..5b1333e3
--- /dev/null
+++ b/src/passwd/getgr_r.c
@@ -0,0 +1,53 @@
+#include "pwf.h"
+
+#define FIX(x) (gr->gr_##x = gr->gr_##x-line+buf)
+
+static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, size_t size, struct group **res)
+{
+	FILE *f;
+	char *line = 0;
+	size_t len = 0;
+	char **mem = 0;
+	size_t nmem = 0;
+	int rv = 0;
+	size_t i;
+
+	f = fopen("/etc/group", "rb");
+	if (!f) return errno;
+
+	*res = 0;
+	while (__getgrent_a(f, gr, &line, &len, &mem, &nmem)) {
+		if (name && !strcmp(name, gr->gr_name)
+		|| !name && gr->gr_gid == gid) {
+			if (size < len + nmem*sizeof(char *) + 32) {
+				rv = ERANGE;
+				break;
+			}
+			*res = gr;
+			buf += (16-(uintptr_t)buf)%16;
+			gr->gr_mem = (void *)buf;
+			buf += nmem*sizeof(char *);
+			memcpy(buf, line, len);
+			FIX(name);
+			FIX(passwd);
+			for (i=0; mem[i]; i++)
+				gr->gr_mem[i] = mem[i]-line+buf;
+			gr->gr_mem[i] = 0;
+			break;
+		}
+	}
+ 	free(mem);
+ 	free(line);
+	fclose(f);
+	return rv;
+}
+
+int getgrnam_r(const char *name, struct group *gr, char *buf, size_t size, struct group **res)
+{
+	return getgr_r(name, 0, gr, buf, size, res);
+}
+
+int getgruid_r(gid_t gid, struct group *gr, char *buf, size_t size, struct group **res)
+{
+	return getgr_r(0, gid, gr, buf, size, res);
+}
diff --git a/src/passwd/getgrent.c b/src/passwd/getgrent.c
new file mode 100644
index 00000000..e9d25eba
--- /dev/null
+++ b/src/passwd/getgrent.c
@@ -0,0 +1,39 @@
+#include "pwf.h"
+
+static FILE *f;
+
+void setgrent()
+{
+	if (f) fclose(f);
+	f = 0;
+}
+
+weak_alias(setgrent, endgrent);
+
+struct group *getgrent()
+{
+	static char *line, **mem;
+	static struct group gr;
+	size_t size=0, nmem=0;
+	if (!f) f = fopen("/etc/group", "rb");
+	if (!f) return 0;
+	return __getgrent_a(f, &gr, &line, &size, &mem, &nmem);
+}
+
+struct group *getgrgid(gid_t gid)
+{
+	struct group *gr;
+	setgrent();
+	while ((gr=getgrent()) && gr->gr_gid != gid);
+	endgrent();
+	return gr;
+}
+
+struct group *getgrnam(const char *name)
+{
+	struct group *gr;
+	setgrent();
+	while ((gr=getgrent()) && strcmp(gr->gr_name, name));
+	endgrent();
+	return gr;
+}
diff --git a/src/passwd/getgrent_a.c b/src/passwd/getgrent_a.c
new file mode 100644
index 00000000..ccb51d52
--- /dev/null
+++ b/src/passwd/getgrent_a.c
@@ -0,0 +1,46 @@
+#include "pwf.h"
+
+struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem)
+{
+	ssize_t l;
+	char *s, *mems;
+	size_t i;
+
+	for (;;) {
+		if ((l=getline(line, size, f)) < 0) {
+			free(*line);
+			*line = 0;
+			return 0;
+		}
+		line[0][l-1] = 0;
+
+		s = line[0];
+		gr->gr_name = s++;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; gr->gr_passwd = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; gr->gr_gid = atoi(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; mems = s;
+		break;
+	}
+
+	for (*nmem=!!*s; *s; s++)
+		if (*s==',') ++*nmem;
+	free(*mem);
+	*mem = calloc(sizeof(char *), *nmem+1);
+	if (!*mem) {
+		free(*line);
+		*line = 0;
+		return 0;
+	}
+	mem[0][0] = mems;
+	for (s=mems, i=0; *s; s++)
+		if (*s==',') *s++ = 0, mem[0][++i] = s;
+	mem[0][++i] = 0;
+	gr->gr_mem = *mem;
+	return gr;
+}
diff --git a/src/passwd/getpw_r.c b/src/passwd/getpw_r.c
new file mode 100644
index 00000000..7b331e8a
--- /dev/null
+++ b/src/passwd/getpw_r.c
@@ -0,0 +1,46 @@
+#include "pwf.h"
+
+#define FIX(x) (pw->pw_##x = pw->pw_##x-line+buf)
+
+static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res)
+{
+	FILE *f;
+	char *line = 0;
+	size_t len = 0;
+	int rv = 0;
+
+	f = fopen("/etc/passwd", "rb");
+	if (!f) return errno;
+
+	*res = 0;
+	while (__getpwent_a(f, pw, &line, &len)) {
+		if (name && !strcmp(name, pw->pw_name)
+		|| !name && pw->pw_uid == uid) {
+			if (size < len) {
+				rv = ERANGE;
+				break;
+			}
+			*res = pw;
+			memcpy(buf, line, len);
+			FIX(name);
+			FIX(passwd);
+			FIX(gecos);
+			FIX(dir);
+			FIX(shell);
+			break;
+		}
+	}
+ 	free(line);
+	fclose(f);
+	return rv;
+}
+
+int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res)
+{
+	return getpw_r(name, 0, pw, buf, size, res);
+}
+
+int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res)
+{
+	return getpw_r(0, uid, pw, buf, size, res);
+}
diff --git a/src/passwd/getpwent.c b/src/passwd/getpwent.c
new file mode 100644
index 00000000..dabd411a
--- /dev/null
+++ b/src/passwd/getpwent.c
@@ -0,0 +1,39 @@
+#include "pwf.h"
+
+static FILE *f;
+
+void setpwent()
+{
+	if (f) fclose(f);
+	f = 0;
+}
+
+weak_alias(setpwent, endpwent);
+
+struct passwd *getpwent()
+{
+	static char *line;
+	static struct passwd pw;
+	size_t size=0;
+	if (!f) f = fopen("/etc/passwd", "rb");
+	if (!f) return 0;
+	return __getpwent_a(f, &pw, &line, &size);
+}
+
+struct passwd *getpwuid(uid_t uid)
+{
+	struct passwd *pw;
+	setpwent();
+	while ((pw=getpwent()) && pw->pw_uid != uid);
+	endpwent();
+	return pw;
+}
+
+struct passwd *getpwnam(const char *name)
+{
+	struct passwd *pw;
+	setpwent();
+	while ((pw=getpwent()) && strcmp(pw->pw_name, name));
+	endpwent();
+	return pw;
+}
diff --git a/src/passwd/getpwent_a.c b/src/passwd/getpwent_a.c
new file mode 100644
index 00000000..aaf84edd
--- /dev/null
+++ b/src/passwd/getpwent_a.c
@@ -0,0 +1,37 @@
+#include "pwf.h"
+
+struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size)
+{
+	ssize_t l;
+	char *s;
+	for (;;) {
+		if ((l=getline(line, size, f)) < 0) {
+			free(*line);
+			*line = 0;
+			return 0;
+		}
+		line[0][l-1] = 0;
+
+		s = line[0];
+		pw->pw_name = s++;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_passwd = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_uid = atoi(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_gid = atoi(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_gecos = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_dir = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_shell = s;
+		return pw;
+	}
+}
diff --git a/src/passwd/getspent.c b/src/passwd/getspent.c
new file mode 100644
index 00000000..8574a480
--- /dev/null
+++ b/src/passwd/getspent.c
@@ -0,0 +1,14 @@
+#include "pwf.h"
+
+void setspent()
+{
+}
+
+void endspent()
+{
+}
+
+struct spwd *getspent()
+{
+	return 0;
+}
diff --git a/src/passwd/getspnam.c b/src/passwd/getspnam.c
new file mode 100644
index 00000000..041f8965
--- /dev/null
+++ b/src/passwd/getspnam.c
@@ -0,0 +1,17 @@
+#include "pwf.h"
+
+#define LINE_LIM 256
+
+struct spwd *getspnam(const char *name)
+{
+	static struct spwd sp;
+	static char *line;
+	struct spwd *res;
+	int e;
+
+	if (!line) line = malloc(LINE_LIM);
+	if (!line) return 0;
+	e = getspnam_r(name, &sp, line, LINE_LIM, &res);
+	if (e) errno = e;
+	return res;
+}
diff --git a/src/passwd/getspnam_r.c b/src/passwd/getspnam_r.c
new file mode 100644
index 00000000..1dd39ce0
--- /dev/null
+++ b/src/passwd/getspnam_r.c
@@ -0,0 +1,89 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include "pwf.h"
+
+/* This implementation support Openwall-style TCB passwords in place of
+ * traditional shadow, if the appropriate directories and files exist.
+ * Thus, it is careful to avoid following symlinks or blocking on fifos
+ * which a malicious user might create in place of his or her TCB shadow
+ * file. It also avoids any allocation to prevent memory-exhaustion
+ * attacks via huge TCB shadow files. */
+
+int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res)
+{
+	char path[20+NAME_MAX];
+	FILE *f = 0;
+	int rv = 0;
+	int fd;
+	size_t k, l = strlen(name);
+	char *s;
+	int skip = 0;
+
+	*res = 0;
+
+	/* Disallow potentially-malicious user names */
+	if (*name=='.' || strchr(name, '/') || !l)
+		return EINVAL;
+
+	/* Buffer size must at least be able to hold name, plus some.. */
+	if (size < l+100) return ERANGE;
+
+	/* Protect against truncation */
+	if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path)
+		return EINVAL;
+
+	fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK);
+	if (fd >= 0) {
+		f = fdopen(fd, "rb");
+		if (!f) {
+			close(fd);
+			return errno;
+		}
+	} else {
+		f = fopen("/etc/shadow", "rb");
+		if (!f) return errno;
+	}
+
+	while (fgets(buf, size, f) && (k=strlen(buf))>0) {
+		if (skip || strncmp(name, buf, l)) {
+			skip = buf[k-1] != '\n';
+			continue;
+		}
+		if (buf[k-1] != '\n') {
+			rv = ERANGE;
+			break;
+		}
+		buf[k-1] = 0;
+
+		s = buf;
+		sp->sp_namp = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_pwdp = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_lstchg = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_min = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_max = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_warn = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_inact = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_expire = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_flag = atol(s);
+		*res = sp;
+		break;
+	}
+	fclose(f);
+	return rv;
+}
diff --git a/src/passwd/lckpwdf.c b/src/passwd/lckpwdf.c
new file mode 100644
index 00000000..2feda617
--- /dev/null
+++ b/src/passwd/lckpwdf.c
@@ -0,0 +1,11 @@
+#include <shadow.h>
+
+int lckpwdf()
+{
+	return 0;
+}
+
+int ulckpwdf()
+{
+	return 0;
+}
diff --git a/src/passwd/pwf.h b/src/passwd/pwf.h
new file mode 100644
index 00000000..0a76ef80
--- /dev/null
+++ b/src/passwd/pwf.h
@@ -0,0 +1,13 @@
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include "libc.h"
+
+struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size);
+struct spwd *__getspent_a(FILE *f, struct spwd *sp, char **line, size_t *size);
+struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem);