/* Records that the user has logged out. */ void record_logout(pid_t pid, const char *tty, const char *user) { struct logininfo *li; li = login_alloc_entry(pid, user, NULL, tty); login_logout(li); login_free_entry(li); }
void record_utmp_only(pid_t pid, const char *ttyname, const char *user, const char *host, struct sockaddr *addr, socklen_t addrlen) { struct logininfo *li; li = login_alloc_entry(pid, user, host, ttyname); login_set_addr(li, addr, addrlen); login_utmp_only(li); login_free_entry(li); }
/* clean a session channel */ void closechansess(struct Channel *channel) { struct ChanSess *chansess; unsigned int i; struct logininfo *li; chansess = (struct ChanSess*)channel->typedata; TRACE(("enter closechansess")); if (chansess == NULL) { TRACE(("leave closechansess: chansess == NULL")); return; } m_free(chansess->cmd); m_free(chansess->term); if (chansess->tty) { /* write the utmp/wtmp login record */ li = login_alloc_entry(chansess->pid, ses.authstate.username, ses.hostname, chansess->tty); login_logout(li); login_free_entry(li); //BRCM commented next line // pty_release(chansess->tty); m_free(chansess->tty); } #ifndef DISABLE_X11FWD x11cleanup(chansess); #endif #ifndef DISABLE_AGENTFWD agentcleanup(chansess); #endif /* clear child pid entries */ for (i = 0; i < ses.childpidsize; i++) { if (ses.childpids[i].chansess == chansess) { assert(ses.childpids[i].pid > 0); TRACE(("closing pid %d\n", ses.childpids[i].pid)); TRACE(("exited = %d\n", chansess->exited)); ses.childpids[i].pid = -1; ses.childpids[i].chansess = NULL; } } m_free(chansess); TRACE(("leave closechansess")); }
/* * Records that the user has logged in. I wish these parts of operating * systems were more standardized. */ void record_login(pid_t pid, const char *tty, const char *user, uid_t uid, const char *host, struct sockaddr *addr, socklen_t addrlen) { struct logininfo *li; /* save previous login details before writing new */ store_lastlog_message(user, uid); li = login_alloc_entry(pid, user, host, tty); login_set_addr(li, addr, addrlen); login_login(li); login_free_entry(li); }
int testAPI() { struct logininfo *li1; struct passwd *pw; struct hostent *he; struct sockaddr_in sa_in4; char cmdstring[256], stripline[8]; char username[32]; #ifdef HAVE_TIME_H time_t t0, t1, t2, logintime, logouttime; char s_t0[64],s_t1[64],s_t2[64]; char s_logintime[64], s_logouttime[64]; /* ctime() strings */ #endif printf("**\n** Testing the API...\n**\n"); pw = getpwuid(getuid()); strlcpy(username, pw->pw_name, sizeof(username)); /* gethostname(hostname, sizeof(hostname)); */ printf("login_alloc_entry test (no host info):\n"); /* FIXME fake tty more effectively - this could upset some platforms */ li1 = login_alloc_entry((int)getpid(), username, NULL, ttyname(0)); strlcpy(li1->progname, "OpenSSH-logintest", sizeof(li1->progname)); if (be_verbose) dump_logininfo(li1, "li1"); printf("Setting host address info for 'localhost' (may call out):\n"); if (! (he = gethostbyname("localhost"))) { printf("Couldn't set hostname(lookup failed)\n"); } else { /* NOTE: this is messy, but typically a program wouldn't have to set * any of this, a sockaddr_in* would be already prepared */ memcpy((void *)&(sa_in4.sin_addr), (void *)&(he->h_addr_list[0][0]), sizeof(struct in_addr)); login_set_addr(li1, (struct sockaddr *) &sa_in4, sizeof(sa_in4)); strlcpy(li1->hostname, "localhost", sizeof(li1->hostname)); } if (be_verbose) dump_logininfo(li1, "li1"); if ((int)geteuid() != 0) { printf("NOT RUNNING LOGIN TESTS - you are not root!\n"); return 1; } if (nologtest) return 1; line_stripname(stripline, li1->line, sizeof(stripline)); printf("Performing an invalid login attempt (no type field)\n--\n"); login_write(li1); printf("--\n(Should have written errors to stderr)\n"); #ifdef HAVE_TIME_H (void)time(&t0); strlcpy(s_t0, ctime(&t0), sizeof(s_t0)); t1 = login_get_lastlog_time(getuid()); strlcpy(s_t1, ctime(&t1), sizeof(s_t1)); printf("Before logging in:\n\tcurrent time is %d - %s\t" "lastlog time is %d - %s\n", (int)t0, s_t0, (int)t1, s_t1); #endif printf("Performing a login on line %s ", stripline); #ifdef HAVE_TIME_H (void)time(&logintime); strlcpy(s_logintime, ctime(&logintime), sizeof(s_logintime)); printf("at %d - %s", (int)logintime, s_logintime); #endif printf("--\n"); login_login(li1); snprintf(cmdstring, sizeof(cmdstring), "who | grep '%s '", stripline); system(cmdstring); printf("--\nPausing for %d second(s)...\n", PAUSE_BEFORE_LOGOUT); sleep(PAUSE_BEFORE_LOGOUT); printf("Performing a logout "); #ifdef HAVE_TIME_H (void)time(&logouttime); strlcpy(s_logouttime, ctime(&logouttime), sizeof(s_logouttime)); printf("at %d - %s", (int)logouttime, s_logouttime); #endif printf("\nThe root login shown above should be gone.\n" "If the root login hasn't gone, but another user on the same\n" "pty has, this is OK - we're hacking it here, and there\n" "shouldn't be two users on one pty in reality...\n" "-- ('who' output follows)\n"); login_logout(li1); system(cmdstring); printf("-- ('who' output ends)\n"); #ifdef HAVE_TIME_H t2 = login_get_lastlog_time(getuid()); strlcpy(s_t2, ctime(&t2), sizeof(s_t2)); printf("After logging in, lastlog time is %d - %s\n", (int)t2, s_t2); if (t1 == t2) printf("The lastlog times before and after logging in are the " "same.\nThis indicates that lastlog is ** NOT WORKING " "CORRECTLY **\n"); else if (t0 != t2) /* We can be off by a second or so, even when recording works fine. * I'm not 100% sure why, but it's true. */ printf("** The login time and the lastlog time differ.\n" "** This indicates that lastlog is either recording the " "wrong time,\n** or retrieving the wrong entry.\n" "If it's off by less than %d second(s) " "run the test again.\n", PAUSE_BEFORE_LOGOUT); else printf("lastlog agrees with the login time. This is a good thing.\n"); #endif printf("--\nThe output of 'last' shown next should have " "an entry for root \n on %s for the time shown above:\n--\n", stripline); snprintf(cmdstring, sizeof(cmdstring), "last | grep '%s ' | head -3", stripline); system(cmdstring); printf("--\nEnd of login test.\n"); login_free_entry(li1); return 1; } /* testAPI() */
/* Execute a command or shell within a pty environment, and set up * redirection as appropriate. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { pid_t pid; struct logininfo *li; TRACE(("enter ptycommand")); /* we already have a pty allocated */ assert(chansess->master != -1 && chansess->tty != NULL); pid = fork(); if (pid < 0) return DROPBEAR_FAILURE; if (pid == 0) { /* child */ /* redirect stdin/stdout/stderr */ close(chansess->master); pty_make_controlling_tty(&chansess->slave, chansess->tty); if ((dup2(chansess->slave, STDIN_FILENO) < 0) || (dup2(chansess->slave, STDERR_FILENO) < 0) || (dup2(chansess->slave, STDOUT_FILENO) < 0)) { TRACE(("leave ptycommand: error redirecting filedesc")); return DROPBEAR_FAILURE; } close(chansess->slave); /* write the utmp/wtmp login record - must be after changing the * terminal used for stdout with the dup2 above */ li= login_alloc_entry(getpid(), ses.authstate.username, ses.hostname, chansess->tty); login_login(li); login_free_entry(li); m_free(chansess->tty); execchild(chansess); /* not reached */ } else { /* parent */ TRACE(("continue ptycommand: parent")); chansess->pid = pid; /* add a child pid */ addchildpid(chansess, pid); close(chansess->slave); channel->infd = chansess->master; channel->outfd = chansess->master; /* don't need to set stderr here */ ses.maxfd = MAX(ses.maxfd, chansess->master); if (fcntl(chansess->master, F_SETFL, O_NONBLOCK) < 0) { dropbear_exit("Couldn't set nonblocking"); } } TRACE(("leave ptycommand")); return DROPBEAR_SUCCESS; }