xref: /dflybsd-src/lib/libc/gen/utmpx.c (revision 625fc06ff2945c974c3128d8ece6488e8f80d0aa)
159a92d18SAlex Hornung /*-
259a92d18SAlex Hornung  * Copyright (c) 2002 The NetBSD Foundation, Inc.
359a92d18SAlex Hornung  * All rights reserved.
459a92d18SAlex Hornung  *
559a92d18SAlex Hornung  * This code is derived from software contributed to The NetBSD Foundation
659a92d18SAlex Hornung  * by Christos Zoulas.
759a92d18SAlex Hornung  *
859a92d18SAlex Hornung  * Redistribution and use in source and binary forms, with or without
959a92d18SAlex Hornung  * modification, are permitted provided that the following conditions
1059a92d18SAlex Hornung  * are met:
1159a92d18SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
1259a92d18SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
1359a92d18SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
1459a92d18SAlex Hornung  *    notice, this list of conditions and the following disclaimer in the
1559a92d18SAlex Hornung  *    documentation and/or other materials provided with the distribution.
1659a92d18SAlex Hornung  *
1759a92d18SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1859a92d18SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1959a92d18SAlex Hornung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2059a92d18SAlex Hornung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2159a92d18SAlex Hornung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2259a92d18SAlex Hornung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2359a92d18SAlex Hornung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2459a92d18SAlex Hornung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2559a92d18SAlex Hornung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2659a92d18SAlex Hornung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2759a92d18SAlex Hornung  * POSSIBILITY OF SUCH DAMAGE.
2859a92d18SAlex Hornung  */
2959a92d18SAlex Hornung 
3059a92d18SAlex Hornung #include "namespace.h"
3159a92d18SAlex Hornung #include <sys/types.h>
3259a92d18SAlex Hornung #include <sys/param.h>
3359a92d18SAlex Hornung #include <sys/socket.h>
3459a92d18SAlex Hornung #include <sys/stat.h>
3559a92d18SAlex Hornung #include <sys/time.h>
3659a92d18SAlex Hornung #include <sys/wait.h>
3759a92d18SAlex Hornung 
3859a92d18SAlex Hornung #include <assert.h>
3959a92d18SAlex Hornung #include <errno.h>
4059a92d18SAlex Hornung #include <fcntl.h>
4159a92d18SAlex Hornung #include <stdio.h>
4259a92d18SAlex Hornung #include <stdlib.h>
4359a92d18SAlex Hornung #include <string.h>
4459a92d18SAlex Hornung #include <unistd.h>
4559a92d18SAlex Hornung #include <pwd.h>
4659a92d18SAlex Hornung #include <utmpx.h>
4759a92d18SAlex Hornung #include <vis.h>
48*625fc06fSSascha Wildner #include "un-namespace.h"
49*625fc06fSSascha Wildner 
50*625fc06fSSascha Wildner #include <db.h>
5159a92d18SAlex Hornung 
5265f10536SSascha Wildner static FILE *fp;
5359a92d18SAlex Hornung static int readonly = 0;
5459a92d18SAlex Hornung static struct utmpx ut;
5559a92d18SAlex Hornung static char utfile[MAXPATHLEN] = _PATH_UTMPX;
5659a92d18SAlex Hornung 
5759a92d18SAlex Hornung static struct utmpx *utmp_update(const struct utmpx *);
5859a92d18SAlex Hornung 
5959a92d18SAlex Hornung static const char vers[] = "utmpx-2.00";
6059a92d18SAlex Hornung static utx_db_t dbtype = UTX_DB_UTMPX;
6159a92d18SAlex Hornung DB *lastlogx_db = NULL;
6259a92d18SAlex Hornung 
639ae6396eSSascha Wildner void past_getutmp(void *, void *);
649ae6396eSSascha Wildner void past_getutmpx(void *, void *);
659ae6396eSSascha Wildner 
6659a92d18SAlex Hornung static int
_open_db(const char * fname)677bb7a6edSSascha Wildner _open_db(const char *fname)
6859a92d18SAlex Hornung {
6959a92d18SAlex Hornung 	struct stat st;
7059a92d18SAlex Hornung 
7165f10536SSascha Wildner 	if ((fp = fopen(fname, "re+")) == NULL)
7265f10536SSascha Wildner 		if ((fp = fopen(fname, "we+")) == NULL) {
7365f10536SSascha Wildner 			if ((fp = fopen(fname, "re")) == NULL)
7459a92d18SAlex Hornung 				goto fail;
7559a92d18SAlex Hornung 			else
7659a92d18SAlex Hornung 				readonly = 1;
7759a92d18SAlex Hornung 		}
7859a92d18SAlex Hornung 
7959a92d18SAlex Hornung 	/* get file size in order to check if new file */
80*625fc06fSSascha Wildner 	if (_fstat(fileno(fp), &st) == -1)
8159a92d18SAlex Hornung 		goto failclose;
8259a92d18SAlex Hornung 
8359a92d18SAlex Hornung 	if (st.st_size == 0) {
8459a92d18SAlex Hornung 		/* new file, add signature record */
8559a92d18SAlex Hornung 		(void)memset(&ut, 0, sizeof(ut));
8659a92d18SAlex Hornung 		ut.ut_type = SIGNATURE;
8759a92d18SAlex Hornung 		(void)memcpy(ut.ut_user, vers, sizeof(vers));
8859a92d18SAlex Hornung 		if (fwrite(&ut, sizeof(ut), 1, fp) != 1)
8959a92d18SAlex Hornung 			goto failclose;
9059a92d18SAlex Hornung 	} else {
9159a92d18SAlex Hornung 		/* old file, read signature record */
9259a92d18SAlex Hornung 		if (fread(&ut, sizeof(ut), 1, fp) != 1)
9359a92d18SAlex Hornung 			goto failclose;
9459a92d18SAlex Hornung 		if (memcmp(ut.ut_user, vers, 5) != 0 ||
9559a92d18SAlex Hornung 		    ut.ut_type != SIGNATURE) {
9659a92d18SAlex Hornung 			errno = EINVAL;
9759a92d18SAlex Hornung 			goto failclose;
9859a92d18SAlex Hornung 		}
9959a92d18SAlex Hornung 	}
10059a92d18SAlex Hornung 
10159a92d18SAlex Hornung 	return 0;
10259a92d18SAlex Hornung failclose:
10359a92d18SAlex Hornung 	(void)fclose(fp);
10459a92d18SAlex Hornung fail:
10559a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
10659a92d18SAlex Hornung 	return -1;
10759a92d18SAlex Hornung }
10859a92d18SAlex Hornung 
10959a92d18SAlex Hornung int
setutxdb(utx_db_t db_type,const char * fname)1107bb7a6edSSascha Wildner setutxdb(utx_db_t db_type, const char *fname)
11159a92d18SAlex Hornung {
11259a92d18SAlex Hornung 	switch (db_type) {
11359a92d18SAlex Hornung 	case UTX_DB_UTMPX:
11459a92d18SAlex Hornung 		if (fname == NULL)
11559a92d18SAlex Hornung 			fname = _PATH_UTMPX;
11659a92d18SAlex Hornung 		break;
11759a92d18SAlex Hornung 
11859a92d18SAlex Hornung 	case UTX_DB_WTMPX:
11959a92d18SAlex Hornung 		if (fname == NULL)
12059a92d18SAlex Hornung 			fname = _PATH_WTMPX;
12159a92d18SAlex Hornung 		break;
12259a92d18SAlex Hornung 
12359a92d18SAlex Hornung 	default:
12459a92d18SAlex Hornung 		errno = EINVAL;
12559a92d18SAlex Hornung 		return -1;
12659a92d18SAlex Hornung 	}
12759a92d18SAlex Hornung 
12859a92d18SAlex Hornung 	/* A previous db file is still open */
12959a92d18SAlex Hornung 	if (fp != NULL) {
13059a92d18SAlex Hornung 		fclose(fp);
13159a92d18SAlex Hornung 		fp = NULL;
13259a92d18SAlex Hornung 	}
13359a92d18SAlex Hornung 	if ((_open_db(fname)) == -1)
13459a92d18SAlex Hornung 		return -1;
13559a92d18SAlex Hornung 
13659a92d18SAlex Hornung 	dbtype = db_type;
13759a92d18SAlex Hornung 	return 0;
13859a92d18SAlex Hornung }
13959a92d18SAlex Hornung 
14059a92d18SAlex Hornung void
setutxent(void)1415d7d35b1SSascha Wildner setutxent(void)
14259a92d18SAlex Hornung {
14359a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
14459a92d18SAlex Hornung 	if (fp == NULL)
14559a92d18SAlex Hornung 		return;
14659a92d18SAlex Hornung 	(void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
14759a92d18SAlex Hornung }
14859a92d18SAlex Hornung 
14959a92d18SAlex Hornung void
endutxent(void)1505d7d35b1SSascha Wildner endutxent(void)
15159a92d18SAlex Hornung {
15259a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
15359a92d18SAlex Hornung 
15459a92d18SAlex Hornung 	if (fp != NULL) {
15559a92d18SAlex Hornung 		(void)fclose(fp);
15659a92d18SAlex Hornung 		fp = NULL;
15759a92d18SAlex Hornung 		readonly = 0;
15859a92d18SAlex Hornung 	}
15959a92d18SAlex Hornung }
16059a92d18SAlex Hornung 
16159a92d18SAlex Hornung struct utmpx *
getutxent(void)1625d7d35b1SSascha Wildner getutxent(void)
16359a92d18SAlex Hornung {
16459a92d18SAlex Hornung 	if (fp == NULL) {
16559a92d18SAlex Hornung 		if ((_open_db(utfile)) == -1)
16659a92d18SAlex Hornung 			goto fail;
16759a92d18SAlex Hornung 	}
16859a92d18SAlex Hornung 
16959a92d18SAlex Hornung 	if (fread(&ut, sizeof(ut), 1, fp) != 1)
17059a92d18SAlex Hornung 		goto fail;
17159a92d18SAlex Hornung 
17259a92d18SAlex Hornung 	return &ut;
17359a92d18SAlex Hornung fail:
17459a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
17559a92d18SAlex Hornung 	return NULL;
17659a92d18SAlex Hornung }
17759a92d18SAlex Hornung 
17859a92d18SAlex Hornung struct utmpx *
getutxid(const struct utmpx * utx)17959a92d18SAlex Hornung getutxid(const struct utmpx *utx)
18059a92d18SAlex Hornung {
18159a92d18SAlex Hornung 
18259a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
18359a92d18SAlex Hornung 
18459a92d18SAlex Hornung 	if (utx->ut_type == EMPTY)
18559a92d18SAlex Hornung 		return NULL;
18659a92d18SAlex Hornung 
18759a92d18SAlex Hornung 	do {
18859a92d18SAlex Hornung 		if (ut.ut_type == EMPTY)
18959a92d18SAlex Hornung 			continue;
19059a92d18SAlex Hornung 		switch (utx->ut_type) {
19159a92d18SAlex Hornung 		case EMPTY:
19259a92d18SAlex Hornung 			return NULL;
19359a92d18SAlex Hornung 		case RUN_LVL:
19459a92d18SAlex Hornung 		case BOOT_TIME:
19559a92d18SAlex Hornung 		case OLD_TIME:
19659a92d18SAlex Hornung 		case NEW_TIME:
19759a92d18SAlex Hornung 			if (ut.ut_type == utx->ut_type)
19859a92d18SAlex Hornung 				return &ut;
19959a92d18SAlex Hornung 			break;
20059a92d18SAlex Hornung 		case INIT_PROCESS:
20159a92d18SAlex Hornung 		case LOGIN_PROCESS:
20259a92d18SAlex Hornung 		case USER_PROCESS:
20359a92d18SAlex Hornung 		case DEAD_PROCESS:
20459a92d18SAlex Hornung 			switch (ut.ut_type) {
20559a92d18SAlex Hornung 			case INIT_PROCESS:
20659a92d18SAlex Hornung 			case LOGIN_PROCESS:
20759a92d18SAlex Hornung 			case USER_PROCESS:
20859a92d18SAlex Hornung 			case DEAD_PROCESS:
20959a92d18SAlex Hornung 				if (memcmp(ut.ut_id, utx->ut_id,
21059a92d18SAlex Hornung 				    sizeof(ut.ut_id)) == 0)
21159a92d18SAlex Hornung 					return &ut;
21259a92d18SAlex Hornung 				break;
21359a92d18SAlex Hornung 			default:
21459a92d18SAlex Hornung 				break;
21559a92d18SAlex Hornung 			}
21659a92d18SAlex Hornung 			break;
21759a92d18SAlex Hornung 		default:
21859a92d18SAlex Hornung 			return NULL;
21959a92d18SAlex Hornung 		}
22059a92d18SAlex Hornung 	} while (getutxent() != NULL);
22159a92d18SAlex Hornung 	return NULL;
22259a92d18SAlex Hornung }
22359a92d18SAlex Hornung 
22459a92d18SAlex Hornung struct utmpx *
getutxline(const struct utmpx * utx)22559a92d18SAlex Hornung getutxline(const struct utmpx *utx)
22659a92d18SAlex Hornung {
22759a92d18SAlex Hornung 
22859a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
22959a92d18SAlex Hornung 
23059a92d18SAlex Hornung 	do {
23159a92d18SAlex Hornung 		switch (ut.ut_type) {
23259a92d18SAlex Hornung 		case EMPTY:
23359a92d18SAlex Hornung 			break;
23459a92d18SAlex Hornung 		case LOGIN_PROCESS:
23559a92d18SAlex Hornung 		case USER_PROCESS:
23659a92d18SAlex Hornung 			if (strncmp(ut.ut_line, utx->ut_line,
23759a92d18SAlex Hornung 			    sizeof(ut.ut_line)) == 0)
23859a92d18SAlex Hornung 				return &ut;
23959a92d18SAlex Hornung 			break;
24059a92d18SAlex Hornung 		default:
24159a92d18SAlex Hornung 			break;
24259a92d18SAlex Hornung 		}
24359a92d18SAlex Hornung 	} while (getutxent() != NULL);
24459a92d18SAlex Hornung 	return NULL;
24559a92d18SAlex Hornung }
24659a92d18SAlex Hornung 
24759a92d18SAlex Hornung struct utmpx *
getutxuser(const char * user)248974aa081SSascha Wildner getutxuser(const char *user)
249974aa081SSascha Wildner {
250974aa081SSascha Wildner 	_DIAGASSERT(utx != NULL);
251974aa081SSascha Wildner 
252974aa081SSascha Wildner 	do {
253974aa081SSascha Wildner 		switch (ut.ut_type) {
254974aa081SSascha Wildner 		case EMPTY:
255974aa081SSascha Wildner 			break;
256974aa081SSascha Wildner 		case USER_PROCESS:
257974aa081SSascha Wildner 			if (strncmp(ut.ut_user, user, sizeof(ut.ut_user)) == 0)
258974aa081SSascha Wildner 				return &ut;
259974aa081SSascha Wildner 			break;
260974aa081SSascha Wildner 		default:
261974aa081SSascha Wildner 			break;
262974aa081SSascha Wildner 		}
263974aa081SSascha Wildner 	} while (getutxent() != NULL);
264974aa081SSascha Wildner 	return NULL;
265974aa081SSascha Wildner }
266974aa081SSascha Wildner 
267974aa081SSascha Wildner struct utmpx *
pututxline(const struct utmpx * utx)26859a92d18SAlex Hornung pututxline(const struct utmpx *utx)
26959a92d18SAlex Hornung {
27059a92d18SAlex Hornung 	struct passwd *pw;
27159a92d18SAlex Hornung 	struct lastlogx ll;
27259a92d18SAlex Hornung 	struct utmpx temp, *u = NULL;
27359a92d18SAlex Hornung 	int gotlock = 0;
27459a92d18SAlex Hornung 
27559a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
27659a92d18SAlex Hornung 
27759a92d18SAlex Hornung 	if (utx == NULL)
27859a92d18SAlex Hornung 		return NULL;
27959a92d18SAlex Hornung 
28059a92d18SAlex Hornung 	if (utx->ut_type == USER_PROCESS) {
28159a92d18SAlex Hornung 		ll.ll_tv = utx->ut_tv;
28259a92d18SAlex Hornung 		strcpy(ll.ll_host, utx->ut_host);
28359a92d18SAlex Hornung 		strcpy(ll.ll_line, utx->ut_line);
28459a92d18SAlex Hornung 		pw = getpwnam(utx->ut_name);
28559a92d18SAlex Hornung 		if (pw != NULL)
28659a92d18SAlex Hornung 			updlastlogx(_PATH_LASTLOGX, pw->pw_uid, &ll);
28759a92d18SAlex Hornung 	}
28859a92d18SAlex Hornung 
28959a92d18SAlex Hornung 	if (strcmp(_PATH_UTMPX, utfile) == 0)
29059a92d18SAlex Hornung 		if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0))
29159a92d18SAlex Hornung 			return utmp_update(utx);
29259a92d18SAlex Hornung 
29359a92d18SAlex Hornung 
29459a92d18SAlex Hornung 	(void)memcpy(&temp, utx, sizeof(temp));
29559a92d18SAlex Hornung 
29659a92d18SAlex Hornung 	if (fp == NULL) {
29759a92d18SAlex Hornung 		(void)getutxent();
29859a92d18SAlex Hornung 		if (fp == NULL || readonly)
29959a92d18SAlex Hornung 			return NULL;
30059a92d18SAlex Hornung 	}
30159a92d18SAlex Hornung 
30259a92d18SAlex Hornung 	if (getutxid(&temp) == NULL) {
30359a92d18SAlex Hornung 		setutxent();
30459a92d18SAlex Hornung 		if (getutxid(&temp) == NULL) {
30559a92d18SAlex Hornung 			if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
30659a92d18SAlex Hornung 				return NULL;
30759a92d18SAlex Hornung 			gotlock++;
30859a92d18SAlex Hornung 			if (fseeko(fp, (off_t)0, SEEK_END) == -1)
30959a92d18SAlex Hornung 				goto fail;
31059a92d18SAlex Hornung 		}
31159a92d18SAlex Hornung 	}
31259a92d18SAlex Hornung 
31359a92d18SAlex Hornung 	if (!gotlock) {
31459a92d18SAlex Hornung 		/* we are not appending */
31559a92d18SAlex Hornung 		if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
31659a92d18SAlex Hornung 			return NULL;
31759a92d18SAlex Hornung 	}
31859a92d18SAlex Hornung 
31959a92d18SAlex Hornung 	if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
32059a92d18SAlex Hornung 		goto fail;
32159a92d18SAlex Hornung 
32259a92d18SAlex Hornung 	if (fflush(fp) == -1)
32359a92d18SAlex Hornung 		goto fail;
32459a92d18SAlex Hornung 
32559a92d18SAlex Hornung 	u = memcpy(&ut, &temp, sizeof(ut));
32659a92d18SAlex Hornung fail:
32759a92d18SAlex Hornung 	if (gotlock) {
32859a92d18SAlex Hornung 		if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
32959a92d18SAlex Hornung 			return NULL;
33059a92d18SAlex Hornung 	}
33159a92d18SAlex Hornung 	return u;
33259a92d18SAlex Hornung }
33359a92d18SAlex Hornung 
33459a92d18SAlex Hornung static struct utmpx *
utmp_update(const struct utmpx * utx)33559a92d18SAlex Hornung utmp_update(const struct utmpx *utx)
33659a92d18SAlex Hornung {
33759a92d18SAlex Hornung 	char buf[sizeof(*utx) * 4 + 1];
33859a92d18SAlex Hornung 	pid_t pid;
33959a92d18SAlex Hornung 	int status;
34059a92d18SAlex Hornung 
34159a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
34259a92d18SAlex Hornung 
34359a92d18SAlex Hornung 	(void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
34465f10536SSascha Wildner 	    VIS_WHITE | VIS_NOLOCALE);
34559a92d18SAlex Hornung 	switch (pid = fork()) {
34659a92d18SAlex Hornung 	case 0:
34759a92d18SAlex Hornung 		(void)execl(_PATH_UTMP_UPDATE,
34859a92d18SAlex Hornung 		    strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf, NULL);
34959a92d18SAlex Hornung 		_exit(1);
35059a92d18SAlex Hornung 		/*NOTREACHED*/
35159a92d18SAlex Hornung 	case -1:
35259a92d18SAlex Hornung 		return NULL;
35359a92d18SAlex Hornung 	default:
354*625fc06fSSascha Wildner 		if (_waitpid(pid, &status, 0) == -1)
35559a92d18SAlex Hornung 			return NULL;
35659a92d18SAlex Hornung 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
35759a92d18SAlex Hornung 			return memcpy(&ut, utx, sizeof(ut));
35859a92d18SAlex Hornung 		return NULL;
35959a92d18SAlex Hornung 	}
36059a92d18SAlex Hornung 
36159a92d18SAlex Hornung }
36259a92d18SAlex Hornung 
36359a92d18SAlex Hornung /*
36459a92d18SAlex Hornung  * The following are extensions and not part of the X/Open spec.
36559a92d18SAlex Hornung  */
366bdb02cd9SAlex Hornung void
updwtmpx(const char * file,const struct utmpx * utx)36759a92d18SAlex Hornung updwtmpx(const char *file, const struct utmpx *utx)
36859a92d18SAlex Hornung {
369bdb02cd9SAlex Hornung 	(void)_updwtmpx(file, utx);
370bdb02cd9SAlex Hornung }
371bdb02cd9SAlex Hornung 
372bdb02cd9SAlex Hornung int
_updwtmpx(const char * file,const struct utmpx * utx)373bdb02cd9SAlex Hornung _updwtmpx(const char *file, const struct utmpx *utx)
374bdb02cd9SAlex Hornung {
37559a92d18SAlex Hornung 	int fd;
37659a92d18SAlex Hornung 	int saved_errno;
37721391921SSascha Wildner 	struct stat st;
37859a92d18SAlex Hornung 
37959a92d18SAlex Hornung 	_DIAGASSERT(file != NULL);
38059a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
38159a92d18SAlex Hornung 
382*625fc06fSSascha Wildner 	fd = _open(file, O_WRONLY|O_APPEND|O_SHLOCK|O_CLOEXEC);
38359a92d18SAlex Hornung 
38459a92d18SAlex Hornung 	if (fd == -1) {
385*625fc06fSSascha Wildner 		if ((fd = _open(file, O_CREAT|O_WRONLY|O_EXLOCK|O_CLOEXEC, 0644)) == -1)
38621391921SSascha Wildner 			goto fail;
38721391921SSascha Wildner 	}
388*625fc06fSSascha Wildner 	if (_fstat(fd, &st) == -1)
38921391921SSascha Wildner 		goto failclose;
39021391921SSascha Wildner 	if (st.st_size == 0) {
39121391921SSascha Wildner 		/* new file, add signature record */
39259a92d18SAlex Hornung 		(void)memset(&ut, 0, sizeof(ut));
39359a92d18SAlex Hornung 		ut.ut_type = SIGNATURE;
39459a92d18SAlex Hornung 		(void)memcpy(ut.ut_user, vers, sizeof(vers));
395*625fc06fSSascha Wildner 		if (_write(fd, &ut, sizeof(ut)) == -1)
39621391921SSascha Wildner 			goto failclose;
39759a92d18SAlex Hornung 	}
398*625fc06fSSascha Wildner 	if (_write(fd, utx, sizeof(*utx)) == -1)
39921391921SSascha Wildner 		goto failclose;
400806a5ed7SSascha Wildner 	if (_close(fd) == -1)
40159a92d18SAlex Hornung 		return -1;
40259a92d18SAlex Hornung 	return 0;
40359a92d18SAlex Hornung 
40421391921SSascha Wildner failclose:
40559a92d18SAlex Hornung 	saved_errno = errno;
406806a5ed7SSascha Wildner 	(void) _close(fd);
40759a92d18SAlex Hornung 	errno = saved_errno;
40821391921SSascha Wildner fail:
40959a92d18SAlex Hornung 	return -1;
41059a92d18SAlex Hornung }
41159a92d18SAlex Hornung 
41259a92d18SAlex Hornung int
utmpxname(const char * fname)41359a92d18SAlex Hornung utmpxname(const char *fname)
41459a92d18SAlex Hornung {
41559a92d18SAlex Hornung 	size_t len;
41659a92d18SAlex Hornung 
41759a92d18SAlex Hornung 	_DIAGASSERT(fname != NULL);
41859a92d18SAlex Hornung 
41959a92d18SAlex Hornung 	len = strlen(fname);
42059a92d18SAlex Hornung 
42159a92d18SAlex Hornung 	if (len >= sizeof(utfile))
42259a92d18SAlex Hornung 		return 0;
42359a92d18SAlex Hornung 
42459a92d18SAlex Hornung 	/* must end in x! */
42559a92d18SAlex Hornung 	if (fname[len - 1] != 'x')
42659a92d18SAlex Hornung 		return 0;
42759a92d18SAlex Hornung 
42859a92d18SAlex Hornung 	(void)strlcpy(utfile, fname, sizeof(utfile));
42959a92d18SAlex Hornung 	endutxent();
43059a92d18SAlex Hornung 	return 1;
43159a92d18SAlex Hornung }
43259a92d18SAlex Hornung 
433e2e9821dSSascha Wildner 
434e2e9821dSSascha Wildner __sym_compat(getutmp, past_getutmp, DF404.0);
43559a92d18SAlex Hornung void
past_getutmp(void * ux __unused,void * u __unused)436bdbb2472SSascha Wildner past_getutmp(void *ux __unused, void *u __unused)
43759a92d18SAlex Hornung {
43859a92d18SAlex Hornung }
43959a92d18SAlex Hornung 
440e2e9821dSSascha Wildner __sym_compat(getutmpx, past_getutmpx, DF404.0);
44159a92d18SAlex Hornung void
past_getutmpx(void * u __unused,void * ux __unused)442bdbb2472SSascha Wildner past_getutmpx(void *u __unused, void *ux __unused)
44359a92d18SAlex Hornung {
44459a92d18SAlex Hornung }
44559a92d18SAlex Hornung 
44659a92d18SAlex Hornung struct lastlogx *
getlastlogx(const char * fname,uid_t uid,struct lastlogx * ll)44759a92d18SAlex Hornung getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
44859a92d18SAlex Hornung {
44959a92d18SAlex Hornung 	DBT key, data;
45059a92d18SAlex Hornung 	DB *db;
45159a92d18SAlex Hornung 
45259a92d18SAlex Hornung 	_DIAGASSERT(fname != NULL);
45359a92d18SAlex Hornung 	_DIAGASSERT(ll != NULL);
45459a92d18SAlex Hornung 
45565f10536SSascha Wildner 	db = dbopen(fname, O_RDONLY|O_SHLOCK|O_CLOEXEC, 0, DB_HASH, NULL);
45659a92d18SAlex Hornung 
45759a92d18SAlex Hornung 	if (db == NULL)
45859a92d18SAlex Hornung 		return NULL;
45959a92d18SAlex Hornung 
46059a92d18SAlex Hornung 	key.data = &uid;
46159a92d18SAlex Hornung 	key.size = sizeof(uid);
46259a92d18SAlex Hornung 
46359a92d18SAlex Hornung 	if ((db->get)(db, &key, &data, 0) != 0)
46459a92d18SAlex Hornung 		goto error;
46559a92d18SAlex Hornung 
46659a92d18SAlex Hornung 	if (data.size != sizeof(*ll)) {
46759a92d18SAlex Hornung 		errno = EFTYPE;
46859a92d18SAlex Hornung 		goto error;
46959a92d18SAlex Hornung 	}
47059a92d18SAlex Hornung 
47159a92d18SAlex Hornung 	if (ll == NULL)
47259a92d18SAlex Hornung 		if ((ll = malloc(sizeof(*ll))) == NULL)
47359a92d18SAlex Hornung 			goto done;
47459a92d18SAlex Hornung 
47559a92d18SAlex Hornung 	(void)memcpy(ll, data.data, sizeof(*ll));
47659a92d18SAlex Hornung 	goto done;
47759a92d18SAlex Hornung error:
47859a92d18SAlex Hornung 	ll = NULL;
47959a92d18SAlex Hornung done:
48059a92d18SAlex Hornung 	(db->close)(db);
48159a92d18SAlex Hornung 	return ll;
48259a92d18SAlex Hornung }
48359a92d18SAlex Hornung 
48459a92d18SAlex Hornung int
updlastlogx(const char * fname,uid_t uid,struct lastlogx * ll)48559a92d18SAlex Hornung updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
48659a92d18SAlex Hornung {
48759a92d18SAlex Hornung 	DBT key, data;
48859a92d18SAlex Hornung 	int error = 0;
48959a92d18SAlex Hornung 	DB *db;
49059a92d18SAlex Hornung 
49159a92d18SAlex Hornung 	_DIAGASSERT(fname != NULL);
49259a92d18SAlex Hornung 	_DIAGASSERT(ll != NULL);
49359a92d18SAlex Hornung 
49465f10536SSascha Wildner 	db = dbopen(fname, O_RDWR|O_CREAT|O_EXLOCK|O_CLOEXEC, 0644, DB_HASH, NULL);
49559a92d18SAlex Hornung 
49659a92d18SAlex Hornung 	if (db == NULL)
49759a92d18SAlex Hornung 		return -1;
49859a92d18SAlex Hornung 
49959a92d18SAlex Hornung 	key.data = &uid;
50059a92d18SAlex Hornung 	key.size = sizeof(uid);
50159a92d18SAlex Hornung 	data.data = ll;
50259a92d18SAlex Hornung 	data.size = sizeof(*ll);
50359a92d18SAlex Hornung 	if ((db->put)(db, &key, &data, 0) != 0)
50459a92d18SAlex Hornung 		error = -1;
50559a92d18SAlex Hornung 
50659a92d18SAlex Hornung 	(db->close)(db);
50759a92d18SAlex Hornung 	return error;
50859a92d18SAlex Hornung }
509