xref: /illumos-gate/usr/src/lib/libc/port/gen/getut.c (revision 00ae5933)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
28*00ae5933SToomas Soome /*	  All Rights Reserved	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Compatibility routines to read and write alternate
327c478bd9Sstevel@tonic-gate  * utmp-like files.  These routines are only used in
337c478bd9Sstevel@tonic-gate  * the case where utmpname() is used to change to a file
347c478bd9Sstevel@tonic-gate  * other than /var/adm/utmp or /var/adm/wtmp.  In this case,
357c478bd9Sstevel@tonic-gate  * we assume that someone really wants to read old utmp-format
367c478bd9Sstevel@tonic-gate  * files.  Otherwise, the getutent, setutent, getutid, setutline,
377c478bd9Sstevel@tonic-gate  * and pututline functions are actually wrappers around the
387c478bd9Sstevel@tonic-gate  * equivalent function operating on utmpx-like files.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417257d1b4Sraf #include "lint.h"
427c478bd9Sstevel@tonic-gate #include <stdio.h>
437c478bd9Sstevel@tonic-gate #include <sys/param.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <utmpx.h>
477c478bd9Sstevel@tonic-gate #include <errno.h>
487c478bd9Sstevel@tonic-gate #include <fcntl.h>
497c478bd9Sstevel@tonic-gate #include <string.h>
507c478bd9Sstevel@tonic-gate #include <strings.h>
517c478bd9Sstevel@tonic-gate #include <stdlib.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
537c478bd9Sstevel@tonic-gate #include <ctype.h>
547c478bd9Sstevel@tonic-gate #include <utime.h>
557c478bd9Sstevel@tonic-gate #include <sys/wait.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	IDLEN	4	/* length of id field in utmp */
587c478bd9Sstevel@tonic-gate #define	SC_WILDC	0xff	/* wild char for utmp ids */
597c478bd9Sstevel@tonic-gate #define	MAXVAL	255	/* max value for an id 'character' */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #ifdef ut_time
627c478bd9Sstevel@tonic-gate #undef ut_time
637c478bd9Sstevel@tonic-gate #endif
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void	utmp_frec2api(const struct futmp *, struct utmp *);
667c478bd9Sstevel@tonic-gate static void	utmp_api2frec(const struct utmp *, struct futmp *);
67*00ae5933SToomas Soome struct utmp	*_compat_getutent(void);
687c478bd9Sstevel@tonic-gate struct utmp	*_compat_getutid(const struct utmp *);
697c478bd9Sstevel@tonic-gate struct utmp	*_compat_getutline(const struct utmp *);
707c478bd9Sstevel@tonic-gate struct utmp	*_compat_pututline(const struct utmp *);
717c478bd9Sstevel@tonic-gate void		_compat_setutent(void);
727c478bd9Sstevel@tonic-gate void		_compat_endutent(void);
737c478bd9Sstevel@tonic-gate void		_compat_updwtmp(const char *, struct utmp *);
747c478bd9Sstevel@tonic-gate struct utmp	*_compat_makeut(struct utmp *);
757c478bd9Sstevel@tonic-gate struct utmp	*_compat_modut(struct utmp *);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static void	unlockut(void);
787c478bd9Sstevel@tonic-gate static int	idcmp(const char *, const char *);
797c478bd9Sstevel@tonic-gate static int	allocid(char *, unsigned char *);
807c478bd9Sstevel@tonic-gate static int	lockut(void);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate static int fd = -1;	/* File descriptor for the utmp file. */
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * name of the current utmp-like file - set by utmpname (getutx.c)
867c478bd9Sstevel@tonic-gate  * only if running in backward compatibility mode
87e8ed0869SJohn Beck  * We don't modify this, but we can't declare it const or lint will freak.
887c478bd9Sstevel@tonic-gate  */
89e8ed0869SJohn Beck extern char _compat_utmpfile[];
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #ifdef ERRDEBUG
927c478bd9Sstevel@tonic-gate static long loc_utmp;	/* Where in "utmp" the current "ubuf" was found. */
937c478bd9Sstevel@tonic-gate #endif
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static struct futmp fubuf;	/* Copy of last entry read in. */
967c478bd9Sstevel@tonic-gate static struct utmp ubuf;	/* Last entry returned to client */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * In the 64-bit world, the utmp data structure grows because of
1007c478bd9Sstevel@tonic-gate  * the ut_time field (a time_t) at the end of it.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate static void
utmp_frec2api(const struct futmp * src,struct utmp * dst)1037c478bd9Sstevel@tonic-gate utmp_frec2api(const struct futmp *src, struct utmp *dst)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	if (src == NULL)
1067c478bd9Sstevel@tonic-gate 		return;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
1097c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
1107c478bd9Sstevel@tonic-gate 	(void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
1117c478bd9Sstevel@tonic-gate 	dst->ut_pid = src->ut_pid;
1127c478bd9Sstevel@tonic-gate 	dst->ut_type = src->ut_type;
1137c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_termination = src->ut_exit.e_termination;
1147c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_exit = src->ut_exit.e_exit;
1157c478bd9Sstevel@tonic-gate 	dst->ut_time = (time_t)src->ut_time;
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static void
utmp_api2frec(const struct utmp * src,struct futmp * dst)1197c478bd9Sstevel@tonic-gate utmp_api2frec(const struct utmp *src, struct futmp *dst)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	if (src == NULL)
1227c478bd9Sstevel@tonic-gate 		return;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
1257c478bd9Sstevel@tonic-gate 	(void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
1267c478bd9Sstevel@tonic-gate 	(void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
1277c478bd9Sstevel@tonic-gate 	dst->ut_pid = src->ut_pid;
1287c478bd9Sstevel@tonic-gate 	dst->ut_type = src->ut_type;
1297c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_termination = src->ut_exit.e_termination;
1307c478bd9Sstevel@tonic-gate 	dst->ut_exit.e_exit = src->ut_exit.e_exit;
1317c478bd9Sstevel@tonic-gate 	dst->ut_time = (time32_t)src->ut_time;
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * "getutent_frec" gets the raw version of the next entry in the utmp file.
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate static struct futmp *
getutent_frec(void)1387c478bd9Sstevel@tonic-gate getutent_frec(void)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	/*
1417c478bd9Sstevel@tonic-gate 	 * If the "utmp" file is not open, attempt to open it for
1427c478bd9Sstevel@tonic-gate 	 * reading.  If there is no file, attempt to create one.  If
1437c478bd9Sstevel@tonic-gate 	 * both attempts fail, return NULL.  If the file exists, but
1447c478bd9Sstevel@tonic-gate 	 * isn't readable and writeable, do not attempt to create.
1457c478bd9Sstevel@tonic-gate 	 */
1467c478bd9Sstevel@tonic-gate 	if (fd < 0) {
1477c478bd9Sstevel@tonic-gate 		if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0) {
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 			/*
1507c478bd9Sstevel@tonic-gate 			 * If the open failed for permissions, try opening
1517c478bd9Sstevel@tonic-gate 			 * it only for reading.  All "pututline()" later
1527c478bd9Sstevel@tonic-gate 			 * will fail the writes.
1537c478bd9Sstevel@tonic-gate 			 */
1547c478bd9Sstevel@tonic-gate 			if ((fd = open(_compat_utmpfile, O_RDONLY)) < 0)
1557c478bd9Sstevel@tonic-gate 				return (NULL);
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* Try to read in the next entry from the utmp file.  */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if (read(fd, &fubuf, sizeof (fubuf)) != sizeof (fubuf)) {
1627c478bd9Sstevel@tonic-gate 		bzero(&fubuf, sizeof (fubuf));
1637c478bd9Sstevel@tonic-gate 		return (NULL);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* Save the location in the file where this entry was found. */
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	(void) lseek(fd, 0L, 1);
1697c478bd9Sstevel@tonic-gate 	return (&fubuf);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate  * "_compat_getutent" gets the next entry in the utmp file.
1747c478bd9Sstevel@tonic-gate  */
1757c478bd9Sstevel@tonic-gate struct utmp *
_compat_getutent(void)1767c478bd9Sstevel@tonic-gate _compat_getutent(void)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	struct futmp *futp;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	futp = getutent_frec();
1817c478bd9Sstevel@tonic-gate 	utmp_frec2api(&fubuf, &ubuf);
1827c478bd9Sstevel@tonic-gate 	if (futp == NULL)
1837c478bd9Sstevel@tonic-gate 		return (NULL);
1847c478bd9Sstevel@tonic-gate 	return (&ubuf);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /*
1887c478bd9Sstevel@tonic-gate  * "_compat_getutid" finds the specified entry in the utmp file.  If
1897c478bd9Sstevel@tonic-gate  * it can't find it, it returns NULL.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate struct utmp *
_compat_getutid(const struct utmp * entry)1927c478bd9Sstevel@tonic-gate _compat_getutid(const struct utmp *entry)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	short type;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	utmp_api2frec(&ubuf, &fubuf);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	/*
1997c478bd9Sstevel@tonic-gate 	 * Start looking for entry.  Look in our current buffer before
2007c478bd9Sstevel@tonic-gate 	 * reading in new entries.
2017c478bd9Sstevel@tonic-gate 	 */
2027c478bd9Sstevel@tonic-gate 	do {
2037c478bd9Sstevel@tonic-gate 		/*
2047c478bd9Sstevel@tonic-gate 		 * If there is no entry in "ubuf", skip to the read.
2057c478bd9Sstevel@tonic-gate 		 */
2067c478bd9Sstevel@tonic-gate 		if (fubuf.ut_type != EMPTY) {
2077c478bd9Sstevel@tonic-gate 			switch (entry->ut_type) {
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 			/*
2107c478bd9Sstevel@tonic-gate 			 * Do not look for an entry if the user sent
2117c478bd9Sstevel@tonic-gate 			 * us an EMPTY entry.
2127c478bd9Sstevel@tonic-gate 			 */
2137c478bd9Sstevel@tonic-gate 			case EMPTY:
2147c478bd9Sstevel@tonic-gate 				return (NULL);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 			/*
2177c478bd9Sstevel@tonic-gate 			 * For RUN_LVL, BOOT_TIME, DOWN_TIME,
2187c478bd9Sstevel@tonic-gate 			 * OLD_TIME, and NEW_TIME entries, only the
2197c478bd9Sstevel@tonic-gate 			 * types have to match.  If they do, return
2207c478bd9Sstevel@tonic-gate 			 * the address of internal buffer.
2217c478bd9Sstevel@tonic-gate 			 */
2227c478bd9Sstevel@tonic-gate 			case RUN_LVL:
2237c478bd9Sstevel@tonic-gate 			case BOOT_TIME:
2247c478bd9Sstevel@tonic-gate 			case DOWN_TIME:
2257c478bd9Sstevel@tonic-gate 			case OLD_TIME:
2267c478bd9Sstevel@tonic-gate 			case NEW_TIME:
2277c478bd9Sstevel@tonic-gate 				if (entry->ut_type == fubuf.ut_type) {
2287c478bd9Sstevel@tonic-gate 					utmp_frec2api(&fubuf, &ubuf);
2297c478bd9Sstevel@tonic-gate 					return (&ubuf);
2307c478bd9Sstevel@tonic-gate 				}
2317c478bd9Sstevel@tonic-gate 				break;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 			/*
2347c478bd9Sstevel@tonic-gate 			 * For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS,
2357c478bd9Sstevel@tonic-gate 			 * and DEAD_PROCESS the type of the entry in "fubuf",
2367c478bd9Sstevel@tonic-gate 			 * must be one of the above and id's must match.
2377c478bd9Sstevel@tonic-gate 			 */
2387c478bd9Sstevel@tonic-gate 			case INIT_PROCESS:
2397c478bd9Sstevel@tonic-gate 			case LOGIN_PROCESS:
2407c478bd9Sstevel@tonic-gate 			case USER_PROCESS:
2417c478bd9Sstevel@tonic-gate 			case DEAD_PROCESS:
2427c478bd9Sstevel@tonic-gate 				if (((type = fubuf.ut_type) == INIT_PROCESS ||
2437c478bd9Sstevel@tonic-gate 				    type == LOGIN_PROCESS ||
2447c478bd9Sstevel@tonic-gate 				    type == USER_PROCESS ||
2457c478bd9Sstevel@tonic-gate 				    type == DEAD_PROCESS) &&
2467c478bd9Sstevel@tonic-gate 				    fubuf.ut_id[0] == entry->ut_id[0] &&
2477c478bd9Sstevel@tonic-gate 				    fubuf.ut_id[1] == entry->ut_id[1] &&
2487c478bd9Sstevel@tonic-gate 				    fubuf.ut_id[2] == entry->ut_id[2] &&
2497c478bd9Sstevel@tonic-gate 				    fubuf.ut_id[3] == entry->ut_id[3]) {
2507c478bd9Sstevel@tonic-gate 					utmp_frec2api(&fubuf, &ubuf);
2517c478bd9Sstevel@tonic-gate 					return (&ubuf);
2527c478bd9Sstevel@tonic-gate 				}
2537c478bd9Sstevel@tonic-gate 				break;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 			/* Do not search for illegal types of entry. */
2567c478bd9Sstevel@tonic-gate 			default:
2577c478bd9Sstevel@tonic-gate 				return (NULL);
2587c478bd9Sstevel@tonic-gate 			}
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 	} while (getutent_frec() != NULL);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/* the proper entry wasn't found. */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	utmp_frec2api(&fubuf, &ubuf);
2657c478bd9Sstevel@tonic-gate 	return (NULL);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate  * "_compat_getutline" searches the "utmp" file for a LOGIN_PROCESS or
2707c478bd9Sstevel@tonic-gate  * USER_PROCESS with the same "line" as the specified "entry".
2717c478bd9Sstevel@tonic-gate  */
2727c478bd9Sstevel@tonic-gate struct utmp *
_compat_getutline(const struct utmp * entry)2737c478bd9Sstevel@tonic-gate _compat_getutline(const struct utmp *entry)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	utmp_api2frec(&ubuf, &fubuf);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	do {
2787c478bd9Sstevel@tonic-gate 		/*
2797c478bd9Sstevel@tonic-gate 		 * If the current entry is the one we are interested in,
2807c478bd9Sstevel@tonic-gate 		 * return a pointer to it.
2817c478bd9Sstevel@tonic-gate 		 */
2827c478bd9Sstevel@tonic-gate 		if (fubuf.ut_type != EMPTY &&
2837c478bd9Sstevel@tonic-gate 		    (fubuf.ut_type == LOGIN_PROCESS ||
2847c478bd9Sstevel@tonic-gate 		    fubuf.ut_type == USER_PROCESS) &&
2857c478bd9Sstevel@tonic-gate 		    strncmp(&entry->ut_line[0], &fubuf.ut_line[0],
2867c478bd9Sstevel@tonic-gate 		    sizeof (fubuf.ut_line)) == 0) {
2877c478bd9Sstevel@tonic-gate 			utmp_frec2api(&fubuf, &ubuf);
2887c478bd9Sstevel@tonic-gate 			return (&ubuf);
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 	} while (getutent_frec() != NULL);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	utmp_frec2api(&fubuf, &ubuf);
2937c478bd9Sstevel@tonic-gate 	return (NULL);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * "_compat_pututline" writes the structure sent into the utmp file
2987c478bd9Sstevel@tonic-gate  * If there is already an entry with the same id, then it is
2997c478bd9Sstevel@tonic-gate  * overwritten, otherwise a new entry is made at the end of the
3007c478bd9Sstevel@tonic-gate  * utmp file.
3017c478bd9Sstevel@tonic-gate  */
3027c478bd9Sstevel@tonic-gate struct utmp *
_compat_pututline(const struct utmp * entry)3037c478bd9Sstevel@tonic-gate _compat_pututline(const struct utmp *entry)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	int fc;
3067c478bd9Sstevel@tonic-gate 	struct utmp *answer;
3077c478bd9Sstevel@tonic-gate 	struct utmp tmpbuf;
3087c478bd9Sstevel@tonic-gate 	struct futmp ftmpbuf;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * Copy the user supplied entry into our temporary buffer to
3127c478bd9Sstevel@tonic-gate 	 * avoid the possibility that the user is actually passing us
3137c478bd9Sstevel@tonic-gate 	 * the address of "ubuf".
3147c478bd9Sstevel@tonic-gate 	 */
3157c478bd9Sstevel@tonic-gate 	tmpbuf = *entry;
3167c478bd9Sstevel@tonic-gate 	utmp_api2frec(entry, &ftmpbuf);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	(void) getutent_frec();
3197c478bd9Sstevel@tonic-gate 	if (fd < 0) {
3207c478bd9Sstevel@tonic-gate #ifdef	ERRDEBUG
3217c478bd9Sstevel@tonic-gate 		gdebug("pututline: Unable to create utmp file.\n");
3227c478bd9Sstevel@tonic-gate #endif
3237c478bd9Sstevel@tonic-gate 		return (NULL);
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/* Make sure file is writable */
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if ((fc = fcntl(fd, F_GETFL, NULL)) == -1 || (fc & O_RDWR) != O_RDWR)
3297c478bd9Sstevel@tonic-gate 		return (NULL);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/*
3327c478bd9Sstevel@tonic-gate 	 * Find the proper entry in the utmp file.  Start at the current
3337c478bd9Sstevel@tonic-gate 	 * location.  If it isn't found from here to the end of the
3347c478bd9Sstevel@tonic-gate 	 * file, then reset to the beginning of the file and try again.
3357c478bd9Sstevel@tonic-gate 	 * If it still isn't found, then write a new entry at the end of
3367c478bd9Sstevel@tonic-gate 	 * the file.  (Making sure the location is an integral number of
3377c478bd9Sstevel@tonic-gate 	 * utmp structures into the file incase the file is scribbled.)
3387c478bd9Sstevel@tonic-gate 	 */
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (_compat_getutid(&tmpbuf) == NULL) {
3417c478bd9Sstevel@tonic-gate #ifdef	ERRDEBUG
3427c478bd9Sstevel@tonic-gate 		gdebug("1st getutid() failed. fd: %d", fd);
3437c478bd9Sstevel@tonic-gate #endif
3447c478bd9Sstevel@tonic-gate 		_compat_setutent();
3457c478bd9Sstevel@tonic-gate 		if (_compat_getutid(&tmpbuf) == NULL) {
3467c478bd9Sstevel@tonic-gate #ifdef	ERRDEBUG
3477c478bd9Sstevel@tonic-gate 			loc_utmp = lseek(fd, 0L, 1);
3487c478bd9Sstevel@tonic-gate 			gdebug("2nd getutid() failed. fd: %d loc_utmp: %ld\n",
3497c478bd9Sstevel@tonic-gate 			    fd, loc_utmp);
3507c478bd9Sstevel@tonic-gate #endif
3517c478bd9Sstevel@tonic-gate 			(void) fcntl(fd, F_SETFL, fc | O_APPEND);
3527c478bd9Sstevel@tonic-gate 		} else
3537c478bd9Sstevel@tonic-gate 			(void) lseek(fd, -(long)sizeof (struct futmp), 1);
3547c478bd9Sstevel@tonic-gate 	} else
3557c478bd9Sstevel@tonic-gate 		(void) lseek(fd, -(long)sizeof (struct futmp), 1);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/*
3587c478bd9Sstevel@tonic-gate 	 * Write out the user supplied structure.  If the write fails,
3597c478bd9Sstevel@tonic-gate 	 * then the user probably doesn't have permission to write the
3607c478bd9Sstevel@tonic-gate 	 * utmp file.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	if (write(fd, &ftmpbuf, sizeof (ftmpbuf)) != sizeof (ftmpbuf)) {
3637c478bd9Sstevel@tonic-gate #ifdef	ERRDEBUG
3647c478bd9Sstevel@tonic-gate 		gdebug("pututline failed: write-%d\n", errno);
3657c478bd9Sstevel@tonic-gate #endif
3667c478bd9Sstevel@tonic-gate 		answer = NULL;
3677c478bd9Sstevel@tonic-gate 	} else {
3687c478bd9Sstevel@tonic-gate 		/*
3697c478bd9Sstevel@tonic-gate 		 * Copy the new user structure into ubuf so that it will
3707c478bd9Sstevel@tonic-gate 		 * be up to date in the future.
3717c478bd9Sstevel@tonic-gate 		 */
3727c478bd9Sstevel@tonic-gate 		fubuf = ftmpbuf;
3737c478bd9Sstevel@tonic-gate 		utmp_frec2api(&fubuf, &ubuf);
3747c478bd9Sstevel@tonic-gate 		answer = &ubuf;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate #ifdef	ERRDEBUG
3777c478bd9Sstevel@tonic-gate 		gdebug("id: %c%c loc: %ld\n", fubuf.ut_id[0],
3787c478bd9Sstevel@tonic-gate 		    fubuf.ut_id[1], fubuf.ut_id[2], fubuf.ut_id[3],
3797c478bd9Sstevel@tonic-gate 		    loc_utmp);
3807c478bd9Sstevel@tonic-gate #endif
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFL, fc);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	return (answer);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * "_compat_setutent" just resets the utmp file back to the beginning.
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate void
_compat_setutent(void)3927c478bd9Sstevel@tonic-gate _compat_setutent(void)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	if (fd != -1)
3957c478bd9Sstevel@tonic-gate 		(void) lseek(fd, 0L, 0);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/*
3987c478bd9Sstevel@tonic-gate 	 * Zero the stored copy of the last entry read, since we are
3997c478bd9Sstevel@tonic-gate 	 * resetting to the beginning of the file.
4007c478bd9Sstevel@tonic-gate 	 */
4017c478bd9Sstevel@tonic-gate 	bzero(&ubuf, sizeof (ubuf));
4027c478bd9Sstevel@tonic-gate 	bzero(&fubuf, sizeof (fubuf));
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate  * "_compat_endutent" closes the utmp file.
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate void
_compat_endutent(void)4097c478bd9Sstevel@tonic-gate _compat_endutent(void)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	if (fd != -1)
4127c478bd9Sstevel@tonic-gate 		(void) close(fd);
4137c478bd9Sstevel@tonic-gate 	fd = -1;
4147c478bd9Sstevel@tonic-gate 	bzero(&ubuf, sizeof (ubuf));
4157c478bd9Sstevel@tonic-gate 	bzero(&fubuf, sizeof (fubuf));
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate  * If one of wtmp and wtmpx files exist, create the other, and the record.
4217c478bd9Sstevel@tonic-gate  * If they both exist add the record.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate void
_compat_updwtmp(const char * file,struct utmp * ut)4247c478bd9Sstevel@tonic-gate _compat_updwtmp(const char *file, struct utmp *ut)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	struct futmp fut;
4277c478bd9Sstevel@tonic-gate 	int fd;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	fd = open(file, O_WRONLY | O_APPEND);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if (fd < 0) {
4337c478bd9Sstevel@tonic-gate 		if ((fd = open(file, O_WRONLY|O_CREAT, 0644)) < 0)
4347c478bd9Sstevel@tonic-gate 			return;
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	(void) lseek(fd, 0, 2);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	utmp_api2frec(ut, &fut);
4407c478bd9Sstevel@tonic-gate 	(void) write(fd, &fut, sizeof (fut));
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	(void) close(fd);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate  * makeut - create a utmp entry, recycling an id if a wild card is
4497c478bd9Sstevel@tonic-gate  *	specified.
4507c478bd9Sstevel@tonic-gate  *
4517c478bd9Sstevel@tonic-gate  *	args:	utmp - point to utmp structure to be created
4527c478bd9Sstevel@tonic-gate  */
4537c478bd9Sstevel@tonic-gate struct utmp *
_compat_makeut(struct utmp * utmp)4547c478bd9Sstevel@tonic-gate _compat_makeut(struct utmp *utmp)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	int i;
4577c478bd9Sstevel@tonic-gate 	struct utmp *utp;	/* "current" utmp entry being examined */
4587c478bd9Sstevel@tonic-gate 	int wild;		/* flag, true iff wild card char seen */
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* the last id we matched that was NOT a dead proc */
4617c478bd9Sstevel@tonic-gate 	unsigned char saveid[IDLEN];
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	wild = 0;
4647c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; i++)
4657c478bd9Sstevel@tonic-gate 		if ((unsigned char)utmp->ut_id[i] == SC_WILDC) {
4667c478bd9Sstevel@tonic-gate 			wild = 1;
4677c478bd9Sstevel@tonic-gate 			break;
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (wild) {
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		/*
4737c478bd9Sstevel@tonic-gate 		 * try to lock the utmp file, only needed if we're
4747c478bd9Sstevel@tonic-gate 		 * doing wildcard matching
4757c478bd9Sstevel@tonic-gate 		 */
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		if (lockut())
4787c478bd9Sstevel@tonic-gate 			return (0);
4797c478bd9Sstevel@tonic-gate 		_compat_setutent();
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		/* find the first alphanumeric character */
4827c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAXVAL; ++i)
4837c478bd9Sstevel@tonic-gate 			if (isalnum(i))
4847c478bd9Sstevel@tonic-gate 				break;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		(void) memset(saveid, i, IDLEN);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		while ((utp = _compat_getutent()) != 0) {
4897c478bd9Sstevel@tonic-gate 			if (idcmp(utmp->ut_id, utp->ut_id))
4907c478bd9Sstevel@tonic-gate 				continue;
4917c478bd9Sstevel@tonic-gate 			if (utp->ut_type == DEAD_PROCESS)
4927c478bd9Sstevel@tonic-gate 				break;
4937c478bd9Sstevel@tonic-gate 			(void) memcpy(saveid, utp->ut_id, IDLEN);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		if (utp) {
4977c478bd9Sstevel@tonic-gate 			/*
4987c478bd9Sstevel@tonic-gate 			 * found an unused entry, reuse it
4997c478bd9Sstevel@tonic-gate 			 */
5007c478bd9Sstevel@tonic-gate 			(void) memcpy(utmp->ut_id, utp->ut_id, IDLEN);
5017c478bd9Sstevel@tonic-gate 			utp = _compat_pututline(utmp);
5027c478bd9Sstevel@tonic-gate 			if (utp)
5037c478bd9Sstevel@tonic-gate 				_compat_updwtmp(WTMP_FILE, utp);
5047c478bd9Sstevel@tonic-gate 			_compat_endutent();
5057c478bd9Sstevel@tonic-gate 			unlockut();
5067c478bd9Sstevel@tonic-gate 			return (utp);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		} else {
5097c478bd9Sstevel@tonic-gate 			/*
5107c478bd9Sstevel@tonic-gate 			 * nothing available, try to allocate an id
5117c478bd9Sstevel@tonic-gate 			 */
5127c478bd9Sstevel@tonic-gate 			if (allocid(utmp->ut_id, saveid)) {
5137c478bd9Sstevel@tonic-gate 				_compat_endutent();
5147c478bd9Sstevel@tonic-gate 				unlockut();
5157c478bd9Sstevel@tonic-gate 				return (NULL);
5167c478bd9Sstevel@tonic-gate 			} else {
5177c478bd9Sstevel@tonic-gate 				utp = _compat_pututline(utmp);
5187c478bd9Sstevel@tonic-gate 				if (utp)
5197c478bd9Sstevel@tonic-gate 					_compat_updwtmp(WTMP_FILE, utp);
5207c478bd9Sstevel@tonic-gate 				_compat_endutent();
5217c478bd9Sstevel@tonic-gate 				unlockut();
5227c478bd9Sstevel@tonic-gate 				return (utp);
5237c478bd9Sstevel@tonic-gate 			}
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 	} else {
5267c478bd9Sstevel@tonic-gate 		utp = _compat_pututline(utmp);
5277c478bd9Sstevel@tonic-gate 		if (utp)
5287c478bd9Sstevel@tonic-gate 			_compat_updwtmp(WTMP_FILE, utp);
5297c478bd9Sstevel@tonic-gate 		_compat_endutent();
5307c478bd9Sstevel@tonic-gate 		return (utp);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate  * _compat_modut - modify a utmp entry.
5377c478bd9Sstevel@tonic-gate  *
5387c478bd9Sstevel@tonic-gate  *	args:	utmp - point to utmp structure to be created
5397c478bd9Sstevel@tonic-gate  */
5407c478bd9Sstevel@tonic-gate struct utmp *
_compat_modut(struct utmp * utp)5417c478bd9Sstevel@tonic-gate _compat_modut(struct utmp *utp)
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 	int i;					/* scratch variable */
5447c478bd9Sstevel@tonic-gate 	struct utmp utmp;			/* holding area */
5457c478bd9Sstevel@tonic-gate 	struct utmp *ucp = &utmp;		/* and a pointer to it */
5467c478bd9Sstevel@tonic-gate 	struct utmp *up;	/* "current" utmp entry being examined */
5477c478bd9Sstevel@tonic-gate 	struct futmp *fup;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i)
5507c478bd9Sstevel@tonic-gate 		if ((unsigned char)utp->ut_id[i] == SC_WILDC)
5517c478bd9Sstevel@tonic-gate 			return (0);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/* copy the supplied utmp structure someplace safe */
5547c478bd9Sstevel@tonic-gate 	utmp = *utp;
5557c478bd9Sstevel@tonic-gate 	_compat_setutent();
556*00ae5933SToomas Soome 	while ((fup = getutent_frec()) != NULL) {
5577c478bd9Sstevel@tonic-gate 		if (idcmp(ucp->ut_id, fup->ut_id))
5587c478bd9Sstevel@tonic-gate 			continue;
5597c478bd9Sstevel@tonic-gate 		break;
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 	up = _compat_pututline(ucp);
5627c478bd9Sstevel@tonic-gate 	if (up)
5637c478bd9Sstevel@tonic-gate 		_compat_updwtmp(WTMP_FILE, up);
5647c478bd9Sstevel@tonic-gate 	_compat_endutent();
5657c478bd9Sstevel@tonic-gate 	return (up);
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate  * idcmp - compare two id strings, return 0 if same, non-zero if not *
5727c478bd9Sstevel@tonic-gate  *	args:	s1 - first id string
5737c478bd9Sstevel@tonic-gate  *		s2 - second id string
5747c478bd9Sstevel@tonic-gate  */
5757c478bd9Sstevel@tonic-gate static int
idcmp(const char * s1,const char * s2)5767c478bd9Sstevel@tonic-gate idcmp(const char *s1, const char *s2)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	int i;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i)
5817c478bd9Sstevel@tonic-gate 		if ((unsigned char)*s1 != SC_WILDC && (*s1++ != *s2++))
5827c478bd9Sstevel@tonic-gate 			return (-1);
5837c478bd9Sstevel@tonic-gate 	return (0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  * allocid - allocate an unused id for utmp, either by recycling a
5897c478bd9Sstevel@tonic-gate  *	DEAD_PROCESS entry or creating a new one.  This routine only
5907c478bd9Sstevel@tonic-gate  *	gets called if a wild card character was specified.
5917c478bd9Sstevel@tonic-gate  *
5927c478bd9Sstevel@tonic-gate  *	args:	srcid - pattern for new id
5937c478bd9Sstevel@tonic-gate  *		saveid - last id matching pattern for a non-dead process
5947c478bd9Sstevel@tonic-gate  */
5957c478bd9Sstevel@tonic-gate static int
allocid(char * srcid,unsigned char * saveid)5967c478bd9Sstevel@tonic-gate allocid(char *srcid, unsigned char *saveid)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	int i;		/* scratch variable */
5997c478bd9Sstevel@tonic-gate 	int changed;	/* flag to indicate that a new id has been generated */
6007c478bd9Sstevel@tonic-gate 	char copyid[IDLEN];	/* work area */
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	(void) memcpy(copyid, srcid, IDLEN);
6037c478bd9Sstevel@tonic-gate 	changed = 0;
6047c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i) {
6057c478bd9Sstevel@tonic-gate 		/*
6067c478bd9Sstevel@tonic-gate 		 * if this character isn't wild, it'll
6077c478bd9Sstevel@tonic-gate 		 * be part of the generated id
6087c478bd9Sstevel@tonic-gate 		 */
6097c478bd9Sstevel@tonic-gate 		if ((unsigned char) copyid[i] != SC_WILDC)
6107c478bd9Sstevel@tonic-gate 			continue;
6117c478bd9Sstevel@tonic-gate 		/*
6127c478bd9Sstevel@tonic-gate 		 * it's a wild character, retrieve the
6137c478bd9Sstevel@tonic-gate 		 * character from the saved id
6147c478bd9Sstevel@tonic-gate 		 */
6157c478bd9Sstevel@tonic-gate 		copyid[i] = saveid[i];
6167c478bd9Sstevel@tonic-gate 		/*
6177c478bd9Sstevel@tonic-gate 		 * if we haven't changed anything yet,
6187c478bd9Sstevel@tonic-gate 		 * try to find a new char to use
6197c478bd9Sstevel@tonic-gate 		 */
6207c478bd9Sstevel@tonic-gate 		if (!changed && (saveid[i] < MAXVAL)) {
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate /*
6237c478bd9Sstevel@tonic-gate  * Note: this algorithm is taking the "last matched" id and trying to make
6247c478bd9Sstevel@tonic-gate  * a 1 character change to it to create a new one.  Rather than special-case
6257c478bd9Sstevel@tonic-gate  * the first time (when no perturbation is really necessary), just don't
6267c478bd9Sstevel@tonic-gate  * allocate the first valid id.
6277c478bd9Sstevel@tonic-gate  */
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 			while (++saveid[i] < MAXVAL) {
6307c478bd9Sstevel@tonic-gate 				/* make sure new char is alphanumeric */
6317c478bd9Sstevel@tonic-gate 				if (isalnum(saveid[i])) {
6327c478bd9Sstevel@tonic-gate 					copyid[i] = saveid[i];
6337c478bd9Sstevel@tonic-gate 					changed = 1;
6347c478bd9Sstevel@tonic-gate 					break;
6357c478bd9Sstevel@tonic-gate 				}
6367c478bd9Sstevel@tonic-gate 			}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 			if (!changed) {
6397c478bd9Sstevel@tonic-gate 				/*
6407c478bd9Sstevel@tonic-gate 				 * Then 'reset' the current count at
6417c478bd9Sstevel@tonic-gate 				 * this position to it's lowest valid
6427c478bd9Sstevel@tonic-gate 				 * value, and propagate the carry to
6437c478bd9Sstevel@tonic-gate 				 * the next wild-card slot
6447c478bd9Sstevel@tonic-gate 				 *
6457c478bd9Sstevel@tonic-gate 				 * See 1113208.
6467c478bd9Sstevel@tonic-gate 				 */
6477c478bd9Sstevel@tonic-gate 				saveid[i] = 0;
6487c478bd9Sstevel@tonic-gate 				while (!isalnum(saveid[i]))
6497c478bd9Sstevel@tonic-gate 					saveid[i]++;
6507c478bd9Sstevel@tonic-gate 				copyid[i] = ++saveid[i];
6517c478bd9Sstevel@tonic-gate 			}
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	/* changed is true if we were successful in allocating an id */
6557c478bd9Sstevel@tonic-gate 	if (changed) {
6567c478bd9Sstevel@tonic-gate 		(void) memcpy(srcid, copyid, IDLEN);
6577c478bd9Sstevel@tonic-gate 		return (0);
6587c478bd9Sstevel@tonic-gate 	} else
6597c478bd9Sstevel@tonic-gate 		return (-1);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * lockut - lock utmp file
6657c478bd9Sstevel@tonic-gate  */
6667c478bd9Sstevel@tonic-gate static int
lockut(void)6677c478bd9Sstevel@tonic-gate lockut(void)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0)
6707c478bd9Sstevel@tonic-gate 		return (-1);
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (lockf(fd, F_LOCK, 0) < 0) {
6737c478bd9Sstevel@tonic-gate 		(void) close(fd);
6747c478bd9Sstevel@tonic-gate 		fd = -1;
6757c478bd9Sstevel@tonic-gate 		return (-1);
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	return (0);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate /*
6827c478bd9Sstevel@tonic-gate  * unlockut - unlock utmp file
6837c478bd9Sstevel@tonic-gate  */
6847c478bd9Sstevel@tonic-gate static void
unlockut(void)6857c478bd9Sstevel@tonic-gate unlockut(void)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate 	(void) lockf(fd, F_ULOCK, 0);
6887c478bd9Sstevel@tonic-gate 	(void) close(fd);
6897c478bd9Sstevel@tonic-gate 	fd = -1;
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate #ifdef  ERRDEBUG
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate #include <stdarg.h>
6977c478bd9Sstevel@tonic-gate #include <stdio.h>
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate static void
gdebug(const char * fmt,...)7007c478bd9Sstevel@tonic-gate gdebug(const char *fmt, ...)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	FILE *fp;
7037c478bd9Sstevel@tonic-gate 	int errnum;
7047c478bd9Sstevel@tonic-gate 	va_list ap;
7057c478bd9Sstevel@tonic-gate 
706004388ebScasper 	if ((fp = fopen("/etc/dbg.getut", "a+F")) == NULL)
7077c478bd9Sstevel@tonic-gate 		return;
7087c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
7097c478bd9Sstevel@tonic-gate 	(void) vfprintf(fp, fmt, ap);
7107c478bd9Sstevel@tonic-gate 	va_end(ap);
7117c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate #endif
714