From 895fe289612f5147e649e8a4c11b34a485a33edc Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Thu, 21 Sep 2017 09:01:20 +0200 Subject: [PATCH 01/22] Initial support for utmp/wtmp on linux --- sesman/sesexec/session.c | 5 +++ sesman/sesexec/utmp.c | 95 ++++++++++++++++++++++++++++++++++++++++ sesman/sesexec/utmp.h | 44 +++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 sesman/sesexec/utmp.c create mode 100644 sesman/sesexec/utmp.h diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index a495097327..71468c92a7 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -656,6 +656,9 @@ session_start_wrapped(struct login_info *login_info, } else { + utmp_login(window_manager_pid, + s->display, login_info->username, + login_info->ip_addr); LOG(LOG_LEVEL_INFO, "Starting the xrdp channel server for display :%d", s->display); @@ -886,6 +889,8 @@ session_process_child_exit(struct session_data *sd, sd->win_mgr, sd->params.display, wm_wait_time); } + utmp_logout(sd->win_mgr, sd->params.display, g_login_info->username, + g_login_info->ip_addr); sd->win_mgr = -1; if (sd->x_server > 0) diff --git a/sesman/sesexec/utmp.c b/sesman/sesexec/utmp.c new file mode 100644 index 0000000000..7a6aa35178 --- /dev/null +++ b/sesman/sesexec/utmp.c @@ -0,0 +1,95 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Emmanuel Blindauer 2017 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * @file utmp.c + * @brief utmp/wtmp handling code + * + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include +#include +#include +#include +#include "log.h" + +#include +#include + +/* + * Prepare the utmpx struct and write it. + * this can handle login and logout at once with the 'state' parameter + */ + +int +add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state) +{ + struct utmpx ut; + struct timeval tv; + + memset (&ut, 0, sizeof (ut)); + + ut.ut_type=state; + ut.ut_pid = pid; + gettimeofday(&tv, NULL); + ut.ut_tv.tv_sec = tv.tv_sec; + ut.ut_tv.tv_usec = tv.tv_usec; + strncpy(ut.ut_line, line , sizeof (ut.ut_line)); + strncpy(ut.ut_user, user , sizeof (ut.ut_user)); + strncpy(ut.ut_host, rhostname, sizeof (ut.ut_host)); + + /* utmp */ + setutxent(); + pututxline(&ut); + endutxent (); + + /* wtmp XXX hardcoded! */ + updwtmpx("/var/log/wtmp", &ut); + + return 0; +} + +int +utmp_login(int pid, int display, const char *user, const char *rhostname) +{ + char str_display[16]; + + log_message(LOG_LEVEL_DEBUG, + "adding login info for utmp/wtmp: %d - %d - %s - %s", + pid, display, user, rhostname); + g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); + return add_xtmp_entry(pid, str_display, user, rhostname, USER_PROCESS); +} + +int +utmp_logout(int pid, int display, const char *user, const char *rhostname) +{ + char str_display[16]; + + log_message(LOG_LEVEL_DEBUG, + "adding logout info for utmp/wtmp: %d - %d - %s - %s", + pid, display, user, rhostname); + g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); + return add_xtmp_entry(pid, str_display, user, rhostname, DEAD_PROCESS); +} diff --git a/sesman/sesexec/utmp.h b/sesman/sesexec/utmp.h new file mode 100644 index 0000000000..636450f399 --- /dev/null +++ b/sesman/sesexec/utmp.h @@ -0,0 +1,44 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Emmanuel Blindauer 2017 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * @file utmp.h + * @brief utmp/wtmp handling code + * + */ + +#ifndef UTMP_H +#define UTMP_H + +#define XRDP_LINE_FORMAT "xrdp:%d" +/** + * + * @brief + * + * @param pid + * @return 0 + */ + +int add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state); + +int utmp_login(int pid, int display, const char *user, const char *rhostname); + +int utmp_logout(int pid, int display, const char *user, const char *rhostname); + +#endif From 42388ca009848f40d727e1c73ae29c396ea4bcc4 Mon Sep 17 00:00:00 2001 From: Koichiro IWAO Date: Fri, 22 Sep 2017 14:43:10 +0900 Subject: [PATCH 02/22] remove trailing space --- sesman/sesexec/utmp.c | 20 ++++++++++---------- sesman/sesexec/utmp.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sesman/sesexec/utmp.c b/sesman/sesexec/utmp.c index 7a6aa35178..c28a8dc8bc 100644 --- a/sesman/sesexec/utmp.c +++ b/sesman/sesexec/utmp.c @@ -37,7 +37,7 @@ #include #include -/* +/* * Prepare the utmpx struct and write it. * this can handle login and logout at once with the 'state' parameter */ @@ -55,12 +55,12 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec; - strncpy(ut.ut_line, line , sizeof (ut.ut_line)); - strncpy(ut.ut_user, user , sizeof (ut.ut_user)); + strncpy(ut.ut_line, line , sizeof (ut.ut_line)); + strncpy(ut.ut_user, user , sizeof (ut.ut_user)); strncpy(ut.ut_host, rhostname, sizeof (ut.ut_host)); /* utmp */ - setutxent(); + setutxent(); pututxline(&ut); endutxent (); @@ -70,25 +70,25 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam return 0; } -int +int utmp_login(int pid, int display, const char *user, const char *rhostname) { char str_display[16]; - log_message(LOG_LEVEL_DEBUG, - "adding login info for utmp/wtmp: %d - %d - %s - %s", + log_message(LOG_LEVEL_DEBUG, + "adding login info for utmp/wtmp: %d - %d - %s - %s", pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); return add_xtmp_entry(pid, str_display, user, rhostname, USER_PROCESS); } -int +int utmp_logout(int pid, int display, const char *user, const char *rhostname) { char str_display[16]; - log_message(LOG_LEVEL_DEBUG, - "adding logout info for utmp/wtmp: %d - %d - %s - %s", + log_message(LOG_LEVEL_DEBUG, + "adding logout info for utmp/wtmp: %d - %d - %s - %s", pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); return add_xtmp_entry(pid, str_display, user, rhostname, DEAD_PROCESS); diff --git a/sesman/sesexec/utmp.h b/sesman/sesexec/utmp.h index 636450f399..f378ad8b3e 100644 --- a/sesman/sesexec/utmp.h +++ b/sesman/sesexec/utmp.h @@ -29,10 +29,10 @@ #define XRDP_LINE_FORMAT "xrdp:%d" /** * - * @brief - * + * @brief + * * @param pid - * @return 0 + * @return 0 */ int add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state); From c103d2308bd3922b0e337516b355eefbc27558e1 Mon Sep 17 00:00:00 2001 From: Koichiro IWAO Date: Fri, 22 Sep 2017 14:56:45 +0900 Subject: [PATCH 03/22] sesman: add utmp files to makefile --- sesman/sesexec/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sesman/sesexec/Makefile.am b/sesman/sesexec/Makefile.am index b7d5abb60f..e874096737 100644 --- a/sesman/sesexec/Makefile.am +++ b/sesman/sesexec/Makefile.am @@ -25,6 +25,8 @@ xrdp_sesexec_SOURCES = \ env.h \ login_info.c \ login_info.h \ + utmp.c \ + utmp.h \ xauth.c \ xauth.h \ xwait.c \ From 3ea306249b46e6fbad46b8c5aa70b9ba3da5fd29 Mon Sep 17 00:00:00 2001 From: Koichiro IWAO Date: Fri, 22 Sep 2017 15:01:29 +0900 Subject: [PATCH 04/22] don't forget include utmp.h --- sesman/sesexec/session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index 71468c92a7..df7f964964 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -48,6 +48,7 @@ #include "os_calls.h" #include "sesexec.h" #include "string_calls.h" +#include "utmp.h" #include "xauth.h" #include "xwait.h" #include "xrdp_sockets.h" From 56eec32b7e45ced7d1bba4315eaef33043ad6404 Mon Sep 17 00:00:00 2001 From: Koichiro IWAO Date: Fri, 22 Sep 2017 15:21:14 +0900 Subject: [PATCH 05/22] os_calls.h needs to be included to use g_snprintf() --- sesman/sesexec/utmp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sesman/sesexec/utmp.c b/sesman/sesexec/utmp.c index c28a8dc8bc..ffef17d67b 100644 --- a/sesman/sesexec/utmp.c +++ b/sesman/sesexec/utmp.c @@ -32,7 +32,9 @@ #include #include #include + #include "log.h" +#include "os_calls.h" #include #include From bacda8049258f13e8085584f6ce3c2ed71c9bf1a Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Tue, 26 Sep 2017 21:06:44 +0200 Subject: [PATCH 06/22] WIP utmp/wtmp - renamed the two files, including the header was conflicting with official headers - configure look for utmp/utmpx headers, wo we know which struct to use - reworked the usage for linux, works mostly (last still showing 'gone' for loggued users) --- configure.ac | 2 ++ sesman/sesexec/Makefile.am | 4 +-- sesman/sesexec/session.c | 2 +- sesman/sesexec/{utmp.c => sessionrecord.c} | 30 ++++++++++++---------- sesman/sesexec/{utmp.h => sessionrecord.h} | 18 ++++++++++--- 5 files changed, 37 insertions(+), 19 deletions(-) rename sesman/sesexec/{utmp.c => sessionrecord.c} (85%) rename sesman/sesexec/{utmp.h => sessionrecord.h} (83%) diff --git a/configure.ac b/configure.ac index 6d0403a1cb..e62e83c226 100644 --- a/configure.ac +++ b/configure.ac @@ -514,6 +514,8 @@ AC_CHECK_HEADER([X11/extensions/Xrandr.h], [], [AC_MSG_ERROR([please install libxrandr-dev or libXrandr-devel])], [#include ]) +AC_CHECK_HEADERS(utmp.h utmpx.h) + CFLAGS="$save_CFLAGS" # perform unit tests if libcheck and libmocka found diff --git a/sesman/sesexec/Makefile.am b/sesman/sesexec/Makefile.am index e874096737..c270c4c0e0 100644 --- a/sesman/sesexec/Makefile.am +++ b/sesman/sesexec/Makefile.am @@ -25,8 +25,8 @@ xrdp_sesexec_SOURCES = \ env.h \ login_info.c \ login_info.h \ - utmp.c \ - utmp.h \ + sessionrecord.c \ + sessionrecord.h \ xauth.c \ xauth.h \ xwait.c \ diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index df7f964964..a54aa23e7b 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -47,8 +47,8 @@ #include "login_info.h" #include "os_calls.h" #include "sesexec.h" +#include "sessionrecord.h" #include "string_calls.h" -#include "utmp.h" #include "xauth.h" #include "xwait.h" #include "xrdp_sockets.h" diff --git a/sesman/sesexec/utmp.c b/sesman/sesexec/sessionrecord.c similarity index 85% rename from sesman/sesexec/utmp.c rename to sesman/sesexec/sessionrecord.c index ffef17d67b..f833a82965 100644 --- a/sesman/sesexec/utmp.c +++ b/sesman/sesexec/sessionrecord.c @@ -18,7 +18,7 @@ /** * - * @file utmp.c + * @file sessionrecord.c * @brief utmp/wtmp handling code * */ @@ -27,27 +27,26 @@ #include #endif -#include -#include +#include #include -#include #include +#include +#include +#include #include "log.h" #include "os_calls.h" +#include "sessionrecord.h" -#include -#include - -/* - * Prepare the utmpx struct and write it. +/* + * Prepare the utmp/ struct and write it. * this can handle login and logout at once with the 'state' parameter */ int add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state) { - struct utmpx ut; + _utmp ut; struct timeval tv; memset (&ut, 0, sizeof (ut)); @@ -66,9 +65,14 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam pututxline(&ut); endutxent (); - /* wtmp XXX hardcoded! */ - updwtmpx("/var/log/wtmp", &ut); - + /* wtmp XXX hardcoded! UTMPX_FILE pb def*/ +#ifdef HAVE_UTMPX_H + log_message(LOG_LEVEL_DEBUG, "HAVE_UTMPX_H"); + updwtmpx(_PATH_WTMP, &ut); +#elif defined(HAVE_UTMP_H) + log_message(LOG_LEVEL_DEBUG, "HAVE_UTMP_H"); + updwtmp("/var/log/wtmp", &ut); +#endif return 0; } diff --git a/sesman/sesexec/utmp.h b/sesman/sesexec/sessionrecord.h similarity index 83% rename from sesman/sesexec/utmp.h rename to sesman/sesexec/sessionrecord.h index f378ad8b3e..1dbe9e6efe 100644 --- a/sesman/sesexec/utmp.h +++ b/sesman/sesexec/sessionrecord.h @@ -18,13 +18,25 @@ /** * - * @file utmp.h + * @file sessionrecord.h * @brief utmp/wtmp handling code * */ -#ifndef UTMP_H -#define UTMP_H +#ifndef SESSIONRECORD_H +#define SESSIONRECORD_H + + +#ifdef HAVE_UTMPX_H +#include +typedef struct utmpx _utmp; +#else +#include +typedef struct utmp _utmp; +#endif + + + #define XRDP_LINE_FORMAT "xrdp:%d" /** From d3a751cff862feb2d6c18ee10ab40805d997fd78 Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Wed, 27 Sep 2017 22:28:53 +0200 Subject: [PATCH 07/22] Add GNU_SOURCE to configure.ac: it allow usage f more GNU functions, like updwtmpx --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index e62e83c226..98bf02d23e 100644 --- a/configure.ac +++ b/configure.ac @@ -5,6 +5,7 @@ AC_INIT([xrdp], [0.10.80], [xrdp-devel@googlegroups.com]) AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in) AM_INIT_AUTOMAKE([1.7.2 foreign]) AC_CONFIG_MACRO_DIR([m4]) +AC_GNU_SOURCE AC_PROG_CC AC_PROG_CXX AC_C_CONST From e32671cd79930ff8721bff25d0965f1ed1dbe673 Mon Sep 17 00:00:00 2001 From: Koichiro IWAO Date: Fri, 6 Oct 2017 10:50:54 +0900 Subject: [PATCH 08/22] Include sys/time.h to use gettimeofday() --- sesman/sesexec/sessionrecord.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index f833a82965..f349338099 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -32,13 +32,14 @@ #include #include #include +#include #include #include "log.h" #include "os_calls.h" #include "sessionrecord.h" -/* +/* * Prepare the utmp/ struct and write it. * this can handle login and logout at once with the 'state' parameter */ From eaffeaf53fc06f8b26fdff7484161beaf223e7ee Mon Sep 17 00:00:00 2001 From: Koichiro IWAO Date: Fri, 6 Oct 2017 10:55:37 +0900 Subject: [PATCH 09/22] cosmetic changes --- sesman/sesexec/sessionrecord.c | 19 +++++++++++-------- sesman/sesexec/sessionrecord.h | 5 +---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index f349338099..ff06b397a2 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -50,16 +50,16 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam _utmp ut; struct timeval tv; - memset (&ut, 0, sizeof (ut)); + memset(&ut, 0, sizeof(ut)); ut.ut_type=state; ut.ut_pid = pid; gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec; - strncpy(ut.ut_line, line , sizeof (ut.ut_line)); - strncpy(ut.ut_user, user , sizeof (ut.ut_user)); - strncpy(ut.ut_host, rhostname, sizeof (ut.ut_host)); + strncpy(ut.ut_line, line , sizeof(ut.ut_line)); + strncpy(ut.ut_user, user , sizeof(ut.ut_user)); + strncpy(ut.ut_host, rhostname, sizeof(ut.ut_host)); /* utmp */ setutxent(); @@ -74,6 +74,7 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam log_message(LOG_LEVEL_DEBUG, "HAVE_UTMP_H"); updwtmp("/var/log/wtmp", &ut); #endif + return 0; } @@ -83,9 +84,10 @@ utmp_login(int pid, int display, const char *user, const char *rhostname) char str_display[16]; log_message(LOG_LEVEL_DEBUG, - "adding login info for utmp/wtmp: %d - %d - %s - %s", - pid, display, user, rhostname); + "adding login info for utmp/wtmp: %d - %d - %s - %s", + pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); + return add_xtmp_entry(pid, str_display, user, rhostname, USER_PROCESS); } @@ -95,8 +97,9 @@ utmp_logout(int pid, int display, const char *user, const char *rhostname) char str_display[16]; log_message(LOG_LEVEL_DEBUG, - "adding logout info for utmp/wtmp: %d - %d - %s - %s", - pid, display, user, rhostname); + "adding logout info for utmp/wtmp: %d - %d - %s - %s", + pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); + return add_xtmp_entry(pid, str_display, user, rhostname, DEAD_PROCESS); } diff --git a/sesman/sesexec/sessionrecord.h b/sesman/sesexec/sessionrecord.h index 1dbe9e6efe..b52c30939e 100644 --- a/sesman/sesexec/sessionrecord.h +++ b/sesman/sesexec/sessionrecord.h @@ -26,7 +26,6 @@ #ifndef SESSIONRECORD_H #define SESSIONRECORD_H - #ifdef HAVE_UTMPX_H #include typedef struct utmpx _utmp; @@ -35,10 +34,8 @@ typedef struct utmpx _utmp; typedef struct utmp _utmp; #endif - - - #define XRDP_LINE_FORMAT "xrdp:%d" + /** * * @brief From 2af2e032c3ae8eeb0614161a3dc8b54cf58dc9e3 Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Sat, 11 Nov 2017 11:26:21 +0100 Subject: [PATCH 10/22] Add the loginuid pam module, as we are starting a session. So /proc//loginuid will be filled by the uid of the user. This will fix entries in 'last' with "gone - no logout" instead of 'still logged in' --- instfiles/pam.d/xrdp-sesman.debian | 2 ++ instfiles/pam.d/xrdp-sesman.redhat | 3 +++ instfiles/pam.d/xrdp-sesman.suse | 3 +++ 3 files changed, 8 insertions(+) diff --git a/instfiles/pam.d/xrdp-sesman.debian b/instfiles/pam.d/xrdp-sesman.debian index bab1e57201..a85ce7519e 100644 --- a/instfiles/pam.d/xrdp-sesman.debian +++ b/instfiles/pam.d/xrdp-sesman.debian @@ -9,6 +9,8 @@ auth required pam_env.so readenv=1 envfile=/etc/default/locale @include common-password +# Set the loginuid process attribute. +session required pam_loginuid.so @include common-session -session optional pam_gnome_keyring.so auto_start -session optional pam_kwallet5.so auto_start diff --git a/instfiles/pam.d/xrdp-sesman.redhat b/instfiles/pam.d/xrdp-sesman.redhat index 9da2690bc3..aa444ad607 100644 --- a/instfiles/pam.d/xrdp-sesman.redhat +++ b/instfiles/pam.d/xrdp-sesman.redhat @@ -1,5 +1,8 @@ #%PAM-1.0 auth include password-auth account include password-auth + +# Set the loginuid process attribute. +session required pam_loginuid.so session include password-auth password include password-auth diff --git a/instfiles/pam.d/xrdp-sesman.suse b/instfiles/pam.d/xrdp-sesman.suse index a7c7836ce1..44e5b24e21 100644 --- a/instfiles/pam.d/xrdp-sesman.suse +++ b/instfiles/pam.d/xrdp-sesman.suse @@ -1,5 +1,8 @@ #%PAM-1.0 auth include common-auth account include common-account + +# Set the loginuid process attribute. +session required pam_loginuid.so session include common-session password include common-password From 547388ddcea7741e7c41b71c9a8be4ee0b3506cf Mon Sep 17 00:00:00 2001 From: Blindauer Emmanuel Date: Sat, 11 Nov 2017 17:22:26 +0100 Subject: [PATCH 11/22] Add support for FreeBSD --- sesman/sesexec/sessionrecord.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index ff06b397a2..4336994fb0 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -20,7 +20,8 @@ * * @file sessionrecord.c * @brief utmp/wtmp handling code - * + * Idea: Only implement actual utmp, i.e. utmpx for 99%. + * See http://80386.nl/unix/utmpx/ */ #if defined(HAVE_CONFIG_H) @@ -64,13 +65,15 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam /* utmp */ setutxent(); pututxline(&ut); - endutxent (); + endutxent(); - /* wtmp XXX hardcoded! UTMPX_FILE pb def*/ + /* wtmp : update on linux, FreeBSD uses utx */ #ifdef HAVE_UTMPX_H - log_message(LOG_LEVEL_DEBUG, "HAVE_UTMPX_H"); +#if !defined(__FreeBSD__) updwtmpx(_PATH_WTMP, &ut); +#endif #elif defined(HAVE_UTMP_H) + /* Does such system still exist ? */ log_message(LOG_LEVEL_DEBUG, "HAVE_UTMP_H"); updwtmp("/var/log/wtmp", &ut); #endif From 58b3989655e159d9f5c69f209c24548ae171569c Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Sun, 12 Nov 2017 11:58:45 +0100 Subject: [PATCH 12/22] don't forget a free use g_* --- sesman/sesexec/sessionrecord.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index 4336994fb0..0402ad72bf 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -77,6 +77,7 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam log_message(LOG_LEVEL_DEBUG, "HAVE_UTMP_H"); updwtmp("/var/log/wtmp", &ut); #endif + g_free(hostname); return 0; } From 22f17ad123576a56d6500c3982621dff9bd53b29 Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Sun, 12 Nov 2017 17:18:15 +0100 Subject: [PATCH 13/22] More g_* functions usage Follow coding standard --- sesman/sesexec/sessionrecord.c | 9 +++++---- sesman/sesexec/sessionrecord.h | 10 ++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index 0402ad72bf..979c778e37 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -38,6 +38,7 @@ #include "log.h" #include "os_calls.h" +#include "string_calls.h" #include "sessionrecord.h" /* @@ -51,16 +52,16 @@ add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostnam _utmp ut; struct timeval tv; - memset(&ut, 0, sizeof(ut)); + g_memset(&ut, 0, sizeof(ut)); ut.ut_type=state; ut.ut_pid = pid; gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec; - strncpy(ut.ut_line, line , sizeof(ut.ut_line)); - strncpy(ut.ut_user, user , sizeof(ut.ut_user)); - strncpy(ut.ut_host, rhostname, sizeof(ut.ut_host)); + g_strncpy(ut.ut_line, line , sizeof(ut.ut_line)); + g_strncpy(ut.ut_user, user , sizeof(ut.ut_user)); + g_strncpy(ut.ut_host, rhostname, sizeof(ut.ut_host)); /* utmp */ setutxent(); diff --git a/sesman/sesexec/sessionrecord.h b/sesman/sesexec/sessionrecord.h index b52c30939e..e72d4e881c 100644 --- a/sesman/sesexec/sessionrecord.h +++ b/sesman/sesexec/sessionrecord.h @@ -36,16 +36,14 @@ typedef struct utmp _utmp; #define XRDP_LINE_FORMAT "xrdp:%d" +int add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state); + /** + * @brief functions for adding utmp entries. one at login, one for logout * - * @brief - * - * @param pid + * @param pid of the session, display, login, and hostname * @return 0 */ - -int add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state); - int utmp_login(int pid, int display, const char *user, const char *rhostname); int utmp_logout(int pid, int display, const char *user, const char *rhostname); From da0f3cefd7a0565fd3ecbc7f531f4dddff8feac9 Mon Sep 17 00:00:00 2001 From: BLINDAUER Emmanuel Date: Thu, 29 Mar 2018 19:26:20 +0200 Subject: [PATCH 14/22] Move some definitions, and small fixes --- sesman/sesexec/sessionrecord.c | 76 ++++++++++++++++++++++++---------- sesman/sesexec/sessionrecord.h | 16 +------ 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index 979c778e37..7f4c56ee26 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -41,49 +41,81 @@ #include "string_calls.h" #include "sessionrecord.h" +#ifdef HAVE_UTMPX_H +#include +typedef struct utmpx _utmp; +#else +#include +typedef struct utmp _utmp; +#endif + + +#define XRDP_LINE_FORMAT "xrdp:%d" + +/* + * update the wtmp file on UTMPX platforms (~ Linux) + * but no on FreeBSD : FreeBSD uses utx to do the job + */ +#ifdef HAVE_UTMPX_H +#if !defined(__FreeBSD__) +static inline void +_updwtmp(const _utmp *ut) +{ + updwtmpx(_PATH_WTMP, ut); +} +#else +static inline void +_updwtmp(const _utmp ut) +{ +} +#endif +#elif defined(HAVE_UTMP_H) +/* Does such system still exist ? */ +_updwtmp(const _utmp *ut) +{ + log_message(LOG_LEVEL_DEBUG, + "Unsupported system: HAVE_UTMP_H defined without HAVE_UTMPX_H"); + updwtmp("/var/log/wtmp", ut); +} +#endif + + /* - * Prepare the utmp/ struct and write it. + * Prepare the utmp struct and write it. * this can handle login and logout at once with the 'state' parameter */ -int -add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state) +void +add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rhostname, const short state) { _utmp ut; struct timeval tv; g_memset(&ut, 0, sizeof(ut)); - ut.ut_type=state; + ut.ut_type = state; ut.ut_pid = pid; gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec; - g_strncpy(ut.ut_line, line , sizeof(ut.ut_line)); + g_strncpy(ut.ut_line, display_id, sizeof(ut.ut_line)); g_strncpy(ut.ut_user, user , sizeof(ut.ut_user)); g_strncpy(ut.ut_host, rhostname, sizeof(ut.ut_host)); - /* utmp */ + /* update the utmp file */ + /* open utmp */ setutxent(); + /* add the computed entry */ pututxline(&ut); + /* closes utmp */ endutxent(); - /* wtmp : update on linux, FreeBSD uses utx */ -#ifdef HAVE_UTMPX_H -#if !defined(__FreeBSD__) - updwtmpx(_PATH_WTMP, &ut); -#endif -#elif defined(HAVE_UTMP_H) - /* Does such system still exist ? */ - log_message(LOG_LEVEL_DEBUG, "HAVE_UTMP_H"); - updwtmp("/var/log/wtmp", &ut); -#endif - g_free(hostname); + /* update the wtmp file if needed */ - return 0; + _updwtmp(&ut); } -int +void utmp_login(int pid, int display, const char *user, const char *rhostname) { char str_display[16]; @@ -93,10 +125,10 @@ utmp_login(int pid, int display, const char *user, const char *rhostname) pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); - return add_xtmp_entry(pid, str_display, user, rhostname, USER_PROCESS); + add_xtmp_entry(pid, str_display, user, rhostname, USER_PROCESS); } -int +void utmp_logout(int pid, int display, const char *user, const char *rhostname) { char str_display[16]; @@ -106,5 +138,5 @@ utmp_logout(int pid, int display, const char *user, const char *rhostname) pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); - return add_xtmp_entry(pid, str_display, user, rhostname, DEAD_PROCESS); + add_xtmp_entry(pid, str_display, user, rhostname, DEAD_PROCESS); } diff --git a/sesman/sesexec/sessionrecord.h b/sesman/sesexec/sessionrecord.h index e72d4e881c..3fa73bd2f1 100644 --- a/sesman/sesexec/sessionrecord.h +++ b/sesman/sesexec/sessionrecord.h @@ -26,26 +26,14 @@ #ifndef SESSIONRECORD_H #define SESSIONRECORD_H -#ifdef HAVE_UTMPX_H -#include -typedef struct utmpx _utmp; -#else -#include -typedef struct utmp _utmp; -#endif - -#define XRDP_LINE_FORMAT "xrdp:%d" - -int add_xtmp_entry(int pid, const char *line, const char *user, const char *rhostname, short state); /** * @brief functions for adding utmp entries. one at login, one for logout * * @param pid of the session, display, login, and hostname - * @return 0 */ -int utmp_login(int pid, int display, const char *user, const char *rhostname); +void utmp_login(int pid, int display, const char *user, const char *rhostname); -int utmp_logout(int pid, int display, const char *user, const char *rhostname); +void utmp_logout(int pid, int display, const char *user, const char *rhostname); #endif From 49f60fc64fc4db0420d44487ac0f4aa9866adf5b Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 29 Jun 2023 15:05:25 +0100 Subject: [PATCH 15/22] Remove AC_GNU_SOURCE AC_GNU_SOURCE is replaced with AC_USE_SYSTEM_EXTENSIONS (available from autoconf 2.6.0) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 98bf02d23e..db8a5708fa 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_INIT([xrdp], [0.10.80], [xrdp-devel@googlegroups.com]) AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in) AM_INIT_AUTOMAKE([1.7.2 foreign]) AC_CONFIG_MACRO_DIR([m4]) -AC_GNU_SOURCE +AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_CXX AC_C_CONST From bc9b35c38cac8fc35475c0af4e69d9294d7d575f Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 29 Jun 2023 15:20:39 +0100 Subject: [PATCH 16/22] Rename struct exit_status in os_calls This conflicts with struct exit_status in --- common/os_calls.c | 24 ++++++++++++++---------- common/os_calls.h | 16 ++++++++-------- sesman/sesexec/sesexec.c | 2 +- sesman/sesexec/session.c | 10 +++++----- sesman/sesexec/session.h | 4 ++-- sesman/sesexec/xwait.c | 6 +++--- tests/common/test_os_calls_signals.c | 14 +++++++------- xrdp/xrdp_listen.c | 4 ++-- 8 files changed, 42 insertions(+), 38 deletions(-) diff --git a/common/os_calls.c b/common/os_calls.c index b8f6b63376..da288fbe60 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -3302,10 +3302,10 @@ g_set_allusercontext(int uid) /*****************************************************************************/ /* does not work in win32 returns pid of process that exits or zero if signal occurred - an exit_status struct can optionally be passed in to get the + a proc_exit_status struct can optionally be passed in to get the exit status of the child */ int -g_waitchild(struct exit_status *e) +g_waitchild(struct proc_exit_status *e) { #if defined(_WIN32) return 0; @@ -3313,14 +3313,14 @@ g_waitchild(struct exit_status *e) int wstat; int rv; - struct exit_status dummy; + struct proc_exit_status dummy; if (e == NULL) { e = &dummy; // Set this, then throw it away } - e->reason = E_XR_UNEXPECTED; + e->reason = E_PXR_UNEXPECTED; e->val = 0; rv = waitpid(-1, &wstat, WNOHANG); @@ -3335,12 +3335,12 @@ g_waitchild(struct exit_status *e) } else if (WIFEXITED(wstat)) { - e->reason = E_XR_STATUS_CODE; + e->reason = E_PXR_STATUS_CODE; e->val = WEXITSTATUS(wstat); } else if (WIFSIGNALED(wstat)) { - e->reason = E_XR_SIGNAL; + e->reason = E_PXR_SIGNAL; e->val = WTERMSIG(wstat); } @@ -3381,10 +3381,14 @@ g_waitpid(int pid) Note that signal handlers are established with BSD-style semantics, so this call is NOT interrupted by a signal */ -struct exit_status +struct proc_exit_status g_waitpid_status(int pid) { - struct exit_status exit_status = {.reason = E_XR_UNEXPECTED, .val = 0}; + struct proc_exit_status exit_status = + { + .reason = E_PXR_UNEXPECTED, + .val = 0 + }; #if !defined(_WIN32) if (pid > 0) @@ -3399,12 +3403,12 @@ g_waitpid_status(int pid) { if (WIFEXITED(status)) { - exit_status.reason = E_XR_STATUS_CODE; + exit_status.reason = E_PXR_STATUS_CODE; exit_status.val = WEXITSTATUS(status); } if (WIFSIGNALED(status)) { - exit_status.reason = E_XR_SIGNAL; + exit_status.reason = E_PXR_SIGNAL; exit_status.val = WTERMSIG(status); } } diff --git a/common/os_calls.h b/common/os_calls.h index aa64b41ff6..9fdbad8b1b 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -23,16 +23,16 @@ #include "arch.h" -enum exit_reason +enum proc_exit_reason { - E_XR_STATUS_CODE = 0, ///< 'val' contains exit status - E_XR_SIGNAL, ///< 'val' contains a signal number - E_XR_UNEXPECTED + E_PXR_STATUS_CODE = 0, ///< 'val' contains exit status + E_PXR_SIGNAL, ///< 'val' contains a signal number + E_PXR_UNEXPECTED }; -struct exit_status +struct proc_exit_status { - enum exit_reason reason; + enum proc_exit_reason reason; int val; }; @@ -352,9 +352,9 @@ int g_setlogin(const char *name); */ int g_set_allusercontext(int uid); #endif -int g_waitchild(struct exit_status *e); +int g_waitchild(struct proc_exit_status *e); int g_waitpid(int pid); -struct exit_status g_waitpid_status(int pid); +struct proc_exit_status g_waitpid_status(int pid); /* * Sets the process group ID of the indicated process to the specified value. * (POSIX.1) diff --git a/sesman/sesexec/sesexec.c b/sesman/sesexec/sesexec.c index 3e9763dded..67b493e8d2 100644 --- a/sesman/sesexec/sesexec.c +++ b/sesman/sesexec/sesexec.c @@ -241,7 +241,7 @@ sesexec_terminate_main_loop(int status) static void process_sigchld_event(void) { - struct exit_status e; + struct proc_exit_status e; int pid; // Check for any finished children diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index a54aa23e7b..7eb5399b1c 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -811,11 +811,11 @@ cleanup_sockets(int uid, int display) /******************************************************************************/ static void -exit_status_to_str(const struct exit_status *e, char buff[], int bufflen) +exit_status_to_str(const struct proc_exit_status *e, char buff[], int bufflen) { switch (e->reason) { - case E_XR_STATUS_CODE: + case E_PXR_STATUS_CODE: if (e->val == 0) { g_snprintf(buff, bufflen, "exit code zero"); @@ -826,7 +826,7 @@ exit_status_to_str(const struct exit_status *e, char buff[], int bufflen) } break; - case E_XR_SIGNAL: + case E_PXR_SIGNAL: { char sigstr[MAXSTRSIGLEN]; g_snprintf(buff, bufflen, "signal %s", @@ -844,7 +844,7 @@ exit_status_to_str(const struct exit_status *e, char buff[], int bufflen) void session_process_child_exit(struct session_data *sd, int pid, - const struct exit_status *e) + const struct proc_exit_status *e) { if (pid == sd->x_server) { @@ -864,7 +864,7 @@ session_process_child_exit(struct session_data *sd, { int wm_wait_time = g_time1() - sd->start_time; - if (e->reason == E_XR_STATUS_CODE && e->val == 0) + if (e->reason == E_PXR_STATUS_CODE && e->val == 0) { LOG(LOG_LEVEL_INFO, "Window manager (pid %d, display %d) " diff --git a/sesman/sesexec/session.h b/sesman/sesexec/session.h index dee9fe360c..5cfab1409f 100644 --- a/sesman/sesexec/session.h +++ b/sesman/sesexec/session.h @@ -35,7 +35,7 @@ #include "xrdp_constants.h" struct login_info; -struct exit_status; +struct proc_exit_status; /** * Information used to start a session @@ -89,7 +89,7 @@ session_start(struct login_info *login_info, void session_process_child_exit(struct session_data *sd, int pid, - const struct exit_status *e); + const struct proc_exit_status *e); /** * Returns a count of active processes in the session diff --git a/sesman/sesexec/xwait.c b/sesman/sesexec/xwait.c index 9a7bd376f6..7531d4514e 100644 --- a/sesman/sesexec/xwait.c +++ b/sesman/sesexec/xwait.c @@ -142,7 +142,7 @@ wait_for_xserver(uid_t uid, } else { - struct exit_status e; + struct proc_exit_status e; fd[0] = -1; // File descriptor closed by fclose() log_waitforx_messages(dp); @@ -150,11 +150,11 @@ wait_for_xserver(uid_t uid, e = g_waitpid_status(pid); switch (e.reason) { - case E_XR_STATUS_CODE: + case E_PXR_STATUS_CODE: rv = (enum xwait_status)e.val; break; - case E_XR_SIGNAL: + case E_PXR_SIGNAL: { char sigstr[MAXSTRSIGLEN]; LOG(LOG_LEVEL_ERROR, diff --git a/tests/common/test_os_calls_signals.c b/tests/common/test_os_calls_signals.c index e917bfec16..a44f9276b8 100644 --- a/tests/common/test_os_calls_signals.c +++ b/tests/common/test_os_calls_signals.c @@ -79,7 +79,7 @@ END_TEST /******************************************************************************/ START_TEST(test_g_signal_child_stop_1) { - struct exit_status e; + struct proc_exit_status e; g_reset_wait_obj(g_wobj1); ck_assert_int_eq(g_is_wait_obj_set(g_wobj1), 0); @@ -98,7 +98,7 @@ START_TEST(test_g_signal_child_stop_1) e = g_waitpid_status(pid); - ck_assert_int_eq(e.reason, E_XR_STATUS_CODE); + ck_assert_int_eq(e.reason, E_PXR_STATUS_CODE); ck_assert_int_eq(e.val, 45); // Try another one to make sure the signal handler is still in place. @@ -116,7 +116,7 @@ START_TEST(test_g_signal_child_stop_1) e = g_waitpid_status(pid); - ck_assert_int_eq(e.reason, E_XR_SIGNAL); + ck_assert_int_eq(e.reason, E_PXR_SIGNAL); ck_assert_int_eq(e.val, SIGSEGV); // Clean up @@ -133,7 +133,7 @@ START_TEST(test_g_signal_child_stop_2) int pids[CHILD_COUNT]; unsigned int i; - struct exit_status e; + struct proc_exit_status e; g_reset_wait_obj(g_wobj1); ck_assert_int_eq(g_is_wait_obj_set(g_wobj1), 0); @@ -157,7 +157,7 @@ START_TEST(test_g_signal_child_stop_2) for (i = 0 ; i < CHILD_COUNT; ++i) { e = g_waitpid_status(pids[i]); - ck_assert_int_eq(e.reason, E_XR_STATUS_CODE); + ck_assert_int_eq(e.reason, E_PXR_STATUS_CODE); ck_assert_int_eq(e.val, (i + 1)); } @@ -246,12 +246,12 @@ START_TEST(test_waitpid_not_interrupted_by_sig) g_reset_wait_obj(g_wobj1); g_set_alarm(set_wobj1, 1); - struct exit_status e = g_waitpid_status(child_pid); + struct proc_exit_status e = g_waitpid_status(child_pid); // We should have had the alarm... ck_assert_int_ne(g_is_wait_obj_set(g_wobj1), 0); // ..and got the status of the child - ck_assert_int_eq(e.reason, E_XR_STATUS_CODE); + ck_assert_int_eq(e.reason, E_PXR_STATUS_CODE); ck_assert_int_eq(e.val, 42); // Clean up diff --git a/xrdp/xrdp_listen.c b/xrdp/xrdp_listen.c index 5dd9c19b56..49426e8dbe 100644 --- a/xrdp/xrdp_listen.c +++ b/xrdp/xrdp_listen.c @@ -856,12 +856,12 @@ xrdp_listen_conn_in(struct trans *self, struct trans *new_self) static void process_pending_sigchld_events(void) { - struct exit_status e; + struct proc_exit_status e; int pid; while ((pid = g_waitchild(&e)) > 0) { - if (e.reason == E_XR_SIGNAL) + if (e.reason == E_PXR_SIGNAL) { char sigstr[MAXSTRSIGLEN]; LOG(LOG_LEVEL_ERROR, From bf53a76ea1b5a1f8151c0cf354b5302ee0321ca3 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:09:43 +0100 Subject: [PATCH 17/22] Remove wtmp updating code --- instfiles/pam.d/xrdp-sesman.arch | 4 ++- instfiles/pam.d/xrdp-sesman.debian | 2 ++ instfiles/pam.d/xrdp-sesman.redhat | 3 +++ instfiles/pam.d/xrdp-sesman.suse | 3 +++ instfiles/pam.d/xrdp-sesman.system | 4 +++ sesman/sesexec/sessionrecord.c | 42 +++++------------------------- 6 files changed, 21 insertions(+), 37 deletions(-) diff --git a/instfiles/pam.d/xrdp-sesman.arch b/instfiles/pam.d/xrdp-sesman.arch index 2763612e9c..7b4a36164d 100644 --- a/instfiles/pam.d/xrdp-sesman.arch +++ b/instfiles/pam.d/xrdp-sesman.arch @@ -1,4 +1,3 @@ -#%PAM-1.0 auth include system-remote-login -auth optional pam_gnome_keyring.so -auth optional pam_kwallet5.so @@ -8,5 +7,8 @@ account include system-remote-login password include system-remote-login session include system-remote-login +# For wtmp/lastlog support uncomment one of the following lines:- +#session optional pam_lastlog.so quiet +#session optional pam_lastlog2.so silent -session optional pam_gnome_keyring.so auto_start -session optional pam_kwallet5.so auto_start diff --git a/instfiles/pam.d/xrdp-sesman.debian b/instfiles/pam.d/xrdp-sesman.debian index a85ce7519e..2dd2ecb8b2 100644 --- a/instfiles/pam.d/xrdp-sesman.debian +++ b/instfiles/pam.d/xrdp-sesman.debian @@ -11,6 +11,8 @@ auth required pam_env.so readenv=1 envfile=/etc/default/locale # Set the loginuid process attribute. session required pam_loginuid.so +# Update wtmp/lastlog +session optional pam_lastlog.so quiet @include common-session -session optional pam_gnome_keyring.so auto_start -session optional pam_kwallet5.so auto_start diff --git a/instfiles/pam.d/xrdp-sesman.redhat b/instfiles/pam.d/xrdp-sesman.redhat index aa444ad607..02c0ed97fc 100644 --- a/instfiles/pam.d/xrdp-sesman.redhat +++ b/instfiles/pam.d/xrdp-sesman.redhat @@ -4,5 +4,8 @@ account include password-auth # Set the loginuid process attribute. session required pam_loginuid.so +# Update wtmp/lastlog +session optional pam_lastlog.so quiet + session include password-auth password include password-auth diff --git a/instfiles/pam.d/xrdp-sesman.suse b/instfiles/pam.d/xrdp-sesman.suse index 44e5b24e21..87d40780e0 100644 --- a/instfiles/pam.d/xrdp-sesman.suse +++ b/instfiles/pam.d/xrdp-sesman.suse @@ -4,5 +4,8 @@ account include common-account # Set the loginuid process attribute. session required pam_loginuid.so +# Update lastlog database +session optional pam_lastlog2.so silent + session include common-session password include common-password diff --git a/instfiles/pam.d/xrdp-sesman.system b/instfiles/pam.d/xrdp-sesman.system index 5025a0f985..172360c6df 100644 --- a/instfiles/pam.d/xrdp-sesman.system +++ b/instfiles/pam.d/xrdp-sesman.system @@ -2,4 +2,8 @@ auth include system-auth account include system-auth password include system-auth + +# For wtmp/lastlog support uncomment one of the following lines:- +#session optional pam_lastlog.so quiet +#session optional pam_lastlog2.so silent session include system-auth diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index 7f4c56ee26..f50bf79081 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -19,7 +19,10 @@ /** * * @file sessionrecord.c - * @brief utmp/wtmp handling code + * @brief utmp handling code + * + * wtmp/lastlog/btmp is handled by PAM or (on FreeBSD) UTX + * * Idea: Only implement actual utmp, i.e. utmpx for 99%. * See http://80386.nl/unix/utmpx/ */ @@ -28,7 +31,6 @@ #include #endif -#include #include #include #include @@ -52,34 +54,6 @@ typedef struct utmp _utmp; #define XRDP_LINE_FORMAT "xrdp:%d" -/* - * update the wtmp file on UTMPX platforms (~ Linux) - * but no on FreeBSD : FreeBSD uses utx to do the job - */ -#ifdef HAVE_UTMPX_H -#if !defined(__FreeBSD__) -static inline void -_updwtmp(const _utmp *ut) -{ - updwtmpx(_PATH_WTMP, ut); -} -#else -static inline void -_updwtmp(const _utmp ut) -{ -} -#endif -#elif defined(HAVE_UTMP_H) -/* Does such system still exist ? */ -_updwtmp(const _utmp *ut) -{ - log_message(LOG_LEVEL_DEBUG, - "Unsupported system: HAVE_UTMP_H defined without HAVE_UTMPX_H"); - updwtmp("/var/log/wtmp", ut); -} -#endif - - /* * Prepare the utmp struct and write it. * this can handle login and logout at once with the 'state' parameter @@ -109,10 +83,6 @@ add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rh pututxline(&ut); /* closes utmp */ endutxent(); - - /* update the wtmp file if needed */ - - _updwtmp(&ut); } void @@ -121,7 +91,7 @@ utmp_login(int pid, int display, const char *user, const char *rhostname) char str_display[16]; log_message(LOG_LEVEL_DEBUG, - "adding login info for utmp/wtmp: %d - %d - %s - %s", + "adding login info for utmp: %d - %d - %s - %s", pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); @@ -134,7 +104,7 @@ utmp_logout(int pid, int display, const char *user, const char *rhostname) char str_display[16]; log_message(LOG_LEVEL_DEBUG, - "adding logout info for utmp/wtmp: %d - %d - %s - %s", + "adding logout info for utmp: %d - %d - %s - %s", pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); From 3b6c9bcba3c79d658415fb900504bd152a238e01 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:45:50 +0100 Subject: [PATCH 18/22] Add --enable-utmp to configure.ac --- .github/workflows/build.yml | 5 +++-- configure.ac | 11 ++++++++++- sesman/sesexec/Makefile.am | 4 ++++ sesman/sesexec/sessionrecord.c | 18 ++++++++++++------ 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7844013f5..d118eebc2b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -110,10 +110,11 @@ jobs: # define the standard environment variable used in the rest of the steps. CONF_FLAGS_amd64_min: "--disable-ipv6 --disable-jpeg --disable-fuse --disable-mp3lame --disable-fdkaac --disable-opus --disable-rfxcodec --disable-painter - --disable-pixman" + --disable-pixman --disable-utmp" CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame --enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter - --enable-pixman --with-imlib2 --with-freetype2 --enable-tests" + --enable-pixman --enable-utmp + --with-imlib2 --with-freetype2 --enable-tests" CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-mp3lame --enable-opus --enable-rfxcodec --enable-painter --disable-pixman --with-imlib2 --with-freetype2 diff --git a/configure.ac b/configure.ac index db8a5708fa..819557cf2a 100644 --- a/configure.ac +++ b/configure.ac @@ -183,6 +183,11 @@ AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin], [], [enable_rdpsndaudin=no]) AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes]) +AC_ARG_ENABLE(utmp, AS_HELP_STRING([--enable-utmp], + [Update utmp (default: no)]), + [], [enable_utmp=no]) +AM_CONDITIONAL(XRDP_UTMP, [test x$enable_utmp = xyes]) + AC_ARG_WITH(imlib2, AS_HELP_STRING([--with-imlib2=ARG], [imlib2 library to use for non-BMP backgrounds (ARG=yes/no/)]),,) AC_ARG_WITH(freetype2, AS_HELP_STRING([--with-freetype2=ARG], [freetype2 library to use for rendering fonts (ARG=yes/no/)]),,) @@ -515,7 +520,10 @@ AC_CHECK_HEADER([X11/extensions/Xrandr.h], [], [AC_MSG_ERROR([please install libxrandr-dev or libXrandr-devel])], [#include ]) -AC_CHECK_HEADERS(utmp.h utmpx.h) +if test "x$enable_utmp" = "xyes" +then + AC_CHECK_HEADERS(utmp.h utmpx.h) +fi CFLAGS="$save_CFLAGS" @@ -634,6 +642,7 @@ echo " ipv6only $enable_ipv6only" echo " vsock $enable_vsock" echo " auth mechanism $auth_mech" echo " rdpsndaudin $enable_rdpsndaudin" +echo " utmp support $enable_utmp" echo echo " with imlib2 $use_imlib2" echo " with freetype2 $use_freetype2" diff --git a/sesman/sesexec/Makefile.am b/sesman/sesexec/Makefile.am index c270c4c0e0..7adb959150 100644 --- a/sesman/sesexec/Makefile.am +++ b/sesman/sesexec/Makefile.am @@ -9,6 +9,10 @@ AM_CPPFLAGS = \ SESEXEC_EXTRA_LIBS = +if XRDP_UTMP + AM_CPPFLAGS += -DUSE_UTMP +endif + pkglibexec_PROGRAMS = \ xrdp-sesexec diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index f50bf79081..cbbd6eb4b0 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -31,6 +31,8 @@ #include #endif +#ifdef USE_UTMP + #include #include #include @@ -38,19 +40,20 @@ #include #include -#include "log.h" -#include "os_calls.h" -#include "string_calls.h" -#include "sessionrecord.h" - #ifdef HAVE_UTMPX_H #include typedef struct utmpx _utmp; #else -#include +#include typedef struct utmp _utmp; #endif +#endif // USE_UTMP + +#include "log.h" +#include "os_calls.h" +#include "string_calls.h" +#include "sessionrecord.h" #define XRDP_LINE_FORMAT "xrdp:%d" @@ -62,6 +65,7 @@ typedef struct utmp _utmp; void add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rhostname, const short state) { +#if USE_UTMP _utmp ut; struct timeval tv; @@ -83,6 +87,8 @@ add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rh pututxline(&ut); /* closes utmp */ endutxent(); + +#endif // USE_UTMP } void From 98d654556613749a6225ac4efa4e95d2b1c4aead Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:45:14 +0100 Subject: [PATCH 19/22] Don't use DEAD_PROCESS/USER_PROCESS for add_xtmp_entry If we're not compiling with USE_UTMP, these defines will not be available --- sesman/sesexec/sessionrecord.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index cbbd6eb4b0..dcc7aea13b 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -31,6 +31,21 @@ #include #endif + +#include "sessionrecord.h" +#include "login_info.h" +#include "log.h" + +// Operational mode of add_xtmp_entry() +// +// We can't use USER_PROCESS/DEAD_PROCESS directly, as they +// won't be available for platforms without USE_UTMP +enum add_xtmp_mode +{ + MODE_LOGIN, + MODE_LOGOUT +}; + #ifdef USE_UTMP #include @@ -50,20 +65,18 @@ typedef struct utmp _utmp; #endif // USE_UTMP -#include "log.h" #include "os_calls.h" #include "string_calls.h" -#include "sessionrecord.h" #define XRDP_LINE_FORMAT "xrdp:%d" /* * Prepare the utmp struct and write it. - * this can handle login and logout at once with the 'state' parameter + * this can handle login and logout at once with the 'mode' parameter */ void -add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rhostname, const short state) +add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rhostname, enum add_xtmp_mode mode) { #if USE_UTMP _utmp ut; @@ -71,7 +84,7 @@ add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rh g_memset(&ut, 0, sizeof(ut)); - ut.ut_type = state; + ut.ut_type = (mode == MODE_LOGIN) ? USER_PROCESS : DEAD_PROCESS; ut.ut_pid = pid; gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; @@ -101,7 +114,7 @@ utmp_login(int pid, int display, const char *user, const char *rhostname) pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); - add_xtmp_entry(pid, str_display, user, rhostname, USER_PROCESS); + add_xtmp_entry(pid, str_display, user, rhostname, MODE_LOGIN); } void @@ -114,5 +127,5 @@ utmp_logout(int pid, int display, const char *user, const char *rhostname) pid, display, user, rhostname); g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); - add_xtmp_entry(pid, str_display, user, rhostname, DEAD_PROCESS); + add_xtmp_entry(pid, str_display, user, rhostname, MODE_LOGOUT); } From 04c67a50392d4d597d2d4d5b39ca81410174eaa1 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 29 Jun 2023 17:06:28 +0100 Subject: [PATCH 20/22] Set ut_id field The utmp record is generally looked up by the ut_id field. Setting this field means we can use a blank username and host when the session exits --- sesman/sesexec/session.c | 7 ++---- sesman/sesexec/sessionrecord.c | 45 ++++++++++++++++++++-------------- sesman/sesexec/sessionrecord.h | 19 ++++++++++---- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index 7eb5399b1c..f8f7af864e 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -657,9 +657,7 @@ session_start_wrapped(struct login_info *login_info, } else { - utmp_login(window_manager_pid, - s->display, login_info->username, - login_info->ip_addr); + utmp_login(window_manager_pid, s->display, login_info); LOG(LOG_LEVEL_INFO, "Starting the xrdp channel server for display :%d", s->display); @@ -890,8 +888,7 @@ session_process_child_exit(struct session_data *sd, sd->win_mgr, sd->params.display, wm_wait_time); } - utmp_logout(sd->win_mgr, sd->params.display, g_login_info->username, - g_login_info->ip_addr); + utmp_logout(sd->win_mgr, sd->params.display); sd->win_mgr = -1; if (sd->x_server > 0) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index dcc7aea13b..d1aa6c9a91 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -69,29 +69,42 @@ typedef struct utmp _utmp; #include "string_calls.h" #define XRDP_LINE_FORMAT "xrdp:%d" +// ut_id is a very small field on some platforms, so use the display +// number in hex +#define XRDP_ID_FORMAT ":%x" /* * Prepare the utmp struct and write it. * this can handle login and logout at once with the 'mode' parameter */ -void -add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rhostname, enum add_xtmp_mode mode) +static void +add_xtmp_entry(int pid, int display, const struct login_info *login_info, + enum add_xtmp_mode mode) { #if USE_UTMP + char idbuff[16]; + char str_display[16]; + _utmp ut; struct timeval tv; g_memset(&ut, 0, sizeof(ut)); + g_snprintf(str_display, sizeof(str_display), XRDP_LINE_FORMAT, display); + g_snprintf(idbuff, sizeof(idbuff), XRDP_ID_FORMAT, display); + gettimeofday(&tv, NULL); ut.ut_type = (mode == MODE_LOGIN) ? USER_PROCESS : DEAD_PROCESS; ut.ut_pid = pid; - gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec; - g_strncpy(ut.ut_line, display_id, sizeof(ut.ut_line)); - g_strncpy(ut.ut_user, user , sizeof(ut.ut_user)); - g_strncpy(ut.ut_host, rhostname, sizeof(ut.ut_host)); + g_strncpy(ut.ut_line, str_display, sizeof(ut.ut_line)); + g_strncpy(ut.ut_id, idbuff, sizeof(ut.ut_id)); + if (login_info != NULL) + { + g_strncpy(ut.ut_user, login_info->username , sizeof(ut.ut_user)); + g_strncpy(ut.ut_host, login_info->ip_addr, sizeof(ut.ut_host)); + } /* update the utmp file */ /* open utmp */ @@ -105,27 +118,21 @@ add_xtmp_entry(int pid, const char *display_id, const char *user, const char *rh } void -utmp_login(int pid, int display, const char *user, const char *rhostname) +utmp_login(int pid, int display, const struct login_info *login_info) { - char str_display[16]; - log_message(LOG_LEVEL_DEBUG, "adding login info for utmp: %d - %d - %s - %s", - pid, display, user, rhostname); - g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); + pid, display, login_info->username, login_info->ip_addr); - add_xtmp_entry(pid, str_display, user, rhostname, MODE_LOGIN); + add_xtmp_entry(pid, display, login_info, MODE_LOGIN); } void -utmp_logout(int pid, int display, const char *user, const char *rhostname) +utmp_logout(int pid, int display) { - char str_display[16]; - log_message(LOG_LEVEL_DEBUG, - "adding logout info for utmp: %d - %d - %s - %s", - pid, display, user, rhostname); - g_snprintf(str_display, 15, XRDP_LINE_FORMAT, display); + log_message(LOG_LEVEL_DEBUG, "adding logout info for utmp: %d - %d", + pid, display); - add_xtmp_entry(pid, str_display, user, rhostname, MODE_LOGOUT); + add_xtmp_entry(pid, display, NULL, MODE_LOGOUT); } diff --git a/sesman/sesexec/sessionrecord.h b/sesman/sesexec/sessionrecord.h index 3fa73bd2f1..28a26b49c9 100644 --- a/sesman/sesexec/sessionrecord.h +++ b/sesman/sesexec/sessionrecord.h @@ -19,21 +19,30 @@ /** * * @file sessionrecord.h - * @brief utmp/wtmp handling code + * @brief utmp handling code * */ #ifndef SESSIONRECORD_H #define SESSIONRECORD_H +struct login_info; /** - * @brief functions for adding utmp entries. one at login, one for logout + * @brief Record login in utmp * - * @param pid of the session, display, login, and hostname + * @param pid PID of window manager + * @param display Display number + * @param login_info Information about logged in user */ -void utmp_login(int pid, int display, const char *user, const char *rhostname); +void utmp_login(int pid, int display, const struct login_info *login_info); -void utmp_logout(int pid, int display, const char *user, const char *rhostname); +/** + * @brief Record logout in utmp + * + * @param pid PID of window manager + * @param display Display number + */ +void utmp_logout(int pid, int display); #endif From b53c683edff1af897a351a09f950eed845d6a25e Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 29 Jun 2023 17:27:06 +0100 Subject: [PATCH 21/22] Allow some utmpx fields to be optional POSIX.1 doesn't define ut_host in struct utmpx. Also, Linux has support for an exit status value in ut_exit. This commit adds conditional code for both ut_host and ut_exit to maximise portability. --- configure.ac | 9 +++++++ m4/axrdp.m4 | 43 ++++++++++++++++++++++++++++++++++ sesman/sesexec/session.c | 2 +- sesman/sesexec/sessionrecord.c | 27 ++++++++++++++------- sesman/sesexec/sessionrecord.h | 8 +++++-- 5 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 m4/axrdp.m4 diff --git a/configure.ac b/configure.ac index 819557cf2a..0862809d59 100644 --- a/configure.ac +++ b/configure.ac @@ -523,6 +523,10 @@ AC_CHECK_HEADER([X11/extensions/Xrandr.h], [], if test "x$enable_utmp" = "xyes" then AC_CHECK_HEADERS(utmp.h utmpx.h) + + # Test for non-standard extensions in struct utmpx + AXRDP_CHECK_UTMPX_MEMBER_EXISTS([ut_host], [HAVE_UTMPX_UT_HOST]) + AXRDP_CHECK_UTMPX_MEMBER_EXISTS([ut_exit], [HAVE_UTMPX_UT_EXIT]) fi CFLAGS="$save_CFLAGS" @@ -643,6 +647,11 @@ echo " vsock $enable_vsock" echo " auth mechanism $auth_mech" echo " rdpsndaudin $enable_rdpsndaudin" echo " utmp support $enable_utmp" +if test x$enable_utmp = xyes; then + echo " utmpx.ut_host $ac_cv_utmpx_has_ut_host" + echo " utmpx.ut_exit $ac_cv_utmpx_has_ut_exit" +fi + echo echo " with imlib2 $use_imlib2" echo " with freetype2 $use_freetype2" diff --git a/m4/axrdp.m4 b/m4/axrdp.m4 new file mode 100644 index 0000000000..4ba87e5d42 --- /dev/null +++ b/m4/axrdp.m4 @@ -0,0 +1,43 @@ +# SYNOPSIS +# +# AXRDP_CHECK_UTMPX_MEMBER_EXISTS(MEMBER, COMPILE-DEFINE) +# +# EXAMPLE +# +# AXRDP_CHECK_UTMPX_MEMBER_EXISTS([ut_exit], [HAVE_UTMPX_UT_EXIT]) +# +# DESCRIPTION +# +# If the member MEMBER exists in the utmpx struct, the COMPILE-DEFINE +# is set for the C compiler. +# +# The shell variable 'ac_cv_utmpx_has_$MEMBER' is set to 'yes' or 'no' +# and cached +# +AC_DEFUN([AXRDP_CHECK_UTMPX_MEMBER_EXISTS], +[ + AS_VAR_PUSHDEF([x_var], [ac_cv_utmpx_has_$1]) + AS_VAR_PUSHDEF([x_define], [$2]) + AC_CACHE_CHECK( + [for $1 in struct utmpx], + [x_var], + [AC_COMPILE_IFELSE( + [AC_LANG_SOURCE([[ +# include +# include + int main() + { + return offsetof(struct utmpx,$1); + }]])], + [AS_VAR_SET([x_var], [yes])], + [AS_VAR_SET([x_var], [no])])] + ) + AS_VAR_IF( + [x_var], + [yes], + [AC_DEFINE([x_define], [1], [Define if '$1' is in struct utmpx.])]) + AS_VAR_POPDEF([x_var]) + AS_VAR_POPDEF([x_define]) +]) + + diff --git a/sesman/sesexec/session.c b/sesman/sesexec/session.c index f8f7af864e..f9c408205b 100644 --- a/sesman/sesexec/session.c +++ b/sesman/sesexec/session.c @@ -888,7 +888,7 @@ session_process_child_exit(struct session_data *sd, sd->win_mgr, sd->params.display, wm_wait_time); } - utmp_logout(sd->win_mgr, sd->params.display); + utmp_logout(sd->win_mgr, sd->params.display, e); sd->win_mgr = -1; if (sd->x_server > 0) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index d1aa6c9a91..e642876df1 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -48,10 +48,6 @@ enum add_xtmp_mode #ifdef USE_UTMP -#include -#include -#include -#include #include #include @@ -80,7 +76,7 @@ typedef struct utmp _utmp; static void add_xtmp_entry(int pid, int display, const struct login_info *login_info, - enum add_xtmp_mode mode) + enum add_xtmp_mode mode, const struct proc_exit_status *e) { #if USE_UTMP char idbuff[16]; @@ -102,9 +98,22 @@ add_xtmp_entry(int pid, int display, const struct login_info *login_info, g_strncpy(ut.ut_id, idbuff, sizeof(ut.ut_id)); if (login_info != NULL) { - g_strncpy(ut.ut_user, login_info->username , sizeof(ut.ut_user)); + g_strncpy(ut.ut_user, login_info->username, sizeof(ut.ut_user)); +#ifdef HAVE_UTMPX_UT_HOST g_strncpy(ut.ut_host, login_info->ip_addr, sizeof(ut.ut_host)); +#endif + } + +#ifdef HAVE_UTMPX_UT_EXIT + if (e != NULL && e->reason == E_PXR_STATUS_CODE) + { + ut.ut_exit.e_exit = e->val; } + else if (e != NULL && e->reason == E_PXR_SIGNAL) + { + ut.ut_exit.e_termination = e->val; + } +#endif /* update the utmp file */ /* open utmp */ @@ -124,15 +133,15 @@ utmp_login(int pid, int display, const struct login_info *login_info) "adding login info for utmp: %d - %d - %s - %s", pid, display, login_info->username, login_info->ip_addr); - add_xtmp_entry(pid, display, login_info, MODE_LOGIN); + add_xtmp_entry(pid, display, login_info, MODE_LOGIN, NULL); } void -utmp_logout(int pid, int display) +utmp_logout(int pid, int display, const struct proc_exit_status *exit_status) { log_message(LOG_LEVEL_DEBUG, "adding logout info for utmp: %d - %d", pid, display); - add_xtmp_entry(pid, display, NULL, MODE_LOGOUT); + add_xtmp_entry(pid, display, NULL, MODE_LOGOUT, exit_status); } diff --git a/sesman/sesexec/sessionrecord.h b/sesman/sesexec/sessionrecord.h index 28a26b49c9..d547877182 100644 --- a/sesman/sesexec/sessionrecord.h +++ b/sesman/sesexec/sessionrecord.h @@ -27,6 +27,7 @@ #define SESSIONRECORD_H struct login_info; +struct proc_exit_status; /** * @brief Record login in utmp @@ -35,14 +36,17 @@ struct login_info; * @param display Display number * @param login_info Information about logged in user */ -void utmp_login(int pid, int display, const struct login_info *login_info); +void +utmp_login(int pid, int display, const struct login_info *login_info); /** * @brief Record logout in utmp * * @param pid PID of window manager * @param display Display number + * @param exit_status Exit status of process */ -void utmp_logout(int pid, int display); +void +utmp_logout(int pid, int display, const struct proc_exit_status *exit_status); #endif From 8cea9b03ab2d63283517151094824b5cfb63d862 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:09:49 +0100 Subject: [PATCH 22/22] Replace g_strncpy() with str2memcpy() g_strncpy() is the wrong function for copying strings in struct utmp[x] as it always terminates strings. strncpy() itself would be a good choice, but is marked by many compilers as being unsafe to use. str2memcpy() is taken from util-linux, and is exactly right for this application. --- sesman/sesexec/sessionrecord.c | 81 ++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/sesman/sesexec/sessionrecord.c b/sesman/sesexec/sessionrecord.c index e642876df1..d9dce5a4aa 100644 --- a/sesman/sesexec/sessionrecord.c +++ b/sesman/sesexec/sessionrecord.c @@ -14,6 +14,12 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * str2memcpy() is taken from util-linux/include/strutils.h v2.39 which + * has the following header:- + * + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. */ /** @@ -31,7 +37,6 @@ #include #endif - #include "sessionrecord.h" #include "login_info.h" #include "log.h" @@ -49,6 +54,7 @@ enum add_xtmp_mode #ifdef USE_UTMP #include +#include #include #ifdef HAVE_UTMPX_H @@ -59,8 +65,6 @@ typedef struct utmpx _utmp; typedef struct utmp _utmp; #endif -#endif // USE_UTMP - #include "os_calls.h" #include "string_calls.h" @@ -69,16 +73,50 @@ typedef struct utmp _utmp; // number in hex #define XRDP_ID_FORMAT ":%x" -/* +/******************************************************************************/ +/** + * utmp-specific strncpy() replacement + * + * @param dest Destination pointer + * @param src Source pointer + * @param n bytes to copy + * + * This is like strncpy(), but based on memcpy(), so compilers and static + * analyzers do not complain when sizeof(destination) is the same as 'n' and + * result is not terminated by zero. + * + * ONLY use this function to copy string to logs with fixed sizes + * (wtmp/utmp. ...) where string terminator is optional. + */ +static inline void *__attribute__((nonnull (1))) +str2memcpy(void *dest, const char *src, size_t n) +{ + size_t bytes = strlen(src) + 1; + + if (bytes > n) + { + bytes = n; + } + + memcpy(dest, src, bytes); + return dest; +} + +/******************************************************************************/ +/** * Prepare the utmp struct and write it. - * this can handle login and logout at once with the 'mode' parameter + * + * @param pid PID of session manager + * @param display Display number of session + * @param login_info Login info (NULL for MODE_LOGOUT) + * @param mode see enum add_xtmp_mode + * @param e Exit status (NULL unless MODE_LOGOUT) */ static void add_xtmp_entry(int pid, int display, const struct login_info *login_info, enum add_xtmp_mode mode, const struct proc_exit_status *e) { -#if USE_UTMP char idbuff[16]; char str_display[16]; @@ -92,16 +130,22 @@ add_xtmp_entry(int pid, int display, const struct login_info *login_info, ut.ut_type = (mode == MODE_LOGIN) ? USER_PROCESS : DEAD_PROCESS; ut.ut_pid = pid; - ut.ut_tv.tv_sec = tv.tv_sec; - ut.ut_tv.tv_usec = tv.tv_usec; - g_strncpy(ut.ut_line, str_display, sizeof(ut.ut_line)); - g_strncpy(ut.ut_id, idbuff, sizeof(ut.ut_id)); - if (login_info != NULL) + str2memcpy(ut.ut_id, idbuff, sizeof(ut.ut_id)); + + // Linux utmp(5) suggests ut_line, ut_time, ut_user, and ut_host + // are not set for a DEAD_PROCESS + if (ut.ut_type != DEAD_PROCESS) { - g_strncpy(ut.ut_user, login_info->username, sizeof(ut.ut_user)); + ut.ut_tv.tv_sec = tv.tv_sec; + ut.ut_tv.tv_usec = tv.tv_usec; + str2memcpy(ut.ut_line, str_display, sizeof(ut.ut_line)); + if (login_info != NULL) + { + str2memcpy(ut.ut_user, login_info->username, sizeof(ut.ut_user)); #ifdef HAVE_UTMPX_UT_HOST - g_strncpy(ut.ut_host, login_info->ip_addr, sizeof(ut.ut_host)); + str2memcpy(ut.ut_host, login_info->ip_addr, sizeof(ut.ut_host)); #endif + } } #ifdef HAVE_UTMPX_UT_EXIT @@ -123,9 +167,17 @@ add_xtmp_entry(int pid, int display, const struct login_info *login_info, /* closes utmp */ endutxent(); -#endif // USE_UTMP } +#else // USE_UTMP +static void +add_xtmp_entry(int pid, int display, const struct login_info *login_info, + short state, const struct proc_exit_status *e) +{ +} +#endif + +/******************************************************************************/ void utmp_login(int pid, int display, const struct login_info *login_info) { @@ -136,6 +188,7 @@ utmp_login(int pid, int display, const struct login_info *login_info) add_xtmp_entry(pid, display, login_info, MODE_LOGIN, NULL); } +/******************************************************************************/ void utmp_logout(int pid, int display, const struct proc_exit_status *exit_status) {