1 /* $NetBSD: utmpx.c,v 1.35 2015/05/23 11:48:13 christos Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 __RCSID("$NetBSD: utmpx.c,v 1.35 2015/05/23 11:48:13 christos Exp $");
35 #endif /* LIBC_SCCS and not lint */
37 #include "namespace.h"
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
58 static int readonly
= 0;
59 static int version
= 1;
60 static struct utmpx ut
;
61 static char utfile
[MAXPATHLEN
] = _PATH_UTMPX
;
63 static struct utmpx
*utmp_update(const struct utmpx
*);
65 static const char vers
[] = "utmpx-2.00";
73 old2new(struct utmpx
*utx
)
76 struct timeval
*tv
= &utx
->ut_tv
;
77 (void)memcpy(&otv
, tv
, sizeof(otv
));
78 tv
->tv_sec
= otv
.tv_sec
;
79 tv
->tv_usec
= (suseconds_t
)otv
.tv_usec
;
83 new2old(struct utmpx
*utx
)
86 struct timeval
*tv
= &utx
->ut_tv
;
88 otv
.tv_sec
= (long)tv
->tv_sec
;
89 otv
.tv_usec
= (long)tv
->tv_usec
;
90 (void)memcpy(tv
, &otv
, sizeof(otv
));
97 (void)memset(&ut
, 0, sizeof(ut
));
100 (void)fseeko(fp
, (off_t
)sizeof(ut
), SEEK_SET
);
108 (void)memset(&ut
, 0, sizeof(ut
));
124 if ((fp
= fopen(utfile
, "re+")) == NULL
)
125 if ((fp
= fopen(utfile
, "we+")) == NULL
) {
126 if ((fp
= fopen(utfile
, "re")) == NULL
)
133 /* get file size in order to check if new file */
134 if (fstat(fileno(fp
), &st
) == -1)
137 if (st
.st_size
== 0) {
138 /* new file, add signature record */
139 (void)memset(&ut
, 0, sizeof(ut
));
140 ut
.ut_type
= SIGNATURE
;
141 (void)memcpy(ut
.ut_user
, vers
, sizeof(vers
));
142 if (fwrite(&ut
, sizeof(ut
), 1, fp
) != 1)
145 /* old file, read signature record */
146 if (fread(&ut
, sizeof(ut
), 1, fp
) != 1)
148 if (memcmp(ut
.ut_user
, vers
, 5) != 0 ||
149 ut
.ut_type
!= SIGNATURE
)
152 version
= ut
.ut_user
[6] - '0';
155 if (fread(&ut
, sizeof(ut
), 1, fp
) != 1)
164 (void)memset(&ut
, 0, sizeof(ut
));
170 getutxid(const struct utmpx
*utx
)
173 _DIAGASSERT(utx
!= NULL
);
175 if (utx
->ut_type
== EMPTY
)
179 if (ut
.ut_type
== EMPTY
)
181 switch (utx
->ut_type
) {
188 if (ut
.ut_type
== utx
->ut_type
)
195 switch (ut
.ut_type
) {
200 if (memcmp(ut
.ut_id
, utx
->ut_id
,
201 sizeof(ut
.ut_id
)) == 0)
211 } while (getutxent() != NULL
);
217 getutxline(const struct utmpx
*utx
)
220 _DIAGASSERT(utx
!= NULL
);
223 switch (ut
.ut_type
) {
228 if (strncmp(ut
.ut_line
, utx
->ut_line
,
229 sizeof(ut
.ut_line
)) == 0)
235 } while (getutxent() != NULL
);
241 pututxline(const struct utmpx
*utx
)
243 struct utmpx temp
, *u
= NULL
;
246 _DIAGASSERT(utx
!= NULL
);
251 if (strcmp(_PATH_UTMPX
, utfile
) == 0) {
252 if (geteuid() == 0) {
253 if (fp
!= NULL
&& readonly
)
256 if (fp
== NULL
|| readonly
)
257 return utmp_update(utx
);
262 (void)memcpy(&temp
, utx
, sizeof(temp
));
266 if (fp
== NULL
|| readonly
)
270 if (getutxid(&temp
) == NULL
) {
272 if (getutxid(&temp
) == NULL
) {
273 if (lockf(fileno(fp
), F_LOCK
, (off_t
)0) == -1)
276 if (fseeko(fp
, (off_t
)0, SEEK_END
) == -1)
282 /* we are not appending */
283 if (fseeko(fp
, -(off_t
)sizeof(ut
), SEEK_CUR
) == -1)
289 if (fwrite(&temp
, sizeof (temp
), 1, fp
) != 1)
292 if (fflush(fp
) == -1)
295 u
= memcpy(&ut
, &temp
, sizeof(ut
));
298 if (lockf(fileno(fp
), F_ULOCK
, (off_t
)0) == -1)
305 static struct utmpx
*
306 utmp_update(const struct utmpx
*utx
)
308 char buf
[sizeof(*utx
) * 4 + 1];
312 _DIAGASSERT(utx
!= NULL
);
314 (void)strvisx(buf
, (const char *)(const void *)utx
, sizeof(*utx
),
315 VIS_WHITE
| VIS_NOLOCALE
);
316 switch (pid
= fork()) {
318 (void)execl(_PATH_UTMP_UPDATE
,
319 strrchr(_PATH_UTMP_UPDATE
, '/') + 1, buf
, NULL
);
325 if (waitpid(pid
, &status
, 0) == -1)
327 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 0)
328 return memcpy(&ut
, utx
, sizeof(ut
));
335 * The following are extensions and not part of the X/Open spec.
338 updwtmpx(const char *file
, const struct utmpx
*utx
)
343 _DIAGASSERT(file
!= NULL
);
344 _DIAGASSERT(utx
!= NULL
);
346 fd
= open(file
, O_WRONLY
|O_APPEND
|O_SHLOCK
|O_CLOEXEC
);
349 if ((fd
= open(file
, O_CREAT
|O_WRONLY
|O_EXLOCK
|O_CLOEXEC
, 0644)) == -1)
351 (void)memset(&ut
, 0, sizeof(ut
));
352 ut
.ut_type
= SIGNATURE
;
353 (void)memcpy(ut
.ut_user
, vers
, sizeof(vers
));
354 if (write(fd
, &ut
, sizeof(ut
)) == -1)
357 if (write(fd
, utx
, sizeof(*utx
)) == -1)
372 utmpxname(const char *fname
)
376 _DIAGASSERT(fname
!= NULL
);
380 if (len
>= sizeof(utfile
))
384 if (fname
[len
- 1] != 'x')
387 (void)strlcpy(utfile
, fname
, sizeof(utfile
));
394 getutmp(const struct utmpx
*ux
, struct utmp
*u
)
397 _DIAGASSERT(ux
!= NULL
);
398 _DIAGASSERT(u
!= NULL
);
400 (void)memcpy(u
->ut_name
, ux
->ut_name
, sizeof(u
->ut_name
));
401 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
402 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
403 u
->ut_time
= ux
->ut_tv
.tv_sec
;
407 getutmpx(const struct utmp
*u
, struct utmpx
*ux
)
410 _DIAGASSERT(ux
!= NULL
);
411 _DIAGASSERT(u
!= NULL
);
413 (void)memcpy(ux
->ut_name
, u
->ut_name
, sizeof(u
->ut_name
));
414 (void)memcpy(ux
->ut_line
, u
->ut_line
, sizeof(u
->ut_line
));
415 (void)memcpy(ux
->ut_host
, u
->ut_host
, sizeof(u
->ut_host
));
416 ux
->ut_tv
.tv_sec
= u
->ut_time
;
417 ux
->ut_tv
.tv_usec
= 0;
418 (void)memset(&ux
->ut_ss
, 0, sizeof(ux
->ut_ss
));
420 ux
->ut_type
= USER_PROCESS
;
422 ux
->ut_exit
.e_termination
= 0;
423 ux
->ut_exit
.e_exit
= 0;
427 getlastlogx(const char *fname
, uid_t uid
, struct lastlogx
*ll
)
432 _DIAGASSERT(fname
!= NULL
);
433 _DIAGASSERT(ll
!= NULL
);
435 db
= dbopen(fname
, O_RDONLY
|O_SHLOCK
|O_CLOEXEC
, 0, DB_HASH
, NULL
);
441 key
.size
= sizeof(uid
);
443 if ((db
->get
)(db
, &key
, &data
, 0) != 0)
446 if (data
.size
!= sizeof(*ll
)) {
452 if ((ll
= malloc(sizeof(*ll
))) == NULL
)
455 (void)memcpy(ll
, data
.data
, sizeof(*ll
));
465 updlastlogx(const char *fname
, uid_t uid
, struct lastlogx
*ll
)
471 _DIAGASSERT(fname
!= NULL
);
472 _DIAGASSERT(ll
!= NULL
);
474 db
= dbopen(fname
, O_RDWR
|O_CREAT
|O_EXLOCK
|O_CLOEXEC
, 0644, DB_HASH
, NULL
);
480 key
.size
= sizeof(uid
);
482 data
.size
= sizeof(*ll
);
483 if ((db
->put
)(db
, &key
, &data
, 0) != 0)