1202188Sed/*-
2202188Sed * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3202188Sed * All rights reserved.
4202188Sed *
5202188Sed * Redistribution and use in source and binary forms, with or without
6202188Sed * modification, are permitted provided that the following conditions
7202188Sed * are met:
8202188Sed * 1. Redistributions of source code must retain the above copyright
9202188Sed *    notice, this list of conditions and the following disclaimer.
10202188Sed * 2. Redistributions in binary form must reproduce the above copyright
11202188Sed *    notice, this list of conditions and the following disclaimer in the
12202188Sed *    documentation and/or other materials provided with the distribution.
13202188Sed *
14202188Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15202188Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16202188Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17202188Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18202188Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19202188Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20202188Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21202188Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22202188Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23202188Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24202188Sed * SUCH DAMAGE.
25202188Sed */
26202188Sed
27202188Sed#include <sys/cdefs.h>
28202188Sed__FBSDID("$FreeBSD$");
29202188Sed
30202188Sed#include "namespace.h"
31202188Sed#include <sys/endian.h>
32202188Sed#include <sys/param.h>
33202188Sed#include <sys/stat.h>
34202188Sed#include <errno.h>
35202188Sed#include <stdio.h>
36202188Sed#include <string.h>
37202188Sed#include <utmpx.h>
38202188Sed#include "utxdb.h"
39202188Sed#include "un-namespace.h"
40202188Sed
41202188Sedstatic FILE *uf = NULL;
42202188Sedstatic int udb;
43202188Sed
44202188Sedint
45202188Sedsetutxdb(int db, const char *file)
46202188Sed{
47202188Sed	struct stat sb;
48202188Sed
49202188Sed	switch (db) {
50202188Sed	case UTXDB_ACTIVE:
51202188Sed		if (file == NULL)
52202188Sed			file = _PATH_UTX_ACTIVE;
53202188Sed		break;
54202188Sed	case UTXDB_LASTLOGIN:
55202188Sed		if (file == NULL)
56202188Sed			file = _PATH_UTX_LASTLOGIN;
57202188Sed		break;
58202188Sed	case UTXDB_LOG:
59202188Sed		if (file == NULL)
60202188Sed			file = _PATH_UTX_LOG;
61202188Sed		break;
62202188Sed	default:
63202188Sed		errno = EINVAL;
64202188Sed		return (-1);
65202188Sed	}
66202188Sed
67202188Sed	if (uf != NULL)
68202188Sed		fclose(uf);
69202188Sed	uf = fopen(file, "r");
70202188Sed	if (uf == NULL)
71202188Sed		return (-1);
72202188Sed
73232408Sed	if (db != UTXDB_LOG) {
74232408Sed		/* Safety check: never use broken files. */
75232408Sed		if (_fstat(fileno(uf), &sb) != -1 &&
76232408Sed		    sb.st_size % sizeof(struct futx) != 0) {
77232408Sed			fclose(uf);
78232408Sed			uf = NULL;
79232408Sed			errno = EFTYPE;
80232408Sed			return (-1);
81232408Sed		}
82232408Sed		/* Prevent reading of partial records. */
83232408Sed		(void)setvbuf(uf, NULL, _IOFBF,
84232408Sed		    rounddown(BUFSIZ, sizeof(struct futx)));
85202188Sed	}
86202188Sed
87202188Sed	udb = db;
88202188Sed	return (0);
89202188Sed}
90202188Sed
91202188Sedvoid
92202188Sedsetutxent(void)
93202188Sed{
94202188Sed
95202188Sed	setutxdb(UTXDB_ACTIVE, NULL);
96202188Sed}
97202188Sed
98202188Sedvoid
99202188Sedendutxent(void)
100202188Sed{
101202188Sed
102202188Sed	if (uf != NULL) {
103202188Sed		fclose(uf);
104202188Sed		uf = NULL;
105202188Sed	}
106202188Sed}
107202188Sed
108202530Sedstatic int
109202530Sedgetfutxent(struct futx *fu)
110202188Sed{
111202188Sed
112202188Sed	if (uf == NULL)
113202188Sed		setutxent();
114202188Sed	if (uf == NULL)
115202530Sed		return (-1);
116202188Sed
117202188Sed	if (udb == UTXDB_LOG) {
118202188Sed		uint16_t len;
119202188Sed
120218846Sed		if (fread(&len, sizeof(len), 1, uf) != 1)
121202530Sed			return (-1);
122202188Sed		len = be16toh(len);
123202530Sed		if (len > sizeof *fu) {
124202188Sed			/* Forward compatibility. */
125218846Sed			if (fread(fu, sizeof(*fu), 1, uf) != 1)
126202530Sed				return (-1);
127218846Sed			fseek(uf, len - sizeof(*fu), SEEK_CUR);
128202188Sed		} else {
129202188Sed			/* Partial record. */
130218846Sed			memset(fu, 0, sizeof(*fu));
131202530Sed			if (fread(fu, len, 1, uf) != 1)
132202530Sed				return (-1);
133202188Sed		}
134202188Sed	} else {
135218846Sed		if (fread(fu, sizeof(*fu), 1, uf) != 1)
136202530Sed			return (-1);
137202188Sed	}
138202530Sed	return (0);
139202188Sed}
140202188Sed
141202188Sedstruct utmpx *
142202188Sedgetutxent(void)
143202188Sed{
144202530Sed	struct futx fu;
145202188Sed
146202530Sed	if (getfutxent(&fu) != 0)
147202188Sed		return (NULL);
148202530Sed	return (futx_to_utx(&fu));
149202188Sed}
150202188Sed
151202188Sedstruct utmpx *
152202188Sedgetutxid(const struct utmpx *id)
153202188Sed{
154202530Sed	struct futx fu;
155202188Sed
156202188Sed	for (;;) {
157202530Sed		if (getfutxent(&fu) != 0)
158202188Sed			return (NULL);
159202188Sed
160202530Sed		switch (fu.fu_type) {
161202188Sed		case USER_PROCESS:
162202188Sed		case INIT_PROCESS:
163202188Sed		case LOGIN_PROCESS:
164202188Sed		case DEAD_PROCESS:
165202188Sed			switch (id->ut_type) {
166202188Sed			case USER_PROCESS:
167202188Sed			case INIT_PROCESS:
168202188Sed			case LOGIN_PROCESS:
169202188Sed			case DEAD_PROCESS:
170202530Sed				if (memcmp(fu.fu_id, id->ut_id,
171218846Sed				    MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
172218846Sed				    0)
173202188Sed					goto found;
174202188Sed			}
175202527Sed			break;
176202530Sed		default:
177202530Sed			if (fu.fu_type == id->ut_type)
178202530Sed				goto found;
179202530Sed			break;
180202188Sed		}
181202188Sed	}
182202188Sed
183202188Sedfound:
184202530Sed	return (futx_to_utx(&fu));
185202188Sed}
186202188Sed
187202188Sedstruct utmpx *
188202188Sedgetutxline(const struct utmpx *line)
189202188Sed{
190202530Sed	struct futx fu;
191202188Sed
192202188Sed	for (;;) {
193202530Sed		if (getfutxent(&fu) != 0)
194202188Sed			return (NULL);
195202188Sed
196202530Sed		switch (fu.fu_type) {
197202188Sed		case USER_PROCESS:
198202188Sed		case LOGIN_PROCESS:
199202530Sed			if (strncmp(fu.fu_line, line->ut_line,
200218846Sed			    MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
201218846Sed			    0)
202202188Sed				goto found;
203202530Sed			break;
204202188Sed		}
205202188Sed	}
206202188Sed
207202188Sedfound:
208202530Sed	return (futx_to_utx(&fu));
209202188Sed}
210202188Sed
211202188Sedstruct utmpx *
212202188Sedgetutxuser(const char *user)
213202188Sed{
214202530Sed	struct futx fu;
215202188Sed
216202188Sed	for (;;) {
217202530Sed		if (getfutxent(&fu) != 0)
218202188Sed			return (NULL);
219202188Sed
220202530Sed		switch (fu.fu_type) {
221202188Sed		case USER_PROCESS:
222218846Sed			if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
223202188Sed				goto found;
224202530Sed			break;
225202188Sed		}
226202188Sed	}
227202188Sed
228202188Sedfound:
229202530Sed	return (futx_to_utx(&fu));
230202188Sed}
231