getutxent.c revision 302408
125184Sjkh/*-
225184Sjkh * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
350193Sbrian * All rights reserved.
425184Sjkh *
525184Sjkh * Redistribution and use in source and binary forms, with or without
625184Sjkh * modification, are permitted provided that the following conditions
725184Sjkh * are met:
825184Sjkh * 1. Redistributions of source code must retain the above copyright
925184Sjkh *    notice, this list of conditions and the following disclaimer.
1025184Sjkh * 2. Redistributions in binary form must reproduce the above copyright
1125184Sjkh *    notice, this list of conditions and the following disclaimer in the
1225184Sjkh *    documentation and/or other materials provided with the distribution.
1325184Sjkh *
1425184Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1525184Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1625184Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1725184Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1825184Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1925184Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2025184Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2125184Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2225184Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2325184Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2425184Sjkh * SUCH DAMAGE.
2525184Sjkh */
2625184Sjkh
2725184Sjkh#include <sys/cdefs.h>
2840006Sphk__FBSDID("$FreeBSD: stable/11/lib/libc/gen/getutxent.c 256537 2013-10-15 13:32:01Z glebius $");
2940006Sphk
3040006Sphk#include "namespace.h"
3140006Sphk#include <sys/endian.h>
3240006Sphk#include <sys/param.h>
3340006Sphk#include <sys/stat.h>
3442621Shm#include <errno.h>
3542621Shm#include <stdio.h>
3642621Shm#include <string.h>
3742621Shm#include <utmpx.h>
3842621Shm#include "utxdb.h"
3942627Sjoerg#include "un-namespace.h"
4042627Sjoerg
4142627Sjoerg#ifdef __NO_TLS
4242627Sjoergstatic FILE *uf = NULL;
4342627Sjoergstatic int udb;
4442627Sjoerg#else
4542627Sjoergstatic _Thread_local FILE *uf = NULL;
4642627Sjoergstatic _Thread_local int udb;
4742627Sjoerg#endif
4842627Sjoerg
4942627Sjoergint
5042627Sjoergsetutxdb(int db, const char *file)
5142627Sjoerg{
5242627Sjoerg	struct stat sb;
5325184Sjkh
5448687Speter	switch (db) {
5548687Speter	case UTXDB_ACTIVE:
5648687Speter		if (file == NULL)
5748687Speter			file = _PATH_UTX_ACTIVE;
5848662Speter		break;
5925184Sjkh	case UTXDB_LASTLOGIN:
6033682Sbrian		if (file == NULL)
6148662Speter			file = _PATH_UTX_LASTLOGIN;
6225184Sjkh		break;
6325184Sjkh	case UTXDB_LOG:
6425184Sjkh		if (file == NULL)
6525184Sjkh			file = _PATH_UTX_LOG;
6648842Sjkh		break;
6748842Sjkh	default:
6848842Sjkh		errno = EINVAL;
6948842Sjkh		return (-1);
7048842Sjkh	}
7148842Sjkh
7248662Speter	if (uf != NULL)
7325184Sjkh		fclose(uf);
7425184Sjkh	uf = fopen(file, "re");
7525184Sjkh	if (uf == NULL)
7625184Sjkh		return (-1);
7725184Sjkh
7825184Sjkh	if (db != UTXDB_LOG) {
7925184Sjkh		/* Safety check: never use broken files. */
8025184Sjkh		if (_fstat(fileno(uf), &sb) != -1 &&
8148662Speter		    sb.st_size % sizeof(struct futx) != 0) {
8225184Sjkh			fclose(uf);
8325184Sjkh			uf = NULL;
8425184Sjkh			errno = EFTYPE;
8525184Sjkh			return (-1);
8625184Sjkh		}
8725184Sjkh		/* Prevent reading of partial records. */
8825184Sjkh		(void)setvbuf(uf, NULL, _IOFBF,
8925184Sjkh		    rounddown(BUFSIZ, sizeof(struct futx)));
9025184Sjkh	}
9148662Speter
9225184Sjkh	udb = db;
9348662Speter	return (0);
9448662Speter}
9548662Speter
9648662Spetervoid
9725184Sjkhsetutxent(void)
9829300Sdanny{
9949122Sbrian
10049122Sbrian	setutxdb(UTXDB_ACTIVE, NULL);
10149122Sbrian}
10249122Sbrian
10349122Sbrianvoid
10449122Sbrianendutxent(void)
10549122Sbrian{
10649122Sbrian
10749122Sbrian	if (uf != NULL) {
10849122Sbrian		fclose(uf);
10950193Sbrian		uf = NULL;
11050193Sbrian	}
11149122Sbrian}
11249122Sbrian
11350063Sbrianstatic int
11449122Sbriangetfutxent(struct futx *fu)
11549122Sbrian{
11629300Sdanny
11729300Sdanny	if (uf == NULL)
11829300Sdanny		setutxent();
11932382Salex	if (uf == NULL)
12032382Salex		return (-1);
12132382Salex
12229300Sdanny	if (udb == UTXDB_LOG) {
12329300Sdanny		uint16_t len;
12429300Sdanny
12529300Sdannyretry:
12641077Speter		if (fread(&len, sizeof(len), 1, uf) != 1)
12729300Sdanny			return (-1);
12829300Sdanny		len = be16toh(len);
12929300Sdanny		if (len == 0) {
13029300Sdanny			/*
13129300Sdanny			 * XXX: Though zero-size records are valid in theory,
13229300Sdanny			 * they can never occur in practice. Zero-size records
13329300Sdanny			 * indicate file corruption. Seek one byte forward, to
13429300Sdanny			 * see if we can find a record there.
13529300Sdanny			 */
13645542Sdes			ungetc('\0', uf);
13745542Sdes			goto retry;
13845542Sdes		}
13945542Sdes		if (len > sizeof *fu) {
14045542Sdes			/* Forward compatibility. */
14145622Sbrian			if (fread(fu, sizeof(*fu), 1, uf) != 1)
14244992Sbrian				return (-1);
14344992Sbrian			fseek(uf, len - sizeof(*fu), SEEK_CUR);
14444992Sbrian		} else {
14544992Sbrian			/* Partial record. */
14644992Sbrian			memset(fu, 0, sizeof(*fu));
14744992Sbrian			if (fread(fu, len, 1, uf) != 1)
14844992Sbrian				return (-1);
14944992Sbrian		}
15044992Sbrian	} else {
15144992Sbrian		if (fread(fu, sizeof(*fu), 1, uf) != 1)
15244992Sbrian			return (-1);
15344992Sbrian	}
15429300Sdanny	return (0);
15533337Salex}
15633337Salex
15733149Salexstruct utmpx *
15833149Salexgetutxent(void)
15933149Salex{
16033149Salex	struct futx fu;
16129300Sdanny
16225184Sjkh	if (getfutxent(&fu) != 0)
16325184Sjkh		return (NULL);
16440006Sphk	return (futx_to_utx(&fu));
16540006Sphk}
16640006Sphk
16740006Sphkstruct utmpx *
16840006Sphkgetutxid(const struct utmpx *id)
16929300Sdanny{
17029300Sdanny	struct futx fu;
17125184Sjkh
17225184Sjkh	for (;;) {
17325184Sjkh		if (getfutxent(&fu) != 0)
17425184Sjkh			return (NULL);
17525184Sjkh
17625184Sjkh		switch (fu.fu_type) {
17725184Sjkh		case USER_PROCESS:
17825184Sjkh		case INIT_PROCESS:
17925184Sjkh		case LOGIN_PROCESS:
18025184Sjkh		case DEAD_PROCESS:
18125184Sjkh			switch (id->ut_type) {
18225184Sjkh			case USER_PROCESS:
18325184Sjkh			case INIT_PROCESS:
18425184Sjkh			case LOGIN_PROCESS:
18527218Spst			case DEAD_PROCESS:
18627218Spst				if (memcmp(fu.fu_id, id->ut_id,
18747755Sbde				    MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
18827218Spst				    0)
18927218Spst					goto found;
19045096Simp			}
19145096Simp			break;
19247755Sbde		default:
19347755Sbde			if (fu.fu_type == id->ut_type)
19445096Simp				goto found;
19545096Simp			break;
19639267Sjkoshy		}
19739267Sjkoshy	}
19847755Sbde
19939267Sjkoshyfound:
20049603Sdes	return (futx_to_utx(&fu));
20149603Sdes}
20249603Sdes
20349603Sdesstruct utmpx *
20449603Sdesgetutxline(const struct utmpx *line)
20549603Sdes{
20649603Sdes	struct futx fu;
20749603Sdes
20849603Sdes	for (;;) {
20949603Sdes		if (getfutxent(&fu) != 0)
21039267Sjkoshy			return (NULL);
21125184Sjkh
21225365Sjkh		switch (fu.fu_type) {
21347755Sbde		case USER_PROCESS:
21425184Sjkh		case LOGIN_PROCESS:
21525184Sjkh			if (strncmp(fu.fu_line, line->ut_line,
21633439Sguido			    MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
21733439Sguido			    0)
21847755Sbde				goto found;
21933439Sguido			break;
22033439Sguido		}
22133439Sguido	}
22233439Sguido
22347755Sbdefound:
22433439Sguido	return (futx_to_utx(&fu));
22533439Sguido}
22647752Sphk
22747752Sphkstruct utmpx *
22847755Sbdegetutxuser(const char *user)
22947752Sphk{
23047752Sphk	struct futx fu;
23125184Sjkh
23225365Sjkh	for (;;) {
23347755Sbde		if (getfutxent(&fu) != 0)
23425184Sjkh			return (NULL);
23525184Sjkh
23636174Sjkh		switch (fu.fu_type) {
23747755Sbde		case USER_PROCESS:
23847755Sbde			if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
23936174Sjkh				goto found;
24036174Sjkh			break;
24136174Sjkh		}
24236174Sjkh	}
24336174Sjkh
24436174Sjkhfound:
24536174Sjkh	return (futx_to_utx(&fu));
24636174Sjkh}
24725184Sjkh