xrdp icon indicating copy to clipboard operation
xrdp copied to clipboard

XRDP not updating lastlog info.

Open kenleach2 opened this issue 5 years ago • 20 comments

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.

kenleach2 avatar Mar 07 '19 06:03 kenleach2

Yes, xrdp doesn't update the info right now. I think that feature is needed. I stack it as a "feature request".

metalefty avatar Mar 08 '19 01:03 metalefty

This appears to be similar to Pull Request #1077 and issue #870

shaneforsythe avatar Mar 14 '19 19:03 shaneforsythe

This should be done after #1961.

metalefty avatar Sep 22 '21 02:09 metalefty

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?

matt335672 avatar Sep 22 '21 10:09 matt335672

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 avatar Sep 22 '21 12:09 kenleach2

@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:-

  1. The config I've suggested above won't work
  2. 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.

matt335672 avatar Sep 23 '21 09:09 matt335672

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

kenleach2 avatar Sep 23 '21 13:09 kenleach2

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.

matt335672 avatar Sep 23 '21 13:09 matt335672

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

kenleach2 avatar Sep 23 '21 14:09 kenleach2

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.

matt335672 avatar Sep 23 '21 15:09 matt335672

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.

moobyfr avatar Sep 23 '21 19:09 moobyfr

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

kenleach2 avatar Sep 23 '21 19:09 kenleach2

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.

matt335672 avatar Sep 24 '21 09:09 matt335672

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

kenleach2 avatar Sep 24 '21 11:09 kenleach2

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.

matt335672 avatar Sep 24 '21 13:09 matt335672

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).

kenleach2 avatar Sep 24 '21 14:09 kenleach2

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"

matt335672 avatar Sep 27 '21 14:09 matt335672

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.

kenleach2 avatar Sep 27 '21 14:09 kenleach2

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.

matt335672 avatar Sep 27 '21 14:09 matt335672

The supplied edit to /etc/pam.d/xrdp-sesman fixed my xrdp lastlog issues on RHEL8

jtcleek avatar Feb 25 '22 17:02 jtcleek