1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program (see the file COPYING); if not, write to the 18 * Free Software Foundation, Inc., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 * 21 **************************************************************** 22 */ 23 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <fcntl.h> 27 28#include "config.h" 29#include "screen.h" 30#include "extern.h" 31 32#ifdef HAVE_UTEMPTER 33#include <utempter.h> 34#endif 35 36 37extern struct display *display; 38#ifdef CAREFULUTMP 39extern struct win *windows; 40#endif 41extern struct win *fore; 42extern char *LoginName; 43extern int real_uid, eff_uid; 44 45 46/* 47 * UTNOKEEP: A (ugly) hack for apollo that does two things: 48 * 1) Always close and reopen the utmp file descriptor. (I don't know 49 * for what reason this is done...) 50 * 2) Implement an unsorted utmp file much like GETUTENT. 51 * (split into UT_CLOSE and UT_UNSORTED) 52 */ 53 54 55#ifdef UTNOKEEP 56# define UT_CLOSE 57# define UT_UNSORTED 58#endif 59 60#ifdef UT_CLOSE 61# undef UT_CLOSE 62# define UT_CLOSE endutent() 63#else 64# define UT_CLOSE 65#endif 66 67 68/* 69 * we have a suid-root helper app that changes the utmp for us 70 * (won't work for login-slots) 71 */ 72#if (defined(sun) && defined(SVR4) && defined(GETUTENT)) || defined(HAVE_UTEMPTER) 73# define UTMP_HELPER 74#endif 75 76 77 78#ifdef UTMPOK 79 80 81static slot_t TtyNameSlot __P((char *)); 82static void makeuser __P((struct utmp *, char *, char *, int)); 83static void makedead __P((struct utmp *)); 84static int pututslot __P((slot_t, struct utmp *, char *, struct win *)); 85static struct utmp *getutslot __P((slot_t)); 86#ifndef GETUTENT 87static struct utmp *getutent __P((void)); 88static void endutent __P((void)); 89static int initutmp __P((void)); 90static void setutent __P((void)); 91#endif 92#if defined(linux) && defined(GETUTENT) 93static struct utmp *xpututline __P((struct utmp *utmp)); 94# define pututline xpututline 95#endif 96 97 98static int utmpok; 99static char UtmpName[] = UTMPFILE; 100#ifndef UTMP_HELPER 101static int utmpfd = -1; 102#endif 103 104 105# if defined(GETUTENT) && (!defined(SVR4) || defined(__hpux)) 106# if defined(hpux) /* cruel hpux release 8.0 */ 107# define pututline _pututline 108# endif /* hpux */ 109extern struct utmp *getutline(), *pututline(); 110# if defined(_SEQUENT_) 111extern struct utmp *ut_add_user(), *ut_delete_user(); 112extern char *ut_find_host(); 113# ifndef UTHOST 114# define UTHOST /* _SEQUENT_ has ut_find_host() */ 115# endif 116# endif /* _SEQUENT_ */ 117# endif /* GETUTENT && !SVR4 */ 118 119# if !defined(GETUTENT) && !defined(UT_UNSORTED) 120# ifdef GETTTYENT 121# include <ttyent.h> 122# else 123struct ttyent { char *ty_name; }; 124static void setttyent __P((void)); 125static struct ttyent *getttyent __P((void)); 126# endif 127# endif /* !GETUTENT && !UT_UNSORTED */ 128 129#ifndef _SEQUENT_ 130# undef D_loginhost 131# define D_loginhost D_utmp_logintty.ut_host 132#endif 133#ifndef UTHOST 134# undef D_loginhost 135# define D_loginhost ((char *)0) 136#endif 137 138 139#endif /* UTMPOK */ 140 141 142/* 143 * SlotToggle - modify the utmp slot of the fore window. 144 * 145 * how > 0 do try to set a utmp slot. 146 * how = 0 try to withdraw a utmp slot. 147 * 148 * w_slot = -1 window not logged in. 149 * w_slot = 0 window not logged in, but should be logged in. 150 * (unable to write utmp, or detached). 151 */ 152 153#ifndef UTMPOK 154void 155SlotToggle(how) 156int how; 157{ 158 debug1("SlotToggle (!UTMPOK) %d\n", how); 159# ifdef UTMPFILE 160 Msg(0, "Unable to modify %s.\n", UTMPFILE); 161# else 162 Msg(0, "Unable to modify utmp-database.\n"); 163# endif 164} 165#endif 166 167 168 169#ifdef UTMPOK 170 171void 172SlotToggle(how) 173int how; 174{ 175 debug1("SlotToggle %d\n", how); 176 if (fore->w_type != W_TYPE_PTY) 177 { 178 Msg(0, "Can only work with normal windows.\n"); 179 return; 180 } 181 if (how) 182 { 183 debug(" try to log in\n"); 184 if ((fore->w_slot == (slot_t) -1) || (fore->w_slot == (slot_t) 0)) 185 { 186#ifdef USRLIMIT 187 if (CountUsers() >= USRLIMIT) 188 { 189 Msg(0, "User limit reached."); 190 return; 191 } 192#endif 193 if (SetUtmp(fore) == 0) 194 Msg(0, "This window is now logged in."); 195 else 196 Msg(0, "This window should now be logged in."); 197 WindowChanged(fore, 'f'); 198 } 199 else 200 Msg(0, "This window is already logged in."); 201 } 202 else 203 { 204 debug(" try to log out\n"); 205 if (fore->w_slot == (slot_t) -1) 206 Msg(0, "This window is already logged out\n"); 207 else if (fore->w_slot == (slot_t) 0) 208 { 209 debug("What a relief! In fact, it was not logged in\n"); 210 Msg(0, "This window is not logged in."); 211 fore->w_slot = (slot_t) -1; 212 } 213 else 214 { 215 RemoveUtmp(fore); 216 if (fore->w_slot != (slot_t) -1) 217 Msg(0, "What? Cannot remove Utmp slot?"); 218 else 219 Msg(0, "This window is no longer logged in."); 220#ifdef CAREFULUTMP 221 CarefulUtmp(); 222#endif 223 WindowChanged(fore, 'f'); 224 } 225 } 226} 227 228 229#ifdef CAREFULUTMP 230 231/* CAREFULUTMP: goodie for paranoid sysadmins: always leave one 232 * window logged in 233 */ 234void 235CarefulUtmp() 236{ 237 struct win *p; 238 239 if (!windows) /* hopeless */ 240 return; 241 debug("CarefulUtmp counting slots\n"); 242 for (p = windows; p; p = p->w_next) 243 if (p->w_ptyfd >= 0 && p->w_slot != (slot_t)-1) 244 return; /* found one, nothing to do */ 245 246 debug("CarefulUtmp: no slots, log one in again.\n"); 247 for (p = windows; p; p = p->w_next) 248 if (p->w_ptyfd >= 0) /* no zombies please */ 249 break; 250 if (!p) 251 return; /* really hopeless */ 252 SetUtmp(p); 253 Msg(0, "Window %d is now logged in.\n", p->w_number); 254} 255#endif /* CAREFULUTMP */ 256 257 258void 259InitUtmp() 260{ 261 debug1("InitUtmp testing '%s'...\n", UtmpName); 262#ifndef UTMP_HELPER 263 if ((utmpfd = open(UtmpName, O_RDWR)) == -1) 264 { 265 if (errno != EACCES) 266 Msg(errno, UtmpName); 267 debug("InitUtmp failed.\n"); 268 utmpok = 0; 269 return; 270 } 271# ifdef GETUTENT 272 close(utmpfd); /* it was just a test */ 273 utmpfd = -1; 274# endif /* GETUTENT */ 275#endif /* UTMP_HELPER */ 276 utmpok = 1; 277} 278 279 280#ifdef USRLIMIT 281int 282CountUsers() 283{ 284 struct utmp *ut; 285 int UserCount; 286 287 debug1("CountUsers() - utmpok=%d\n", utmpok); 288 if (!utmpok) 289 return 0; 290 UserCount = 0; 291 setutent(); 292 while (ut = getutent()) 293 if (SLOT_USED(ut)) 294 UserCount++; 295 UT_CLOSE; 296 return UserCount; 297} 298#endif /* USRLIMIT */ 299 300 301 302/* 303 * the utmp entry for tty is located and removed. 304 * it is stored in D_utmp_logintty. 305 */ 306void 307RemoveLoginSlot() 308{ 309 struct utmp u, *uu; 310 311 ASSERT(display); 312 debug("RemoveLoginSlot: removing your logintty\n"); 313 D_loginslot = TtyNameSlot(D_usertty); 314 if (D_loginslot == (slot_t)0 || D_loginslot == (slot_t)-1) 315 return; 316#ifdef UTMP_HELPER 317 if (eff_uid) /* helpers can't do login slots. sigh. */ 318#else 319 if (!utmpok) 320#endif 321 { 322 D_loginslot = 0; 323 debug("RemoveLoginSlot: utmpok == 0\n"); 324 } 325 else 326 { 327#ifdef _SEQUENT_ 328 { 329 char *p; 330 if ((p = ut_find_host(D_loginslot)) != 0) 331 strncpy(D_loginhost, p, sizeof(D_loginhost) - 1); 332 D_loginhost[sizeof(D_loginhost) - 1] = 0; 333 } 334#endif /* _SEQUENT_ */ 335 336 if ((uu = getutslot(D_loginslot)) == 0) 337 { 338 debug("Utmp slot not found -> not removed"); 339 D_loginslot = 0; 340 } 341 else 342 { 343 D_utmp_logintty = *uu; 344 u = *uu; 345 makedead(&u); 346 if (pututslot(D_loginslot, &u, (char *)0, (struct win *)0) == 0) 347 D_loginslot = 0; 348 } 349 UT_CLOSE; 350 } 351 debug1(" slot %d zapped\n", (int)D_loginslot); 352 if (D_loginslot == (slot_t)0) 353 { 354 /* couldn't remove slot, do a 'mesg n' at least. */ 355 struct stat stb; 356 char *tty; 357 debug("couln't zap slot -> do mesg n\n"); 358 D_loginttymode = 0; 359 if ((tty = ttyname(D_userfd)) && stat(tty, &stb) == 0 && (int)stb.st_uid == real_uid && ((int)stb.st_mode & 0777) != 0666) 360 { 361 D_loginttymode = (int)stb.st_mode & 0777; 362 chmod(D_usertty, stb.st_mode & 0600); 363 } 364 } 365} 366 367/* 368 * D_utmp_logintty is reinserted into utmp 369 */ 370void 371RestoreLoginSlot() 372{ 373 char *tty; 374 375 debug("RestoreLoginSlot()\n"); 376 ASSERT(display); 377 if (utmpok && D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1) 378 { 379 debug1(" logging you in again (slot %#x)\n", (int)D_loginslot); 380 if (pututslot(D_loginslot, &D_utmp_logintty, D_loginhost, (struct win *)0) == 0) 381 Msg(errno,"Could not write %s", UtmpName); 382 } 383 UT_CLOSE; 384 D_loginslot = (slot_t)0; 385 if (D_loginttymode && (tty = ttyname(D_userfd))) 386 chmod(tty, D_loginttymode); 387} 388 389 390 391/* 392 * Construct a utmp entry for window wi. 393 * the hostname field reflects what we know about the user (display) 394 * location. If d_loginhost is not set, then he is local and we write 395 * down the name of his terminal line; else he is remote and we keep 396 * the hostname here. The letter S and the window id will be appended. 397 * A saved utmp entry in wi->w_savut serves as a template, usually. 398 */ 399 400int 401SetUtmp(wi) 402struct win *wi; 403{ 404 register slot_t slot; 405 struct utmp u; 406 int saved_ut; 407#ifdef UTHOST 408 char *p; 409 char host[sizeof(D_loginhost) + 15]; 410#else 411 char *host = 0; 412#endif /* UTHOST */ 413 414 wi->w_slot = (slot_t)0; 415 if (!utmpok || wi->w_type != W_TYPE_PTY) 416 return -1; 417 if ((slot = TtyNameSlot(wi->w_tty)) == (slot_t)0) 418 { 419 debug1("SetUtmp failed (tty %s).\n",wi->w_tty); 420 return -1; 421 } 422 debug2("SetUtmp %d will get slot %d...\n", wi->w_number, (int)slot); 423 424 bzero((char *)&u, sizeof(u)); 425 if ((saved_ut = bcmp((char *) &wi->w_savut, (char *)&u, sizeof(u)))) 426 /* restore original, of which we will adopt all fields but ut_host */ 427 bcopy((char *)&wi->w_savut, (char *) &u, sizeof(u)); 428 429 if (!saved_ut) 430 makeuser(&u, stripdev(wi->w_tty), LoginName, wi->w_pid); 431 432#ifdef UTHOST 433 host[sizeof(host) - 15] = '\0'; 434 if (display) 435 { 436 strncpy(host, D_loginhost, sizeof(host) - 15); 437 if (D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1 && host[0] != '\0') 438 { 439 /* 440 * we want to set our ut_host field to something like 441 * ":ttyhf:s.0" or 442 * "faui45:s.0" or 443 * "132.199.81.4:s.0" (even this may hurt..), but not 444 * "faui45.informati"......:s.0 445 * HPUX uses host:0.0, so chop at "." and ":" (Eric Backus) 446 */ 447 for (p = host; *p; p++) 448 if ((*p < '0' || *p > '9') && (*p != '.')) 449 break; 450 if (*p) 451 { 452 for (p = host; *p; p++) 453 if (*p == '.' || (*p == ':' && p != host)) 454 { 455 *p = '\0'; 456 break; 457 } 458 } 459 } 460 else 461 { 462 strncpy(host + 1, stripdev(D_usertty), sizeof(host) - 15 - 1); 463 host[0] = ':'; 464 } 465 } 466 else 467 strncpy(host, "local", sizeof(host) - 15); 468 469 sprintf(host + strlen(host), ":S.%d", wi->w_number); 470 debug1("rlogin hostname: '%s'\n", host); 471 472# if !defined(_SEQUENT_) && !defined(sequent) 473 strncpy(u.ut_host, host, sizeof(u.ut_host)); 474# endif 475#endif /* UTHOST */ 476 477 if (pututslot(slot, &u, host, wi) == 0) 478 { 479 Msg(errno,"Could not write %s", UtmpName); 480 UT_CLOSE; 481 return -1; 482 } 483 debug("SetUtmp successful\n"); 484 wi->w_slot = slot; 485 bcopy((char *)&u, (char *)&wi->w_savut, sizeof(u)); 486 UT_CLOSE; 487 return 0; 488} 489 490/* 491 * if slot could be removed or was 0, wi->w_slot = -1; 492 * else not changed. 493 */ 494 495int 496RemoveUtmp(wi) 497struct win *wi; 498{ 499 struct utmp u, *uu; 500 slot_t slot; 501 502 slot = wi->w_slot; 503 debug1("RemoveUtmp slot=%#x\n", slot); 504 if (!utmpok) 505 return -1; 506 if (slot == (slot_t)0 || slot == (slot_t)-1) 507 { 508 wi->w_slot = (slot_t)-1; 509 return 0; 510 } 511 bzero((char *) &u, sizeof(u)); 512#ifdef sgi 513 bcopy((char *)&wi->w_savut, (char *)&u, sizeof(u)); 514 uu = &u; 515#else 516 if ((uu = getutslot(slot)) == 0) 517 { 518 Msg(0, "Utmp slot not found -> not removed"); 519 return -1; 520 } 521 bcopy((char *)uu, (char *)&wi->w_savut, sizeof(wi->w_savut)); 522#endif 523 u = *uu; 524 makedead(&u); 525 if (pututslot(slot, &u, (char *)0, wi) == 0) 526 { 527 Msg(errno,"Could not write %s", UtmpName); 528 UT_CLOSE; 529 return -1; 530 } 531 debug("RemoveUtmp successfull\n"); 532 wi->w_slot = (slot_t)-1; 533 UT_CLOSE; 534 return 0; 535} 536 537 538 539/********************************************************************* 540 * 541 * routines using the getut* api 542 */ 543 544#ifdef GETUTENT 545 546#define SLOT_USED(u) (u->ut_type == USER_PROCESS) 547 548static struct utmp * 549getutslot(slot) 550slot_t slot; 551{ 552 struct utmp u; 553 bzero((char *)&u, sizeof(u)); 554 strncpy(u.ut_line, slot, sizeof(u.ut_line)); 555 setutent(); 556 return getutline(&u); 557} 558 559static int 560pututslot(slot, u, host, wi) 561slot_t slot; 562struct utmp *u; 563char *host; 564struct win *wi; 565{ 566#ifdef _SEQUENT_ 567 if (SLOT_USED(u) && host && *host) 568 return ut_add_user(u.ut_name, slot, u.ut_pid, host) != 0; 569 if (!SLOT_USED(u)) 570 return ut_delete_user(slot, u.ut_pid, 0, 0) != 0; 571#endif 572#ifdef HAVE_UTEMPTER 573 if (eff_uid && wi->w_ptyfd != -1) 574 { 575 /* sigh, linux hackers made the helper functions void */ 576 if (SLOT_USED(u)) 577 addToUtmp(wi->w_tty, host, wi->w_ptyfd); 578 else 579 removeLineFromUtmp(wi->w_tty, wi->w_ptyfd); 580 return 1; /* pray for success */ 581 } 582#endif 583 setutent(); 584 return pututline(u) != 0; 585} 586 587static void 588makedead(u) 589struct utmp *u; 590{ 591 u->ut_type = DEAD_PROCESS; 592#if !defined(linux) || defined(EMPTY) 593 u->ut_exit.e_termination = 0; 594 u->ut_exit.e_exit = 0; 595#endif 596#if !defined(sun) || !defined(SVR4) 597 u->ut_user[0] = 0; /* for Digital UNIX, kilbi@rad.rwth-aachen.de */ 598#endif 599} 600 601static void 602makeuser(u, line, user, pid) 603struct utmp *u; 604char *line, *user; 605int pid; 606{ 607 u->ut_type = USER_PROCESS; 608 strncpy(u->ut_user, user, sizeof(u->ut_user)); 609 /* Now the tricky part... guess ut_id */ 610#if defined(sgi) || defined(linux) 611 strncpy(u->ut_id, line + 3, sizeof(u->ut_id)); 612#else /* sgi */ 613# ifdef _IBMR2 614 strncpy(u->ut_id, line, sizeof(u->ut_id)); 615# else 616 strncpy(u->ut_id, line + strlen(line) - 2, sizeof(u->ut_id)); 617# endif 618#endif /* sgi */ 619 strncpy(u->ut_line, line, sizeof(u->ut_line)); 620 u->ut_pid = pid; 621 (void)time((time_t *)&u->ut_time); 622} 623 624static slot_t 625TtyNameSlot(nam) 626char *nam; 627{ 628 return stripdev(nam); 629} 630 631 632#else /* GETUTENT */ 633 634/********************************************************************* 635 * 636 * getut emulation for systems lacking the api 637 */ 638 639static struct utmp uent; 640 641#define SLOT_USED(u) (u.ut_name[0] != 0) 642 643static int 644initutmp() 645{ 646 if (utmpfd >= 0) 647 return 1; 648 return (utmpfd = open(UtmpName, O_RDWR)) >= 0; 649} 650 651static void 652setutent() 653{ 654 if (utmpfd >= 0) 655 (void)lseek(utmpfd, (off_t)0, 0); 656} 657 658static void 659endutent() 660{ 661 if (utmpfd >= 0) 662 close(utmpfd); 663 utmpfd = -1; 664} 665 666static struct utmp * 667getutent() 668{ 669 if (utmpfd < 0 && !initutmp()) 670 return 0; 671 if (read(utmpfd, &uent, sizeof(uent)) != sizeof(uent)) 672 return 0; 673 return &uent; 674} 675 676static struct utmp * 677getutslot(slot) 678slot_t slot; 679{ 680 if (utmpfd < 0 && !initutmp()) 681 return 0; 682 lseek(utmpfd, (off_t)(slot * sizeof(struct utmp)), 0); 683 if (read(utmpfd, &uent, sizeof(uent)) != sizeof(uent)) 684 return 0; 685 return &uent; 686} 687 688static int 689pututslot(slot, u, host, wi) 690slot_t slot; 691struct utmp *u; 692char *host; 693struct win *wi; 694{ 695#ifdef sequent 696 if (SLOT_USED(u)) 697 return add_utmp(slot, u) != -1; 698#endif 699 if (utmpfd < 0 && !initutmp()) 700 return 0; 701 lseek(utmpfd, (off_t)(slot * sizeof(*u)), 0); 702 if (write(utmpfd, u, sizeof(*u)) != sizeof(*u)) 703 return 0; 704 return 1; 705} 706 707 708static void 709makedead(u) 710struct utmp *u; 711{ 712#ifdef UT_UNSORTED 713 bzero(u->ut_name, sizeof(u->ut_name)); 714# ifdef UTHOST 715 bzero(u->ut_host, sizeof(u->ut_host)); 716# endif 717#else 718 bzero((char *)u, sizeof(*u)); 719#endif 720} 721 722 723static void 724makeuser(u, line, user, pid) 725struct utmp *u; 726char *line, *user; 727int pid; 728{ 729 strncpy(u->ut_line, line, sizeof(u->ut_line)); 730 strncpy(u->ut_name, user, sizeof(u->ut_name)); 731 (void)time((time_t *)&u->ut_time); 732} 733 734static slot_t 735TtyNameSlot(nam) 736char *nam; 737{ 738 slot_t slot; 739 char *line; 740#ifndef UT_UNSORTED 741 struct ttyent *tp; 742#endif 743 744 line = stripdev(nam); 745#ifdef UT_UNSORTED 746 setutent(); 747 if (utmpfd < 0) 748 return -1; 749 for (slot = 0; getutent(); slot++) 750 if (strcmp(uent.ut_line, line) == 0) 751 break; 752 UT_CLOSE; 753#else 754 slot = 1; 755 setttyent(); 756 while ((tp = getttyent()) != 0 && strcmp(line, tp->ty_name) != 0) 757 slot++; 758#endif 759 return slot; 760} 761 762#endif /* GETUTENT */ 763 764 765 766/********************************************************************* 767 * 768 * Cheap plastic imitation of ttyent routines. 769 */ 770 771#if !defined(GETTTYENT) && !defined(GETUTENT) && !defined(UT_UNSORTED) 772 773 774static char *tt, *ttnext; 775static char ttys[] = "/etc/ttys"; 776 777static void 778setttyent() 779{ 780 if (ttnext == 0) 781 { 782 struct stat s; 783 register int f; 784 register char *p, *ep; 785 786 if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1) 787 Panic(errno, ttys); 788 if ((tt = malloc((unsigned) s.st_size + 1)) == 0) 789 Panic(0, strnomem); 790 if (read(f, tt, s.st_size) != s.st_size) 791 Panic(errno, ttys); 792 close(f); 793 for (p = tt, ep = p + s.st_size; p < ep; p++) 794 if (*p == '\n') 795 *p = '\0'; 796 *p = '\0'; 797 } 798 ttnext = tt; 799} 800 801static struct ttyent * 802getttyent() 803{ 804 static struct ttyent t; 805 806 if (*ttnext == '\0') 807 return NULL; 808 t.ty_name = ttnext + 2; 809 ttnext += strlen(ttnext) + 1; 810 return &t; 811} 812 813#endif /* !GETTTYENT && !GETUTENT && !UT_UNSORTED*/ 814 815 816 817#endif /* UTMPOK */ 818 819 820 821 822/********************************************************************* 823 * 824 * getlogin() replacement (for SVR4 machines) 825 */ 826 827# if defined(BUGGYGETLOGIN) && defined(UTMP_FILE) 828char * 829getlogin() 830{ 831 char *tty = NULL; 832#ifdef utmp 833# undef utmp 834#endif 835 struct utmp u; 836 static char retbuf[sizeof(u.ut_user)+1]; 837 int fd; 838 839 for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++) 840 ; 841 if ((tty == NULL) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0)) 842 return NULL; 843 tty = stripdev(tty); 844 retbuf[0] = '\0'; 845 while (read(fd, (char *)&u, sizeof(struct utmp)) == sizeof(struct utmp)) 846 { 847 if (!strncmp(tty, u.ut_line, sizeof(u.ut_line))) 848 { 849 strncpy(retbuf, u.ut_user, sizeof(u.ut_user)); 850 retbuf[sizeof(u.ut_user)] = '\0'; 851 if (u.ut_type == USER_PROCESS) 852 break; 853 } 854 } 855 close(fd); 856 857 return *retbuf ? retbuf : NULL; 858} 859# endif /* BUGGYGETLOGIN */ 860 861#if defined(linux) && defined(GETUTENT) 862# undef pututline 863 864/* aargh, linux' pututline returns void! */ 865struct utmp * 866xpututline(u) 867struct utmp *u; 868{ 869 struct utmp *u2; 870 pututline(u); 871 setutent(); 872 u2 = getutline(u); 873 if (u2 == 0) 874 return u->ut_type == DEAD_PROCESS ? u : 0; 875 return u->ut_type == u2->ut_type ? u : 0; 876} 877#endif 878 879