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