logintest.c revision 98937
198937Sdes/* 298937Sdes * Copyright (c) 2000 Andre Lucas. All rights reserved. 398937Sdes * 498937Sdes * Redistribution and use in source and binary forms, with or without 598937Sdes * modification, are permitted provided that the following conditions 698937Sdes * are met: 798937Sdes * 1. Redistributions of source code must retain the above copyright 898937Sdes * notice, this list of conditions and the following disclaimer. 998937Sdes * 2. Redistributions in binary form must reproduce the above copyright 1098937Sdes * notice, this list of conditions and the following disclaimer in the 1198937Sdes * documentation and/or other materials provided with the distribution. 1298937Sdes * 3. All advertising materials mentioning features or use of this software 1398937Sdes * must display the following acknowledgement: 1498937Sdes * This product includes software developed by Markus Friedl. 1598937Sdes * 4. The name of the author may not be used to endorse or promote products 1698937Sdes * derived from this software without specific prior written permission. 1798937Sdes * 1898937Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1998937Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2098937Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2198937Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2298937Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2398937Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2498937Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2598937Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2698937Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2798937Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2898937Sdes */ 2998937Sdes 3098937Sdes/** 3198937Sdes ** logintest.c: simple test driver for platform-independent login recording 3298937Sdes ** and lastlog retrieval 3398937Sdes **/ 3498937Sdes 3598937Sdes#include "includes.h" 3698937Sdes 3798937Sdes#include <sys/types.h> 3898937Sdes#include <sys/wait.h> 3998937Sdes#include <unistd.h> 4098937Sdes#include <stdlib.h> 4198937Sdes#include <stdio.h> 4298937Sdes#include <string.h> 4398937Sdes#include <pwd.h> 4498937Sdes#include <netdb.h> 4598937Sdes#ifdef HAVE_TIME_H 4698937Sdes#include <time.h> 4798937Sdes#endif 4898937Sdes 4998937Sdes#include "loginrec.h" 5098937Sdes 5198937SdesRCSID("$Id: logintest.c,v 1.8 2001/04/05 23:05:22 stevesk Exp $"); 5298937Sdes 5398937Sdes#ifdef HAVE___PROGNAME 5498937Sdesextern char *__progname; 5598937Sdes#else 5698937Sdeschar *__progname; 5798937Sdes#endif 5898937Sdes 5998937Sdes#define PAUSE_BEFORE_LOGOUT 3 6098937Sdes 6198937Sdesint nologtest = 0; 6298937Sdesint compile_opts_only = 0; 6398937Sdesint be_verbose = 0; 6498937Sdes 6598937Sdes 6698937Sdes/* Dump a logininfo to stdout. Assumes a tab size of 8 chars. */ 6798937Sdesvoid 6898937Sdesdump_logininfo(struct logininfo *li, char *descname) 6998937Sdes{ 7098937Sdes /* yes I know how nasty this is */ 7198937Sdes printf("struct logininfo %s = {\n\t" 7298937Sdes "progname\t'%s'\n\ttype\t\t%d\n\t" 7398937Sdes "pid\t\t%d\n\tuid\t\t%d\n\t" 7498937Sdes "line\t\t'%s'\n\tusername\t'%s'\n\t" 7598937Sdes "hostname\t'%s'\n\texit\t\t%d\n\ttermination\t%d\n\t" 7698937Sdes "tv_sec\t%d\n\ttv_usec\t%d\n\t" 7798937Sdes "struct login_netinfo hostaddr {\n\t\t" 7898937Sdes "struct sockaddr sa {\n" 7998937Sdes "\t\t\tfamily\t%d\n\t\t}\n" 8098937Sdes "\t}\n" 8198937Sdes "}\n", 8298937Sdes descname, li->progname, li->type, 8398937Sdes li->pid, li->uid, li->line, 8498937Sdes li->username, li->hostname, li->exit, 8598937Sdes li->termination, li->tv_sec, li->tv_usec, 8698937Sdes li->hostaddr.sa.sa_family); 8798937Sdes} 8898937Sdes 8998937Sdes 9098937Sdesint 9198937SdestestAPI() 9298937Sdes{ 9398937Sdes struct logininfo *li1; 9498937Sdes struct passwd *pw; 9598937Sdes struct hostent *he; 9698937Sdes struct sockaddr_in sa_in4; 9798937Sdes char cmdstring[256], stripline[8]; 9898937Sdes char username[32]; 9998937Sdes#ifdef HAVE_TIME_H 10098937Sdes time_t t0, t1, t2, logintime, logouttime; 10198937Sdes char s_t0[64],s_t1[64],s_t2[64]; 10298937Sdes char s_logintime[64], s_logouttime[64]; /* ctime() strings */ 10398937Sdes#endif 10498937Sdes 10598937Sdes printf("**\n** Testing the API...\n**\n"); 10698937Sdes 10798937Sdes pw = getpwuid(getuid()); 10898937Sdes strlcpy(username, pw->pw_name, sizeof(username)); 10998937Sdes 11098937Sdes /* gethostname(hostname, sizeof(hostname)); */ 11198937Sdes 11298937Sdes printf("login_alloc_entry test (no host info):\n"); 11398937Sdes 11498937Sdes /* FIXME fake tty more effectively - this could upset some platforms */ 11598937Sdes li1 = login_alloc_entry((int)getpid(), username, NULL, ttyname(0)); 11698937Sdes strlcpy(li1->progname, "OpenSSH-logintest", sizeof(li1->progname)); 11798937Sdes 11898937Sdes if (be_verbose) 11998937Sdes dump_logininfo(li1, "li1"); 12098937Sdes 12198937Sdes printf("Setting host address info for 'localhost' (may call out):\n"); 12298937Sdes if (! (he = gethostbyname("localhost"))) { 12398937Sdes printf("Couldn't set hostname(lookup failed)\n"); 12498937Sdes } else { 12598937Sdes /* NOTE: this is messy, but typically a program wouldn't have to set 12698937Sdes * any of this, a sockaddr_in* would be already prepared */ 12798937Sdes memcpy((void *)&(sa_in4.sin_addr), (void *)&(he->h_addr_list[0][0]), 12898937Sdes sizeof(struct in_addr)); 12998937Sdes login_set_addr(li1, (struct sockaddr *) &sa_in4, sizeof(sa_in4)); 13098937Sdes strlcpy(li1->hostname, "localhost", sizeof(li1->hostname)); 13198937Sdes } 13298937Sdes if (be_verbose) 13398937Sdes dump_logininfo(li1, "li1"); 13498937Sdes 13598937Sdes if ((int)geteuid() != 0) { 13698937Sdes printf("NOT RUNNING LOGIN TESTS - you are not root!\n"); 13798937Sdes return 1; 13898937Sdes } 13998937Sdes 14098937Sdes if (nologtest) 14198937Sdes return 1; 14298937Sdes 14398937Sdes line_stripname(stripline, li1->line, sizeof(stripline)); 14498937Sdes 14598937Sdes printf("Performing an invalid login attempt (no type field)\n--\n"); 14698937Sdes login_write(li1); 14798937Sdes printf("--\n(Should have written errors to stderr)\n"); 14898937Sdes 14998937Sdes#ifdef HAVE_TIME_H 15098937Sdes (void)time(&t0); 15198937Sdes strlcpy(s_t0, ctime(&t0), sizeof(s_t0)); 15298937Sdes t1 = login_get_lastlog_time(getuid()); 15398937Sdes strlcpy(s_t1, ctime(&t1), sizeof(s_t1)); 15498937Sdes printf("Before logging in:\n\tcurrent time is %d - %s\t" 15598937Sdes "lastlog time is %d - %s\n", 15698937Sdes (int)t0, s_t0, (int)t1, s_t1); 15798937Sdes#endif 15898937Sdes 15998937Sdes printf("Performing a login on line %s ", stripline); 16098937Sdes#ifdef HAVE_TIME_H 16198937Sdes (void)time(&logintime); 16298937Sdes strlcpy(s_logintime, ctime(&logintime), sizeof(s_logintime)); 16398937Sdes printf("at %d - %s", (int)logintime, s_logintime); 16498937Sdes#endif 16598937Sdes printf("--\n"); 16698937Sdes login_login(li1); 16798937Sdes 16898937Sdes snprintf(cmdstring, sizeof(cmdstring), "who | grep '%s '", 16998937Sdes stripline); 17098937Sdes system(cmdstring); 17198937Sdes 17298937Sdes printf("--\nPausing for %d second(s)...\n", PAUSE_BEFORE_LOGOUT); 17398937Sdes sleep(PAUSE_BEFORE_LOGOUT); 17498937Sdes 17598937Sdes printf("Performing a logout "); 17698937Sdes#ifdef HAVE_TIME_H 17798937Sdes (void)time(&logouttime); 17898937Sdes strlcpy(s_logouttime, ctime(&logouttime), sizeof(s_logouttime)); 17998937Sdes printf("at %d - %s", (int)logouttime, s_logouttime); 18098937Sdes#endif 18198937Sdes printf("\nThe root login shown above should be gone.\n" 18298937Sdes "If the root login hasn't gone, but another user on the same\n" 18398937Sdes "pty has, this is OK - we're hacking it here, and there\n" 18498937Sdes "shouldn't be two users on one pty in reality...\n" 18598937Sdes "-- ('who' output follows)\n"); 18698937Sdes login_logout(li1); 18798937Sdes 18898937Sdes system(cmdstring); 18998937Sdes printf("-- ('who' output ends)\n"); 19098937Sdes 19198937Sdes#ifdef HAVE_TIME_H 19298937Sdes t2 = login_get_lastlog_time(getuid()); 19398937Sdes strlcpy(s_t2, ctime(&t2), sizeof(s_t2)); 19498937Sdes printf("After logging in, lastlog time is %d - %s\n", (int)t2, s_t2); 19598937Sdes if (t1 == t2) 19698937Sdes printf("The lastlog times before and after logging in are the " 19798937Sdes "same.\nThis indicates that lastlog is ** NOT WORKING " 19898937Sdes "CORRECTLY **\n"); 19998937Sdes else if (t0 != t2) 20098937Sdes /* We can be off by a second or so, even when recording works fine. 20198937Sdes * I'm not 100% sure why, but it's true. */ 20298937Sdes printf("** The login time and the lastlog time differ.\n" 20398937Sdes "** This indicates that lastlog is either recording the " 20498937Sdes "wrong time,\n** or retrieving the wrong entry.\n" 20598937Sdes "If it's off by less than %d second(s) " 20698937Sdes "run the test again.\n", PAUSE_BEFORE_LOGOUT); 20798937Sdes else 20898937Sdes printf("lastlog agrees with the login time. This is a good thing.\n"); 20998937Sdes 21098937Sdes#endif 21198937Sdes 21298937Sdes printf("--\nThe output of 'last' shown next should have " 21398937Sdes "an entry for root \n on %s for the time shown above:\n--\n", 21498937Sdes stripline); 21598937Sdes snprintf(cmdstring, sizeof(cmdstring), "last | grep '%s ' | head -3", 21698937Sdes stripline); 21798937Sdes system(cmdstring); 21898937Sdes 21998937Sdes printf("--\nEnd of login test.\n"); 22098937Sdes 22198937Sdes login_free_entry(li1); 22298937Sdes 22398937Sdes return 1; 22498937Sdes} /* testAPI() */ 22598937Sdes 22698937Sdes 22798937Sdesvoid 22898937SdestestLineName(char *line) 22998937Sdes{ 23098937Sdes /* have to null-terminate - these functions are designed for 23198937Sdes * structures with fixed-length char arrays, and don't null-term.*/ 23298937Sdes char full[17], strip[9], abbrev[5]; 23398937Sdes 23498937Sdes memset(full, '\0', sizeof(full)); 23598937Sdes memset(strip, '\0', sizeof(strip)); 23698937Sdes memset(abbrev, '\0', sizeof(abbrev)); 23798937Sdes 23898937Sdes line_fullname(full, line, sizeof(full)-1); 23998937Sdes line_stripname(strip, full, sizeof(strip)-1); 24098937Sdes line_abbrevname(abbrev, full, sizeof(abbrev)-1); 24198937Sdes printf("%s: %s, %s, %s\n", line, full, strip, abbrev); 24298937Sdes 24398937Sdes} /* testLineName() */ 24498937Sdes 24598937Sdes 24698937Sdesint 24798937SdestestOutput() 24898937Sdes{ 24998937Sdes printf("**\n** Testing linename functions\n**\n"); 25098937Sdes testLineName("/dev/pts/1"); 25198937Sdes testLineName("pts/1"); 25298937Sdes testLineName("pts/999"); 25398937Sdes testLineName("/dev/ttyp00"); 25498937Sdes testLineName("ttyp00"); 25598937Sdes 25698937Sdes return 1; 25798937Sdes} /* testOutput() */ 25898937Sdes 25998937Sdes 26098937Sdes/* show which options got compiled in */ 26198937Sdesvoid 26298937SdesshowOptions(void) 26398937Sdes{ 26498937Sdes printf("**\n** Compile-time options\n**\n"); 26598937Sdes 26698937Sdes printf("login recording methods selected:\n"); 26798937Sdes#ifdef USE_LOGIN 26898937Sdes printf("\tUSE_LOGIN\n"); 26998937Sdes#endif 27098937Sdes#ifdef USE_UTMP 27198937Sdes printf("\tUSE_UTMP (UTMP_FILE=%s)\n", UTMP_FILE); 27298937Sdes#endif 27398937Sdes#ifdef USE_UTMPX 27498937Sdes printf("\tUSE_UTMPX (UTMPX_FILE=%s)\n", UTMPX_FILE); 27598937Sdes#endif 27698937Sdes#ifdef USE_WTMP 27798937Sdes printf("\tUSE_WTMP (WTMP_FILE=%s)\n", WTMP_FILE); 27898937Sdes#endif 27998937Sdes#ifdef USE_WTMPX 28098937Sdes printf("\tUSE_WTMPX (WTMPX_FILE=%s)\n", WTMPX_FILE); 28198937Sdes#endif 28298937Sdes#ifdef USE_LASTLOG 28398937Sdes printf("\tUSE_LASTLOG (LASTLOG_FILE=%s)\n", LASTLOG_FILE); 28498937Sdes#endif 28598937Sdes printf("\n"); 28698937Sdes 28798937Sdes} /* showOptions() */ 28898937Sdes 28998937Sdes 29098937Sdesint 29198937Sdesmain(int argc, char *argv[]) 29298937Sdes{ 29398937Sdes printf("Platform-independent login recording test driver\n"); 29498937Sdes 29598937Sdes __progname = get_progname(argv[0]); 29698937Sdes if (argc == 2) { 29798937Sdes if (strncmp(argv[1], "-i", 3) == 0) 29898937Sdes compile_opts_only = 1; 29998937Sdes else if (strncmp(argv[1], "-v", 3) == 0) 30098937Sdes be_verbose=1; 30198937Sdes } 30298937Sdes 30398937Sdes if (!compile_opts_only) { 30498937Sdes if (be_verbose && !testOutput()) 30598937Sdes return 1; 30698937Sdes 30798937Sdes if (!testAPI()) 30898937Sdes return 1; 30998937Sdes } 31098937Sdes 31198937Sdes showOptions(); 31298937Sdes 31398937Sdes return 0; 31498937Sdes} /* main() */ 31598937Sdes 316