1 /* 2 * Copyright (c) 2000 Andre Lucas. All rights reserved. 3 * Portions copyright (c) 1998 Todd C. Miller 4 * Portions copyright (c) 1996 Jason Downs 5 * Portions copyright (c) 1996 Theo de Raadt 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * The btmp logging code is derived from login.c from util-linux and is under 30 * the the following license: 31 * 32 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms are permitted 36 * provided that the above copyright notice and this paragraph are 37 * duplicated in all such forms and that any documentation, 38 * advertising materials, and other materials related to such 39 * distribution and use acknowledge that the software was developed 40 * by the University of California, Berkeley. The name of the 41 * University may not be used to endorse or promote products derived 42 * from this software without specific prior written permission. 43 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 44 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 45 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 46 */ 47 48 49 /** 50 ** loginrec.c: platform-independent login recording and lastlog retrieval 51 **/ 52 53 /* 54 * The new login code explained 55 * ============================ 56 * 57 * This code attempts to provide a common interface to login recording 58 * (utmp and friends) and last login time retrieval. 59 * 60 * Its primary means of achieving this is to use 'struct logininfo', a 61 * union of all the useful fields in the various different types of 62 * system login record structures one finds on UNIX variants. 63 * 64 * We depend on autoconf to define which recording methods are to be 65 * used, and which fields are contained in the relevant data structures 66 * on the local system. Many C preprocessor symbols affect which code 67 * gets compiled here. 68 * 69 * The code is designed to make it easy to modify a particular 70 * recording method, without affecting other methods nor requiring so 71 * many nested conditional compilation blocks as were commonplace in 72 * the old code. 73 * 74 * For login recording, we try to use the local system's libraries as 75 * these are clearly most likely to work correctly. For utmp systems 76 * this usually means login() and logout() or setutent() etc., probably 77 * in libutil, along with logwtmp() etc. On these systems, we fall back 78 * to writing the files directly if we have to, though this method 79 * requires very thorough testing so we do not corrupt local auditing 80 * information. These files and their access methods are very system 81 * specific indeed. 82 * 83 * For utmpx systems, the corresponding library functions are 84 * setutxent() etc. To the author's knowledge, all utmpx systems have 85 * these library functions and so no direct write is attempted. If such 86 * a system exists and needs support, direct analogues of the [uw]tmp 87 * code should suffice. 88 * 89 * Retrieving the time of last login ('lastlog') is in some ways even 90 * more problemmatic than login recording. Some systems provide a 91 * simple table of all users which we seek based on uid and retrieve a 92 * relatively standard structure. Others record the same information in 93 * a directory with a separate file, and others don't record the 94 * information separately at all. For systems in the latter category, 95 * we look backwards in the wtmp or wtmpx file for the last login entry 96 * for our user. Naturally this is slower and on busy systems could 97 * incur a significant performance penalty. 98 * 99 * Calling the new code 100 * -------------------- 101 * 102 * In OpenSSH all login recording and retrieval is performed in 103 * login.c. Here you'll find working examples. Also, in the logintest.c 104 * program there are more examples. 105 * 106 * Internal handler calling method 107 * ------------------------------- 108 * 109 * When a call is made to login_login() or login_logout(), both 110 * routines set a struct logininfo flag defining which action (log in, 111 * or log out) is to be taken. They both then call login_write(), which 112 * calls whichever of the many structure-specific handlers autoconf 113 * selects for the local system. 114 * 115 * The handlers themselves handle system data structure specifics. Both 116 * struct utmp and struct utmpx have utility functions (see 117 * construct_utmp*()) to try to make it simpler to add extra systems 118 * that introduce new features to either structure. 119 * 120 * While it may seem terribly wasteful to replicate so much similar 121 * code for each method, experience has shown that maintaining code to 122 * write both struct utmp and utmpx in one function, whilst maintaining 123 * support for all systems whether they have library support or not, is 124 * a difficult and time-consuming task. 125 * 126 * Lastlog support proceeds similarly. Functions login_get_lastlog() 127 * (and its OpenSSH-tuned friend login_get_lastlog_time()) call 128 * getlast_entry(), which tries one of three methods to find the last 129 * login time. It uses local system lastlog support if it can, 130 * otherwise it tries wtmp or wtmpx before giving up and returning 0, 131 * meaning "tilt". 132 * 133 * Maintenance 134 * ----------- 135 * 136 * In many cases it's possible to tweak autoconf to select the correct 137 * methods for a particular platform, either by improving the detection 138 * code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE 139 * symbols for the platform. 140 * 141 * Use logintest to check which symbols are defined before modifying 142 * configure.ac and loginrec.c. (You have to build logintest yourself 143 * with 'make logintest' as it's not built by default.) 144 * 145 * Otherwise, patches to the specific method(s) are very helpful! 146 */ 147 148 #include "includes.h" 149 150 #include <sys/types.h> 151 #include <sys/stat.h> 152 #include <sys/socket.h> 153 #ifdef HAVE_SYS_TIME_H 154 # include <sys/time.h> 155 #endif 156 157 #include <netinet/in.h> 158 159 #include <stdlib.h> 160 #include <errno.h> 161 #include <fcntl.h> 162 #ifdef HAVE_PATHS_H 163 # include <paths.h> 164 #endif 165 #include <pwd.h> 166 #include <stdarg.h> 167 #include <stdio.h> 168 #include <string.h> 169 #include <time.h> 170 #include <unistd.h> 171 172 #include "xmalloc.h" 173 #include "sshkey.h" 174 #include "hostfile.h" 175 #include "ssh.h" 176 #include "loginrec.h" 177 #include "log.h" 178 #include "atomicio.h" 179 #include "packet.h" 180 #include "canohost.h" 181 #include "auth.h" 182 #include "sshbuf.h" 183 #include "ssherr.h" 184 #include "misc.h" 185 186 #ifdef HAVE_UTIL_H 187 # include <util.h> 188 #endif 189 190 /** 191 ** prototypes for helper functions in this file 192 **/ 193 194 #if HAVE_UTMP_H 195 void set_utmp_time(struct logininfo *li, struct utmp *ut); 196 void construct_utmp(struct logininfo *li, struct utmp *ut); 197 #endif 198 199 #ifdef HAVE_UTMPX_H 200 void set_utmpx_time(struct logininfo *li, struct utmpx *ut); 201 void construct_utmpx(struct logininfo *li, struct utmpx *ut); 202 #endif 203 204 int utmp_write_entry(struct logininfo *li); 205 int utmpx_write_entry(struct logininfo *li); 206 int wtmp_write_entry(struct logininfo *li); 207 int wtmpx_write_entry(struct logininfo *li); 208 int lastlog_write_entry(struct logininfo *li); 209 int syslogin_write_entry(struct logininfo *li); 210 211 int getlast_entry(struct logininfo *li); 212 int lastlog_get_entry(struct logininfo *li); 213 int utmpx_get_entry(struct logininfo *li); 214 int wtmp_get_entry(struct logininfo *li); 215 int wtmpx_get_entry(struct logininfo *li); 216 217 extern struct sshbuf *loginmsg; 218 219 /* pick the shortest string */ 220 #define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2)) 221 222 /** 223 ** platform-independent login functions 224 **/ 225 226 /* 227 * login_login(struct logininfo *) - Record a login 228 * 229 * Call with a pointer to a struct logininfo initialised with 230 * login_init_entry() or login_alloc_entry() 231 * 232 * Returns: 233 * >0 if successful 234 * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 235 */ 236 int 237 login_login(struct logininfo *li) 238 { 239 li->type = LTYPE_LOGIN; 240 return (login_write(li)); 241 } 242 243 244 /* 245 * login_logout(struct logininfo *) - Record a logout 246 * 247 * Call as with login_login() 248 * 249 * Returns: 250 * >0 if successful 251 * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 252 */ 253 int 254 login_logout(struct logininfo *li) 255 { 256 li->type = LTYPE_LOGOUT; 257 return (login_write(li)); 258 } 259 260 /* 261 * login_get_lastlog_time(int) - Retrieve the last login time 262 * 263 * Retrieve the last login time for the given uid. Will try to use the 264 * system lastlog facilities if they are available, but will fall back 265 * to looking in wtmp/wtmpx if necessary 266 * 267 * Returns: 268 * 0 on failure, or if user has never logged in 269 * Time in seconds from the epoch if successful 270 * 271 * Useful preprocessor symbols: 272 * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog 273 * info 274 * USE_LASTLOG: If set, indicates the presence of system lastlog 275 * facilities. If this and DISABLE_LASTLOG are not set, 276 * try to retrieve lastlog information from wtmp/wtmpx. 277 */ 278 unsigned int 279 login_get_lastlog_time(const uid_t uid) 280 { 281 struct logininfo li; 282 283 if (login_get_lastlog(&li, uid)) 284 return (li.tv_sec); 285 else 286 return (0); 287 } 288 289 /* 290 * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry 291 * 292 * Retrieve a logininfo structure populated (only partially) with 293 * information from the system lastlog data, or from wtmp/wtmpx if no 294 * system lastlog information exists. 295 * 296 * Note this routine must be given a pre-allocated logininfo. 297 * 298 * Returns: 299 * >0: A pointer to your struct logininfo if successful 300 * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 301 */ 302 struct logininfo * 303 login_get_lastlog(struct logininfo *li, const uid_t uid) 304 { 305 struct passwd *pw; 306 307 memset(li, '\0', sizeof(*li)); 308 li->uid = uid; 309 310 /* 311 * If we don't have a 'real' lastlog, we need the username to 312 * reliably search wtmp(x) for the last login (see 313 * wtmp_get_entry().) 314 */ 315 pw = getpwuid(uid); 316 if (pw == NULL) 317 fatal("%s: Cannot find account for uid %ld", __func__, 318 (long)uid); 319 320 if (strlcpy(li->username, pw->pw_name, sizeof(li->username)) >= 321 sizeof(li->username)) { 322 error("%s: username too long (%lu > max %lu)", __func__, 323 (unsigned long)strlen(pw->pw_name), 324 (unsigned long)sizeof(li->username) - 1); 325 return NULL; 326 } 327 328 if (getlast_entry(li)) 329 return (li); 330 else 331 return (NULL); 332 } 333 334 /* 335 * login_alloc_entry(int, char*, char*, char*) - Allocate and initialise 336 * a logininfo structure 337 * 338 * This function creates a new struct logininfo, a data structure 339 * meant to carry the information required to portably record login info. 340 * 341 * Returns a pointer to a newly created struct logininfo. If memory 342 * allocation fails, the program halts. 343 */ 344 struct 345 logininfo *login_alloc_entry(pid_t pid, const char *username, 346 const char *hostname, const char *line) 347 { 348 struct logininfo *newli; 349 350 newli = xmalloc(sizeof(*newli)); 351 login_init_entry(newli, pid, username, hostname, line); 352 return (newli); 353 } 354 355 356 /* login_free_entry(struct logininfo *) - free struct memory */ 357 void 358 login_free_entry(struct logininfo *li) 359 { 360 free(li); 361 } 362 363 364 /* login_init_entry(struct logininfo *, int, char*, char*, char*) 365 * - initialise a struct logininfo 366 * 367 * Populates a new struct logininfo, a data structure meant to carry 368 * the information required to portably record login info. 369 * 370 * Returns: 1 371 */ 372 int 373 login_init_entry(struct logininfo *li, pid_t pid, const char *username, 374 const char *hostname, const char *line) 375 { 376 struct passwd *pw; 377 378 memset(li, 0, sizeof(*li)); 379 380 li->pid = pid; 381 382 /* set the line information */ 383 if (line) 384 line_fullname(li->line, line, sizeof(li->line)); 385 386 if (username) { 387 strlcpy(li->username, username, sizeof(li->username)); 388 pw = getpwnam(li->username); 389 if (pw == NULL) { 390 fatal("%s: Cannot find user \"%s\"", __func__, 391 li->username); 392 } 393 li->uid = pw->pw_uid; 394 } 395 396 if (hostname) 397 strlcpy(li->hostname, hostname, sizeof(li->hostname)); 398 399 return (1); 400 } 401 402 /* 403 * login_set_current_time(struct logininfo *) - set the current time 404 * 405 * Set the current time in a logininfo structure. This function is 406 * meant to eliminate the need to deal with system dependencies for 407 * time handling. 408 */ 409 void 410 login_set_current_time(struct logininfo *li) 411 { 412 struct timeval tv; 413 414 gettimeofday(&tv, NULL); 415 416 li->tv_sec = tv.tv_sec; 417 li->tv_usec = tv.tv_usec; 418 } 419 420 /* copy a sockaddr_* into our logininfo */ 421 void 422 login_set_addr(struct logininfo *li, const struct sockaddr *sa, 423 const unsigned int sa_size) 424 { 425 unsigned int bufsize = sa_size; 426 427 /* make sure we don't overrun our union */ 428 if (sizeof(li->hostaddr) < sa_size) 429 bufsize = sizeof(li->hostaddr); 430 431 memcpy(&li->hostaddr.sa, sa, bufsize); 432 } 433 434 435 /** 436 ** login_write: Call low-level recording functions based on autoconf 437 ** results 438 **/ 439 int 440 login_write(struct logininfo *li) 441 { 442 #ifndef HAVE_CYGWIN 443 if (geteuid() != 0) { 444 logit("Attempt to write login records by non-root user (aborting)"); 445 return (1); 446 } 447 #endif 448 449 /* set the timestamp */ 450 login_set_current_time(li); 451 #ifdef USE_LOGIN 452 syslogin_write_entry(li); 453 #endif 454 #ifdef USE_LASTLOG 455 if (li->type == LTYPE_LOGIN) 456 lastlog_write_entry(li); 457 #endif 458 #ifdef USE_UTMP 459 utmp_write_entry(li); 460 #endif 461 #ifdef USE_WTMP 462 wtmp_write_entry(li); 463 #endif 464 #ifdef USE_UTMPX 465 utmpx_write_entry(li); 466 #endif 467 #ifdef USE_WTMPX 468 wtmpx_write_entry(li); 469 #endif 470 #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN 471 if (li->type == LTYPE_LOGIN && 472 !sys_auth_record_login(li->username,li->hostname,li->line, 473 loginmsg)) 474 logit("Writing login record failed for %s", li->username); 475 #endif 476 #ifdef SSH_AUDIT_EVENTS 477 if (li->type == LTYPE_LOGIN) 478 audit_session_open(li); 479 else if (li->type == LTYPE_LOGOUT) 480 audit_session_close(li); 481 #endif 482 return (0); 483 } 484 485 #ifdef LOGIN_NEEDS_UTMPX 486 int 487 login_utmp_only(struct logininfo *li) 488 { 489 li->type = LTYPE_LOGIN; 490 login_set_current_time(li); 491 # ifdef USE_UTMP 492 utmp_write_entry(li); 493 # endif 494 # ifdef USE_WTMP 495 wtmp_write_entry(li); 496 # endif 497 # ifdef USE_UTMPX 498 utmpx_write_entry(li); 499 # endif 500 # ifdef USE_WTMPX 501 wtmpx_write_entry(li); 502 # endif 503 return (0); 504 } 505 #endif 506 507 /** 508 ** getlast_entry: Call low-level functions to retrieve the last login 509 ** time. 510 **/ 511 512 /* take the uid in li and return the last login time */ 513 int 514 getlast_entry(struct logininfo *li) 515 { 516 #ifdef USE_LASTLOG 517 return(lastlog_get_entry(li)); 518 #else /* !USE_LASTLOG */ 519 #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \ 520 defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER) 521 return (utmpx_get_entry(li)); 522 #endif 523 524 #if defined(DISABLE_LASTLOG) 525 /* On some systems we shouldn't even try to obtain last login 526 * time, e.g. AIX */ 527 return (0); 528 # elif defined(USE_WTMP) && \ 529 (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) 530 /* retrieve last login time from utmp */ 531 return (wtmp_get_entry(li)); 532 # elif defined(USE_WTMPX) && \ 533 (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) 534 /* If wtmp isn't available, try wtmpx */ 535 return (wtmpx_get_entry(li)); 536 # else 537 /* Give up: No means of retrieving last login time */ 538 return (0); 539 # endif /* DISABLE_LASTLOG */ 540 #endif /* USE_LASTLOG */ 541 } 542 543 544 545 /* 546 * 'line' string utility functions 547 * 548 * These functions process the 'line' string into one of three forms: 549 * 550 * 1. The full filename (including '/dev') 551 * 2. The stripped name (excluding '/dev') 552 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00 553 * /dev/pts/1 -> ts/1 ) 554 * 555 * Form 3 is used on some systems to identify a .tmp.? entry when 556 * attempting to remove it. Typically both addition and removal is 557 * performed by one application - say, sshd - so as long as the choice 558 * uniquely identifies a terminal it's ok. 559 */ 560 561 562 /* 563 * line_fullname(): add the leading '/dev/' if it doesn't exist make 564 * sure dst has enough space, if not just copy src (ugh) 565 */ 566 char * 567 line_fullname(char *dst, const char *src, u_int dstsize) 568 { 569 memset(dst, '\0', dstsize); 570 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) 571 strlcpy(dst, src, dstsize); 572 else { 573 strlcpy(dst, "/dev/", dstsize); 574 strlcat(dst, src, dstsize); 575 } 576 return (dst); 577 } 578 579 /* line_stripname(): strip the leading '/dev' if it exists, return dst */ 580 char * 581 line_stripname(char *dst, const char *src, int dstsize) 582 { 583 memset(dst, '\0', dstsize); 584 if (strncmp(src, "/dev/", 5) == 0) 585 strlcpy(dst, src + 5, dstsize); 586 else 587 strlcpy(dst, src, dstsize); 588 return (dst); 589 } 590 591 /* 592 * line_abbrevname(): Return the abbreviated (usually four-character) 593 * form of the line (Just use the last <dstsize> characters of the 594 * full name.) 595 * 596 * NOTE: use strncpy because we do NOT necessarily want zero 597 * termination 598 */ 599 char * 600 line_abbrevname(char *dst, const char *src, int dstsize) 601 { 602 size_t len; 603 604 memset(dst, '\0', dstsize); 605 606 /* Always skip prefix if present */ 607 if (strncmp(src, "/dev/", 5) == 0) 608 src += 5; 609 610 #ifdef WITH_ABBREV_NO_TTY 611 if (strncmp(src, "tty", 3) == 0) 612 src += 3; 613 #endif 614 615 len = strlen(src); 616 617 if (len > 0) { 618 if (((int)len - dstsize) > 0) 619 src += ((int)len - dstsize); 620 621 /* note: _don't_ change this to strlcpy */ 622 strncpy(dst, src, (size_t)dstsize); 623 } 624 625 return (dst); 626 } 627 628 /** 629 ** utmp utility functions 630 ** 631 ** These functions manipulate struct utmp, taking system differences 632 ** into account. 633 **/ 634 635 #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN) 636 637 /* build the utmp structure */ 638 void 639 set_utmp_time(struct logininfo *li, struct utmp *ut) 640 { 641 # if defined(HAVE_TV_IN_UTMP) 642 ut->ut_tv.tv_sec = li->tv_sec; 643 ut->ut_tv.tv_usec = li->tv_usec; 644 # elif defined(HAVE_TIME_IN_UTMP) 645 ut->ut_time = li->tv_sec; 646 # endif 647 } 648 649 void 650 construct_utmp(struct logininfo *li, 651 struct utmp *ut) 652 { 653 # ifdef HAVE_ADDR_V6_IN_UTMP 654 struct sockaddr_in6 *sa6; 655 # endif 656 657 memset(ut, '\0', sizeof(*ut)); 658 659 /* First fill out fields used for both logins and logouts */ 660 661 # ifdef HAVE_ID_IN_UTMP 662 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id)); 663 # endif 664 665 # ifdef HAVE_TYPE_IN_UTMP 666 /* This is done here to keep utmp constants out of struct logininfo */ 667 switch (li->type) { 668 case LTYPE_LOGIN: 669 ut->ut_type = USER_PROCESS; 670 break; 671 case LTYPE_LOGOUT: 672 ut->ut_type = DEAD_PROCESS; 673 break; 674 } 675 # endif 676 set_utmp_time(li, ut); 677 678 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line)); 679 680 # ifdef HAVE_PID_IN_UTMP 681 ut->ut_pid = li->pid; 682 # endif 683 684 /* If we're logging out, leave all other fields blank */ 685 if (li->type == LTYPE_LOGOUT) 686 return; 687 688 /* 689 * These fields are only used when logging in, and are blank 690 * for logouts. 691 */ 692 693 /* Use strncpy because we don't necessarily want null termination */ 694 strncpy(ut->ut_name, li->username, 695 MIN_SIZEOF(ut->ut_name, li->username)); 696 # ifdef HAVE_HOST_IN_UTMP 697 strncpy(ut->ut_host, li->hostname, 698 MIN_SIZEOF(ut->ut_host, li->hostname)); 699 # endif 700 # ifdef HAVE_ADDR_IN_UTMP 701 /* this is just a 32-bit IP address */ 702 if (li->hostaddr.sa.sa_family == AF_INET) 703 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 704 # endif 705 # ifdef HAVE_ADDR_V6_IN_UTMP 706 /* this is just a 128-bit IPv6 address */ 707 if (li->hostaddr.sa.sa_family == AF_INET6) { 708 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); 709 memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); 710 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { 711 ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; 712 ut->ut_addr_v6[1] = 0; 713 ut->ut_addr_v6[2] = 0; 714 ut->ut_addr_v6[3] = 0; 715 } 716 } 717 # endif 718 } 719 #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */ 720 721 /** 722 ** utmpx utility functions 723 ** 724 ** These functions manipulate struct utmpx, accounting for system 725 ** variations. 726 **/ 727 728 #if defined(USE_UTMPX) || defined (USE_WTMPX) 729 /* build the utmpx structure */ 730 void 731 set_utmpx_time(struct logininfo *li, struct utmpx *utx) 732 { 733 # if defined(HAVE_TV_IN_UTMPX) 734 utx->ut_tv.tv_sec = li->tv_sec; 735 utx->ut_tv.tv_usec = li->tv_usec; 736 # elif defined(HAVE_TIME_IN_UTMPX) 737 utx->ut_time = li->tv_sec; 738 # endif 739 } 740 741 void 742 construct_utmpx(struct logininfo *li, struct utmpx *utx) 743 { 744 # ifdef HAVE_ADDR_V6_IN_UTMP 745 struct sockaddr_in6 *sa6; 746 # endif 747 memset(utx, '\0', sizeof(*utx)); 748 749 # ifdef HAVE_ID_IN_UTMPX 750 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); 751 # endif 752 753 /* this is done here to keep utmp constants out of loginrec.h */ 754 switch (li->type) { 755 case LTYPE_LOGIN: 756 utx->ut_type = USER_PROCESS; 757 break; 758 case LTYPE_LOGOUT: 759 utx->ut_type = DEAD_PROCESS; 760 break; 761 } 762 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); 763 set_utmpx_time(li, utx); 764 utx->ut_pid = li->pid; 765 766 /* strncpy(): Don't necessarily want null termination */ 767 strncpy(utx->ut_user, li->username, 768 MIN_SIZEOF(utx->ut_user, li->username)); 769 770 if (li->type == LTYPE_LOGOUT) 771 return; 772 773 /* 774 * These fields are only used when logging in, and are blank 775 * for logouts. 776 */ 777 778 # ifdef HAVE_HOST_IN_UTMPX 779 strncpy(utx->ut_host, li->hostname, 780 MIN_SIZEOF(utx->ut_host, li->hostname)); 781 # endif 782 # ifdef HAVE_SS_IN_UTMPX 783 utx->ut_ss = li->hostaddr.sa_storage; 784 # endif 785 # ifdef HAVE_ADDR_IN_UTMPX 786 /* this is just a 32-bit IP address */ 787 if (li->hostaddr.sa.sa_family == AF_INET) 788 utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 789 # endif 790 # ifdef HAVE_ADDR_V6_IN_UTMP 791 /* this is just a 128-bit IPv6 address */ 792 if (li->hostaddr.sa.sa_family == AF_INET6) { 793 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); 794 memcpy(utx->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); 795 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { 796 utx->ut_addr_v6[0] = utx->ut_addr_v6[3]; 797 utx->ut_addr_v6[1] = 0; 798 utx->ut_addr_v6[2] = 0; 799 utx->ut_addr_v6[3] = 0; 800 } 801 } 802 # endif 803 # ifdef HAVE_SYSLEN_IN_UTMPX 804 /* ut_syslen is the length of the utx_host string */ 805 utx->ut_syslen = MINIMUM(strlen(li->hostname), sizeof(utx->ut_host)); 806 # endif 807 } 808 #endif /* USE_UTMPX || USE_WTMPX */ 809 810 /** 811 ** Low-level utmp functions 812 **/ 813 814 /* FIXME: (ATL) utmp_write_direct needs testing */ 815 #ifdef USE_UTMP 816 817 /* if we can, use pututline() etc. */ 818 # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ 819 defined(HAVE_PUTUTLINE) 820 # define UTMP_USE_LIBRARY 821 # endif 822 823 824 /* write a utmp entry with the system's help (pututline() and pals) */ 825 # ifdef UTMP_USE_LIBRARY 826 static int 827 utmp_write_library(struct logininfo *li, struct utmp *ut) 828 { 829 setutent(); 830 pututline(ut); 831 # ifdef HAVE_ENDUTENT 832 endutent(); 833 # endif 834 return (1); 835 } 836 # else /* UTMP_USE_LIBRARY */ 837 838 /* 839 * Write a utmp entry direct to the file 840 * This is a slightly modification of code in OpenBSD's login.c 841 */ 842 static int 843 utmp_write_direct(struct logininfo *li, struct utmp *ut) 844 { 845 struct utmp old_ut; 846 register int fd; 847 int tty; 848 849 /* FIXME: (ATL) ttyslot() needs local implementation */ 850 851 #if defined(HAVE_GETTTYENT) 852 struct ttyent *ty; 853 854 tty=0; 855 setttyent(); 856 while (NULL != (ty = getttyent())) { 857 tty++; 858 if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) 859 break; 860 } 861 endttyent(); 862 863 if (NULL == ty) { 864 logit("%s: tty not found", __func__); 865 return (0); 866 } 867 #else /* FIXME */ 868 869 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */ 870 871 #endif /* HAVE_GETTTYENT */ 872 873 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) { 874 off_t pos, ret; 875 876 pos = (off_t)tty * sizeof(struct utmp); 877 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { 878 logit("%s: lseek: %s", __func__, strerror(errno)); 879 close(fd); 880 return (0); 881 } 882 if (ret != pos) { 883 logit("%s: Couldn't seek to tty %d slot in %s", 884 __func__, tty, UTMP_FILE); 885 close(fd); 886 return (0); 887 } 888 /* 889 * Prevent luser from zero'ing out ut_host. 890 * If the new ut_line is empty but the old one is not 891 * and ut_line and ut_name match, preserve the old ut_line. 892 */ 893 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && 894 (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && 895 (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && 896 (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) 897 memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); 898 899 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { 900 logit("%s: lseek: %s", __func__, strerror(errno)); 901 close(fd); 902 return (0); 903 } 904 if (ret != pos) { 905 logit("%s: Couldn't seek to tty %d slot in %s", 906 __func__, tty, UTMP_FILE); 907 close(fd); 908 return (0); 909 } 910 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { 911 logit("%s: error writing %s: %s", __func__, 912 UTMP_FILE, strerror(errno)); 913 close(fd); 914 return (0); 915 } 916 917 close(fd); 918 return (1); 919 } else { 920 return (0); 921 } 922 } 923 # endif /* UTMP_USE_LIBRARY */ 924 925 static int 926 utmp_perform_login(struct logininfo *li) 927 { 928 struct utmp ut; 929 930 construct_utmp(li, &ut); 931 # ifdef UTMP_USE_LIBRARY 932 if (!utmp_write_library(li, &ut)) { 933 logit("%s: utmp_write_library() failed", __func__); 934 return (0); 935 } 936 # else 937 if (!utmp_write_direct(li, &ut)) { 938 logit("%s: utmp_write_direct() failed", __func__); 939 return (0); 940 } 941 # endif 942 return (1); 943 } 944 945 946 static int 947 utmp_perform_logout(struct logininfo *li) 948 { 949 struct utmp ut; 950 951 construct_utmp(li, &ut); 952 # ifdef UTMP_USE_LIBRARY 953 if (!utmp_write_library(li, &ut)) { 954 logit("%s: utmp_write_library() failed", __func__); 955 return (0); 956 } 957 # else 958 if (!utmp_write_direct(li, &ut)) { 959 logit("%s: utmp_write_direct() failed", __func__); 960 return (0); 961 } 962 # endif 963 return (1); 964 } 965 966 967 int 968 utmp_write_entry(struct logininfo *li) 969 { 970 switch(li->type) { 971 case LTYPE_LOGIN: 972 return (utmp_perform_login(li)); 973 974 case LTYPE_LOGOUT: 975 return (utmp_perform_logout(li)); 976 977 default: 978 logit("%s: invalid type field", __func__); 979 return (0); 980 } 981 } 982 #endif /* USE_UTMP */ 983 984 985 /** 986 ** Low-level utmpx functions 987 **/ 988 989 /* not much point if we don't want utmpx entries */ 990 #ifdef USE_UTMPX 991 992 /* if we have the wherewithall, use pututxline etc. */ 993 # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \ 994 defined(HAVE_PUTUTXLINE) 995 # define UTMPX_USE_LIBRARY 996 # endif 997 998 999 /* write a utmpx entry with the system's help (pututxline() and pals) */ 1000 # ifdef UTMPX_USE_LIBRARY 1001 static int 1002 utmpx_write_library(struct logininfo *li, struct utmpx *utx) 1003 { 1004 setutxent(); 1005 pututxline(utx); 1006 1007 # ifdef HAVE_ENDUTXENT 1008 endutxent(); 1009 # endif 1010 return (1); 1011 } 1012 1013 # else /* UTMPX_USE_LIBRARY */ 1014 1015 /* write a utmp entry direct to the file */ 1016 static int 1017 utmpx_write_direct(struct logininfo *li, struct utmpx *utx) 1018 { 1019 logit("%s: not implemented!", __func__); 1020 return (0); 1021 } 1022 # endif /* UTMPX_USE_LIBRARY */ 1023 1024 static int 1025 utmpx_perform_login(struct logininfo *li) 1026 { 1027 struct utmpx utx; 1028 1029 construct_utmpx(li, &utx); 1030 # ifdef UTMPX_USE_LIBRARY 1031 if (!utmpx_write_library(li, &utx)) { 1032 logit("%s: utmp_write_library() failed", __func__); 1033 return (0); 1034 } 1035 # else 1036 if (!utmpx_write_direct(li, &ut)) { 1037 logit("%s: utmp_write_direct() failed", __func__); 1038 return (0); 1039 } 1040 # endif 1041 return (1); 1042 } 1043 1044 1045 static int 1046 utmpx_perform_logout(struct logininfo *li) 1047 { 1048 struct utmpx utx; 1049 1050 construct_utmpx(li, &utx); 1051 # ifdef HAVE_ID_IN_UTMPX 1052 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id)); 1053 # endif 1054 # ifdef HAVE_TYPE_IN_UTMPX 1055 utx.ut_type = DEAD_PROCESS; 1056 # endif 1057 1058 # ifdef UTMPX_USE_LIBRARY 1059 utmpx_write_library(li, &utx); 1060 # else 1061 utmpx_write_direct(li, &utx); 1062 # endif 1063 return (1); 1064 } 1065 1066 int 1067 utmpx_write_entry(struct logininfo *li) 1068 { 1069 switch(li->type) { 1070 case LTYPE_LOGIN: 1071 return (utmpx_perform_login(li)); 1072 case LTYPE_LOGOUT: 1073 return (utmpx_perform_logout(li)); 1074 default: 1075 logit("%s: invalid type field", __func__); 1076 return (0); 1077 } 1078 } 1079 #endif /* USE_UTMPX */ 1080 1081 1082 /** 1083 ** Low-level wtmp functions 1084 **/ 1085 1086 #ifdef USE_WTMP 1087 1088 /* 1089 * Write a wtmp entry direct to the end of the file 1090 * This is a slight modification of code in OpenBSD's logwtmp.c 1091 */ 1092 static int 1093 wtmp_write(struct logininfo *li, struct utmp *ut) 1094 { 1095 struct stat buf; 1096 int fd, ret = 1; 1097 1098 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 1099 logit("%s: problem writing %s: %s", __func__, 1100 WTMP_FILE, strerror(errno)); 1101 return (0); 1102 } 1103 if (fstat(fd, &buf) == 0) 1104 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { 1105 ftruncate(fd, buf.st_size); 1106 logit("%s: problem writing %s: %s", __func__, 1107 WTMP_FILE, strerror(errno)); 1108 ret = 0; 1109 } 1110 close(fd); 1111 return (ret); 1112 } 1113 1114 static int 1115 wtmp_perform_login(struct logininfo *li) 1116 { 1117 struct utmp ut; 1118 1119 construct_utmp(li, &ut); 1120 return (wtmp_write(li, &ut)); 1121 } 1122 1123 1124 static int 1125 wtmp_perform_logout(struct logininfo *li) 1126 { 1127 struct utmp ut; 1128 1129 construct_utmp(li, &ut); 1130 return (wtmp_write(li, &ut)); 1131 } 1132 1133 1134 int 1135 wtmp_write_entry(struct logininfo *li) 1136 { 1137 switch(li->type) { 1138 case LTYPE_LOGIN: 1139 return (wtmp_perform_login(li)); 1140 case LTYPE_LOGOUT: 1141 return (wtmp_perform_logout(li)); 1142 default: 1143 logit("%s: invalid type field", __func__); 1144 return (0); 1145 } 1146 } 1147 1148 1149 /* 1150 * Notes on fetching login data from wtmp/wtmpx 1151 * 1152 * Logouts are usually recorded with (amongst other things) a blank 1153 * username on a given tty line. However, some systems (HP-UX is one) 1154 * leave all fields set, but change the ut_type field to DEAD_PROCESS. 1155 * 1156 * Since we're only looking for logins here, we know that the username 1157 * must be set correctly. On systems that leave it in, we check for 1158 * ut_type==USER_PROCESS (indicating a login.) 1159 * 1160 * Portability: Some systems may set something other than USER_PROCESS 1161 * to indicate a login process. I don't know of any as I write. Also, 1162 * it's possible that some systems may both leave the username in 1163 * place and not have ut_type. 1164 */ 1165 1166 /* return true if this wtmp entry indicates a login */ 1167 static int 1168 wtmp_islogin(struct logininfo *li, struct utmp *ut) 1169 { 1170 if (strncmp(li->username, ut->ut_name, 1171 MIN_SIZEOF(li->username, ut->ut_name)) == 0) { 1172 # ifdef HAVE_TYPE_IN_UTMP 1173 if (ut->ut_type & USER_PROCESS) 1174 return (1); 1175 # else 1176 return (1); 1177 # endif 1178 } 1179 return (0); 1180 } 1181 1182 int 1183 wtmp_get_entry(struct logininfo *li) 1184 { 1185 struct stat st; 1186 struct utmp ut; 1187 int fd, found = 0; 1188 1189 /* Clear the time entries in our logininfo */ 1190 li->tv_sec = li->tv_usec = 0; 1191 1192 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { 1193 logit("%s: problem opening %s: %s", __func__, 1194 WTMP_FILE, strerror(errno)); 1195 return (0); 1196 } 1197 if (fstat(fd, &st) != 0) { 1198 logit("%s: couldn't stat %s: %s", __func__, 1199 WTMP_FILE, strerror(errno)); 1200 close(fd); 1201 return (0); 1202 } 1203 1204 /* Seek to the start of the last struct utmp */ 1205 if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { 1206 /* Looks like we've got a fresh wtmp file */ 1207 close(fd); 1208 return (0); 1209 } 1210 1211 while (!found) { 1212 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { 1213 logit("%s: read of %s failed: %s", __func__, 1214 WTMP_FILE, strerror(errno)); 1215 close (fd); 1216 return (0); 1217 } 1218 if (wtmp_islogin(li, &ut) ) { 1219 found = 1; 1220 /* 1221 * We've already checked for a time in struct 1222 * utmp, in login_getlast() 1223 */ 1224 # ifdef HAVE_TIME_IN_UTMP 1225 li->tv_sec = ut.ut_time; 1226 # else 1227 # if HAVE_TV_IN_UTMP 1228 li->tv_sec = ut.ut_tv.tv_sec; 1229 # endif 1230 # endif 1231 line_fullname(li->line, ut.ut_line, 1232 MIN_SIZEOF(li->line, ut.ut_line)); 1233 # ifdef HAVE_HOST_IN_UTMP 1234 strlcpy(li->hostname, ut.ut_host, 1235 MIN_SIZEOF(li->hostname, ut.ut_host)); 1236 # endif 1237 continue; 1238 } 1239 /* Seek back 2 x struct utmp */ 1240 if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { 1241 /* We've found the start of the file, so quit */ 1242 close(fd); 1243 return (0); 1244 } 1245 } 1246 1247 /* We found an entry. Tidy up and return */ 1248 close(fd); 1249 return (1); 1250 } 1251 # endif /* USE_WTMP */ 1252 1253 1254 /** 1255 ** Low-level wtmpx functions 1256 **/ 1257 1258 #ifdef USE_WTMPX 1259 /* 1260 * Write a wtmpx entry direct to the end of the file 1261 * This is a slight modification of code in OpenBSD's logwtmp.c 1262 */ 1263 static int 1264 wtmpx_write(struct logininfo *li, struct utmpx *utx) 1265 { 1266 #ifndef HAVE_UPDWTMPX 1267 struct stat buf; 1268 int fd, ret = 1; 1269 1270 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 1271 logit("%s: problem opening %s: %s", __func__, 1272 WTMPX_FILE, strerror(errno)); 1273 return (0); 1274 } 1275 1276 if (fstat(fd, &buf) == 0) 1277 if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) { 1278 ftruncate(fd, buf.st_size); 1279 logit("%s: problem writing %s: %s", __func__, 1280 WTMPX_FILE, strerror(errno)); 1281 ret = 0; 1282 } 1283 close(fd); 1284 1285 return (ret); 1286 #else 1287 updwtmpx(WTMPX_FILE, utx); 1288 return (1); 1289 #endif 1290 } 1291 1292 1293 static int 1294 wtmpx_perform_login(struct logininfo *li) 1295 { 1296 struct utmpx utx; 1297 1298 construct_utmpx(li, &utx); 1299 return (wtmpx_write(li, &utx)); 1300 } 1301 1302 1303 static int 1304 wtmpx_perform_logout(struct logininfo *li) 1305 { 1306 struct utmpx utx; 1307 1308 construct_utmpx(li, &utx); 1309 return (wtmpx_write(li, &utx)); 1310 } 1311 1312 1313 int 1314 wtmpx_write_entry(struct logininfo *li) 1315 { 1316 switch(li->type) { 1317 case LTYPE_LOGIN: 1318 return (wtmpx_perform_login(li)); 1319 case LTYPE_LOGOUT: 1320 return (wtmpx_perform_logout(li)); 1321 default: 1322 logit("%s: invalid type field", __func__); 1323 return (0); 1324 } 1325 } 1326 1327 /* Please see the notes above wtmp_islogin() for information about the 1328 next two functions */ 1329 1330 /* Return true if this wtmpx entry indicates a login */ 1331 static int 1332 wtmpx_islogin(struct logininfo *li, struct utmpx *utx) 1333 { 1334 if (strncmp(li->username, utx->ut_user, 1335 MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) { 1336 # ifdef HAVE_TYPE_IN_UTMPX 1337 if (utx->ut_type == USER_PROCESS) 1338 return (1); 1339 # else 1340 return (1); 1341 # endif 1342 } 1343 return (0); 1344 } 1345 1346 1347 int 1348 wtmpx_get_entry(struct logininfo *li) 1349 { 1350 struct stat st; 1351 struct utmpx utx; 1352 int fd, found=0; 1353 1354 /* Clear the time entries */ 1355 li->tv_sec = li->tv_usec = 0; 1356 1357 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { 1358 logit("%s: problem opening %s: %s", __func__, 1359 WTMPX_FILE, strerror(errno)); 1360 return (0); 1361 } 1362 if (fstat(fd, &st) != 0) { 1363 logit("%s: couldn't stat %s: %s", __func__, 1364 WTMPX_FILE, strerror(errno)); 1365 close(fd); 1366 return (0); 1367 } 1368 1369 /* Seek to the start of the last struct utmpx */ 1370 if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { 1371 /* probably a newly rotated wtmpx file */ 1372 close(fd); 1373 return (0); 1374 } 1375 1376 while (!found) { 1377 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { 1378 logit("%s: read of %s failed: %s", __func__, 1379 WTMPX_FILE, strerror(errno)); 1380 close (fd); 1381 return (0); 1382 } 1383 /* 1384 * Logouts are recorded as a blank username on a particular 1385 * line. So, we just need to find the username in struct utmpx 1386 */ 1387 if (wtmpx_islogin(li, &utx)) { 1388 found = 1; 1389 # if defined(HAVE_TV_IN_UTMPX) 1390 li->tv_sec = utx.ut_tv.tv_sec; 1391 # elif defined(HAVE_TIME_IN_UTMPX) 1392 li->tv_sec = utx.ut_time; 1393 # endif 1394 line_fullname(li->line, utx.ut_line, sizeof(li->line)); 1395 # if defined(HAVE_HOST_IN_UTMPX) 1396 strlcpy(li->hostname, utx.ut_host, 1397 MIN_SIZEOF(li->hostname, utx.ut_host)); 1398 # endif 1399 continue; 1400 } 1401 if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { 1402 close(fd); 1403 return (0); 1404 } 1405 } 1406 1407 close(fd); 1408 return (1); 1409 } 1410 #endif /* USE_WTMPX */ 1411 1412 /** 1413 ** Low-level libutil login() functions 1414 **/ 1415 1416 #ifdef USE_LOGIN 1417 static int 1418 syslogin_perform_login(struct logininfo *li) 1419 { 1420 struct utmp *ut; 1421 1422 ut = xmalloc(sizeof(*ut)); 1423 construct_utmp(li, ut); 1424 login(ut); 1425 free(ut); 1426 1427 return (1); 1428 } 1429 1430 static int 1431 syslogin_perform_logout(struct logininfo *li) 1432 { 1433 # ifdef HAVE_LOGOUT 1434 char line[UT_LINESIZE]; 1435 1436 (void)line_stripname(line, li->line, sizeof(line)); 1437 1438 if (!logout(line)) 1439 logit("%s: logout() returned an error", __func__); 1440 # ifdef HAVE_LOGWTMP 1441 else 1442 logwtmp(line, "", ""); 1443 # endif 1444 /* FIXME: (ATL - if the need arises) What to do if we have 1445 * login, but no logout? what if logout but no logwtmp? All 1446 * routines are in libutil so they should all be there, 1447 * but... */ 1448 # endif 1449 return (1); 1450 } 1451 1452 int 1453 syslogin_write_entry(struct logininfo *li) 1454 { 1455 switch (li->type) { 1456 case LTYPE_LOGIN: 1457 return (syslogin_perform_login(li)); 1458 case LTYPE_LOGOUT: 1459 return (syslogin_perform_logout(li)); 1460 default: 1461 logit("%s: Invalid type field", __func__); 1462 return (0); 1463 } 1464 } 1465 #endif /* USE_LOGIN */ 1466 1467 /* end of file log-syslogin.c */ 1468 1469 /** 1470 ** Low-level lastlog functions 1471 **/ 1472 1473 #ifdef USE_LASTLOG 1474 1475 #if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME) 1476 /* open the file (using filemode) and seek to the login entry */ 1477 static int 1478 lastlog_openseek(struct logininfo *li, int *fd, int filemode) 1479 { 1480 off_t offset; 1481 char lastlog_file[1024]; 1482 struct stat st; 1483 1484 if (stat(LASTLOG_FILE, &st) != 0) { 1485 logit("%s: Couldn't stat %s: %s", __func__, 1486 LASTLOG_FILE, strerror(errno)); 1487 return (0); 1488 } 1489 if (S_ISDIR(st.st_mode)) { 1490 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", 1491 LASTLOG_FILE, li->username); 1492 } else if (S_ISREG(st.st_mode)) { 1493 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); 1494 } else { 1495 logit("%s: %.100s is not a file or directory!", __func__, 1496 LASTLOG_FILE); 1497 return (0); 1498 } 1499 1500 *fd = open(lastlog_file, filemode, 0600); 1501 if (*fd < 0) { 1502 debug("%s: Couldn't open %s: %s", __func__, 1503 lastlog_file, strerror(errno)); 1504 return (0); 1505 } 1506 1507 if (S_ISREG(st.st_mode)) { 1508 /* find this uid's offset in the lastlog file */ 1509 offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog)); 1510 1511 if (lseek(*fd, offset, SEEK_SET) != offset) { 1512 logit("%s: %s->lseek(): %s", __func__, 1513 lastlog_file, strerror(errno)); 1514 close(*fd); 1515 return (0); 1516 } 1517 } 1518 1519 return (1); 1520 } 1521 #endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */ 1522 1523 #ifdef LASTLOG_WRITE_PUTUTXLINE 1524 int 1525 lastlog_write_entry(struct logininfo *li) 1526 { 1527 switch(li->type) { 1528 case LTYPE_LOGIN: 1529 return 1; /* lastlog written by pututxline */ 1530 default: 1531 logit("lastlog_write_entry: Invalid type field"); 1532 return 0; 1533 } 1534 } 1535 #else /* LASTLOG_WRITE_PUTUTXLINE */ 1536 int 1537 lastlog_write_entry(struct logininfo *li) 1538 { 1539 struct lastlog last; 1540 int fd; 1541 1542 switch(li->type) { 1543 case LTYPE_LOGIN: 1544 /* create our struct lastlog */ 1545 memset(&last, '\0', sizeof(last)); 1546 line_stripname(last.ll_line, li->line, sizeof(last.ll_line)); 1547 strlcpy(last.ll_host, li->hostname, 1548 MIN_SIZEOF(last.ll_host, li->hostname)); 1549 last.ll_time = li->tv_sec; 1550 1551 if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) 1552 return (0); 1553 1554 /* write the entry */ 1555 if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) { 1556 close(fd); 1557 logit("%s: Error writing to %s: %s", __func__, 1558 LASTLOG_FILE, strerror(errno)); 1559 return (0); 1560 } 1561 1562 close(fd); 1563 return (1); 1564 default: 1565 logit("%s: Invalid type field", __func__); 1566 return (0); 1567 } 1568 } 1569 #endif /* LASTLOG_WRITE_PUTUTXLINE */ 1570 1571 #ifdef HAVE_GETLASTLOGXBYNAME 1572 int 1573 lastlog_get_entry(struct logininfo *li) 1574 { 1575 struct lastlogx l, *ll; 1576 1577 if ((ll = getlastlogxbyname(li->username, &l)) == NULL) { 1578 memset(&l, '\0', sizeof(l)); 1579 ll = &l; 1580 } 1581 line_fullname(li->line, ll->ll_line, sizeof(li->line)); 1582 strlcpy(li->hostname, ll->ll_host, 1583 MIN_SIZEOF(li->hostname, ll->ll_host)); 1584 li->tv_sec = ll->ll_tv.tv_sec; 1585 li->tv_usec = ll->ll_tv.tv_usec; 1586 return (1); 1587 } 1588 #else /* HAVE_GETLASTLOGXBYNAME */ 1589 int 1590 lastlog_get_entry(struct logininfo *li) 1591 { 1592 struct lastlog last; 1593 int fd, ret; 1594 1595 if (!lastlog_openseek(li, &fd, O_RDONLY)) 1596 return (0); 1597 1598 ret = atomicio(read, fd, &last, sizeof(last)); 1599 close(fd); 1600 1601 switch (ret) { 1602 case 0: 1603 memset(&last, '\0', sizeof(last)); 1604 /* FALLTHRU */ 1605 case sizeof(last): 1606 line_fullname(li->line, last.ll_line, sizeof(li->line)); 1607 strlcpy(li->hostname, last.ll_host, 1608 MIN_SIZEOF(li->hostname, last.ll_host)); 1609 li->tv_sec = last.ll_time; 1610 return (1); 1611 case -1: 1612 error("%s: Error reading from %s: %s", __func__, 1613 LASTLOG_FILE, strerror(errno)); 1614 return (0); 1615 default: 1616 error("%s: Error reading from %s: Expecting %d, got %d", 1617 __func__, LASTLOG_FILE, (int)sizeof(last), ret); 1618 return (0); 1619 } 1620 1621 /* NOTREACHED */ 1622 return (0); 1623 } 1624 #endif /* HAVE_GETLASTLOGXBYNAME */ 1625 #endif /* USE_LASTLOG */ 1626 1627 #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \ 1628 defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER) 1629 int 1630 utmpx_get_entry(struct logininfo *li) 1631 { 1632 struct utmpx *utx; 1633 1634 if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0) 1635 return (0); 1636 utx = getutxuser(li->username); 1637 if (utx == NULL) { 1638 endutxent(); 1639 return (0); 1640 } 1641 1642 line_fullname(li->line, utx->ut_line, 1643 MIN_SIZEOF(li->line, utx->ut_line)); 1644 strlcpy(li->hostname, utx->ut_host, 1645 MIN_SIZEOF(li->hostname, utx->ut_host)); 1646 li->tv_sec = utx->ut_tv.tv_sec; 1647 li->tv_usec = utx->ut_tv.tv_usec; 1648 endutxent(); 1649 return (1); 1650 } 1651 #endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */ 1652 1653 #ifdef USE_BTMP 1654 /* 1655 * Logs failed login attempts in _PATH_BTMP if that exists. 1656 * The most common login failure is to give password instead of username. 1657 * So the _PATH_BTMP file checked for the correct permission, so that 1658 * only root can read it. 1659 */ 1660 1661 void 1662 record_failed_login(struct ssh *ssh, const char *username, const char *hostname, 1663 const char *ttyn) 1664 { 1665 int fd; 1666 struct utmp ut; 1667 struct sockaddr_storage from; 1668 socklen_t fromlen = sizeof(from); 1669 struct sockaddr_in *a4; 1670 struct sockaddr_in6 *a6; 1671 time_t t; 1672 struct stat fst; 1673 1674 if (geteuid() != 0) 1675 return; 1676 if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) { 1677 debug("Unable to open the btmp file %s: %s", _PATH_BTMP, 1678 strerror(errno)); 1679 return; 1680 } 1681 if (fstat(fd, &fst) < 0) { 1682 logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP, 1683 strerror(errno)); 1684 goto out; 1685 } 1686 if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){ 1687 logit("Excess permission or bad ownership on file %s", 1688 _PATH_BTMP); 1689 goto out; 1690 } 1691 1692 memset(&ut, 0, sizeof(ut)); 1693 /* strncpy because we don't necessarily want nul termination */ 1694 strncpy(ut.ut_user, username, sizeof(ut.ut_user)); 1695 strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); 1696 1697 time(&t); 1698 ut.ut_time = t; /* ut_time is not always a time_t */ 1699 ut.ut_type = LOGIN_PROCESS; 1700 ut.ut_pid = getpid(); 1701 1702 /* strncpy because we don't necessarily want nul termination */ 1703 strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); 1704 1705 if (ssh_packet_connection_is_on_socket(ssh) && 1706 getpeername(ssh_packet_get_connection_in(ssh), 1707 (struct sockaddr *)&from, &fromlen) == 0) { 1708 ipv64_normalise_mapped(&from, &fromlen); 1709 if (from.ss_family == AF_INET) { 1710 a4 = (struct sockaddr_in *)&from; 1711 memcpy(&ut.ut_addr, &(a4->sin_addr), 1712 MIN_SIZEOF(ut.ut_addr, a4->sin_addr)); 1713 } 1714 #ifdef HAVE_ADDR_V6_IN_UTMP 1715 if (from.ss_family == AF_INET6) { 1716 a6 = (struct sockaddr_in6 *)&from; 1717 memcpy(&ut.ut_addr_v6, &(a6->sin6_addr), 1718 MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr)); 1719 } 1720 #endif 1721 } 1722 1723 if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut)) 1724 error("Failed to write to %s: %s", _PATH_BTMP, 1725 strerror(errno)); 1726 1727 out: 1728 close(fd); 1729 } 1730 #endif /* USE_BTMP */ 1731