1 /* $NetBSD: utmpx.c,v 1.6 2002/04/15 16:47:03 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.6 2002/04/15 16:47:03 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 <stdlib.h> 53 #include <string.h> 54 #include <vis.h> 55 #include <utmp.h> 56 #include <utmpx.h> 57 #include <unistd.h> 58 #include <fcntl.h> 59 60 static FILE *fp; 61 static struct utmpx ut; 62 static char utfile[MAXPATHLEN] = _PATH_UTMPX; 63 64 static struct utmpx *utmp_update(const struct utmpx *); 65 66 static const char vers[] = "utmpx-1.00"; 67 68 void 69 setutxent() 70 { 71 (void)memset(&ut, 0, sizeof(ut)); 72 if (fp == NULL) 73 return; 74 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET); 75 } 76 77 78 void 79 endutxent() 80 { 81 (void)memset(&ut, 0, sizeof(ut)); 82 if (fp != NULL) 83 (void)fclose(fp); 84 } 85 86 87 struct utmpx * 88 getutxent() 89 { 90 if (fp == NULL) { 91 struct stat st; 92 93 if ((fp = fopen(utfile, "r+")) == NULL) 94 if ((fp = fopen(utfile, "w+")) == NULL) 95 if ((fp = fopen(utfile, "r")) == NULL) 96 goto fail; 97 98 /* get file size in order to check if new file */ 99 if (fstat(fileno(fp), &st) == -1) 100 goto failclose; 101 102 if (st.st_size == 0) { 103 /* new file, add signature record */ 104 (void)memset(&ut, 0, sizeof(ut)); 105 ut.ut_type = SIGNATURE; 106 (void)memcpy(ut.ut_user, vers, sizeof(vers)); 107 if (fwrite(&ut, sizeof(ut), 1, fp) != 1) 108 goto failclose; 109 } else { 110 /* old file, read signature record */ 111 if (fread(&ut, sizeof(ut), 1, fp) != 1) 112 goto failclose; 113 if (memcmp(ut.ut_user, vers, sizeof(vers)) != 0 || 114 ut.ut_type != SIGNATURE) 115 goto failclose; 116 } 117 } 118 119 if (fread(&ut, sizeof(ut), 1, fp) != 1) 120 goto fail; 121 122 return &ut; 123 failclose: 124 (void)fclose(fp); 125 fail: 126 (void)memset(&ut, 0, sizeof(ut)); 127 return NULL; 128 } 129 130 131 struct utmpx * 132 getutxid(const struct utmpx *utx) 133 { 134 if (utx->ut_type == EMPTY) 135 return NULL; 136 137 do { 138 if (ut.ut_type == EMPTY) 139 continue; 140 switch (utx->ut_type) { 141 case EMPTY: 142 return NULL; 143 case RUN_LVL: 144 case BOOT_TIME: 145 case OLD_TIME: 146 case NEW_TIME: 147 if (ut.ut_type == utx->ut_type) 148 return &ut; 149 break; 150 case INIT_PROCESS: 151 case LOGIN_PROCESS: 152 case USER_PROCESS: 153 case DEAD_PROCESS: 154 switch (ut.ut_type) { 155 case INIT_PROCESS: 156 case LOGIN_PROCESS: 157 case USER_PROCESS: 158 case DEAD_PROCESS: 159 if (memcmp(ut.ut_id, utx->ut_id, 160 sizeof(ut.ut_id)) == 0) 161 return &ut; 162 break; 163 default: 164 break; 165 } 166 break; 167 default: 168 return NULL; 169 } 170 } 171 while (getutxent() != NULL); 172 return NULL; 173 } 174 175 176 struct utmpx * 177 getutxline(const struct utmpx *utx) 178 { 179 do { 180 switch (ut.ut_type) { 181 case EMPTY: 182 break; 183 case LOGIN_PROCESS: 184 case USER_PROCESS: 185 if (strncmp(ut.ut_line, utx->ut_line, 186 sizeof(ut.ut_line)) == 0) 187 return &ut; 188 break; 189 default: 190 break; 191 } 192 } 193 while (getutxent() != NULL); 194 return NULL; 195 } 196 197 198 struct utmpx * 199 pututxline(const struct utmpx *utx) 200 { 201 struct utmpx temp, *u = NULL; 202 int gotlock = 0; 203 204 if (strcmp(_PATH_UTMPX, utfile) == 0 && geteuid() != 0) 205 return utmp_update(utx); 206 207 if (utx == NULL) 208 return NULL; 209 210 (void)memcpy(&temp, utx, sizeof(temp)); 211 212 if (fp == NULL) { 213 (void)getutxent(); 214 if (fp == NULL) 215 return NULL; 216 } 217 218 if (getutxid(&temp) == NULL) { 219 setutxent(); 220 if (getutxid(&temp) == NULL) { 221 if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1) 222 return NULL; 223 gotlock++; 224 if (fseeko(fp, (off_t)0, SEEK_END) == -1) 225 goto fail; 226 } 227 } 228 229 if (!gotlock) { 230 /* we are not appending */ 231 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1) 232 return NULL; 233 } 234 235 if (fwrite(&temp, sizeof (temp), 1, fp) != 1) 236 goto fail; 237 238 if (fflush(fp) == -1) 239 goto fail; 240 241 u = memcpy(&ut, &temp, sizeof(ut)); 242 fail: 243 if (gotlock) { 244 if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1) 245 return NULL; 246 } 247 return u; 248 } 249 250 251 static struct utmpx * 252 utmp_update(const struct utmpx *utx) 253 { 254 char buf[sizeof(*utx) * 4 + 1]; 255 pid_t pid; 256 int status; 257 258 (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx), 259 VIS_WHITE); 260 switch (pid = fork()) { 261 case 0: 262 (void)execl(_PATH_UTMP_UPDATE, 263 strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf); 264 exit(1); 265 /*NOTREACHED*/ 266 case -1: 267 return NULL; 268 default: 269 if (waitpid(pid, &status, 0) == -1) 270 return NULL; 271 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 272 return memcpy(&ut, utx, sizeof(ut)); 273 return NULL; 274 } 275 276 } 277 278 void 279 updwtmpx(const char *file, const struct utmpx *utx) 280 { 281 int fd = open(file, O_WRONLY | O_APPEND); 282 if (fd == -1) { 283 if ((fd = open(file, O_CREAT | O_WRONLY, 0644)) == -1) 284 return; 285 (void)memset(&ut, 0, sizeof(ut)); 286 ut.ut_type = SIGNATURE; 287 (void)memcpy(ut.ut_user, vers, sizeof(vers)); 288 (void)write(fd, &ut, sizeof(ut)); 289 } 290 (void)write(fd, utx, sizeof(*utx)); 291 (void)close(fd); 292 } 293 294 295 /* 296 * The following are extensions and not part of the X/Open spec 297 */ 298 int 299 utmpxname(const char *fname) 300 { 301 size_t len = strlen(fname); 302 303 if (len >= sizeof(utfile)) 304 return 0; 305 306 /* must end in x! */ 307 if (fname[len - 1] != 'x') 308 return 0; 309 310 (void)strcpy(utfile, fname); 311 endutxent(); 312 return 1; 313 } 314 315 316 void 317 getutmp(const struct utmpx *ux, struct utmp *u) 318 { 319 (void)memcpy(u->ut_name, ux->ut_name, sizeof(u->ut_name)); 320 (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line)); 321 (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host)); 322 u->ut_time = ux->ut_tv.tv_sec; 323 } 324 325 void 326 getutmpx(const struct utmp *u, struct utmpx *ux) 327 { 328 (void)memcpy(ux->ut_name, u->ut_name, sizeof(u->ut_name)); 329 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line)); 330 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host)); 331 ux->ut_tv.tv_sec = u->ut_time; 332 ux->ut_tv.tv_usec = 0; 333 (void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss)); 334 ux->ut_pid = 0; 335 ux->ut_type = USER_PROCESS; 336 ux->ut_session = 0; 337 ux->ut_exit.e_termination = 0; 338 ux->ut_exit.e_exit = 0; 339 } 340