[Pkg-shadow-commits] r2935 - in upstream/trunk: . lib libmisc src

Nicolas FRANÇOIS nekral-guest at alioth.debian.org
Mon May 18 18:32:17 UTC 2009


Author: nekral-guest
Date: 2009-05-18 18:32:17 +0000 (Mon, 18 May 2009)
New Revision: 2935

Added:
   upstream/trunk/libmisc/user_busy.c
Modified:
   upstream/trunk/ChangeLog
   upstream/trunk/NEWS
   upstream/trunk/lib/prototypes.h
   upstream/trunk/libmisc/Makefile.am
   upstream/trunk/src/userdel.c
Log:
	* src/userdel.c, libmisc/user_busy.c, libmisc/Makefile.am,
	lib/prototypes.h: Move user_busy() to libmisc/user_busy.c.
	* NEWS, libmisc/user_busy.c: On Linux, do not check if an user is
	logged in with utmp, but check if the user is running some
	processes. If not on Linux, continue to search for an utmp record,
	but make sure the process recorded in the utmp entry is still
	running.


Modified: upstream/trunk/ChangeLog
===================================================================
--- upstream/trunk/ChangeLog	2009-05-18 18:28:06 UTC (rev 2934)
+++ upstream/trunk/ChangeLog	2009-05-18 18:32:17 UTC (rev 2935)
@@ -1,5 +1,15 @@
-2009-05-17  Nicolas François  <nicolas.francois at centraliens.net>
+2009-05-18  Nicolas François  <nicolas.francois at centraliens.net>
 
+	* src/userdel.c, libmisc/user_busy.c, libmisc/Makefile.am,
+	lib/prototypes.h: Move user_busy() to libmisc/user_busy.c.
+	* NEWS, libmisc/user_busy.c: On Linux, do not check if an user is
+	logged in with utmp, but check if the user is running some
+	processes. If not on Linux, continue to search for an utmp record,
+	but make sure the process recorded in the utmp entry is still
+	running.
+
+2009-05-18  Nicolas François  <nicolas.francois at centraliens.net>
+
 	* man/usermod.8.xml: Document the -m/--move-home option.
 
 2009-05-17  Nicolas François  <nicolas.francois at centraliens.net>

Modified: upstream/trunk/NEWS
===================================================================
--- upstream/trunk/NEWS	2009-05-18 18:28:06 UTC (rev 2934)
+++ upstream/trunk/NEWS	2009-05-18 18:32:17 UTC (rev 2935)
@@ -5,6 +5,11 @@
 - login
   * Fix failures with empty usernames on non PAM versions.
   * Fix CONSOLE (securetty) support on non PAM versions.
+- userdel
+  * On Linux, do not check if an user is logged in with utmp, but check if
+    the user is running some processes.
+  * If not on Linux, continue to search for an utmp record, but make sure
+    the process recorded in the utmp entry is still running.
 
 shadow-4.1.3.1 -> shadow-4.1.4						2009-05-10
 

Modified: upstream/trunk/lib/prototypes.h
===================================================================
--- upstream/trunk/lib/prototypes.h	2009-05-18 18:28:06 UTC (rev 2934)
+++ upstream/trunk/lib/prototypes.h	2009-05-18 18:32:17 UTC (rev 2935)
@@ -363,6 +363,9 @@
 /* ulimit.c */
 extern int set_filesize_limit (int blocks);
 
+/* user_busy.c */
+extern int user_busy (const char *name, uid_t uid);
+
 /* utmp.c */
 extern /*@null@*/struct utmp *get_current_utmp (void);
 extern struct utmp *prepare_utmp (const char *name,

Modified: upstream/trunk/libmisc/Makefile.am
===================================================================
--- upstream/trunk/libmisc/Makefile.am	2009-05-18 18:28:06 UTC (rev 2934)
+++ upstream/trunk/libmisc/Makefile.am	2009-05-18 18:32:17 UTC (rev 2935)
@@ -56,6 +56,7 @@
 	ttytype.c \
 	tz.c \
 	ulimit.c \
+	user_busy.c \
 	utmp.c \
 	valid.c \
 	xgetpwnam.c \

Added: upstream/trunk/libmisc/user_busy.c
===================================================================
--- upstream/trunk/libmisc/user_busy.c	                        (rev 0)
+++ upstream/trunk/libmisc/user_busy.c	2009-05-18 18:32:17 UTC (rev 2935)
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1991 - 1994, Julianne Frances Haugh
+ * Copyright (c) 1996 - 2000, Marek Michałkiewicz
+ * Copyright (c) 2000 - 2006, Tomasz Kłoczko
+ * Copyright (c) 2007 - 2009, Nicolas François
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ident "$Id: $"
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include "defines.h"
+#include "prototypes.h"
+
+#ifdef __linux__
+static int check_status (const char *sname, uid_t uid);
+static int user_busy_processes (uid_t uid);
+#else				/* !__linux__ */
+static int user_busy_utmp (const char *name);
+#endif				/* !__linux__ */
+
+/*
+ * user_busy - check if an user if currently running processes
+ */
+int user_busy (const char *name, uid_t uid)
+{
+	/* There are no standard ways to get the list of processes.
+	 * An option could be to run an external tool (ps).
+	 */
+#ifdef __linux__
+	/* On Linux, directly parse /proc */
+	return user_busy_processes (uid);
+#else				/* !__linux__ */
+	/* If we cannot rely on /proc, check is there is a record in utmp
+	 * indicating that the user is still logged in */
+	return user_busy_utmp (name);
+#endif				/* !__linux__ */
+}
+
+#ifndef __linux__
+static int user_busy_utmp (const char *name)
+{
+#ifdef USE_UTMPX
+	struct utmpx *utent;
+
+	setutxent ();
+	while ((utent = getutxent ()) != NULL)
+#else				/* !USE_UTMPX */
+	struct utmp *utent;
+
+	setutent ();
+	while ((utent = getutent ()) != NULL)
+#endif				/* !USE_UTMPX */
+	{
+		if (utent->ut_type != USER_PROCESS) {
+			continue;
+		}
+		if (strncmp (utent->ut_user, name, sizeof utent->ut_user) != 0) {
+			continue;
+		}
+		if (kill (utent->ut_pid, 0) != 0) {
+			continue;
+		}
+
+		return USER_BUSY;
+	}
+}
+#endif				/* !__linux__ */
+
+#ifdef __linux__
+static int check_status (const char *sname, uid_t uid)
+{
+	/* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
+	char status[40];
+	char line[1024];
+	FILE *sfile;
+
+	snprintf (status, 40, "/proc/%s/status", sname);
+	status[39] = '\0';
+
+	sfile = fopen (status, "r");
+	if (NULL == sfile) {
+		return 0;
+	}
+	while (fgets (line, sizeof (line), sfile) == line) {
+		if (strncmp (line, "Uid:\t", 5) == 0) {
+			unsigned long ruid, euid, suid;
+			assert (uid == (unsigned long) uid);
+			if (sscanf (line,
+			            "Uid:\t%lu\t%lu\t%lu\n",
+			            &ruid, &euid, &suid) == 3) {
+				if (   (ruid == (unsigned long) uid)
+				    || (euid == (unsigned long) uid)
+				    || (suid == (unsigned long) uid)) {
+					(void) fclose (sfile);
+					return 1;
+				}
+			} else {
+				/* Ignore errors. This is just a best effort. */
+			}
+			(void) fclose (sfile);
+			return 0;
+		}
+	}
+	(void) fclose (sfile);
+	return 0;
+}
+
+static int user_busy_processes (uid_t uid)
+{
+	DIR *proc;
+	struct dirent *ent;
+	char *tmp_d_name;
+	pid_t pid;
+	DIR *task_dir;
+	/* 22: /proc/xxxxxxxxxx/task + \0 */
+	char task_path[22];
+	char root_path[22];
+	struct stat sbroot;
+	struct stat sbroot_process;
+
+	proc = opendir ("/proc");
+	if (proc == NULL) {
+		perror ("opendir /proc");
+		return 0;
+	}
+	if (stat ("/", &sbroot) != 0) {
+		perror ("stat (\"/\")");
+		(void) closedir (proc);
+		return 0;
+	}
+
+	while ((ent = readdir (proc)) != NULL) {
+		tmp_d_name = ent->d_name;
+		/*
+		 * Ingo Molnar's patch introducing NPTL for 2.4 hides
+		 * threads in the /proc directory by prepending a period.
+		 * This patch is applied by default in some RedHat
+		 * kernels.
+		 */
+		if (   (strcmp (tmp_d_name, ".") == 0)
+		    || (strcmp (tmp_d_name, "..") == 0)) {
+			continue;
+		}
+		if (*tmp_d_name == '.') {
+			tmp_d_name++;
+		}
+
+		/* Check if this is a valid PID */
+		if (get_pid (tmp_d_name, &pid) == 0) {
+			continue;
+		}
+
+		/* Check if the process is in our chroot */
+		snprintf (root_path, 22, "/proc/%lu/root", (unsigned long) pid);
+		root_path[21] = '\0';
+		if (stat (root_path, &sbroot_process) != 0) {
+			continue;
+		}
+		if (   (sbroot.st_dev != sbroot_process.st_dev)
+		    || (sbroot.st_ino != sbroot_process.st_ino)) {
+			continue;
+		}
+
+		if (check_status (tmp_d_name, uid) != 0) {
+			(void) closedir (proc);
+			return 1;
+		}
+
+		snprintf (task_path, 22, "/proc/%lu/task", (unsigned long) pid);
+		task_path[21] = '\0';
+		task_dir = opendir (task_path);
+		if (task_dir != NULL) {
+			while ((ent = readdir (task_dir)) != NULL) {
+				pid_t tid;
+				if (get_pid (ent->d_name, &tid) == 0) {
+					continue;
+				}
+				if (tid == pid) {
+					continue;
+				}
+				if (check_status (task_path+6, uid) != 0) {
+					(void) closedir (proc);
+					return 1;
+				}
+			}
+			(void) closedir (task_dir);
+		} else {
+			/* Ignore errors. This is just a best effort */
+		}
+	}
+
+	(void) closedir (proc);
+	return 0;
+}
+#endif				/* __linux__ */
+

Modified: upstream/trunk/src/userdel.c
===================================================================
--- upstream/trunk/src/userdel.c	2009-05-18 18:28:06 UTC (rev 2934)
+++ upstream/trunk/src/userdel.c	2009-05-18 18:32:17 UTC (rev 2935)
@@ -100,7 +100,6 @@
 static void fail_exit (int);
 static void open_files (void);
 static void update_user (void);
-static void user_busy (const char *, uid_t);
 static void user_cancel (const char *);
 
 #ifdef EXTRA_CHECK_HOME_DIR
@@ -576,57 +575,6 @@
 	SYSLOG ((LOG_INFO, "delete user '%s'\n", user_name));
 }
 
-/*
- * user_busy - see if user is logged in.
- *
- * XXX - should probably check if there are any processes owned
- * by this user. Also, I think this check should be in usermod
- * as well (at least when changing username or UID).  --marekm
- */
-static void user_busy (const char *name, uid_t uid)
-{
-
-/*
- * We see if the user is logged in by looking for the user name
- * in the utmp file.
- */
-#ifdef USE_UTMPX
-	struct utmpx *utent;
-
-	setutxent ();
-	while ((utent = getutxent ()) != NULL)
-#else				/* !USE_UTMPX */
-	struct utmp *utent;
-
-	setutent ();
-	while ((utent = getutent ()) != NULL)
-#endif				/* !USE_UTMPX */
-	{
-		if (utent->ut_type != USER_PROCESS) {
-			continue;
-		}
-		if (strncmp (utent->ut_user, name, sizeof utent->ut_user) != 0) {
-			continue;
-		}
-		if (kill (utent->ut_pid, 0) != 0) {
-			continue;
-		}
-
-		fprintf (stderr,
-		         _("%s: user %s is currently logged in\n"),
-		         Prog, name);
-		if (!fflg) {
-#ifdef WITH_AUDIT
-			audit_logger (AUDIT_DEL_USER, Prog,
-			              "deleting user logged in",
-			              name, AUDIT_NO_ID,
-			              SHADOW_AUDIT_FAILURE);
-#endif
-			exit (E_USER_BUSY);
-		}
-	}
-}
-
 /* 
  * user_cancel - cancel cron and at jobs
  *
@@ -648,7 +596,7 @@
 	if (pid == 0) {
 		execl (cmd, cmd, user, (char *) 0);
 		perror (cmd);
-		_exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
+		exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
 	} else if ((pid_t)-1 == pid) {
 		perror ("fork");
 		return;
@@ -893,8 +841,23 @@
 #endif
 	/*
 	 * Check to make certain the user isn't logged in.
+	 * Note: This is a best effort basis. The user may log in between,
+	 * a cron job may be started on her behalf, etc.
 	 */
-	user_busy (user_name, user_id);
+	if (user_busy (user_name, user_id) != 0) {
+		fprintf (stderr,
+		         _("%s: user %s is currently logged in\n"),
+		         Prog, user_name);
+		if (!fflg) {
+#ifdef WITH_AUDIT
+			audit_logger (AUDIT_DEL_USER, Prog,
+			              "deleting user logged in",
+			              user_name, AUDIT_NO_ID,
+			              SHADOW_AUDIT_FAILURE);
+#endif
+			exit (E_USER_BUSY);
+		}
+	}
 
 	/*
 	 * Do the hard stuff - open the files, create the user entries,




More information about the Pkg-shadow-commits mailing list