xref: /onnv-gate/usr/src/lib/libc/port/gen/getut.c (revision 7767:905db6a104b6)
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