Home | History | Annotate | Line # | Download | only in gen
utmpx.c revision 1.3
      1 /*	$NetBSD: utmpx.c,v 1.3 2002/03/05 16:16:02 christos Exp $	 */
      2 
      3 /*-
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 #include <sys/cdefs.h>
     39 
     40 #if defined(LIBC_SCCS) && !defined(lint)
     41 __RCSID("$NetBSD: utmpx.c,v 1.3 2002/03/05 16:16:02 christos Exp $");
     42 #endif /* LIBC_SCCS and not lint */
     43 
     44 #include <sys/types.h>
     45 #include <sys/param.h>
     46 #include <sys/wait.h>
     47 #include <sys/socket.h>
     48 #include <sys/time.h>
     49 #include <sys/stat.h>
     50 
     51 #include <stdio.h>
     52 #include <string.h>
     53 #include <vis.h>
     54 #include <utmpx.h>
     55 #include <unistd.h>
     56 #include <fcntl.h>
     57 
     58 static FILE *fp;
     59 static struct utmpx ut;
     60 static char utfile[MAXPATHLEN] = _PATH_UTMPX;
     61 
     62 static struct utmpx *utmp_update(const struct utmpx *);
     63 
     64 static const char vers[] = "utmpx-1.00";
     65 
     66 void
     67 setutxent()
     68 {
     69 	(void)memset(&ut, 0, sizeof(ut));
     70 	if (fp == NULL)
     71 		return;
     72 	(void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
     73 }
     74 
     75 
     76 void
     77 endutxent()
     78 {
     79 	(void)memset(&ut, 0, sizeof(ut));
     80 	if (fp != NULL)
     81 		(void)fclose(fp);
     82 }
     83 
     84 
     85 struct utmpx *
     86 getutxent()
     87 {
     88 	if (fp == NULL) {
     89 		struct stat st;
     90 
     91 		if ((fp = fopen(utfile, "r+")) == NULL)
     92 			if ((fp = fopen(utfile, "r")) == NULL)
     93 				goto fail;
     94 
     95 		/* get file size in order to check if new file */
     96 		if (fstat(fileno(fp), &st) == -1)
     97 			goto failclose;
     98 
     99 		if (st.st_size == 0) {
    100 			/* new file, add signature record */
    101 			(void)memset(&ut, 0, sizeof(ut));
    102 			ut.ut_type = SIGNATURE;
    103 			(void)memcpy(ut.ut_user, vers, sizeof(vers));
    104 			if (fwrite(&ut, sizeof(ut), 1, fp) != sizeof(ut))
    105 				goto failclose;
    106 		} else {
    107 			/* old file, read signature record */
    108 			if (fread(&ut, sizeof(ut), 1, fp) != sizeof(ut))
    109 				goto failclose;
    110 			if (memcmp(ut.ut_user, vers, sizeof(vers)) != 0 ||
    111 			    ut.ut_type != SIGNATURE)
    112 				goto failclose;
    113 		}
    114 	}
    115 
    116 	if (fread(&ut, sizeof(ut), 1, fp) != sizeof(ut))
    117 		goto fail;
    118 
    119 	return &ut;
    120 failclose:
    121 	(void)fclose(fp);
    122 fail:
    123 	(void)memset(&ut, 0, sizeof(ut));
    124 	return NULL;
    125 }
    126 
    127 
    128 struct utmpx *
    129 getutxid(const struct utmpx *utx)
    130 {
    131 	if (utx->ut_type == EMPTY)
    132 		return NULL;
    133 
    134 	do {
    135 		if (ut.ut_type == EMPTY)
    136 			continue;
    137 		switch (utx->ut_type) {
    138 		case EMPTY:
    139 			return NULL;
    140 		case RUN_LVL:
    141 		case BOOT_TIME:
    142 		case OLD_TIME:
    143 		case NEW_TIME:
    144 			if (ut.ut_type == utx->ut_type)
    145 				return &ut;
    146 			break;
    147 		case INIT_PROCESS:
    148 		case LOGIN_PROCESS:
    149 		case USER_PROCESS:
    150 		case DEAD_PROCESS:
    151 			switch (ut.ut_type) {
    152 			case INIT_PROCESS:
    153 			case LOGIN_PROCESS:
    154 			case USER_PROCESS:
    155 			case DEAD_PROCESS:
    156 				if (memcmp(ut.ut_id, utx->ut_id,
    157 				    sizeof(ut.ut_id)) == 0)
    158 					return &ut;
    159 				break;
    160 			default:
    161 				break;
    162 			}
    163 			break;
    164 		default:
    165 			return NULL;
    166 		}
    167 	}
    168 	while (getutxent() != NULL);
    169 	return NULL;
    170 }
    171 
    172 
    173 struct utmpx *
    174 getutxline(const struct utmpx *utx)
    175 {
    176 	do {
    177 		switch (ut.ut_type) {
    178 		case EMPTY:
    179 			break;
    180 		case LOGIN_PROCESS:
    181 		case USER_PROCESS:
    182 			if (strncmp(ut.ut_line, utx->ut_line,
    183 			    sizeof(ut.ut_line)) == 0)
    184 				return &ut;
    185 			break;
    186 		default:
    187 			break;
    188 		}
    189 	}
    190 	while (getutxent() != NULL);
    191 	return NULL;
    192 }
    193 
    194 
    195 struct utmpx *
    196 pututxline(const struct utmpx *utx)
    197 {
    198 	struct utmpx temp, *u = NULL;
    199 	int gotlock = 0;
    200 
    201 	if (strcmp(_PATH_UTMPX, utfile) == 0 && geteuid() != 0)
    202 		return utmp_update(utx);
    203 
    204 	if (utx == NULL)
    205 		return NULL;
    206 
    207 	(void)memcpy(&temp, utx, sizeof(temp));
    208 
    209 	if (fp == NULL) {
    210 		(void)getutxent();
    211 		if (fp == NULL)
    212 			return NULL;
    213 	}
    214 
    215 	if (getutxid(&temp) == NULL) {
    216 		setutxent();
    217 		if (getutxid(&temp) == NULL) {
    218 			if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
    219 				return NULL;
    220 			gotlock++;
    221 			if (fseeko(fp, (off_t)0, SEEK_END) == -1)
    222 				goto fail;
    223 		}
    224 	}
    225 
    226 	if (!gotlock) {
    227 		/* we are not appending */
    228 		if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
    229 			return NULL;
    230 	}
    231 
    232 	if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
    233 		goto fail;
    234 
    235 	if (fflush(fp) == -1)
    236 		goto fail;
    237 
    238 	u = memcpy(&ut, &temp, sizeof(ut));
    239 fail:
    240 	if (gotlock) {
    241 		if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
    242 			return NULL;
    243 	}
    244 	return u;
    245 }
    246 
    247 
    248 static struct utmpx *
    249 utmp_update(const struct utmpx *utx)
    250 {
    251 	char buf[sizeof(*utx) * 4 + 1];
    252 	pid_t pid;
    253 	int status;
    254 
    255 	(void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
    256 	    VIS_WHITE);
    257 	switch (pid = fork()) {
    258 	case 0:
    259 		(void)execl(_PATH_UTMP_UPDATE,
    260 		    strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf);
    261 		exit(1);
    262 		/*NOTREACHED*/
    263 	case -1:
    264 		return NULL;
    265 	default:
    266 		if (waitpid(pid, &status, 0) == -1)
    267 			return NULL;
    268 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
    269 			return memcpy(&ut, utx, sizeof(ut));
    270 		return NULL;
    271 	}
    272 
    273 }
    274 
    275 void
    276 updwtmpx(const char *file, const struct utmpx *utx)
    277 {
    278 	int fd = open(file, O_WRONLY | O_APPEND);
    279 	if (fd == -1) {
    280 		if ((fd = open(file, O_CREAT | O_WRONLY, 0644)) == -1)
    281 			return;
    282 		(void)memset(&ut, 0, sizeof(ut));
    283 		ut.ut_type = SIGNATURE;
    284 		(void)memcpy(ut.ut_user, vers, sizeof(vers));
    285 		(void)write(fd, &ut, sizeof(ut));
    286 	}
    287 	(void)write(fd, utx, sizeof(*utx));
    288 	(void)close(fd);
    289 }
    290 
    291 
    292 /*
    293  * The following are extensions and not part of the X/Open spec
    294  */
    295 int
    296 utmpxname(const char *fname)
    297 {
    298 	size_t len = strlen(fname);
    299 
    300 	if (len >= sizeof(utfile))
    301 		return 0;
    302 
    303 	/* must end in x! */
    304 	if (fname[len - 1] != 'x')
    305 		return 0;
    306 
    307 	(void)strcpy(utfile, fname);
    308 	endutxent();
    309 	return 1;
    310 }
    311