10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51914Scasper * Common Development and Distribution License (the "License").
61914Scasper * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
216812Sraf
220Sstevel@tonic-gate /*
236812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate * Compatibility routines to read and write alternate
320Sstevel@tonic-gate * utmp-like files. These routines are only used in
330Sstevel@tonic-gate * the case where utmpname() is used to change to a file
340Sstevel@tonic-gate * other than /var/adm/utmp or /var/adm/wtmp. In this case,
350Sstevel@tonic-gate * we assume that someone really wants to read old utmp-format
360Sstevel@tonic-gate * files. Otherwise, the getutent, setutent, getutid, setutline,
370Sstevel@tonic-gate * and pututline functions are actually wrappers around the
380Sstevel@tonic-gate * equivalent function operating on utmpx-like files.
390Sstevel@tonic-gate */
400Sstevel@tonic-gate
416812Sraf #include "lint.h"
420Sstevel@tonic-gate #include <stdio.h>
430Sstevel@tonic-gate #include <sys/param.h>
440Sstevel@tonic-gate #include <sys/types.h>
450Sstevel@tonic-gate #include <sys/stat.h>
460Sstevel@tonic-gate #include <utmpx.h>
470Sstevel@tonic-gate #include <errno.h>
480Sstevel@tonic-gate #include <fcntl.h>
490Sstevel@tonic-gate #include <string.h>
500Sstevel@tonic-gate #include <strings.h>
510Sstevel@tonic-gate #include <stdlib.h>
520Sstevel@tonic-gate #include <unistd.h>
530Sstevel@tonic-gate #include <ctype.h>
540Sstevel@tonic-gate #include <utime.h>
550Sstevel@tonic-gate #include <sys/wait.h>
560Sstevel@tonic-gate
570Sstevel@tonic-gate #define IDLEN 4 /* length of id field in utmp */
580Sstevel@tonic-gate #define SC_WILDC 0xff /* wild char for utmp ids */
590Sstevel@tonic-gate #define MAXVAL 255 /* max value for an id 'character' */
600Sstevel@tonic-gate
610Sstevel@tonic-gate #ifdef ut_time
620Sstevel@tonic-gate #undef ut_time
630Sstevel@tonic-gate #endif
640Sstevel@tonic-gate
650Sstevel@tonic-gate static void utmp_frec2api(const struct futmp *, struct utmp *);
660Sstevel@tonic-gate static void utmp_api2frec(const struct utmp *, struct futmp *);
670Sstevel@tonic-gate struct utmp *_compat_getutent(void);
680Sstevel@tonic-gate struct utmp *_compat_getutid(const struct utmp *);
690Sstevel@tonic-gate struct utmp *_compat_getutline(const struct utmp *);
700Sstevel@tonic-gate struct utmp *_compat_pututline(const struct utmp *);
710Sstevel@tonic-gate void _compat_setutent(void);
720Sstevel@tonic-gate void _compat_endutent(void);
730Sstevel@tonic-gate void _compat_updwtmp(const char *, struct utmp *);
740Sstevel@tonic-gate struct utmp *_compat_makeut(struct utmp *);
750Sstevel@tonic-gate struct utmp *_compat_modut(struct utmp *);
760Sstevel@tonic-gate
770Sstevel@tonic-gate static void unlockut(void);
780Sstevel@tonic-gate static int idcmp(const char *, const char *);
790Sstevel@tonic-gate static int allocid(char *, unsigned char *);
800Sstevel@tonic-gate static int lockut(void);
810Sstevel@tonic-gate
820Sstevel@tonic-gate
830Sstevel@tonic-gate static int fd = -1; /* File descriptor for the utmp file. */
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * name of the current utmp-like file - set by utmpname (getutx.c)
860Sstevel@tonic-gate * only if running in backward compatibility mode
87*7767SJohn.Beck@Sun.COM * We don't modify this, but we can't declare it const or lint will freak.
880Sstevel@tonic-gate */
89*7767SJohn.Beck@Sun.COM extern char _compat_utmpfile[];
900Sstevel@tonic-gate
910Sstevel@tonic-gate #ifdef ERRDEBUG
920Sstevel@tonic-gate static long loc_utmp; /* Where in "utmp" the current "ubuf" was found. */
930Sstevel@tonic-gate #endif
940Sstevel@tonic-gate
950Sstevel@tonic-gate static struct futmp fubuf; /* Copy of last entry read in. */
960Sstevel@tonic-gate static struct utmp ubuf; /* Last entry returned to client */
970Sstevel@tonic-gate
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate * In the 64-bit world, the utmp data structure grows because of
1000Sstevel@tonic-gate * the ut_time field (a time_t) at the end of it.
1010Sstevel@tonic-gate */
1020Sstevel@tonic-gate static void
utmp_frec2api(const struct futmp * src,struct utmp * dst)1030Sstevel@tonic-gate utmp_frec2api(const struct futmp *src, struct utmp *dst)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate if (src == NULL)
1060Sstevel@tonic-gate return;
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate (void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
1090Sstevel@tonic-gate (void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
1100Sstevel@tonic-gate (void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
1110Sstevel@tonic-gate dst->ut_pid = src->ut_pid;
1120Sstevel@tonic-gate dst->ut_type = src->ut_type;
1130Sstevel@tonic-gate dst->ut_exit.e_termination = src->ut_exit.e_termination;
1140Sstevel@tonic-gate dst->ut_exit.e_exit = src->ut_exit.e_exit;
1150Sstevel@tonic-gate dst->ut_time = (time_t)src->ut_time;
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate static void
utmp_api2frec(const struct utmp * src,struct futmp * dst)1190Sstevel@tonic-gate utmp_api2frec(const struct utmp *src, struct futmp *dst)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate if (src == NULL)
1220Sstevel@tonic-gate return;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate (void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
1250Sstevel@tonic-gate (void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
1260Sstevel@tonic-gate (void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
1270Sstevel@tonic-gate dst->ut_pid = src->ut_pid;
1280Sstevel@tonic-gate dst->ut_type = src->ut_type;
1290Sstevel@tonic-gate dst->ut_exit.e_termination = src->ut_exit.e_termination;
1300Sstevel@tonic-gate dst->ut_exit.e_exit = src->ut_exit.e_exit;
1310Sstevel@tonic-gate dst->ut_time = (time32_t)src->ut_time;
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * "getutent_frec" gets the raw version of the next entry in the utmp file.
1360Sstevel@tonic-gate */
1370Sstevel@tonic-gate static struct futmp *
getutent_frec(void)1380Sstevel@tonic-gate getutent_frec(void)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate * If the "utmp" file is not open, attempt to open it for
1420Sstevel@tonic-gate * reading. If there is no file, attempt to create one. If
1430Sstevel@tonic-gate * both attempts fail, return NULL. If the file exists, but
1440Sstevel@tonic-gate * isn't readable and writeable, do not attempt to create.
1450Sstevel@tonic-gate */
1460Sstevel@tonic-gate if (fd < 0) {
1470Sstevel@tonic-gate if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0) {
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate * If the open failed for permissions, try opening
1510Sstevel@tonic-gate * it only for reading. All "pututline()" later
1520Sstevel@tonic-gate * will fail the writes.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate if ((fd = open(_compat_utmpfile, O_RDONLY)) < 0)
1550Sstevel@tonic-gate return (NULL);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate /* Try to read in the next entry from the utmp file. */
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate if (read(fd, &fubuf, sizeof (fubuf)) != sizeof (fubuf)) {
1620Sstevel@tonic-gate bzero(&fubuf, sizeof (fubuf));
1630Sstevel@tonic-gate return (NULL);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate /* Save the location in the file where this entry was found. */
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate (void) lseek(fd, 0L, 1);
1690Sstevel@tonic-gate return (&fubuf);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate * "_compat_getutent" gets the next entry in the utmp file.
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate struct utmp *
_compat_getutent(void)1760Sstevel@tonic-gate _compat_getutent(void)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate struct futmp *futp;
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate futp = getutent_frec();
1810Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
1820Sstevel@tonic-gate if (futp == NULL)
1830Sstevel@tonic-gate return (NULL);
1840Sstevel@tonic-gate return (&ubuf);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate * "_compat_getutid" finds the specified entry in the utmp file. If
1890Sstevel@tonic-gate * it can't find it, it returns NULL.
1900Sstevel@tonic-gate */
1910Sstevel@tonic-gate struct utmp *
_compat_getutid(const struct utmp * entry)1920Sstevel@tonic-gate _compat_getutid(const struct utmp *entry)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate short type;
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate utmp_api2frec(&ubuf, &fubuf);
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * Start looking for entry. Look in our current buffer before
2000Sstevel@tonic-gate * reading in new entries.
2010Sstevel@tonic-gate */
2020Sstevel@tonic-gate do {
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate * If there is no entry in "ubuf", skip to the read.
2050Sstevel@tonic-gate */
2060Sstevel@tonic-gate if (fubuf.ut_type != EMPTY) {
2070Sstevel@tonic-gate switch (entry->ut_type) {
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate * Do not look for an entry if the user sent
2110Sstevel@tonic-gate * us an EMPTY entry.
2120Sstevel@tonic-gate */
2130Sstevel@tonic-gate case EMPTY:
2140Sstevel@tonic-gate return (NULL);
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate * For RUN_LVL, BOOT_TIME, DOWN_TIME,
2180Sstevel@tonic-gate * OLD_TIME, and NEW_TIME entries, only the
2190Sstevel@tonic-gate * types have to match. If they do, return
2200Sstevel@tonic-gate * the address of internal buffer.
2210Sstevel@tonic-gate */
2220Sstevel@tonic-gate case RUN_LVL:
2230Sstevel@tonic-gate case BOOT_TIME:
2240Sstevel@tonic-gate case DOWN_TIME:
2250Sstevel@tonic-gate case OLD_TIME:
2260Sstevel@tonic-gate case NEW_TIME:
2270Sstevel@tonic-gate if (entry->ut_type == fubuf.ut_type) {
2280Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
2290Sstevel@tonic-gate return (&ubuf);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate break;
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate * For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS,
2350Sstevel@tonic-gate * and DEAD_PROCESS the type of the entry in "fubuf",
2360Sstevel@tonic-gate * must be one of the above and id's must match.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate case INIT_PROCESS:
2390Sstevel@tonic-gate case LOGIN_PROCESS:
2400Sstevel@tonic-gate case USER_PROCESS:
2410Sstevel@tonic-gate case DEAD_PROCESS:
2420Sstevel@tonic-gate if (((type = fubuf.ut_type) == INIT_PROCESS ||
2430Sstevel@tonic-gate type == LOGIN_PROCESS ||
2440Sstevel@tonic-gate type == USER_PROCESS ||
2450Sstevel@tonic-gate type == DEAD_PROCESS) &&
2460Sstevel@tonic-gate fubuf.ut_id[0] == entry->ut_id[0] &&
2470Sstevel@tonic-gate fubuf.ut_id[1] == entry->ut_id[1] &&
2480Sstevel@tonic-gate fubuf.ut_id[2] == entry->ut_id[2] &&
2490Sstevel@tonic-gate fubuf.ut_id[3] == entry->ut_id[3]) {
2500Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
2510Sstevel@tonic-gate return (&ubuf);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate break;
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate /* Do not search for illegal types of entry. */
2560Sstevel@tonic-gate default:
2570Sstevel@tonic-gate return (NULL);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate } while (getutent_frec() != NULL);
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /* the proper entry wasn't found. */
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
2650Sstevel@tonic-gate return (NULL);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate * "_compat_getutline" searches the "utmp" file for a LOGIN_PROCESS or
2700Sstevel@tonic-gate * USER_PROCESS with the same "line" as the specified "entry".
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate struct utmp *
_compat_getutline(const struct utmp * entry)2730Sstevel@tonic-gate _compat_getutline(const struct utmp *entry)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate utmp_api2frec(&ubuf, &fubuf);
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate do {
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * If the current entry is the one we are interested in,
2800Sstevel@tonic-gate * return a pointer to it.
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate if (fubuf.ut_type != EMPTY &&
2830Sstevel@tonic-gate (fubuf.ut_type == LOGIN_PROCESS ||
2840Sstevel@tonic-gate fubuf.ut_type == USER_PROCESS) &&
2850Sstevel@tonic-gate strncmp(&entry->ut_line[0], &fubuf.ut_line[0],
2860Sstevel@tonic-gate sizeof (fubuf.ut_line)) == 0) {
2870Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
2880Sstevel@tonic-gate return (&ubuf);
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate } while (getutent_frec() != NULL);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
2930Sstevel@tonic-gate return (NULL);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate * "_compat_pututline" writes the structure sent into the utmp file
2980Sstevel@tonic-gate * If there is already an entry with the same id, then it is
2990Sstevel@tonic-gate * overwritten, otherwise a new entry is made at the end of the
3000Sstevel@tonic-gate * utmp file.
3010Sstevel@tonic-gate */
3020Sstevel@tonic-gate struct utmp *
_compat_pututline(const struct utmp * entry)3030Sstevel@tonic-gate _compat_pututline(const struct utmp *entry)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate int fc;
3060Sstevel@tonic-gate struct utmp *answer;
3070Sstevel@tonic-gate struct utmp tmpbuf;
3080Sstevel@tonic-gate struct futmp ftmpbuf;
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate * Copy the user supplied entry into our temporary buffer to
3120Sstevel@tonic-gate * avoid the possibility that the user is actually passing us
3130Sstevel@tonic-gate * the address of "ubuf".
3140Sstevel@tonic-gate */
3150Sstevel@tonic-gate tmpbuf = *entry;
3160Sstevel@tonic-gate utmp_api2frec(entry, &ftmpbuf);
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate (void) getutent_frec();
3190Sstevel@tonic-gate if (fd < 0) {
3200Sstevel@tonic-gate #ifdef ERRDEBUG
3210Sstevel@tonic-gate gdebug("pututline: Unable to create utmp file.\n");
3220Sstevel@tonic-gate #endif
3230Sstevel@tonic-gate return (NULL);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /* Make sure file is writable */
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if ((fc = fcntl(fd, F_GETFL, NULL)) == -1 || (fc & O_RDWR) != O_RDWR)
3290Sstevel@tonic-gate return (NULL);
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /*
3320Sstevel@tonic-gate * Find the proper entry in the utmp file. Start at the current
3330Sstevel@tonic-gate * location. If it isn't found from here to the end of the
3340Sstevel@tonic-gate * file, then reset to the beginning of the file and try again.
3350Sstevel@tonic-gate * If it still isn't found, then write a new entry at the end of
3360Sstevel@tonic-gate * the file. (Making sure the location is an integral number of
3370Sstevel@tonic-gate * utmp structures into the file incase the file is scribbled.)
3380Sstevel@tonic-gate */
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate if (_compat_getutid(&tmpbuf) == NULL) {
3410Sstevel@tonic-gate #ifdef ERRDEBUG
3420Sstevel@tonic-gate gdebug("1st getutid() failed. fd: %d", fd);
3430Sstevel@tonic-gate #endif
3440Sstevel@tonic-gate _compat_setutent();
3450Sstevel@tonic-gate if (_compat_getutid(&tmpbuf) == NULL) {
3460Sstevel@tonic-gate #ifdef ERRDEBUG
3470Sstevel@tonic-gate loc_utmp = lseek(fd, 0L, 1);
3480Sstevel@tonic-gate gdebug("2nd getutid() failed. fd: %d loc_utmp: %ld\n",
3490Sstevel@tonic-gate fd, loc_utmp);
3500Sstevel@tonic-gate #endif
3510Sstevel@tonic-gate (void) fcntl(fd, F_SETFL, fc | O_APPEND);
3520Sstevel@tonic-gate } else
3530Sstevel@tonic-gate (void) lseek(fd, -(long)sizeof (struct futmp), 1);
3540Sstevel@tonic-gate } else
3550Sstevel@tonic-gate (void) lseek(fd, -(long)sizeof (struct futmp), 1);
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate * Write out the user supplied structure. If the write fails,
3590Sstevel@tonic-gate * then the user probably doesn't have permission to write the
3600Sstevel@tonic-gate * utmp file.
3610Sstevel@tonic-gate */
3620Sstevel@tonic-gate if (write(fd, &ftmpbuf, sizeof (ftmpbuf)) != sizeof (ftmpbuf)) {
3630Sstevel@tonic-gate #ifdef ERRDEBUG
3640Sstevel@tonic-gate gdebug("pututline failed: write-%d\n", errno);
3650Sstevel@tonic-gate #endif
3660Sstevel@tonic-gate answer = NULL;
3670Sstevel@tonic-gate } else {
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate * Copy the new user structure into ubuf so that it will
3700Sstevel@tonic-gate * be up to date in the future.
3710Sstevel@tonic-gate */
3720Sstevel@tonic-gate fubuf = ftmpbuf;
3730Sstevel@tonic-gate utmp_frec2api(&fubuf, &ubuf);
3740Sstevel@tonic-gate answer = &ubuf;
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate #ifdef ERRDEBUG
3770Sstevel@tonic-gate gdebug("id: %c%c loc: %ld\n", fubuf.ut_id[0],
3780Sstevel@tonic-gate fubuf.ut_id[1], fubuf.ut_id[2], fubuf.ut_id[3],
3790Sstevel@tonic-gate loc_utmp);
3800Sstevel@tonic-gate #endif
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate (void) fcntl(fd, F_SETFL, fc);
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate return (answer);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * "_compat_setutent" just resets the utmp file back to the beginning.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate void
_compat_setutent(void)3920Sstevel@tonic-gate _compat_setutent(void)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate if (fd != -1)
3950Sstevel@tonic-gate (void) lseek(fd, 0L, 0);
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * Zero the stored copy of the last entry read, since we are
3990Sstevel@tonic-gate * resetting to the beginning of the file.
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate bzero(&ubuf, sizeof (ubuf));
4020Sstevel@tonic-gate bzero(&fubuf, sizeof (fubuf));
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate * "_compat_endutent" closes the utmp file.
4070Sstevel@tonic-gate */
4080Sstevel@tonic-gate void
_compat_endutent(void)4090Sstevel@tonic-gate _compat_endutent(void)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate if (fd != -1)
4120Sstevel@tonic-gate (void) close(fd);
4130Sstevel@tonic-gate fd = -1;
4140Sstevel@tonic-gate bzero(&ubuf, sizeof (ubuf));
4150Sstevel@tonic-gate bzero(&fubuf, sizeof (fubuf));
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * If one of wtmp and wtmpx files exist, create the other, and the record.
4210Sstevel@tonic-gate * If they both exist add the record.
4220Sstevel@tonic-gate */
4230Sstevel@tonic-gate void
_compat_updwtmp(const char * file,struct utmp * ut)4240Sstevel@tonic-gate _compat_updwtmp(const char *file, struct utmp *ut)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate struct futmp fut;
4270Sstevel@tonic-gate int fd;
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate fd = open(file, O_WRONLY | O_APPEND);
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate if (fd < 0) {
4330Sstevel@tonic-gate if ((fd = open(file, O_WRONLY|O_CREAT, 0644)) < 0)
4340Sstevel@tonic-gate return;
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate (void) lseek(fd, 0, 2);
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate utmp_api2frec(ut, &fut);
4400Sstevel@tonic-gate (void) write(fd, &fut, sizeof (fut));
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate (void) close(fd);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * makeut - create a utmp entry, recycling an id if a wild card is
4490Sstevel@tonic-gate * specified.
4500Sstevel@tonic-gate *
4510Sstevel@tonic-gate * args: utmp - point to utmp structure to be created
4520Sstevel@tonic-gate */
4530Sstevel@tonic-gate struct utmp *
_compat_makeut(struct utmp * utmp)4540Sstevel@tonic-gate _compat_makeut(struct utmp *utmp)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate int i;
4570Sstevel@tonic-gate struct utmp *utp; /* "current" utmp entry being examined */
4580Sstevel@tonic-gate int wild; /* flag, true iff wild card char seen */
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate /* the last id we matched that was NOT a dead proc */
4610Sstevel@tonic-gate unsigned char saveid[IDLEN];
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate wild = 0;
4640Sstevel@tonic-gate for (i = 0; i < IDLEN; i++)
4650Sstevel@tonic-gate if ((unsigned char)utmp->ut_id[i] == SC_WILDC) {
4660Sstevel@tonic-gate wild = 1;
4670Sstevel@tonic-gate break;
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate if (wild) {
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate * try to lock the utmp file, only needed if we're
4740Sstevel@tonic-gate * doing wildcard matching
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate if (lockut())
4780Sstevel@tonic-gate return (0);
4790Sstevel@tonic-gate _compat_setutent();
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate /* find the first alphanumeric character */
4820Sstevel@tonic-gate for (i = 0; i < MAXVAL; ++i)
4830Sstevel@tonic-gate if (isalnum(i))
4840Sstevel@tonic-gate break;
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate (void) memset(saveid, i, IDLEN);
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate while ((utp = _compat_getutent()) != 0) {
4890Sstevel@tonic-gate if (idcmp(utmp->ut_id, utp->ut_id))
4900Sstevel@tonic-gate continue;
4910Sstevel@tonic-gate if (utp->ut_type == DEAD_PROCESS)
4920Sstevel@tonic-gate break;
4930Sstevel@tonic-gate (void) memcpy(saveid, utp->ut_id, IDLEN);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate if (utp) {
4970Sstevel@tonic-gate /*
4980Sstevel@tonic-gate * found an unused entry, reuse it
4990Sstevel@tonic-gate */
5000Sstevel@tonic-gate (void) memcpy(utmp->ut_id, utp->ut_id, IDLEN);
5010Sstevel@tonic-gate utp = _compat_pututline(utmp);
5020Sstevel@tonic-gate if (utp)
5030Sstevel@tonic-gate _compat_updwtmp(WTMP_FILE, utp);
5040Sstevel@tonic-gate _compat_endutent();
5050Sstevel@tonic-gate unlockut();
5060Sstevel@tonic-gate return (utp);
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate } else {
5090Sstevel@tonic-gate /*
5100Sstevel@tonic-gate * nothing available, try to allocate an id
5110Sstevel@tonic-gate */
5120Sstevel@tonic-gate if (allocid(utmp->ut_id, saveid)) {
5130Sstevel@tonic-gate _compat_endutent();
5140Sstevel@tonic-gate unlockut();
5150Sstevel@tonic-gate return (NULL);
5160Sstevel@tonic-gate } else {
5170Sstevel@tonic-gate utp = _compat_pututline(utmp);
5180Sstevel@tonic-gate if (utp)
5190Sstevel@tonic-gate _compat_updwtmp(WTMP_FILE, utp);
5200Sstevel@tonic-gate _compat_endutent();
5210Sstevel@tonic-gate unlockut();
5220Sstevel@tonic-gate return (utp);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate } else {
5260Sstevel@tonic-gate utp = _compat_pututline(utmp);
5270Sstevel@tonic-gate if (utp)
5280Sstevel@tonic-gate _compat_updwtmp(WTMP_FILE, utp);
5290Sstevel@tonic-gate _compat_endutent();
5300Sstevel@tonic-gate return (utp);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /*
5360Sstevel@tonic-gate * _compat_modut - modify a utmp entry.
5370Sstevel@tonic-gate *
5380Sstevel@tonic-gate * args: utmp - point to utmp structure to be created
5390Sstevel@tonic-gate */
5400Sstevel@tonic-gate struct utmp *
_compat_modut(struct utmp * utp)5410Sstevel@tonic-gate _compat_modut(struct utmp *utp)
5420Sstevel@tonic-gate {
5430Sstevel@tonic-gate int i; /* scratch variable */
5440Sstevel@tonic-gate struct utmp utmp; /* holding area */
5450Sstevel@tonic-gate struct utmp *ucp = &utmp; /* and a pointer to it */
5460Sstevel@tonic-gate struct utmp *up; /* "current" utmp entry being examined */
5470Sstevel@tonic-gate struct futmp *fup;
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate for (i = 0; i < IDLEN; ++i)
5500Sstevel@tonic-gate if ((unsigned char)utp->ut_id[i] == SC_WILDC)
5510Sstevel@tonic-gate return (0);
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate /* copy the supplied utmp structure someplace safe */
5540Sstevel@tonic-gate utmp = *utp;
5550Sstevel@tonic-gate _compat_setutent();
5560Sstevel@tonic-gate while (fup = getutent_frec()) {
5570Sstevel@tonic-gate if (idcmp(ucp->ut_id, fup->ut_id))
5580Sstevel@tonic-gate continue;
5590Sstevel@tonic-gate break;
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate up = _compat_pututline(ucp);
5620Sstevel@tonic-gate if (up)
5630Sstevel@tonic-gate _compat_updwtmp(WTMP_FILE, up);
5640Sstevel@tonic-gate _compat_endutent();
5650Sstevel@tonic-gate return (up);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate * idcmp - compare two id strings, return 0 if same, non-zero if not *
5720Sstevel@tonic-gate * args: s1 - first id string
5730Sstevel@tonic-gate * s2 - second id string
5740Sstevel@tonic-gate */
5750Sstevel@tonic-gate static int
idcmp(const char * s1,const char * s2)5760Sstevel@tonic-gate idcmp(const char *s1, const char *s2)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate int i;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate for (i = 0; i < IDLEN; ++i)
5810Sstevel@tonic-gate if ((unsigned char)*s1 != SC_WILDC && (*s1++ != *s2++))
5820Sstevel@tonic-gate return (-1);
5830Sstevel@tonic-gate return (0);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate /*
5880Sstevel@tonic-gate * allocid - allocate an unused id for utmp, either by recycling a
5890Sstevel@tonic-gate * DEAD_PROCESS entry or creating a new one. This routine only
5900Sstevel@tonic-gate * gets called if a wild card character was specified.
5910Sstevel@tonic-gate *
5920Sstevel@tonic-gate * args: srcid - pattern for new id
5930Sstevel@tonic-gate * saveid - last id matching pattern for a non-dead process
5940Sstevel@tonic-gate */
5950Sstevel@tonic-gate static int
allocid(char * srcid,unsigned char * saveid)5960Sstevel@tonic-gate allocid(char *srcid, unsigned char *saveid)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate int i; /* scratch variable */
5990Sstevel@tonic-gate int changed; /* flag to indicate that a new id has been generated */
6000Sstevel@tonic-gate char copyid[IDLEN]; /* work area */
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate (void) memcpy(copyid, srcid, IDLEN);
6030Sstevel@tonic-gate changed = 0;
6040Sstevel@tonic-gate for (i = 0; i < IDLEN; ++i) {
6050Sstevel@tonic-gate /*
6060Sstevel@tonic-gate * if this character isn't wild, it'll
6070Sstevel@tonic-gate * be part of the generated id
6080Sstevel@tonic-gate */
6090Sstevel@tonic-gate if ((unsigned char) copyid[i] != SC_WILDC)
6100Sstevel@tonic-gate continue;
6110Sstevel@tonic-gate /*
6120Sstevel@tonic-gate * it's a wild character, retrieve the
6130Sstevel@tonic-gate * character from the saved id
6140Sstevel@tonic-gate */
6150Sstevel@tonic-gate copyid[i] = saveid[i];
6160Sstevel@tonic-gate /*
6170Sstevel@tonic-gate * if we haven't changed anything yet,
6180Sstevel@tonic-gate * try to find a new char to use
6190Sstevel@tonic-gate */
6200Sstevel@tonic-gate if (!changed && (saveid[i] < MAXVAL)) {
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate /*
6230Sstevel@tonic-gate * Note: this algorithm is taking the "last matched" id and trying to make
6240Sstevel@tonic-gate * a 1 character change to it to create a new one. Rather than special-case
6250Sstevel@tonic-gate * the first time (when no perturbation is really necessary), just don't
6260Sstevel@tonic-gate * allocate the first valid id.
6270Sstevel@tonic-gate */
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate while (++saveid[i] < MAXVAL) {
6300Sstevel@tonic-gate /* make sure new char is alphanumeric */
6310Sstevel@tonic-gate if (isalnum(saveid[i])) {
6320Sstevel@tonic-gate copyid[i] = saveid[i];
6330Sstevel@tonic-gate changed = 1;
6340Sstevel@tonic-gate break;
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate if (!changed) {
6390Sstevel@tonic-gate /*
6400Sstevel@tonic-gate * Then 'reset' the current count at
6410Sstevel@tonic-gate * this position to it's lowest valid
6420Sstevel@tonic-gate * value, and propagate the carry to
6430Sstevel@tonic-gate * the next wild-card slot
6440Sstevel@tonic-gate *
6450Sstevel@tonic-gate * See 1113208.
6460Sstevel@tonic-gate */
6470Sstevel@tonic-gate saveid[i] = 0;
6480Sstevel@tonic-gate while (!isalnum(saveid[i]))
6490Sstevel@tonic-gate saveid[i]++;
6500Sstevel@tonic-gate copyid[i] = ++saveid[i];
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate /* changed is true if we were successful in allocating an id */
6550Sstevel@tonic-gate if (changed) {
6560Sstevel@tonic-gate (void) memcpy(srcid, copyid, IDLEN);
6570Sstevel@tonic-gate return (0);
6580Sstevel@tonic-gate } else
6590Sstevel@tonic-gate return (-1);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate * lockut - lock utmp file
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate static int
lockut(void)6670Sstevel@tonic-gate lockut(void)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0)
6700Sstevel@tonic-gate return (-1);
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate if (lockf(fd, F_LOCK, 0) < 0) {
6730Sstevel@tonic-gate (void) close(fd);
6740Sstevel@tonic-gate fd = -1;
6750Sstevel@tonic-gate return (-1);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate return (0);
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate /*
6820Sstevel@tonic-gate * unlockut - unlock utmp file
6830Sstevel@tonic-gate */
6840Sstevel@tonic-gate static void
unlockut(void)6850Sstevel@tonic-gate unlockut(void)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate (void) lockf(fd, F_ULOCK, 0);
6880Sstevel@tonic-gate (void) close(fd);
6890Sstevel@tonic-gate fd = -1;
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate #ifdef ERRDEBUG
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate #include <stdarg.h>
6970Sstevel@tonic-gate #include <stdio.h>
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate static void
gdebug(const char * fmt,...)7000Sstevel@tonic-gate gdebug(const char *fmt, ...)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate FILE *fp;
7030Sstevel@tonic-gate int errnum;
7040Sstevel@tonic-gate va_list ap;
7050Sstevel@tonic-gate
7061914Scasper if ((fp = fopen("/etc/dbg.getut", "a+F")) == NULL)
7070Sstevel@tonic-gate return;
7080Sstevel@tonic-gate va_start(ap, fmt);
7090Sstevel@tonic-gate (void) vfprintf(fp, fmt, ap);
7100Sstevel@tonic-gate va_end(ap);
7110Sstevel@tonic-gate (void) fclose(fp);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate #endif
714