xrdp
xrdp copied to clipboard
XRDP not updating lastlog info.
Running xrdp 0.9.6 and have found that user lastlog information is not being updated, after a user connects and successfully logs in. We are running Red Hat Enterprise Linux 6.7 and 7.6.
This prevents certain security rules from being applied, as the user would be locked out, due to inactivity.
Yes, xrdp doesn't update the info right now. I think that feature is needed. I stack it as a "feature request".
This appears to be similar to Pull Request #1077 and issue #870
This should be done after #1961.
Pardon me for jumping in, but as far as I can see this should work already if it's correctly configured. This is based on my experiences with using the EPEL xrdp RPM in a previous life as a sysadmin.
The lastlog file is maintained by pam_lastlog.so
. On RHEL/etc 7 systems, this is called as part of /etc/pam.d/postlogin
If you're using the EPEL xrdp RPM, /etc/pam.d/xrdp-sesman
looks like this:-
#%PAM-1.0
# Generic Fedora config
auth include password-auth
account include password-auth
password include password-auth
session include password-auth
# Gnome specific Fedora config
#auth include gdm-password
#account include gdm-password
#password include gdm-password
#session include gdm-password
On GNOME-only systems, the system manager needs to update this file to work correctly. This is ALL RHEL/etc systems where only GNOME is installed. Otherwise some GNOME features won't work correctly.
If this is done, the problem should be fixed for GNOME, as /etc/pam.d/gdm-password
correctly includes the postlogin section.
On non-GNOME systems, the file maybe needs to look like this to get it working:-
#%PAM-1.0 # Generic Fedora config auth include password-auth account include password-auth password include password-auth session include password-auth # Needed for lastlog support session include postlogin # Gnome specific Fedora config #auth include gdm-password #account include gdm-password #password include gdm-password #session include gdm-password
In any case I don't think it's an XRDP issue, but a packaging issue.
@kenleach2, @shaneforsythe, @ibaldonl - can one of you look into this and see if it solves your problem?
I have tried various configs with PAM but none captured the lastlog info correctly. Ultimately, XRDP needs to make the correct calls to WTMP and such so that the standard auditing works.
Thank you,
Kenneth R. Leach AJM-2512 Specialty Engineering Desk: 609-485-4260 Email: @.@.>
Mailing Address: FAA William J. Hughes Technical Center Building 300, 3rd Floor, Column K21, Office 3W660 Atlantic City International Airport Atlantic City, NJ 08405
@kenleach2 - thanks for coming back to me.
First thing to say is I absolutely agree that we should be making the correct calls to update wtmp and utmp and I've made a note of this against #1961.
I've fired up a CentOS 7 VM to look at this in more detail, and to dig into the authconfig
Python script. My immediate observations are:-
- The config I've suggested above won't work
- I may have something at least a little useful for you in the short term.
The reason the config I've given you is useless is that config generated by authconfig
in /etc/pam.d/lastlogin
isn't that configurable. For non GDM sessions, the line which is executed is this:-
session optional pam_lastlog.so silent noupdate showfailed
The net effect is simply to show the last failed login time to the user.
The only way I can see to change the behaviour of authconfig
is to modify /usr/share/authconfig/authinfo.py
which I can't recommend.
However, I had some success with this file:-
#%PAM-1.0 # Generic Fedora config auth include password-auth account include password-auth password include password-auth session include password-auth # Update lastlog and wtmp session optional pam_lastlog.so silent # Gnome specific Fedora config #auth include gdm-password #account include gdm-password #password include gdm-password #session include gdm-password
With this,, at least /var/log/lastlog
and /var/log/wtmp
are updated. On my VM I've got a testuser
used exclusively for xrdp:-
$ lastlog | grep testuser
testuser :10 Thu Sep 23 09:50:12 +0100 2021
$ who /var/log/wtmp | grep testuser
testuser :10 2021-09-23 09:49
testuser :10 2021-09-23 09:50
I've also had a quick look at CentOS 8 and authselect
. This is slightly more configurable, but not in a useful way. However, the workaround above should also work.
To solve the mystery of how openssh updates lastlog, I had to poke around in the openssh sources. OpenSSH updates lastlog itself directly. I think it unlikely that we'll be following this path, as PAM is available, but it's always an option.
If anyone following this thread thinks this is useful for RHEL/CentOS/etc until we're updating utmp and wtmp directly, I can start a Bugzilla conversation with Red Hat.
Until the wtmp/utmp support is added, I created a script that runs via cron, to update the lastlog info based on the successful connections to sessions in the xrdp-sesman.log file.
Thank you,
Kenneth R. Leach AJM-2512 Specialty Engineering Desk: 609-485-4260 Email: @.@.>
Mailing Address: FAA William J. Hughes Technical Center Building 300, 3rd Floor, Column K21, Office 3W660 Atlantic City International Airport Atlantic City, NJ 08405
Thanks for the info @kenleach2.
For the benefit of others who may be in the same position as you, would you be able to share your script? If you can, feel free to reply via email, and I'll tidy up your response so it's readable in this thread.
If anyone else would like to comment on the changes to /etc/pam.d/xrdp-sesman
above, please do. I think there may be some value in starting the conversation with Red Hat ASAP (the maintainer Bojan is very helpful) but I need some user experiences to guide me here. For clarity, this particular script is delivered by the EPEL RPM rather than by us. I don't think I made that at all clear.
I can share but it is a bit of code. The actual script is the xrdp-lastlog-update script, towards the bottom of this email. However, the xrdp-lastlog-update script relies on a couple of libraries we have written and are also supplied. The SecureCmds library simply supplies the absolute pathname to an OS command. So, rather than have to explicitly use absolute paths for OS commands, they can be updated via the library. The WriteMsg library is simply a formatter for how we like to see output messages on screen and in logs. If one wishes, they can go through and remove the needs for these libraries.
=====[ File: /lib/FAAlibs/SecureCmds.bash begin ]===== #########################################################################
This library contains functions and hashes that assist with the use in
securing commands, using absolute paths, from trusted locations, for
increased security.
It is expected that this library will be sourced from a bash script.
The following are the available items from the library:
GetCmdPath function: direct call : SecureCmds::GetCmdPath "command"
variable assign: var=$(SecureCmds::GetCmdPath)
secure_cmds hash: called by issuing ${secure_cmds[command]}
##########################################################################
Get the list of basic commands.
BASIC_CMD_SET=/usr/bin/get-lib-cmd-info -c
Get the list of known directories where commands would be located.
KNOWN_DIRS=/usr/bin/get-lib-cmd-info -d
function SecureCmds::GetCmdPath { # This routine attempts to associate a given command to one of the known # paths in the KNOWN_DIRS list. If the command was not found in any # of the paths, an error is thrown.
# Get the command.
local cmd=$1
# Loop through each path and see if the command is there.
local cmd_found=0
for dir in $KNOWN_DIRS; do
if [ -f $dir/$cmd ]; then
cmd="$dir/$cmd"
cmd_found=1
break
fi
done
if [ $cmd_found -ne 1 ]; then
# Command not found in paths. Return error.
/bin/echo "ERROR: Command \"$cmd\" could not be found."
else
# Return the command with the absolute path.
/bin/echo "$cmd"
fi
}
Create the secure_cmds hash and make an entry for each
command.
declare -A secure_cmds for command in $BASIC_CMD_SET; do secure_cmds["$command"]=$(SecureCmds::GetCmdPath "$command") done
Unset varibales.
unset BASIC_CMD_SET =====[ File: /lib/FAAlibs/SecureCmds.bash end ]=====
=====[ File: /lib/FAAlibs/WriteMsg.bash begin ]===== #######################################################################
Functions to write messages in defined formats.
It is expected that this library will be sourced from a bash script.
The following are the available items from the library:
WriteMsg::Standard
syntax: WriteMsg::Standard "type" "messsage" "log"
Type can be one of: debug, error, info, logdebug, or warn.
If the log file passed cannot be opened for writing, messages will only
go to STDOUT.
#######################################################################
Source needed libs.
. /lib/FAAlibs/SecureCmds.bash
date="${secure_cmds[date]} +"%a %b %d %Y %H:%M:%S %Z"" host=$(${secure_cmds[hostname]}) prog_pid=$$
declare -A message_type message_type["debug"]='DEBUG' message_type["error"]='ERROR' message_type["info"]='INFO ' message_type["logdebug"]='DEBUG' message_type["logerror"]='ERROR' message_type["loginfo"]='INFO' message_type["logwarn"]='WARN' message_type["warn"]='WARN '
function WriteMsg::Standard { local msg_type=$1 local msg=$2 local log=$3
# See if the standard messages should only be logged, rather
# than also being sent to STDOUT.
local log_only=0
${secure_cmds[echo]} "$msg_type" | ${secure_cmds[egrep]} "^log(debug|error|info|warn)$" 1>/dev/null 2>&1
if [ $? -eq 0 ]; then
log_only=1
fi
# Set log locations for cron versus non-cron runs.
cron_log=$log
non_cron_log=$log
# If a log wasn't specified or we are unable to write to
# the log, send everything to STDOUT.
if [ "$log" = "" ]; then
if [ $log_only -eq 1 ]; then
cron_log=/dev/null
else
cron_log=/dev/stdout
fi
non_cron_log=/dev/null
else
if [ ! -f $log ]; then
${secure_cmds[touch]} $log >/dev/null 2>&1
if [ $? -ne 0 ]; then
if [ $log_only -eq 1 ]; then
cron_log=/dev/null
else
cron_log=/dev/stdout
fi
non_cron_log=/dev/null
fi
fi
fi
if [ ! -t 1 ]; then
# Cron
${secure_cmds[printf]} "%-23s %-5s: %-13s: %-5s: %s\n" "`eval $date`" ${message_type[$msg_type]} $host $prog_pid "$msg" >>$cron_log
else
# Not cron
if [ $log_only -eq 1 ]; then
${secure_cmds[printf]} "%-23s %-5s: %-13s: %-5s: %s\n" "`eval $date`" ${message_type[$msg_type]} $host $prog_pid "$msg" >>$non_cron_log
else
${secure_cmds[printf]} "%-23s %-5s: %-13s: %-5s: %s\n" "`eval $date`" ${message_type[$msg_type]} $host $prog_pid "$msg" | ${secure_cmds[tee]} -a $non_cron_log
fi
fi
} =====[ File: /lib/FAAlibs/WriteMsg.bash end ]=====
=====[ File: xrdp-lastlog-update begin ]===== #!/bin/bash
##################################################
This utility is used to update user lastog information
based on successful logins from XRDP sessions.
XRDP does not currently contain code to hook into the
proper authentication modules to update the lastlog
info. Therefore, on systems where XRDP is the only
access method used, user account login information
is not normally updated.
##################################################
Source needed libraries.
. /lib/FAAlibs/SecureCmds.bash . /lib/FAAlibs/WriteMsg.bash
Set command variables.
lastlog_cmd=/usr/bin/lastlog
Set static variables.
prog_name="${secure_cmds[basename]} $0
"
log=/var/log/${prog_name}.log
xrdp_log=/var/log/xrdp-sesman.log
function ProgramEnd { # This function is used to perform tasks, whenever the program has to end. WriteMsg::Standard "info" "$prog_name ended." "$log" }
Make sure a config file exists.
if [ ! -f $config_file ]; then $echo_cmd "No $config_file config file found." exit 1 fi
See if we are being run via cron by checking
whether or not we are run in an interactive
terminal.
if [ ! -t 1 ]; then is_cron=1 fi
WriteMsg::Standard "info" "$prog_name started." "$log"
oldifs=$IFS
IFS=$'\n'
for session_line in ${secure_cmds[egrep]} --no-messages "created session \(access granted\):|reconnected session:" $xrdp_log
; do
# Get login information from the XRDP log entry.
login_date=${secure_cmds[echo]} $session_line | ${secure_cmds[grep]} -o -E "[0-9]{8}"
login_time=${secure_cmds[echo]} $session_line | ${secure_cmds[grep]} -o -E "[0-9]{2}:[0-9]{2}:[0-9]{2}"
xrdp_user=${secure_cmds[echo]} $session_line | ${secure_cmds[awk]} -F, '{print $1}' | ${secure_cmds[awk]} 'NF>1{print $NF}'
xrdp_epoch=${secure_cmds[date]} -d "$login_date $login_time" +"%s"
# Check lastlog to determine when was the last recorded login update.
lastlog_output=`$lastlog_cmd -u $xrdp_user | ${secure_cmds[grep]} "^$xrdp_user"`
lastlog_date=${lastlog_output: -26}
lastlog_epoch=`${secure_cmds[date]} -d "$lastlog_date" +"%s"`
# Update lastlog info, if the user has logged in via XRDP since the latest
# recorded date/time from lastlog.
if [ $xrdp_epoch -gt $lastlog_epoch ]; then
WriteMsg::Standard "info" "Updating lastlog info for $xrdp_user." "$log"
# Determine whether or not lastlog supports a direct update and
# update lastlog info based on what is supported.
$lastlog_cmd -h | ${secure_cmds[grep]} -- '--set' 1>/dev/null 2>&1
if [ $? -eq 0 ]; then
$lastlog_cmd --set --user $xrdp_user
else
${secure_cmds[su]} -l $xrdp_user -c exit 1>/dev/null 2>&1
fi
fi
done IFS=$oldifs
ProgramEnd =====[ File: xrdp-lastlog-update end ]=====
Hope this helps.
Kenneth R. Leach AJM-2512 Specialty Engineering Desk: 609-485-4260 Email: @.@.>
Mailing Address: FAA William J. Hughes Technical Center Building 300, 3rd Floor, Column K21, Office 3W660 Atlantic City International Airport Atlantic City, NJ 08405
Thanks @kenleach2 - that's very kind and may be of use to others reading this thread as another option.
As it happens, my options for tidying up your reply are limited as apparently email replies do not support markdown. However, it should be a simple matter to recover your files from your message above.
As the main author of the wtmp
branch, I wasn't aware of the module pam_lastlog (didn't look the evolution since the last decade!)
This pam module seems to make the job. As the PAM stack seems the default on most system (linux, freebsd), this should really the way to go.
As long as it has been tested and proven to work, I am not sure it matters what fixes it, as long as it works. We have tried numerous things with PAM to get the lastlog info updated, which have not worked. Our PAM configurations already call pam_lastlog. The thing that has to be kept in mind is, access to systems can be from various methods (e.g. SSH, XRDP, etc.). We have to make sure that what is done for XDP still works with the others.
Kenneth R. Leach AJM-2512 Specialty Engineering Desk: 609-485-4260 Email: @.@.>
Mailing Address: FAA William J. Hughes Technical Center Building 300, 3rd Floor, Column K21, Office 3W660 Atlantic City International Airport Atlantic City, NJ 08405
pam_lastlog
on Linux doesn't update utmp, so it's not a complete solution. Oddly, it looks like it does on FreeBSD but I haven't checked the code.
@kenleach2 - what systems are you using? The reason I ask is that /etc/pam.d/xrdp-sesman
on RHEL/CentOS/etc is not the one supplied by us, but rather it's supplied by EPEL. Also, modifying this file will not affect the way that other login methods work.
We are using RHEL 6 and 7.
Kenneth R. Leach AJM-2512 Specialty Engineering Desk: 609-485-4260 Email: @.@.>
Mailing Address: FAA William J. Hughes Technical Center Building 300, 3rd Floor, Column K21, Office 3W660 Atlantic City International Airport Atlantic City, NJ 08405
I'm pretty sure based on my CentOS 7 testing you can get something working using pam_lastlog. That might depend on the minor versions you are using possibly.
RHEL 6 seems to be using linux-pam 1.1.1, which contains the pam_lastlog module, at least. There have been quite a few changes to the module since then.
EPEL for RHEL 6 is now retired, so you won't be able to get xrdp updates from this route anyway. Do I take it from that you're building from source? gcc 4.4 isn't something we build with on a regular basis any more, so there could conceivably be compiler issues.
No, we don’t build it. We use the EPEL copy. However, we will be updating to RHEL 7 and 8 over the coming year(s).
Thanks for the update @kenleach2 .
If you can find some time to investigate this further, we could possibly both benefit. I'm pretty sure my change to /etc/xrdp/xrdp-sesman
can work for you, but I need more to back this up than 'it works for me'. At the same time, it would be good for you to get to the bottom of why you're getting unreliable results from your PAM configurations. Even if we move code into sesman to update wtmp and lastlog, it won't be doing anything that the PAM module isn't doing. There could well be something in your setup I'm not anticipating, and since I'm looking at restructuring our PAM interface at the moment I'd really like to understand what that might be.
I've taken the trouble to knock up a script for CentOS 7 (I know it's not exactly the same as Red Hat) which takes a minimal install, adds a GNOME desktop and gets xrdp working with the modifications I've described above.
I add a user 'testuser' as part of my minimal install. After running the script, testuser
is correctly added to lastlog when I log in
I'm hoping you'll be able to use this script in your environment to figure out where the gap is. I'll be happy to help you with that.
Script is:-
#!/bin/sh
# Run this on an updated minimal CentOS install
# Configure desktop
yum group install -y "GNOME Desktop"
systemctl set-default graphical.target
# Install xrdp
yum install -y epel-release
yum install -y xrdp xrdp-selinux
systemctl enable xrdp xrdp-sesman
firewall-cmd --permanent --add-port=3389/tcp
# Patch /etc/pam.d/xrdp-sesman
if [ ! -x /usr/bin/patch ]; then
yum install -y patch
fi
cd /etc/pam.d/
patch -b <<EOF
--- xrdp-sesman.orig 2021-09-27 11:25:07.211842645 +0100
+++ xrdp-sesman 2021-09-27 11:27:43.511277088 +0100
@@ -1,12 +1,14 @@
#%PAM-1.0
# Generic Fedora config
-auth include password-auth
-account include password-auth
-password include password-auth
-session include password-auth
+#auth include password-auth
+#account include password-auth
+#password include password-auth
+#session include password-auth
# Gnome specific Fedora config
-#auth include gdm-password
-#account include gdm-password
-#password include gdm-password
-#session include gdm-password
+auth include gdm-password
+account include gdm-password
+password include gdm-password
+session include gdm-password
+# Update lastlog and wtmp
+session optional pam_lastlog.so silent
EOF
# Done
echo "System is now configured"
echo "Please reboot for the changes to take effect"
I will not have any time to test this. My servers that run XRDP are in production only and I will no longer be in a role to support these systems, within the next couple of weeks.
I'm in no great rush for this.
At some stage we'll revisit this area and make the changes we think are necessary to support this functionality. Whether that's in the app, or via PAM is not yet decided. Any additional information would be useful if you're able to provide it.
If anyone else reading this thread want to comment, please do.
The supplied edit to /etc/pam.d/xrdp-sesman
fixed my xrdp lastlog issues on RHEL8