Skip to content

lib/shadow.c is 0xDEADBEEF #1228

Open
@alejandro-colomar

Description

@alejandro-colomar

#ifndef HAVE_GETSPNAM

musl libc has getspnam(3), so this very much looks like a dead file.

alx@debian:~/src/musl/libc/master$ grepc -tfd setspent .
./src/passwd/getspent.c:void setspent()
{
}
alx@debian:~/src/musl/libc/master$ grepc -tfd endspent .
./src/passwd/getspent.c:void endspent()
{
}
alx@debian:~/src/musl/libc/master$ grepc -tfd fgetspent .
./src/passwd/fgetspent.c:struct spwd *fgetspent(FILE *f)
{
	static char *line;
	static struct spwd sp;
	size_t size = 0;
	struct spwd *res = 0;
	int cs;
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
	if (getline(&line, &size, f) >= 0 && __parsespent(line, &sp) >= 0) res = &sp;
	pthread_setcancelstate(cs, 0);
	return res;
}
alx@debian:~/src/musl/libc/master$ grepc -tfd getspent .
./src/passwd/getspent.c:struct spwd *getspent()
{
	return 0;
}
alx@debian:~/src/musl/libc/master$ grepc -tfd getspnam .
./src/passwd/getspnam.c:struct spwd *getspnam(const char *name)
{
	static struct spwd sp;
	static char *line;
	struct spwd *res;
	int e;
	int orig_errno = errno;

	if (!line) line = malloc(LINE_LIM);
	if (!line) return 0;
	e = getspnam_r(name, &sp, line, LINE_LIM, &res);
	errno = e ? e : orig_errno;
	return res;
}
alx@debian:~/src/musl/libc/master$ grepc -tfd getspnam_r .
./src/passwd/getspnam_r.c: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);
	int skip = 0;
	int cs;
	int orig_errno = errno;

	*res = 0;

	/* Disallow potentially-malicious user names */
	if (*name=='.' || strchr(name, '/') || !l)
		return errno = EINVAL;

	/* Buffer size must at least be able to hold name, plus some.. */
	if (size < l+100)
		return errno = ERANGE;

	/* Protect against truncation */
	if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path)
		return errno = EINVAL;

	fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC);
	if (fd >= 0) {
		struct stat st = { 0 };
		errno = EINVAL;
		if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) {
			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
			close(fd);
			pthread_setcancelstate(cs, 0);
			return errno;
		}
	} else {
		if (errno != ENOENT && errno != ENOTDIR)
			return errno;
		f = fopen("/etc/shadow", "rbe");
		if (!f) {
			if (errno != ENOENT && errno != ENOTDIR)
				return errno;
			return 0;
		}
	}

	pthread_cleanup_push(cleanup, f);
	while (fgets(buf, size, f) && (k=strlen(buf))>0) {
		if (skip || strncmp(name, buf, l) || buf[l]!=':') {
			skip = buf[k-1] != '\n';
			continue;
		}
		if (buf[k-1] != '\n') {
			rv = ERANGE;
			break;
		}

		if (__parsespent(buf, sp) < 0) continue;
		*res = sp;
		break;
	}
	pthread_cleanup_pop(1);
	errno = rv ? rv : orig_errno;
	return rv;
}

I'm grinding the axe. :)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions