UTMPX(5) فایلهای پیکربندی UTMPX(5)

utmpx - ساختار و رکوردهای ورود کاربر و وضعیت سیستم

#include <utmpx.h>

پروندههای utmpx و ساختار دادههای متناظر، سوابق ورود کاربران، پایگاهداده زمانهای ورود و خروج، فرآیندهای راهاندازی و وضعیت جاری سیستم را ذخیره مینمایند. پرونده utmpx (و همچنین utmp) امکان کسب اطلاعات درباره افرادی را که هم‌اکنون از سیستم استفاده می‌کنند، فراهم می‌سازد. با این حال ممکن است تعداد کاربران در حال استفاده بیشتر از رکوردهای موجود باشد، زیرا همه برنامه‌ها از ثبت گزارش در این پایگاه داده استفاده نمی‌کنند.

هشدار: پرونده utmpx نباید برای دسته کاربران «دیگران» (other) دسترسی نوشتن داشته باشد؛ چرا که بسیاری از ابزارهای سیستمی به درستی و دست‌نخورده بودن آن وابسته‌اند. اگر به کاربرانی غیر از مالک پرونده و گروه مالکی آن اجازه نوشتن بدهید، سیستم در معرض خطر جعل لاگ‌ها و تغییر غیرمجاز پرونده‌های سیستمی قرار خواهد گرفت.

این پرونده توالی یا دنباله‌ای از ساختارهای utmpx است که در پرونده سربرگ <utmpx.h> (و معادل آن struct utmp در <utmp.h>) به صورت زیر تعریف شده است:


/* مقادیر مجاز برای فیلد ut_type */
#define EMPTY         0 /* رکورد حاوی اطلاعات معتبر نیست */
#define RUN_LVL       1 /* تغییر سطح اجرای سیستم (نگاه کنید به init(1)) */
#define BOOT_TIME     2 /* زمان راه‌اندازی سیستم (در ut_tv) */
#define NEW_TIME      3 /* زمان پس از تغییر ساعت سیستم (در ut_tv) */
#define OLD_TIME      4 /* زمان پیش از تغییر ساعت سیستم (در ut_tv) */
#define INIT_PROCESS  5 /* فرآیند مشتق‌شده از init(1) */
#define LOGIN_PROCESS 6 /* فرآیند راهبر نشست برای ورود کاربر */
#define USER_PROCESS  7 /* فرآیند عادی کاربر */
#define DEAD_PROCESS  8 /* فرآیند خاتمه‌یافته */
#define ACCOUNTING    9 /* پیاده‌سازی نشده است */
#define UT_LINESIZE      32
#define UT_NAMESIZE      32
#define UT_HOSTSIZE     256
struct exit_status {              /* نوع داده برای فیلد ut_exit */
    short e_termination;          /* وضعیت خاتمه فرآیند */
    short e_exit;                 /* وضعیت خروج فرآیند */
};
struct utmpx {
    short   ut_type;              /* نوع رکورد */
    pid_t   ut_pid;               /* شناسه PID فرآیند ورود */
    char    ut_line[UT_LINESIZE]; /* نام دستگاه ترمینال بدون پیشوند "/dev/" */
    char    ut_id[4];             /* پسوند نام ترمینال یا شناسه inittab(5) */
    char    ut_user[UT_NAMESIZE]; /* نام کاربری */
    char    ut_host[UT_HOSTSIZE]; /* نام میزبان در ورود از راه دور یا نسخه هسته */
    struct  exit_status ut_exit;  /* وضعیت خروج فرآیندی که خاتمه یافته است */
    /* فیلدهای ut_session و ut_tv در کامپایل ۳۲ و ۶۴ بیتی باید یک‌اندازه باشند */
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
    int32_t ut_session;           /* شناسه نشست (getsid(2)) برای پنجره‌بندی */
    struct {
        int32_t tv_sec;           /* ثانیه */
        int32_t tv_usec;          /* میکروثانیه */
    } ut_tv;                      /* زمان ایجاد رکورد */
#else
     long   ut_session;           /* شناسه نشست */
     struct timeval ut_tv;        /* زمان ایجاد رکورد */
#endif
    int32_t ut_addr_v6[4];        /* نشانی اینترنتی میزبان راه دور (IPv4 در خانه اول) */
    char __unused[20];            /* رزرو شده برای کاربردهای آینده */
};

فیلدهای این ساختار عبارتند از:

نوع رکورد ورود یا رویداد را مشخص می‌کند (مانند BOOT_TIME، INIT_PROCESS، LOGIN_PROCESS، USER_PROCESS یا DEAD_PROCESS).
شناسه عددی فرآیند (PID) مربوط به فرآیند ورود یا نشست جاری.
نام فایل دستگاه ترمینال متناظر با کاربر بدون پیشوند /dev/ (مانند tty1 یا pts/0).
شناسه ترمینال یا پسوند نام آن یا شناسه رکورد در inittab(5) که برای متمایز ساختن نشست‌ها و پایانه‌ها استفاده می‌شود.
نام کاربری فردی که وارد سیستم شده است.
نام میزبان (Hostname) برای اتصال و ورود از راه دور از طریق شبکه، یا نسخه هسته برای پیام‌های سطح اجرای سیستم.
وضعیت خروج فرآیندی که خاتمه یافته و با برچسب DEAD_PROCESS مشخص شده است. این فیلد شامل e_termination (سیگنال خاتمه فرآیند) و e_exit (کد بازگشتی خروج) می‌باشد که توسط init(1) لینوکس استفاده نمی‌شود.
شناسه نشست (Session ID) برای مدیریت رابط کاربری پنجره‌ای و دسته‌بندی پردازه‌ها.
زمان ایجاد یا ثبت این رکورد بر حسب ثانیه و میکروثانیه، منطبق بر ساختار زمانی gettimeofday(2).
نشانی اینترنتی (IP) میزبان راه دور؛ در ارتباطات پروتکل اینترنت نسخه ۴ (IPv4)، تنها بخش اول یعنی ut_addr_v6[0] به کار گرفته می‌شود.

این ساختار، نام فایل خاص مربوط به ترمینال کاربر، نام کاربری ورود به سیستم و زمان ورود را به شکل فرمت زمانی تابع time(2) ارائه می‌دهد. فیلدهای متنی و رشته‌ای در صورتی که طول آنها کمتر از اندازه فیلد باشد، به یک بایت تهی ('\0') ختم می‌شوند.

اولین رکوردهایی که در این پایگاه داده ساخته می‌شوند ناشی از پردازش فایل inittab(5) توسط فرآیند init(1) هستند. با این وجود، پیش از پردازش هر رکورد، init(1) با تغییر دادن ut_type به DEAD_PROCESS و پاک‌سازی فیلدهای ut_user، ut_host و ut_time با بایت‌های تهی، پایگاه داده utmpx را برای هر رکوردی که وضعیت آن DEAD_PROCESS یا RUN_LVL نیست و فرآیندی با شناسه ut_pid برای آن در سیستم وجود ندارد، مرتب و پاک‌سازی می‌نماید. اگر هیچ رکورد خالی با شناسه مورد نیاز ut_id یافت نشود، init(1) یک رکورد جدید ایجاد می‌کند؛ فیلد ut_id را از inittab می‌خواند، فیلدهای ut_pid و ut_time را با مقادیر جاری تنظیم می‌کند و ut_type را برابر با INIT_PROCESS قرار می‌دهد.

برنامه‌های ورود به پایانه مانند mingetty(8) یا agetty(8) رکورد مربوطه را از طریق شناسه فرآیند (PID) پیدا می‌کنند، ut_type را به LOGIN_PROCESS تغییر می‌دهند، زمان ut_time را به‌روزرسانی کرده، فیلد ut_line را مقداردهی می‌کنند و منتظر برقراری اتصال و ورود می‌مانند. سپس برنامه login(1) پس از احراز هویت موفق کاربر، فیلد ut_type را به USER_PROCESS تغییر داده، ut_time را به‌روزرسانی و فیلدهای ut_host و ut_addr را تنظیم می‌کند. بسته به پیاده‌سازی mingetty(8) (یا agetty(8)) و login(1)، رکوردها ممکن است به جای فیلد ارجح ut_pid، بر اساس ut_line مکان‌یابی شوند.

هنگامی که init(1) تشخیص می‌دهد که فرآیندی پایان یافته است، رکورد متناظر با آن را در utmpx به کمک ut_pid پیدا می‌کند، فیلد ut_type را به DEAD_PROCESS تغییر می‌دهد و فیلدهای ut_user، ut_host و ut_time را با بایت‌های تهی پاک می‌کند.

شبیه‌سازهای ترمینال مانند xterm(1) مستقیماً یک رکورد از نوع USER_PROCESS ایجاد نموده و مقدار ut_id را با استفاده از پسوند نام ترمینال (نویسه‌های پس از /dev/[pt]ty) تولید می‌کنند. اگر رکوردی از نوع DEAD_PROCESS با این شناسه بیابند، آن را بازیافت کرده و دوباره استفاده می‌کنند؛ در غیر این صورت یک رکورد تازه پدید می‌آورند. در هنگام خروج نیز در صورت امکان آن را با DEAD_PROCESS علامت‌گذاری می‌کنند و توصیه شده است که فیلدهای ut_line، ut_time، ut_user و ut_host را نیز با بایت تهی پاک نمایند.

برنامه telnetd(8) یک رکورد LOGIN_PROCESS تنظیم می‌کند و باقی مراحل را مطابق روال معمول به login(1) می‌سپارد. پس از پایان نشست شبکه، telnetd(8) رکورد را به شیوه شرح داده شده پاک‌سازی می‌نماید.

پرونده wtmp (و همتای آن wtmpx) تمام رخدادهای ورود و خروج را ثبت و نگهداری می‌کند. ساختار آن دقیقاً مشابه utmpx است، با این تفاوت که یک نام کاربری تهی نشان‌دهنده خروج از ترمینال مربوطه است. علاوه بر این، نام ترمینال ~ همراه با نام کاربری shutdown یا reboot نشان‌دهنده خاموش شدن یا راه‌اندازی مجدد سیستم است و جفت‌نام ترمینال‌های |/} زمان قدیم و جدید سیستم را هنگامی که با دستور date(1) تغییر داده شود، ثبت می‌کنند. پرونده wtmp توسط برنامه‌های login(1)، init(1) و برخی نسخه‌های getty(8) (مانند mingetty(8) یا agetty(8)) مدیریت و نگهداری می‌شود. هیچ‌یک از این برنامه‌ها پرونده مذکور را از ابتدا ایجاد نمی‌کنند؛ بنابراین در صورتی که این پرونده حذف شود، ثبت سوابق غیرفعال می‌گردد.

/var/run/utmp
/run/utmp
/var/log/wtmp

استاندارد POSIX.1 ساختار utmp را مشخص نمی‌کند، بلکه ساختاری با نام utmpx (به عنوان بخشی از الحاقیه XSI) با مشخصات فیلدهای ut_type، ut_pid، ut_line، ut_id، ut_user و ut_tv تعریف کرده است. استاندارد POSIX.1 طول فیلدهای ut_line و ut_user را مشخص نمی‌کند.

سیستم‌عامل لینوکس ساختار utmpx را دقیقاً همانند ساختار utmp تعریف نموده است.

POSIX.1-2008، Linux.

رکوردهای utmp و utmpx در لینوکس نه کاملاً منطبق بر نسخه ۷ یا BSD هستند و نه System V؛ بلکه ترکیبی از هر دو می‌باشند.

نسخه v7/BSD فیلدهای کمتری دارد؛ مهم‌تر از همه فیلد ut_type در آن وجود ندارد، که باعث می‌شود برنامه‌های سبک سنتی BSD رکوردهای خاتمه‌یافته یا مربوط به فرآیندهای ورود را نیز به عنوان کاربر فعال نمایش دهند. علاوه بر این، هیچ فایل پیکربندی برای تخصیص شیارها به نشست‌ها وجود ندارد، زیرا BSD فاقد فیلد ut_id است.

در لینوکس (همانند System V)، مقدار فیلد ut_id یک رکورد پس از مقداردهی اولیه هرگز تغییر نمی‌کند و بدون نیاز به فایل پیکربندی، آن شیار را رزرو نگاه می‌دارد. پاک کردن ut_id ممکن است منجر به شرایط رقابتی (race condition)، مخدوش شدن رکوردهای utmp/utmpx و رخنه‌های امنیتی گردد. پاک‌سازی سایر فیلدها با پر کردن بایت تهی در معناشناسی System V الزامی نبوده، اما باعث می‌شود بسیاری از برنامه‌های مبتنی بر BSD که utmp را تغییر نمی‌دهند نیز بتوانند به درستی کار کنند. سیستم‌عامل لینوکس در مورد محتوای خطوط ترمینال از قواعد BSD پیروی می‌کند.

سیستم‌عامل System V فاقد فیلدهای ut_host یا ut_addr_v6 است.

برخلاف برخی سیستم‌های دیگر که ثبت اطلاعات utmp را می‌توان با حذف فایل متوقف کرد، در لینوکس پرونده utmp/utmpx باید همیشه وجود داشته باشد. اگر مایلید دستور who(1) را غیرفعال کنید، دسترسی خواندن همگانی utmp را مسدود نمایید.

فرمت این پرونده وابسته به معماری پردازنده (machine-dependent) است؛ از این رو توصیه می‌شود تنها در همان معماری که تولید شده پردازش و خوانده شود.

توجه داشته باشید که در پلتفرم‌های دوگانه (biarch) مانند x86-64 و ppc64 که می‌توانند هر دو نوع برنامه‌های ۳۲ بیتی و ۶۴ بیتی را به طور هم‌زمان اجرا کنند، اندازه فیلد ut_tv در حالت ۳۲ بیتی دقیقاً برابر با حالت ۶۴ بیتی در نظر گرفته شده است. همین موضوع در صورت وجود، برای فیلدهای ut_session و ut_time نیز صادق است. این امر اشتراک‌گذاری داده‌ها و حافظه مشترک را میان برنامه‌های ۳۲ و ۶۴ بیتی میسر می‌سازد. این سازگاری با تغییر دادن نوع ut_session به int32_t و نوع ut_tv به یک ساختار با دو فیلد int32_t شامل tv_sec و tv_usec حاصل شده است.

از آنجا که ut_tv ممکن است دقیقاً با struct timeval یکسان نباشد، به جای فراخوانی:


gettimeofday((struct timeval *) &ut.ut_tv, NULL);

رویکرد زیر برای مقداردهی این فیلد پیشنهاد و توصیه می‌شود:


struct utmpx ut;
struct timeval tv;
gettimeofday(&tv, NULL);
ut.ut_tv.tv_sec = tv.tv_sec;
ut.ut_tv.tv_usec = tv.tv_usec;

ac(1), date(1), init(1), last(1), login(1), logname(1), lslogins(1), users(1), utmpdump(1), who(1), getutent(3), getutmp(3), getutxent(3), login(3), logout(3), logwtmp(3), updwtmp(3)

مه ۲۰۲۵ man-pages