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

Index: pam/modules/pam_motd/pam_motd.c
===================================================================
--- pam.orig/modules/pam_motd/pam_motd.c
+++ pam/modules/pam_motd/pam_motd.c
@@ -348,6 +348,65 @@
     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)
 {
@@ -446,6 +505,9 @@
                             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);
