From: Openkylin Developers <packaging@lists.openkylin.top>
Date: Fri, 12 Apr 2024 12:14:16 +0800
Subject: pam_motd-legal-notice

Patch for Ubuntu bug #399071

Display the contents of /etc/legal as part of the MOTD, the first time the
user logs in, and set a flag in the user's homedir if possible to prevent
repeat displays.

Authors: Dustin Kirkland <kirkland@canonical.com>

Upstream status: Ubuntu-specific, maybe submit to Debian
---
 modules/pam_motd/pam_motd.c | 62 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/modules/pam_motd/pam_motd.c b/modules/pam_motd/pam_motd.c
index 8472dd6..9e39770 100644
--- a/modules/pam_motd/pam_motd.c
+++ b/modules/pam_motd/pam_motd.c
@@ -379,6 +379,65 @@ static int try_to_display(pam_handle_t *pamh, char **motd_path_split,
     return PAM_SUCCESS;
 }
 
+int display_legal(pam_handle_t *pamh)
+{
+    int retval = PAM_IGNORE, rc;
+    char *user = NULL;
+    char *dir = NULL;
+    char *flag = NULL;
+    struct passwd *pwd = NULL;
+    struct stat s;
+    int f;
+    /* Get the user name to determine if we need to print the disclaimer */
+    rc = pam_get_item(pamh, PAM_USER, &user);
+    if (rc == PAM_SUCCESS && user != NULL && *(const char *)user != '\0')
+    {
+        PAM_MODUTIL_DEF_PRIVS(privs);
+
+        /* Get the password entry */
+        pwd = pam_modutil_getpwnam (pamh, user);
+        if (pwd != NULL)
+        {
+            if (pam_modutil_drop_priv(pamh, &privs, pwd)) {
+                pam_syslog(pamh, LOG_ERR,
+                           "Unable to change UID to %d temporarily\n",
+                           pwd->pw_uid);
+                retval = PAM_SESSION_ERR;
+                goto finished;
+            }
+
+            if (asprintf(&dir, "%s/.cache", pwd->pw_dir) == -1 || !dir)
+                goto finished;
+            if (asprintf(&flag, "%s/motd.legal-displayed", dir) == -1 || !flag)
+                goto finished;
+
+            if (stat(flag, &s) != 0)
+            {
+                int fd = open("/etc/legal", O_RDONLY, 0);
+                if (fd >= 0) {
+                    try_to_display_fd(pamh, fd);
+                    close(fd);
+                }
+                mkdir(dir, 0700);
+                f = open(flag, O_WRONLY|O_CREAT|O_EXCL,
+                         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+                if (f>=0) close(f);
+            }
+
+finished:
+            if (pam_modutil_regain_priv(pamh, &privs)) {
+                pam_syslog(pamh, LOG_ERR,
+                           "Unable to change UID back to %d\n", privs.old_uid);
+                retval = PAM_SESSION_ERR;
+            }
+
+            _pam_drop(flag);
+            _pam_drop(dir);
+        }
+    }
+    return retval;
+}
+
 int pam_sm_open_session(pam_handle_t *pamh, int flags,
 			int argc, const char **argv)
 {
@@ -477,6 +536,9 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
                             motd_dir_path_split, num_motd_dir_paths,
                             report_missing);
 
+    /* Display the legal disclaimer only if necessary */
+    retval = display_legal(pamh);
+
   out:
     _pam_drop(motd_path_copy);
     _pam_drop(motd_path_split);
