1*59a92d18SAlex Hornung /*- 2*59a92d18SAlex Hornung * Copyright (c) 2002 The NetBSD Foundation, Inc. 3*59a92d18SAlex Hornung * All rights reserved. 4*59a92d18SAlex Hornung * 5*59a92d18SAlex Hornung * This code is derived from software contributed to The NetBSD Foundation 6*59a92d18SAlex Hornung * by Christos Zoulas. 7*59a92d18SAlex Hornung * 8*59a92d18SAlex Hornung * Redistribution and use in source and binary forms, with or without 9*59a92d18SAlex Hornung * modification, are permitted provided that the following conditions 10*59a92d18SAlex Hornung * are met: 11*59a92d18SAlex Hornung * 1. Redistributions of source code must retain the above copyright 12*59a92d18SAlex Hornung * notice, this list of conditions and the following disclaimer. 13*59a92d18SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright 14*59a92d18SAlex Hornung * notice, this list of conditions and the following disclaimer in the 15*59a92d18SAlex Hornung * documentation and/or other materials provided with the distribution. 16*59a92d18SAlex Hornung * 17*59a92d18SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18*59a92d18SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19*59a92d18SAlex Hornung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20*59a92d18SAlex Hornung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21*59a92d18SAlex Hornung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*59a92d18SAlex Hornung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*59a92d18SAlex Hornung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*59a92d18SAlex Hornung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*59a92d18SAlex Hornung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*59a92d18SAlex Hornung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*59a92d18SAlex Hornung * POSSIBILITY OF SUCH DAMAGE. 28*59a92d18SAlex Hornung */ 29*59a92d18SAlex Hornung #include <sys/cdefs.h> 30*59a92d18SAlex Hornung 31*59a92d18SAlex Hornung #include "namespace.h" 32*59a92d18SAlex Hornung #include <sys/types.h> 33*59a92d18SAlex Hornung #include <sys/param.h> 34*59a92d18SAlex Hornung #include <sys/socket.h> 35*59a92d18SAlex Hornung #include <sys/stat.h> 36*59a92d18SAlex Hornung #include <sys/time.h> 37*59a92d18SAlex Hornung #include <sys/wait.h> 38*59a92d18SAlex Hornung 39*59a92d18SAlex Hornung #include <assert.h> 40*59a92d18SAlex Hornung #include <db.h> 41*59a92d18SAlex Hornung #include <errno.h> 42*59a92d18SAlex Hornung #include <fcntl.h> 43*59a92d18SAlex Hornung #include <stdio.h> 44*59a92d18SAlex Hornung #include <stdlib.h> 45*59a92d18SAlex Hornung #include <string.h> 46*59a92d18SAlex Hornung #include <unistd.h> 47*59a92d18SAlex Hornung #include <pwd.h> 48*59a92d18SAlex Hornung #include <utmp.h> 49*59a92d18SAlex Hornung #include <utmpx.h> 50*59a92d18SAlex Hornung #include <vis.h> 51*59a92d18SAlex Hornung 52*59a92d18SAlex Hornung static FILE *fp = NULL; 53*59a92d18SAlex Hornung static int readonly = 0; 54*59a92d18SAlex Hornung static struct utmpx ut; 55*59a92d18SAlex Hornung static char utfile[MAXPATHLEN] = _PATH_UTMPX; 56*59a92d18SAlex Hornung 57*59a92d18SAlex Hornung static struct utmpx *utmp_update(const struct utmpx *); 58*59a92d18SAlex Hornung 59*59a92d18SAlex Hornung static const char vers[] = "utmpx-2.00"; 60*59a92d18SAlex Hornung static utx_db_t dbtype = UTX_DB_UTMPX; 61*59a92d18SAlex Hornung DB *lastlogx_db = NULL; 62*59a92d18SAlex Hornung 63*59a92d18SAlex Hornung static int 64*59a92d18SAlex Hornung _open_db(char *fname) 65*59a92d18SAlex Hornung { 66*59a92d18SAlex Hornung struct stat st; 67*59a92d18SAlex Hornung 68*59a92d18SAlex Hornung if ((fp = fopen(fname, "r+")) == NULL) 69*59a92d18SAlex Hornung if ((fp = fopen(fname, "w+")) == NULL) { 70*59a92d18SAlex Hornung if ((fp = fopen(fname, "r")) == NULL) 71*59a92d18SAlex Hornung goto fail; 72*59a92d18SAlex Hornung else 73*59a92d18SAlex Hornung readonly = 1; 74*59a92d18SAlex Hornung } 75*59a92d18SAlex Hornung 76*59a92d18SAlex Hornung /* get file size in order to check if new file */ 77*59a92d18SAlex Hornung if (fstat(fileno(fp), &st) == -1) 78*59a92d18SAlex Hornung goto failclose; 79*59a92d18SAlex Hornung 80*59a92d18SAlex Hornung if (st.st_size == 0) { 81*59a92d18SAlex Hornung /* new file, add signature record */ 82*59a92d18SAlex Hornung (void)memset(&ut, 0, sizeof(ut)); 83*59a92d18SAlex Hornung ut.ut_type = SIGNATURE; 84*59a92d18SAlex Hornung (void)memcpy(ut.ut_user, vers, sizeof(vers)); 85*59a92d18SAlex Hornung if (fwrite(&ut, sizeof(ut), 1, fp) != 1) 86*59a92d18SAlex Hornung goto failclose; 87*59a92d18SAlex Hornung } else { 88*59a92d18SAlex Hornung /* old file, read signature record */ 89*59a92d18SAlex Hornung if (fread(&ut, sizeof(ut), 1, fp) != 1) 90*59a92d18SAlex Hornung goto failclose; 91*59a92d18SAlex Hornung if (memcmp(ut.ut_user, vers, 5) != 0 || 92*59a92d18SAlex Hornung ut.ut_type != SIGNATURE) { 93*59a92d18SAlex Hornung errno = EINVAL; 94*59a92d18SAlex Hornung goto failclose; 95*59a92d18SAlex Hornung } 96*59a92d18SAlex Hornung } 97*59a92d18SAlex Hornung 98*59a92d18SAlex Hornung return 0; 99*59a92d18SAlex Hornung failclose: 100*59a92d18SAlex Hornung (void)fclose(fp); 101*59a92d18SAlex Hornung fail: 102*59a92d18SAlex Hornung (void)memset(&ut, 0, sizeof(ut)); 103*59a92d18SAlex Hornung return -1; 104*59a92d18SAlex Hornung } 105*59a92d18SAlex Hornung 106*59a92d18SAlex Hornung int 107*59a92d18SAlex Hornung setutxdb(utx_db_t db_type, char *fname) 108*59a92d18SAlex Hornung { 109*59a92d18SAlex Hornung switch (db_type) { 110*59a92d18SAlex Hornung case UTX_DB_UTMPX: 111*59a92d18SAlex Hornung if (fname == NULL) 112*59a92d18SAlex Hornung fname = _PATH_UTMPX; 113*59a92d18SAlex Hornung break; 114*59a92d18SAlex Hornung 115*59a92d18SAlex Hornung case UTX_DB_WTMPX: 116*59a92d18SAlex Hornung if (fname == NULL) 117*59a92d18SAlex Hornung fname = _PATH_WTMPX; 118*59a92d18SAlex Hornung break; 119*59a92d18SAlex Hornung 120*59a92d18SAlex Hornung default: 121*59a92d18SAlex Hornung errno = EINVAL; 122*59a92d18SAlex Hornung return -1; 123*59a92d18SAlex Hornung } 124*59a92d18SAlex Hornung 125*59a92d18SAlex Hornung /* A previous db file is still open */ 126*59a92d18SAlex Hornung if (fp != NULL) { 127*59a92d18SAlex Hornung fclose(fp); 128*59a92d18SAlex Hornung fp = NULL; 129*59a92d18SAlex Hornung } 130*59a92d18SAlex Hornung if ((_open_db(fname)) == -1) 131*59a92d18SAlex Hornung return -1; 132*59a92d18SAlex Hornung 133*59a92d18SAlex Hornung done: 134*59a92d18SAlex Hornung dbtype = db_type; 135*59a92d18SAlex Hornung return 0; 136*59a92d18SAlex Hornung } 137*59a92d18SAlex Hornung 138*59a92d18SAlex Hornung void 139*59a92d18SAlex Hornung setutxent() 140*59a92d18SAlex Hornung { 141*59a92d18SAlex Hornung (void)memset(&ut, 0, sizeof(ut)); 142*59a92d18SAlex Hornung if (fp == NULL) 143*59a92d18SAlex Hornung return; 144*59a92d18SAlex Hornung 145*59a92d18SAlex Hornung #if 0 146*59a92d18SAlex Hornung if (dbtype != UTX_DB_UTMPX) 147*59a92d18SAlex Hornung setutxdb(UTX_DB_UTMPX, utfile); 148*59a92d18SAlex Hornung #endif 149*59a92d18SAlex Hornung (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET); 150*59a92d18SAlex Hornung } 151*59a92d18SAlex Hornung 152*59a92d18SAlex Hornung void 153*59a92d18SAlex Hornung endutxent() 154*59a92d18SAlex Hornung { 155*59a92d18SAlex Hornung (void)memset(&ut, 0, sizeof(ut)); 156*59a92d18SAlex Hornung 157*59a92d18SAlex Hornung if (fp != NULL) { 158*59a92d18SAlex Hornung (void)fclose(fp); 159*59a92d18SAlex Hornung fp = NULL; 160*59a92d18SAlex Hornung readonly = 0; 161*59a92d18SAlex Hornung } 162*59a92d18SAlex Hornung } 163*59a92d18SAlex Hornung 164*59a92d18SAlex Hornung struct utmpx * 165*59a92d18SAlex Hornung getutxent() 166*59a92d18SAlex Hornung { 167*59a92d18SAlex Hornung if (fp == NULL) { 168*59a92d18SAlex Hornung if ((_open_db(utfile)) == -1) 169*59a92d18SAlex Hornung goto fail; 170*59a92d18SAlex Hornung } 171*59a92d18SAlex Hornung 172*59a92d18SAlex Hornung if (fread(&ut, sizeof(ut), 1, fp) != 1) 173*59a92d18SAlex Hornung goto fail; 174*59a92d18SAlex Hornung 175*59a92d18SAlex Hornung return &ut; 176*59a92d18SAlex Hornung fail: 177*59a92d18SAlex Hornung (void)memset(&ut, 0, sizeof(ut)); 178*59a92d18SAlex Hornung return NULL; 179*59a92d18SAlex Hornung } 180*59a92d18SAlex Hornung 181*59a92d18SAlex Hornung struct utmpx * 182*59a92d18SAlex Hornung getutxid(const struct utmpx *utx) 183*59a92d18SAlex Hornung { 184*59a92d18SAlex Hornung 185*59a92d18SAlex Hornung _DIAGASSERT(utx != NULL); 186*59a92d18SAlex Hornung 187*59a92d18SAlex Hornung if (utx->ut_type == EMPTY) 188*59a92d18SAlex Hornung return NULL; 189*59a92d18SAlex Hornung 190*59a92d18SAlex Hornung do { 191*59a92d18SAlex Hornung if (ut.ut_type == EMPTY) 192*59a92d18SAlex Hornung continue; 193*59a92d18SAlex Hornung switch (utx->ut_type) { 194*59a92d18SAlex Hornung case EMPTY: 195*59a92d18SAlex Hornung return NULL; 196*59a92d18SAlex Hornung case RUN_LVL: 197*59a92d18SAlex Hornung case BOOT_TIME: 198*59a92d18SAlex Hornung case OLD_TIME: 199*59a92d18SAlex Hornung case NEW_TIME: 200*59a92d18SAlex Hornung if (ut.ut_type == utx->ut_type) 201*59a92d18SAlex Hornung return &ut; 202*59a92d18SAlex Hornung break; 203*59a92d18SAlex Hornung case INIT_PROCESS: 204*59a92d18SAlex Hornung case LOGIN_PROCESS: 205*59a92d18SAlex Hornung case USER_PROCESS: 206*59a92d18SAlex Hornung case DEAD_PROCESS: 207*59a92d18SAlex Hornung switch (ut.ut_type) { 208*59a92d18SAlex Hornung case INIT_PROCESS: 209*59a92d18SAlex Hornung case LOGIN_PROCESS: 210*59a92d18SAlex Hornung case USER_PROCESS: 211*59a92d18SAlex Hornung case DEAD_PROCESS: 212*59a92d18SAlex Hornung if (memcmp(ut.ut_id, utx->ut_id, 213*59a92d18SAlex Hornung sizeof(ut.ut_id)) == 0) 214*59a92d18SAlex Hornung return &ut; 215*59a92d18SAlex Hornung break; 216*59a92d18SAlex Hornung default: 217*59a92d18SAlex Hornung break; 218*59a92d18SAlex Hornung } 219*59a92d18SAlex Hornung break; 220*59a92d18SAlex Hornung default: 221*59a92d18SAlex Hornung return NULL; 222*59a92d18SAlex Hornung } 223*59a92d18SAlex Hornung } while (getutxent() != NULL); 224*59a92d18SAlex Hornung return NULL; 225*59a92d18SAlex Hornung } 226*59a92d18SAlex Hornung 227*59a92d18SAlex Hornung struct utmpx * 228*59a92d18SAlex Hornung getutxline(const struct utmpx *utx) 229*59a92d18SAlex Hornung { 230*59a92d18SAlex Hornung 231*59a92d18SAlex Hornung _DIAGASSERT(utx != NULL); 232*59a92d18SAlex Hornung 233*59a92d18SAlex Hornung do { 234*59a92d18SAlex Hornung switch (ut.ut_type) { 235*59a92d18SAlex Hornung case EMPTY: 236*59a92d18SAlex Hornung break; 237*59a92d18SAlex Hornung case LOGIN_PROCESS: 238*59a92d18SAlex Hornung case USER_PROCESS: 239*59a92d18SAlex Hornung if (strncmp(ut.ut_line, utx->ut_line, 240*59a92d18SAlex Hornung sizeof(ut.ut_line)) == 0) 241*59a92d18SAlex Hornung return &ut; 242*59a92d18SAlex Hornung break; 243*59a92d18SAlex Hornung default: 244*59a92d18SAlex Hornung break; 245*59a92d18SAlex Hornung } 246*59a92d18SAlex Hornung } while (getutxent() != NULL); 247*59a92d18SAlex Hornung return NULL; 248*59a92d18SAlex Hornung } 249*59a92d18SAlex Hornung 250*59a92d18SAlex Hornung struct utmpx * 251*59a92d18SAlex Hornung pututxline(const struct utmpx *utx) 252*59a92d18SAlex Hornung { 253*59a92d18SAlex Hornung struct passwd *pw; 254*59a92d18SAlex Hornung struct lastlogx ll; 255*59a92d18SAlex Hornung struct utmpx temp, *u = NULL; 256*59a92d18SAlex Hornung int gotlock = 0; 257*59a92d18SAlex Hornung 258*59a92d18SAlex Hornung _DIAGASSERT(utx != NULL); 259*59a92d18SAlex Hornung 260*59a92d18SAlex Hornung if (utx == NULL) 261*59a92d18SAlex Hornung return NULL; 262*59a92d18SAlex Hornung 263*59a92d18SAlex Hornung if (utx->ut_type == USER_PROCESS) { 264*59a92d18SAlex Hornung ll.ll_tv = utx->ut_tv; 265*59a92d18SAlex Hornung strcpy(ll.ll_host, utx->ut_host); 266*59a92d18SAlex Hornung strcpy(ll.ll_line, utx->ut_line); 267*59a92d18SAlex Hornung pw = getpwnam(utx->ut_name); 268*59a92d18SAlex Hornung if (pw != NULL) 269*59a92d18SAlex Hornung updlastlogx(_PATH_LASTLOGX, pw->pw_uid, &ll); 270*59a92d18SAlex Hornung } 271*59a92d18SAlex Hornung 272*59a92d18SAlex Hornung if (strcmp(_PATH_UTMPX, utfile) == 0) 273*59a92d18SAlex Hornung if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0)) 274*59a92d18SAlex Hornung return utmp_update(utx); 275*59a92d18SAlex Hornung 276*59a92d18SAlex Hornung 277*59a92d18SAlex Hornung (void)memcpy(&temp, utx, sizeof(temp)); 278*59a92d18SAlex Hornung 279*59a92d18SAlex Hornung if (fp == NULL) { 280*59a92d18SAlex Hornung (void)getutxent(); 281*59a92d18SAlex Hornung if (fp == NULL || readonly) 282*59a92d18SAlex Hornung return NULL; 283*59a92d18SAlex Hornung } 284*59a92d18SAlex Hornung 285*59a92d18SAlex Hornung if (getutxid(&temp) == NULL) { 286*59a92d18SAlex Hornung setutxent(); 287*59a92d18SAlex Hornung if (getutxid(&temp) == NULL) { 288*59a92d18SAlex Hornung if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1) 289*59a92d18SAlex Hornung return NULL; 290*59a92d18SAlex Hornung gotlock++; 291*59a92d18SAlex Hornung if (fseeko(fp, (off_t)0, SEEK_END) == -1) 292*59a92d18SAlex Hornung goto fail; 293*59a92d18SAlex Hornung } 294*59a92d18SAlex Hornung } 295*59a92d18SAlex Hornung 296*59a92d18SAlex Hornung if (!gotlock) { 297*59a92d18SAlex Hornung /* we are not appending */ 298*59a92d18SAlex Hornung if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1) 299*59a92d18SAlex Hornung return NULL; 300*59a92d18SAlex Hornung } 301*59a92d18SAlex Hornung 302*59a92d18SAlex Hornung if (fwrite(&temp, sizeof (temp), 1, fp) != 1) 303*59a92d18SAlex Hornung goto fail; 304*59a92d18SAlex Hornung 305*59a92d18SAlex Hornung if (fflush(fp) == -1) 306*59a92d18SAlex Hornung goto fail; 307*59a92d18SAlex Hornung 308*59a92d18SAlex Hornung u = memcpy(&ut, &temp, sizeof(ut)); 309*59a92d18SAlex Hornung fail: 310*59a92d18SAlex Hornung if (gotlock) { 311*59a92d18SAlex Hornung if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1) 312*59a92d18SAlex Hornung return NULL; 313*59a92d18SAlex Hornung } 314*59a92d18SAlex Hornung return u; 315*59a92d18SAlex Hornung } 316*59a92d18SAlex Hornung 317*59a92d18SAlex Hornung static struct utmpx * 318*59a92d18SAlex Hornung utmp_update(const struct utmpx *utx) 319*59a92d18SAlex Hornung { 320*59a92d18SAlex Hornung char buf[sizeof(*utx) * 4 + 1]; 321*59a92d18SAlex Hornung pid_t pid; 322*59a92d18SAlex Hornung int status; 323*59a92d18SAlex Hornung 324*59a92d18SAlex Hornung _DIAGASSERT(utx != NULL); 325*59a92d18SAlex Hornung 326*59a92d18SAlex Hornung (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx), 327*59a92d18SAlex Hornung VIS_WHITE); 328*59a92d18SAlex Hornung switch (pid = fork()) { 329*59a92d18SAlex Hornung case 0: 330*59a92d18SAlex Hornung (void)execl(_PATH_UTMP_UPDATE, 331*59a92d18SAlex Hornung strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf, NULL); 332*59a92d18SAlex Hornung _exit(1); 333*59a92d18SAlex Hornung /*NOTREACHED*/ 334*59a92d18SAlex Hornung case -1: 335*59a92d18SAlex Hornung return NULL; 336*59a92d18SAlex Hornung default: 337*59a92d18SAlex Hornung if (waitpid(pid, &status, 0) == -1) 338*59a92d18SAlex Hornung return NULL; 339*59a92d18SAlex Hornung if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 340*59a92d18SAlex Hornung return memcpy(&ut, utx, sizeof(ut)); 341*59a92d18SAlex Hornung return NULL; 342*59a92d18SAlex Hornung } 343*59a92d18SAlex Hornung 344*59a92d18SAlex Hornung } 345*59a92d18SAlex Hornung 346*59a92d18SAlex Hornung /* 347*59a92d18SAlex Hornung * The following are extensions and not part of the X/Open spec. 348*59a92d18SAlex Hornung */ 349*59a92d18SAlex Hornung int 350*59a92d18SAlex Hornung updwtmpx(const char *file, const struct utmpx *utx) 351*59a92d18SAlex Hornung { 352*59a92d18SAlex Hornung int fd; 353*59a92d18SAlex Hornung int saved_errno; 354*59a92d18SAlex Hornung 355*59a92d18SAlex Hornung _DIAGASSERT(file != NULL); 356*59a92d18SAlex Hornung _DIAGASSERT(utx != NULL); 357*59a92d18SAlex Hornung 358*59a92d18SAlex Hornung fd = open(file, O_WRONLY|O_APPEND|O_SHLOCK); 359*59a92d18SAlex Hornung 360*59a92d18SAlex Hornung if (fd == -1) { 361*59a92d18SAlex Hornung if ((fd = open(file, O_CREAT|O_WRONLY|O_EXLOCK, 0644)) == -1) 362*59a92d18SAlex Hornung return -1; 363*59a92d18SAlex Hornung (void)memset(&ut, 0, sizeof(ut)); 364*59a92d18SAlex Hornung ut.ut_type = SIGNATURE; 365*59a92d18SAlex Hornung (void)memcpy(ut.ut_user, vers, sizeof(vers)); 366*59a92d18SAlex Hornung if (write(fd, &ut, sizeof(ut)) == -1) 367*59a92d18SAlex Hornung goto failed; 368*59a92d18SAlex Hornung } 369*59a92d18SAlex Hornung if (write(fd, utx, sizeof(*utx)) == -1) 370*59a92d18SAlex Hornung goto failed; 371*59a92d18SAlex Hornung if (close(fd) == -1) 372*59a92d18SAlex Hornung return -1; 373*59a92d18SAlex Hornung return 0; 374*59a92d18SAlex Hornung 375*59a92d18SAlex Hornung failed: 376*59a92d18SAlex Hornung saved_errno = errno; 377*59a92d18SAlex Hornung (void) close(fd); 378*59a92d18SAlex Hornung errno = saved_errno; 379*59a92d18SAlex Hornung return -1; 380*59a92d18SAlex Hornung } 381*59a92d18SAlex Hornung 382*59a92d18SAlex Hornung int 383*59a92d18SAlex Hornung utmpxname(const char *fname) 384*59a92d18SAlex Hornung { 385*59a92d18SAlex Hornung size_t len; 386*59a92d18SAlex Hornung 387*59a92d18SAlex Hornung _DIAGASSERT(fname != NULL); 388*59a92d18SAlex Hornung 389*59a92d18SAlex Hornung len = strlen(fname); 390*59a92d18SAlex Hornung 391*59a92d18SAlex Hornung if (len >= sizeof(utfile)) 392*59a92d18SAlex Hornung return 0; 393*59a92d18SAlex Hornung 394*59a92d18SAlex Hornung /* must end in x! */ 395*59a92d18SAlex Hornung if (fname[len - 1] != 'x') 396*59a92d18SAlex Hornung return 0; 397*59a92d18SAlex Hornung 398*59a92d18SAlex Hornung (void)strlcpy(utfile, fname, sizeof(utfile)); 399*59a92d18SAlex Hornung endutxent(); 400*59a92d18SAlex Hornung return 1; 401*59a92d18SAlex Hornung } 402*59a92d18SAlex Hornung 403*59a92d18SAlex Hornung void 404*59a92d18SAlex Hornung getutmp(const struct utmpx *ux, struct utmp *u) 405*59a92d18SAlex Hornung { 406*59a92d18SAlex Hornung 407*59a92d18SAlex Hornung _DIAGASSERT(ux != NULL); 408*59a92d18SAlex Hornung _DIAGASSERT(u != NULL); 409*59a92d18SAlex Hornung 410*59a92d18SAlex Hornung (void)memcpy(u->ut_name, ux->ut_name, sizeof(u->ut_name)); 411*59a92d18SAlex Hornung (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line)); 412*59a92d18SAlex Hornung (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host)); 413*59a92d18SAlex Hornung u->ut_time = ux->ut_tv.tv_sec; 414*59a92d18SAlex Hornung } 415*59a92d18SAlex Hornung 416*59a92d18SAlex Hornung void 417*59a92d18SAlex Hornung getutmpx(const struct utmp *u, struct utmpx *ux) 418*59a92d18SAlex Hornung { 419*59a92d18SAlex Hornung 420*59a92d18SAlex Hornung _DIAGASSERT(ux != NULL); 421*59a92d18SAlex Hornung _DIAGASSERT(u != NULL); 422*59a92d18SAlex Hornung 423*59a92d18SAlex Hornung (void)memcpy(ux->ut_name, u->ut_name, sizeof(u->ut_name)); 424*59a92d18SAlex Hornung (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line)); 425*59a92d18SAlex Hornung (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host)); 426*59a92d18SAlex Hornung ux->ut_tv.tv_sec = u->ut_time; 427*59a92d18SAlex Hornung ux->ut_tv.tv_usec = 0; 428*59a92d18SAlex Hornung (void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss)); 429*59a92d18SAlex Hornung ux->ut_pid = 0; 430*59a92d18SAlex Hornung ux->ut_type = USER_PROCESS; 431*59a92d18SAlex Hornung ux->ut_session = 0; 432*59a92d18SAlex Hornung ux->ut_exit.e_termination = 0; 433*59a92d18SAlex Hornung ux->ut_exit.e_exit = 0; 434*59a92d18SAlex Hornung } 435*59a92d18SAlex Hornung 436*59a92d18SAlex Hornung struct lastlogx * 437*59a92d18SAlex Hornung getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll) 438*59a92d18SAlex Hornung { 439*59a92d18SAlex Hornung DBT key, data; 440*59a92d18SAlex Hornung DB *db; 441*59a92d18SAlex Hornung 442*59a92d18SAlex Hornung _DIAGASSERT(fname != NULL); 443*59a92d18SAlex Hornung _DIAGASSERT(ll != NULL); 444*59a92d18SAlex Hornung 445*59a92d18SAlex Hornung db = dbopen(fname, O_RDONLY|O_SHLOCK, 0, DB_HASH, NULL); 446*59a92d18SAlex Hornung 447*59a92d18SAlex Hornung if (db == NULL) 448*59a92d18SAlex Hornung return NULL; 449*59a92d18SAlex Hornung 450*59a92d18SAlex Hornung key.data = &uid; 451*59a92d18SAlex Hornung key.size = sizeof(uid); 452*59a92d18SAlex Hornung 453*59a92d18SAlex Hornung if ((db->get)(db, &key, &data, 0) != 0) 454*59a92d18SAlex Hornung goto error; 455*59a92d18SAlex Hornung 456*59a92d18SAlex Hornung if (data.size != sizeof(*ll)) { 457*59a92d18SAlex Hornung errno = EFTYPE; 458*59a92d18SAlex Hornung goto error; 459*59a92d18SAlex Hornung } 460*59a92d18SAlex Hornung 461*59a92d18SAlex Hornung if (ll == NULL) 462*59a92d18SAlex Hornung if ((ll = malloc(sizeof(*ll))) == NULL) 463*59a92d18SAlex Hornung goto done; 464*59a92d18SAlex Hornung 465*59a92d18SAlex Hornung (void)memcpy(ll, data.data, sizeof(*ll)); 466*59a92d18SAlex Hornung goto done; 467*59a92d18SAlex Hornung error: 468*59a92d18SAlex Hornung ll = NULL; 469*59a92d18SAlex Hornung done: 470*59a92d18SAlex Hornung (db->close)(db); 471*59a92d18SAlex Hornung return ll; 472*59a92d18SAlex Hornung } 473*59a92d18SAlex Hornung 474*59a92d18SAlex Hornung int 475*59a92d18SAlex Hornung updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll) 476*59a92d18SAlex Hornung { 477*59a92d18SAlex Hornung DBT key, data; 478*59a92d18SAlex Hornung int error = 0; 479*59a92d18SAlex Hornung DB *db; 480*59a92d18SAlex Hornung 481*59a92d18SAlex Hornung _DIAGASSERT(fname != NULL); 482*59a92d18SAlex Hornung _DIAGASSERT(ll != NULL); 483*59a92d18SAlex Hornung 484*59a92d18SAlex Hornung db = dbopen(fname, O_RDWR|O_CREAT|O_EXLOCK, 0644, DB_HASH, NULL); 485*59a92d18SAlex Hornung 486*59a92d18SAlex Hornung if (db == NULL) 487*59a92d18SAlex Hornung return -1; 488*59a92d18SAlex Hornung 489*59a92d18SAlex Hornung key.data = &uid; 490*59a92d18SAlex Hornung key.size = sizeof(uid); 491*59a92d18SAlex Hornung data.data = ll; 492*59a92d18SAlex Hornung data.size = sizeof(*ll); 493*59a92d18SAlex Hornung if ((db->put)(db, &key, &data, 0) != 0) 494*59a92d18SAlex Hornung error = -1; 495*59a92d18SAlex Hornung 496*59a92d18SAlex Hornung (db->close)(db); 497*59a92d18SAlex Hornung return error; 498*59a92d18SAlex Hornung } 499