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
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)
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.
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
21 ****************************************************************
24 #include <sys/types.h>
37 extern struct display
*display
;
39 extern struct win
*windows
;
41 extern struct win
*fore
;
42 extern char *LoginName
;
43 extern int real_uid
, eff_uid
;
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)
62 # define UT_CLOSE endutent()
69 * we have a suid-root helper app that changes the utmp for us
70 * (won't work for login-slots)
72 #if (defined(sun) && defined(SVR4) && defined(GETUTENT)) || defined(HAVE_UTEMPTER)
81 static slot_t TtyNameSlot
__P((char *));
82 static void makeuser
__P((struct utmp
*, char *, char *, int));
83 static void makedead
__P((struct utmp
*));
84 static int pututslot
__P((slot_t
, struct utmp
*, char *, struct win
*));
85 static struct utmp
*getutslot
__P((slot_t
));
87 static struct utmp
*getutent
__P((void));
88 static void endutent
__P((void));
89 static int initutmp
__P((void));
90 static void setutent
__P((void));
92 #if defined(linux) && defined(GETUTENT)
93 static struct utmp
*xpututline
__P((struct utmp
*utmp
));
94 # define pututline xpututline
99 static char UtmpName
[] = UTMPFILE
;
101 static int utmpfd
= -1;
105 # if defined(GETUTENT) && (!defined(SVR4) || defined(__hpux))
106 # if defined(hpux) /* cruel hpux release 8.0 */
107 # define pututline _pututline
109 extern struct utmp
*getutline(), *pututline();
110 # if defined(_SEQUENT_)
111 extern struct utmp
*ut_add_user(), *ut_delete_user();
112 extern char *ut_find_host();
114 # define UTHOST /* _SEQUENT_ has ut_find_host() */
116 # endif /* _SEQUENT_ */
117 # endif /* GETUTENT && !SVR4 */
119 # if !defined(GETUTENT) && !defined(UT_UNSORTED)
123 struct ttyent
{ char *ty_name
; };
124 static void setttyent
__P((void));
125 static struct ttyent
*getttyent
__P((void));
127 # endif /* !GETUTENT && !UT_UNSORTED */
131 # define D_loginhost D_utmp_logintty.ut_host
135 # define D_loginhost ((char *)0)
143 * SlotToggle - modify the utmp slot of the fore window.
145 * how > 0 do try to set a utmp slot.
146 * how = 0 try to withdraw a utmp slot.
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).
158 debug1("SlotToggle (!UTMPOK) %d\n", how
);
160 Msg(0, "Unable to modify %s.\n", UTMPFILE
);
162 Msg(0, "Unable to modify utmp-database.\n");
175 debug1("SlotToggle %d\n", how
);
176 if (fore
->w_type
!= W_TYPE_PTY
)
178 Msg(0, "Can only work with normal windows.\n");
183 debug(" try to log in\n");
184 if ((fore
->w_slot
== (slot_t
) -1) || (fore
->w_slot
== (slot_t
) 0))
187 if (CountUsers() >= USRLIMIT
)
189 Msg(0, "User limit reached.");
193 if (SetUtmp(fore
) == 0)
194 Msg(0, "This window is now logged in.");
196 Msg(0, "This window should now be logged in.");
197 WindowChanged(fore
, 'f');
200 Msg(0, "This window is already logged in.");
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)
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;
216 if (fore
->w_slot
!= (slot_t
) -1)
217 Msg(0, "What? Cannot remove Utmp slot?");
219 Msg(0, "This window is no longer logged in.");
223 WindowChanged(fore
, 'f');
231 /* CAREFULUTMP: goodie for paranoid sysadmins: always leave one
239 if (!windows
) /* hopeless */
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 */
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 */
251 return; /* really hopeless */
253 Msg(0, "Window %d is now logged in.\n", p
->w_number
);
255 #endif /* CAREFULUTMP */
261 debug1("InitUtmp testing '%s'...\n", UtmpName
);
263 if ((utmpfd
= open(UtmpName
, O_RDWR
)) == -1)
266 Msg(errno
, UtmpName
);
267 debug("InitUtmp failed.\n");
272 close(utmpfd
); /* it was just a test */
274 # endif /* GETUTENT */
275 #endif /* UTMP_HELPER */
287 debug1("CountUsers() - utmpok=%d\n", utmpok
);
292 while (ut
= getutent())
298 #endif /* USRLIMIT */
303 * the utmp entry for tty is located and removed.
304 * it is stored in D_utmp_logintty.
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)
317 if (eff_uid
) /* helpers can't do login slots. sigh. */
323 debug("RemoveLoginSlot: utmpok == 0\n");
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;
334 #endif /* _SEQUENT_ */
336 if ((uu
= getutslot(D_loginslot
)) == 0)
338 debug("Utmp slot not found -> not removed");
343 D_utmp_logintty
= *uu
;
346 if (pututslot(D_loginslot
, &u
, (char *)0, (struct win
*)0) == 0)
351 debug1(" slot %d zapped\n", (int)D_loginslot
);
352 if (D_loginslot
== (slot_t
)0)
354 /* couldn't remove slot, do a 'mesg n' at least. */
357 debug("couln't zap slot -> do mesg n\n");
359 if ((tty
= ttyname(D_userfd
)) && stat(tty
, &stb
) == 0 && (int)stb
.st_uid
== real_uid
&& ((int)stb
.st_mode
& 0777) != 0666)
361 D_loginttymode
= (int)stb
.st_mode
& 0777;
362 chmod(D_usertty
, stb
.st_mode
& 0600);
368 * D_utmp_logintty is reinserted into utmp
375 debug("RestoreLoginSlot()\n");
377 if (utmpok
&& D_loginslot
!= (slot_t
)0 && D_loginslot
!= (slot_t
)-1)
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
);
384 D_loginslot
= (slot_t
)0;
385 if (D_loginttymode
&& (tty
= ttyname(D_userfd
)))
386 chmod(tty
, D_loginttymode
);
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.
404 register slot_t slot
;
409 char host
[sizeof(D_loginhost
) + 15];
414 wi
->w_slot
= (slot_t
)0;
415 if (!utmpok
|| wi
->w_type
!= W_TYPE_PTY
)
417 if ((slot
= TtyNameSlot(wi
->w_tty
)) == (slot_t
)0)
419 debug1("SetUtmp failed (tty %s).\n",wi
->w_tty
);
422 debug2("SetUtmp %d will get slot %d...\n", wi
->w_number
, (int)slot
);
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
));
430 makeuser(&u
, stripdev(wi
->w_tty
), LoginName
, wi
->w_pid
);
433 host
[sizeof(host
) - 15] = '\0';
436 strncpy(host
, D_loginhost
, sizeof(host
) - 15);
437 if (D_loginslot
!= (slot_t
)0 && D_loginslot
!= (slot_t
)-1 && host
[0] != '\0')
440 * we want to set our ut_host field to something like
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)
447 for (p
= host
; *p
; p
++)
448 if ((*p
< '0' || *p
> '9') && (*p
!= '.'))
452 for (p
= host
; *p
; p
++)
453 if (*p
== '.' || (*p
== ':' && p
!= host
))
462 strncpy(host
+ 1, stripdev(D_usertty
), sizeof(host
) - 15 - 1);
467 strncpy(host
, "local", sizeof(host
) - 15);
469 sprintf(host
+ strlen(host
), ":S.%d", wi
->w_number
);
470 debug1("rlogin hostname: '%s'\n", host
);
472 # if !defined(_SEQUENT_) && !defined(sequent)
473 strncpy(u
.ut_host
, host
, sizeof(u
.ut_host
));
477 if (pututslot(slot
, &u
, host
, wi
) == 0)
479 Msg(errno
,"Could not write %s", UtmpName
);
483 debug("SetUtmp successful\n");
485 bcopy((char *)&u
, (char *)&wi
->w_savut
, sizeof(u
));
491 * if slot could be removed or was 0, wi->w_slot = -1;
503 debug1("RemoveUtmp slot=%#x\n", slot
);
506 if (slot
== (slot_t
)0 || slot
== (slot_t
)-1)
508 wi
->w_slot
= (slot_t
)-1;
511 bzero((char *) &u
, sizeof(u
));
513 bcopy((char *)&wi
->w_savut
, (char *)&u
, sizeof(u
));
516 if ((uu
= getutslot(slot
)) == 0)
518 Msg(0, "Utmp slot not found -> not removed");
521 bcopy((char *)uu
, (char *)&wi
->w_savut
, sizeof(wi
->w_savut
));
525 if (pututslot(slot
, &u
, (char *)0, wi
) == 0)
527 Msg(errno
,"Could not write %s", UtmpName
);
531 debug("RemoveUtmp successfull\n");
532 wi
->w_slot
= (slot_t
)-1;
539 /*********************************************************************
541 * routines using the getut* api
546 #define SLOT_USED(u) (u->ut_type == USER_PROCESS)
553 bzero((char *)&u
, sizeof(u
));
554 strncpy(u
.ut_line
, slot
, sizeof(u
.ut_line
));
556 return getutline(&u
);
560 pututslot(slot
, u
, host
, wi
)
567 if (SLOT_USED(u
) && host
&& *host
)
568 return ut_add_user(u
.ut_name
, slot
, u
.ut_pid
, host
) != 0;
570 return ut_delete_user(slot
, u
.ut_pid
, 0, 0) != 0;
573 if (eff_uid
&& wi
->w_ptyfd
!= -1)
575 /* sigh, linux hackers made the helper functions void */
577 addToUtmp(wi
->w_tty
, host
, wi
->w_ptyfd
);
579 removeLineFromUtmp(wi
->w_tty
, wi
->w_ptyfd
);
580 return 1; /* pray for success */
584 return pututline(u
) != 0;
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;
596 #if !defined(sun) || !defined(SVR4)
597 u
->ut_user
[0] = 0; /* for Digital UNIX, kilbi@rad.rwth-aachen.de */
602 makeuser(u
, line
, user
, pid
)
608 u
->ut_type
= USER_PROCESS
;
609 strncpy(u
->ut_user
, user
, sizeof(u
->ut_user
));
610 /* Now the tricky part... guess ut_id */
611 #if defined(sgi) || defined(linux)
612 strncpy(u
->ut_id
, line
+ 3, sizeof(u
->ut_id
));
615 strncpy(u
->ut_id
, line
, sizeof(u
->ut_id
));
617 strncpy(u
->ut_id
, line
+ strlen(line
) - 2, sizeof(u
->ut_id
));
620 strncpy(u
->ut_line
, line
, sizeof(u
->ut_line
));
622 /* must use temp variable because of NetBSD/sparc64, where
623 * ut_xtime is long(64) but time_t is int(32) */
632 return stripdev(nam
);
638 /*********************************************************************
640 * getut emulation for systems lacking the api
643 static struct utmp uent
;
645 #define SLOT_USED(u) (u.ut_name[0] != 0)
652 return (utmpfd
= open(UtmpName
, O_RDWR
)) >= 0;
659 (void)lseek(utmpfd
, (off_t
)0, 0);
673 if (utmpfd
< 0 && !initutmp())
675 if (read(utmpfd
, &uent
, sizeof(uent
)) != sizeof(uent
))
684 if (utmpfd
< 0 && !initutmp())
686 lseek(utmpfd
, (off_t
)(slot
* sizeof(struct utmp
)), 0);
687 if (read(utmpfd
, &uent
, sizeof(uent
)) != sizeof(uent
))
693 pututslot(slot
, u
, host
, wi
)
701 return add_utmp(slot
, u
) != -1;
703 if (utmpfd
< 0 && !initutmp())
705 lseek(utmpfd
, (off_t
)(slot
* sizeof(*u
)), 0);
706 if (write(utmpfd
, u
, sizeof(*u
)) != sizeof(*u
))
717 bzero(u
->ut_name
, sizeof(u
->ut_name
));
719 bzero(u
->ut_host
, sizeof(u
->ut_host
));
722 bzero((char *)u
, sizeof(*u
));
728 makeuser(u
, line
, user
, pid
)
734 strncpy(u
->ut_line
, line
, sizeof(u
->ut_line
));
735 strncpy(u
->ut_name
, user
, sizeof(u
->ut_name
));
750 line
= stripdev(nam
);
755 for (slot
= 0; getutent(); slot
++)
756 if (strcmp(uent
.ut_line
, line
) == 0)
762 while ((tp
= getttyent()) != 0 && strcmp(line
, tp
->ty_name
) != 0)
768 #endif /* GETUTENT */
772 /*********************************************************************
774 * Cheap plastic imitation of ttyent routines.
777 #if !defined(GETTTYENT) && !defined(GETUTENT) && !defined(UT_UNSORTED)
780 static char *tt
, *ttnext
;
781 static char ttys
[] = "/etc/ttys";
790 register char *p
, *ep
;
792 if ((f
= open(ttys
, O_RDONLY
)) == -1 || fstat(f
, &s
) == -1)
794 if ((tt
= malloc((unsigned) s
.st_size
+ 1)) == 0)
796 if (read(f
, tt
, s
.st_size
) != s
.st_size
)
799 for (p
= tt
, ep
= p
+ s
.st_size
; p
< ep
; p
++)
807 static struct ttyent
*
810 static struct ttyent t
;
814 t
.ty_name
= ttnext
+ 2;
815 ttnext
+= strlen(ttnext
) + 1;
819 #endif /* !GETTTYENT && !GETUTENT && !UT_UNSORTED*/
828 /*********************************************************************
830 * getlogin() replacement (for SVR4 machines)
833 # if defined(BUGGYGETLOGIN) && defined(UTMP_FILE)
842 static char retbuf
[sizeof(u
.ut_user
)+1];
845 for (fd
= 0; fd
<= 2 && (tty
= ttyname(fd
)) == NULL
; fd
++)
847 if ((tty
== NULL
) || ((fd
= open(UTMP_FILE
, O_RDONLY
)) < 0))
851 while (read(fd
, (char *)&u
, sizeof(struct utmp
)) == sizeof(struct utmp
))
853 if (!strncmp(tty
, u
.ut_line
, sizeof(u
.ut_line
)))
855 strncpy(retbuf
, u
.ut_user
, sizeof(u
.ut_user
));
856 retbuf
[sizeof(u
.ut_user
)] = '\0';
857 if (u
.ut_type
== USER_PROCESS
)
863 return *retbuf
? retbuf
: NULL
;
865 # endif /* BUGGYGETLOGIN */
867 #if defined(linux) && defined(GETUTENT)
870 /* aargh, linux' pututline returns void! */
880 return u
->ut_type
== DEAD_PROCESS
? u
: 0;
881 return u
->ut_type
== u2
->ut_type
? u
: 0;