صفحه نخست | سیستم وبلاگ | در مورد من | twitter

پیاده سازی بخشی از دستور lastlog(1)

lastlog(1) دستوری در سیستم‌های شبه یونیکس است که زمان آخرین لاگین کاربر در سیستم را نشان می‌دهد. این اطلاعات در فایلی به نام lastlog و به صورت struct در آفست خاصی از این فایل ذخیره شده است. به عنوان مثال اطلاعات کاربری با USERID=1000 در آفست زیر قرار دارد:

off_t offset = 1000 * sizeof(struct lastlog);

حال کافی است فایل را باز کرده، به آفست مورد نظر رفته و اطلاعات فایل را بخوانیم. برای لینک کردن USERID با نام واقعی باید از توابع مربوط به فایل /etc/passwd استفاده کنیم.

کد این برنامه را ملاحظه می‌کنید:

/*
 * lastlog(1) simulation
 * 
 * Mohsen Safari
 * ----------------------------------
 * 
 * mstafreshi.ir
 * safari.tafreshi@gmail.com
 */

#include <stdio.h>
#include <stdlib.h>
#include <lastlog.h>
#include <err.h>
#include <pwd.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <paths.h>
#include <time.h>
#include <string.h>

void
usage(const char *program_name)
{
	fprintf(stderr, "usage: %s [-h -u login-name]\n", program_name);
	exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
	struct passwd *passwd;
	struct lastlog lastlog;
	ssize_t num_read;
	int fd, flag = 0, opt;
	time_t time;
	struct tm *tm;
	char buf[40];
	char *user = NULL;

	while ((opt = getopt(argc, argv, ":hu:")) != -1) {
		switch (opt) {
		case 'u':
			user = optarg;
			break;
		case 'h':
			usage(argv[0]);
			//NOTREACHED
		case '?':
			errx(EXIT_FAILURE, "unknown option -%c", optopt);
		case ':':
			errx(EXIT_FAILURE, "-%c needs argument", optopt);
		}
	}

	fd = open(_PATH_LASTLOG, O_RDONLY);
	if (fd == -1)
		err(EXIT_FAILURE, "open");

	setpwent();

	memset(&lastlog, 0, sizeof(struct lastlog));
	
	do {
		errno = 0;
		passwd = user ? getpwnam(user) : getpwent();
		if (passwd == NULL) {
			if (errno)
				err(EXIT_FAILURE, "getpw*");

			if (user)
				errx(EXIT_FAILURE, "Unknown user: %s", user);
			// EOF
			break;
		}

		if (lseek(fd, passwd->pw_uid * sizeof(struct lastlog), SEEK_SET) == -1)
			err(EXIT_FAILURE, "lseek");

		if ((num_read = read(fd, &lastlog, sizeof(lastlog))) == -1)
			err(EXIT_FAILURE, "read");

		time = lastlog.ll_time;

		if (time == 0)
			strcpy(buf, "**Never logged in**");
		else {
			tm = localtime(&time);
			strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %z %Y", tm);
		}

		if (!flag) {
			printf("Username         Port     From             Latest\n");
			flag = 1;
		}

		printf("%-16s %-8s %-16s %-s\n", passwd->pw_name, lastlog.ll_line,
				lastlog.ll_host, buf);

	} while (user == NULL);

	endpwent();
	close(fd);

	exit(EXIT_SUCCESS);
}

نمونه خروجی برنامه به صورت زیر است:

$ ./mlastlog | tail -8
mohsen           tty1                      Wed Dec 23 23:51:44 +0330 2020
systemd-coredump                           **Never logged in**
mysql                                      **Never logged in**
debian-tor                                 **Never logged in**
lightdm                                    **Never logged in**
tcpdump                                    **Never logged in**
fake             tty3                      Wed Dec 23 21:22:59 +0330 2020
sara                                       **Never logged in**

$ ./mlastlog -u fake
Username         Port     From             Latest
fake             tty3                      Wed Dec 23 21:22:59 +0330 2020

 

کلیه حقوق برای دارنده‌ی سایت محفوظ است.