From 0a13d2d33a438e711ecb991c777e413f7a68a222 Mon Sep 17 00:00:00 2001
From: Moe Jette <jette1@llnl.gov>
Date: Tue, 29 Jul 2008 23:29:08 +0000
Subject: [PATCH] svn merge -r14620:14652
 https://eris.llnl.gov/svn/slurm/branches/slurm-1.2

---
 NEWS                                          |   2 +
 src/common/read_config.c                      |   8 +-
 src/common/uid.c                              | 127 +++++++++++++++---
 src/common/uid.h                              |   5 +
 src/plugins/jobcomp/filetxt/jobcomp_filetxt.c |  16 +--
 src/plugins/sched/wiki/get_jobs.c             |  13 +-
 src/plugins/sched/wiki2/get_jobs.c            |  13 +-
 .../select/bluegene/plugin/block_sys.c        |  23 ++--
 .../select/bluegene/plugin/select_bluegene.c  |  11 +-
 src/slurmctld/partition_mgr.c                 |  75 +++++++----
 src/slurmd/slurmd/req.c                       |  20 +--
 11 files changed, 200 insertions(+), 113 deletions(-)

diff --git a/NEWS b/NEWS
index cee59fd1229..9fa39721878 100644
--- a/NEWS
+++ b/NEWS
@@ -421,6 +421,8 @@ documents those changes that are of interest to users and admins.
     requeued.
  -- Ignore the show_flag when getting job, step, node or partition information
     for user root.
+ -- Convert some functions to thread-safe versions: getpwnam, getpwuid, 
+    getgrnam, and getgrgid to similar functions with "_r" suffix.
 
 * Changes in SLURM 1.2.33
 =========================
diff --git a/src/common/read_config.c b/src/common/read_config.c
index 2faba8f6ada..6ba28b2a59f 100644
--- a/src/common/read_config.c
+++ b/src/common/read_config.c
@@ -70,6 +70,7 @@
 #include "src/common/parse_time.h"
 #include "src/common/slurm_selecttype_info.h"
 #include "src/common/util-net.h"
+#include "src/common/uid.h"
 
 /* Instantiation of the "extern slurm_ctl_conf_t slurmcltd_conf"
  * found in slurmctld.h */
@@ -1918,14 +1919,13 @@ validate_and_set_defaults(slurm_ctl_conf_t *conf, s_p_hashtbl_t *hashtbl)
 		conf->slurm_user_name = xstrdup("root");
 		conf->slurm_user_id   = 0;
 	} else {
-		struct passwd *slurm_passwd;
-		slurm_passwd = getpwnam(conf->slurm_user_name);
-		if (slurm_passwd == NULL) {
+		uid_t my_uid = uid_from_string(conf->slurm_user_name);
+		if (my_uid == (uid_t) -1) {
 			error ("Invalid user for SlurmUser %s, ignored",
 			       conf->slurm_user_name);
 			xfree(conf->slurm_user_name);
 		} else {
-			conf->slurm_user_id = slurm_passwd->pw_uid;
+			conf->slurm_user_id = my_uid;
 		}
 	}
 
diff --git a/src/common/uid.c b/src/common/uid.c
index fe0ad85acfb..021d3afc352 100644
--- a/src/common/uid.c
+++ b/src/common/uid.c
@@ -41,48 +41,135 @@
 #include <grp.h>
 #include <ctype.h>
 
-#include "uid.h"
+#include "src/common/uid.h"
+#include "src/common/xmalloc.h"
 
 uid_t
 uid_from_string (char *name)
 {
-	struct passwd *pwd = NULL;
-	char *p = NULL;
+	struct passwd pwd, *result;
+	size_t bufsize;
+	char *buffer, *p = NULL;
+	int rc;
 	uid_t uid = (uid_t) strtoul (name, &p, 10);
 
-	if (*p != '\0')
-		pwd = getpwnam (name);
-	else
-		pwd = getpwuid (uid);
-
-	return pwd ? pwd->pw_uid : (uid_t) -1; 
+	bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+	buffer = xmalloc(bufsize);
+	if (*p != '\0') {
+		while (1) {
+			rc = getpwnam_r(name, &pwd, buffer, bufsize, &result);
+			if (rc == EINTR)
+				continue;
+			if (rc != 0)
+				result = NULL;
+			break;
+		}
+		if (result == NULL)
+			uid = (uid_t) -1;
+		else
+			uid = result->pw_uid;
+	} else {
+		while (1) {
+			rc = getpwuid_r(uid, &pwd, buffer, bufsize, &result);
+			if (rc == EINTR)
+				continue;
+			if (rc != 0)
+				result = NULL;
+			break;
+		}
+		if (result == NULL)
+			uid = (uid_t) -1;
+		/* else uid is already correct */
+	}
+	xfree(buffer);
+	return uid; 
 }
 
 char *
 uid_to_string (uid_t uid)
 {
-	struct passwd *pwd = NULL;
+	struct passwd pwd, *result;
+	size_t bufsize;
+	char *buffer;
+	int rc;
 
 	/* Suse Linux does not handle multiple users with UID=0 well */
 	if (uid == 0)
 		return "root";
 
-	pwd = getpwuid(uid);
-	return pwd ? pwd->pw_name : "nobody";
+	bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+	buffer = xmalloc(bufsize);
+	while (1) {
+		rc = getpwuid_r(uid, &pwd, buffer, bufsize, &result);
+		if (rc == EINTR)
+			continue;
+		if (rc != 0)
+			result = NULL;
+		break;
+	}
+	xfree(buffer);
+	return result ? result->pw_name : "nobody";
 }
 
 gid_t
 gid_from_string (char *name)
 {
-	struct group *g = NULL;
-	char *p = NULL;
+	struct group grp, *result;
+	size_t bufsize;
+	char *buffer, *p = NULL;
+	int rc;
 	gid_t gid = (gid_t) strtoul (name, &p, 10);
 
-	if (*p != '\0')
-		g = getgrnam (name);
-	else
-		g = getgrgid (gid);
-
-	return g ? g->gr_gid : (gid_t) -1;
+	bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+	buffer = xmalloc(bufsize);
+	if (*p != '\0') {
+		while (1) {
+			rc = getgrnam_r(name, &grp, buffer, bufsize, &result);
+			if (rc == EINTR)
+				continue;
+			if (rc != 0)
+				result = NULL;
+			break;
+		}
+		if (result == NULL)
+			gid = (gid_t) -1;
+		else
+			gid = result->gr_gid;
+	} else {
+		while (1) {
+			rc = getgrgid_r(gid, &grp, buffer, bufsize, &result);
+			if (rc == EINTR)
+				continue;
+			if (rc != 0)
+				result = NULL;
+			break;
+		}
+		if (result == NULL)
+			gid = (gid_t) -1;
+		/* else gid is already correct */
+	}
+	xfree(buffer);
+	return gid; 
 }
 
+char *
+gid_to_string (gid_t gid)
+{
+	struct group grp, *result;
+	size_t bufsize;
+	char *buffer;
+	int rc;
+
+	bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+	buffer = xmalloc(bufsize);
+	while (1) {
+		rc = getgrgid_r(gid, &grp, buffer, bufsize, &result);
+		if (rc == EINTR)
+			continue;
+		if (rc != 0)
+			result = NULL;
+		break;
+	}
+	xfree(buffer);
+	return result ? result->gr_name : "nobody";
+}
diff --git a/src/common/uid.h b/src/common/uid.h
index 533934ab716..d79a2f6a800 100644
--- a/src/common/uid.h
+++ b/src/common/uid.h
@@ -40,6 +40,7 @@
 #define __SLURM_UID_UTILITY_H__
 
 #include <sys/types.h>
+#include <unistd.h>
 
 /*
  * Return validated uid_t for string in ``name'' which contains
@@ -60,4 +61,8 @@ gid_t gid_from_string (char *name);
  */
 char *uid_to_string (uid_t uid);
 
+/*
+ * Same as uid_to_string, but for group name.
+*/
+char *gid_to_string (gid_t gid);
 #endif /*__SLURM_UID_UTILITY_H__*/
diff --git a/src/plugins/jobcomp/filetxt/jobcomp_filetxt.c b/src/plugins/jobcomp/filetxt/jobcomp_filetxt.c
index a4e67243bab..432a7be1586 100644
--- a/src/plugins/jobcomp/filetxt/jobcomp_filetxt.c
+++ b/src/plugins/jobcomp/filetxt/jobcomp_filetxt.c
@@ -53,6 +53,7 @@
 #include "src/common/slurm_protocol_defs.h"
 #include "src/common/slurm_jobcomp.h"
 #include "src/common/parse_time.h"
+#include "src/common/uid.h"
 #include "filetxt_jobcomp_process.h"
 
 /*
@@ -116,20 +117,13 @@ _get_user_name(uint32_t user_id, char *user_name, int buf_size)
 {
 	static uint32_t cache_uid      = 0;
 	static char     cache_name[32] = "root";
-	struct passwd * user_info      = NULL;
 
-	if (user_id == cache_uid)
-		snprintf(user_name, buf_size, "%s", cache_name);
-	else {
-		user_info = getpwuid((uid_t) user_id);
-		if (user_info && user_info->pw_name[0])
-			snprintf(cache_name, sizeof(cache_name), "%s", 
-				user_info->pw_name);
-		else
-			snprintf(cache_name, sizeof(cache_name), "Unknown");
+	if (user_id != cache_uid) {
+		snprintf(cache_name, sizeof(cache_name), "%s",
+			 uid_to_string((uid_t) user_id));
 		cache_uid = user_id;
-		snprintf(user_name, buf_size, "%s", cache_name);
 	}
+	snprintf(user_name, buf_size, "%s", cache_name);
 }
 
 /* get the group name for the give group_id */
diff --git a/src/plugins/sched/wiki/get_jobs.c b/src/plugins/sched/wiki/get_jobs.c
index 46dbce9a1cc..ece3ed12cda 100644
--- a/src/plugins/sched/wiki/get_jobs.c
+++ b/src/plugins/sched/wiki/get_jobs.c
@@ -48,7 +48,6 @@
 
 static char *	_dump_all_jobs(int *job_cnt, time_t update_time);
 static char *	_dump_job(struct job_record *job_ptr, time_t update_time);
-static char *	_get_group_name(gid_t gid);
 static uint16_t _get_job_cpus_per_task(struct job_record *job_ptr);
 static uint32_t	_get_job_end_time(struct job_record *job_ptr);
 static char *	_get_job_features(struct job_record *job_ptr);
@@ -320,7 +319,7 @@ static char *	_dump_job(struct job_record *job_ptr, time_t update_time)
 	snprintf(tmp, sizeof(tmp),
 		"UNAME=%s;GNAME=%s;",
 		uid_to_string((uid_t) job_ptr->user_id),
-		_get_group_name(job_ptr->group_id));
+		gid_to_string(job_ptr->group_id));
 	xstrcat(buf, tmp);
 
 	return buf;
@@ -363,16 +362,6 @@ static uint32_t	_get_job_min_nodes(struct job_record *job_ptr)
 	return (uint32_t) 1;
 }
 
-static char *	_get_group_name(gid_t gid)
-{
-	struct group *grp;
-
-	grp = getgrgid(gid);
-	if (grp)
-		return grp->gr_name;
-	return "nobody";
-}
-
 static uint32_t _get_job_submit_time(struct job_record *job_ptr)
 {
 	if (job_ptr->details)
diff --git a/src/plugins/sched/wiki2/get_jobs.c b/src/plugins/sched/wiki2/get_jobs.c
index ed5d46d0601..ec130759637 100644
--- a/src/plugins/sched/wiki2/get_jobs.c
+++ b/src/plugins/sched/wiki2/get_jobs.c
@@ -48,7 +48,6 @@
 
 static char *	_dump_all_jobs(int *job_cnt, time_t update_time);
 static char *	_dump_job(struct job_record *job_ptr, time_t update_time);
-static char *	_get_group_name(gid_t gid);
 static void	_get_job_comment(struct job_record *job_ptr, 
 			char *buffer, int buf_size);
 static uint16_t _get_job_cpus_per_task(struct job_record *job_ptr);
@@ -370,7 +369,7 @@ static char *	_dump_job(struct job_record *job_ptr, time_t update_time)
 	snprintf(tmp, sizeof(tmp),
 		"UNAME=%s;GNAME=%s;",
 		uid_to_string((uid_t) job_ptr->user_id),
-		_get_group_name(job_ptr->group_id));
+		gid_to_string(job_ptr->group_id));
 	xstrcat(buf, tmp);
 
 	return buf;
@@ -469,16 +468,6 @@ static uint32_t	_get_job_min_nodes(struct job_record *job_ptr)
 	return (uint32_t) 1;
 }
 
-static char *	_get_group_name(gid_t gid)
-{
-	struct group *grp;
-
-	grp = getgrgid(gid);
-	if (grp)
-		return grp->gr_name;
-	return "nobody";
-}
-
 static uint32_t _get_job_submit_time(struct job_record *job_ptr)
 {
 	if (job_ptr->details)
diff --git a/src/plugins/select/bluegene/plugin/block_sys.c b/src/plugins/select/bluegene/plugin/block_sys.c
index badee49ef4a..40e11e4e430 100755
--- a/src/plugins/select/bluegene/plugin/block_sys.c
+++ b/src/plugins/select/bluegene/plugin/block_sys.c
@@ -37,7 +37,7 @@
 \*****************************************************************************/
 
 #include "bluegene.h"
-
+#include "src/common/uid.h"
 
 /** these are used in the dynamic partitioning algorithm */
 
@@ -158,7 +158,7 @@ static int _post_allocate(bg_record_t *bg_record)
 #ifdef HAVE_BG_FILES	
 	int i;
 	pm_partition_id_t block_id;
-	struct passwd *pw_ent = NULL;
+	uint_t my_uid;
 
 	/* Add partition record to the DB */
 	debug2("adding block\n");
@@ -208,11 +208,12 @@ static int _post_allocate(bg_record_t *bg_record)
 		bg_record->user_name = 
 			xstrdup(slurmctld_conf.slurm_user_name);
 		slurm_conf_unlock();
-	
-		if((pw_ent = getpwnam(bg_record->user_name)) == NULL) {
-			error("getpwnam(%s): %m", bg_record->user_name);
+
+		my_uid = uid_from_string(bg_record->user_name);
+		if (my_uid == (uid_t) -1) {
+			error("getpwnam_r(%s): %m", bg_record->user_name);
 		} else {
-			bg_record->user_uid = pw_ent->pw_uid;
+			bg_record->user_uid = my_uid;
 		} 
 	}
 	/* We are done with the block */
@@ -378,7 +379,7 @@ int read_bg_blocks()
 	rm_partition_t *block_ptr = NULL;
 	char node_name_tmp[255], *user_name = NULL;
 	bg_record_t *bg_record = NULL;
-	struct passwd *pw_ent = NULL;
+	uid_t my_uid;
 	
 	int *coord = NULL;
 	int block_number, block_count;
@@ -707,12 +708,12 @@ int read_bg_blocks()
 				free(user_name);
 					
 			}
-			if((pw_ent = getpwnam(bg_record->user_name)) 
-			   == NULL) {
-				error("getpwnam(%s): %m", 
+			my_uid = uid_from_string(bg_record->user_name);
+			if (my_uid == (uid_t) -1) {
+				error("getpwnam_r(%s): %m", 
 				      bg_record->user_name);
 			} else {
-				bg_record->user_uid = pw_ent->pw_uid;
+				bg_record->user_uid = my_uid;
 			} 
 		}
 		
diff --git a/src/plugins/select/bluegene/plugin/select_bluegene.c b/src/plugins/select/bluegene/plugin/select_bluegene.c
index 3e569b21a7e..ca9039997cb 100644
--- a/src/plugins/select/bluegene/plugin/select_bluegene.c
+++ b/src/plugins/select/bluegene/plugin/select_bluegene.c
@@ -43,6 +43,7 @@
 #include "defined_block.h"
 #endif
 
+#include "src/common/uid.h"
 #include "src/slurmctld/trigger_mgr.h"
 #include <fcntl.h>
  
@@ -360,8 +361,8 @@ extern int select_p_state_restore(char *dir_name)
 	int data_allocated, data_read = 0;
 	char *ver_str = NULL;
 	uint32_t ver_str_len;
-	struct passwd *pw_ent = NULL;
 	int blocks = 0;
+	uid_t my_uid;
 
 	debug("bluegene: select_p_state_restore");
 #ifdef HAVE_BG_FILES
@@ -542,12 +543,12 @@ extern int select_p_state_restore(char *dir_name)
 			bg_record->user_name = 
 				xstrdup(slurmctld_conf.slurm_user_name);
 			slurm_conf_unlock();
-			if((pw_ent = getpwnam(bg_record->user_name)) 
-			   == NULL) {
-				error("getpwnam(%s): %m", 
+			my_uid = uid_from_string(bg_record->user_name);
+			if (my_uid == (uid_t) -1) {
+				error("getpwnam_r(%s): %m", 
 				      bg_record->user_name);
 			} else {
-				bg_record->user_uid = pw_ent->pw_uid;
+				bg_record->user_uid = my_uid;
 			} 
 				
 			bg_record->blrtsimage =
diff --git a/src/slurmctld/partition_mgr.c b/src/slurmctld/partition_mgr.c
index 7876a88ed02..a1cc06871c6 100644
--- a/src/slurmctld/partition_mgr.c
+++ b/src/slurmctld/partition_mgr.c
@@ -58,6 +58,7 @@
 #include "src/common/list.h"
 #include "src/common/node_select.h"
 #include "src/common/pack.h"
+#include "src/common/uid.h"
 #include "src/common/xstring.h"
 
 #include "src/slurmctld/locks.h"
@@ -1051,49 +1052,65 @@ uid_t *_get_groups_members(char *group_names)
  */
 uid_t *_get_group_members(char *group_name)
 {
-	struct group *group_struct_ptr;
-	struct passwd *user_pw_ptr;
-	int i, j;
-	uid_t *group_uids = NULL;
-	int uid_cnt = 0;
-
-	group_struct_ptr = getgrnam(group_name); /* Note: static memory, 
-						  * do not free */
-	if (group_struct_ptr == NULL) {
+	size_t grp_bufsize, pwd_bufsize;
+	char *grp_buffer,  *pwd_buffer;
+	struct group grp,  *grp_result;
+	struct passwd pwd, *pwd_result;
+	uid_t *group_uids;
+	gid_t my_gid;
+	int i, j, rc, uid_cnt;
+	
+	grp_bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+	grp_buffer = xmalloc(grp_bufsize);
+	if (getgrnam_r(group_name, &grp, grp_buffer, grp_bufsize, 
+		       &grp_result)) {
 		error("Could not find configured group %s", group_name);
-		setgrent();
+		xfree(grp_buffer);
 		return NULL;
 	}
+	my_gid = grp_result->gr_gid;
 
-	for (i = 0;; i++) {
-		if (group_struct_ptr->gr_mem[i] == NULL)
+	for (uid_cnt=0; ; uid_cnt++) {
+		if (grp_result->gr_mem[uid_cnt] == NULL)
 			break;
 	}
-
-	uid_cnt = i;
 	group_uids = (uid_t *) xmalloc(sizeof(uid_t) * (uid_cnt + 1));
-	
+
+	pwd_bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+	pwd_buffer = xmalloc(pwd_bufsize);
 	j = 0;
-	for (i = 0; i < uid_cnt; i++) {
-		user_pw_ptr = getpwnam(group_struct_ptr->gr_mem[i]);
-		if (user_pw_ptr) {
-			if (user_pw_ptr->pw_uid)
-				group_uids[j++] = user_pw_ptr->pw_uid;
-		} else
+	for (i=0; i<uid_cnt; i++) {
+		while (1) {
+			rc = getpwnam_r(grp_result->gr_mem[i], &pwd, pwd_buffer,
+					pwd_bufsize, &pwd_result);
+			if (rc == EINTR)
+				continue;
+			else if (rc != 0)
+				pwd_result = NULL;
+			break;
+		}
+		if (pwd_result == NULL) {
 			error("Could not find user %s in configured group %s",
-			      group_struct_ptr->gr_mem[i], group_name);
-		setpwent();
+			      grp_result->gr_mem[i], group_name);
+		} else {
+			if (pwd_result->pw_uid)
+				group_uids[j++] = pwd_result->pw_uid;
+		}
 	}
-	
-	while((user_pw_ptr = getpwent())) {
-		if(user_pw_ptr->pw_gid != group_struct_ptr->gr_gid)
+	xfree(pwd_buffer);
+	xfree(grp_buffer);
+
+	/* NOTE: code below not reentrant, avoid these functions elsewhere */
+	setpwent();
+	while ((pwd_result = getpwent())) {
+		if (pwd_result->pw_gid != my_gid)
 			continue;
 		j++;
 		xrealloc(group_uids, ((j+1) * sizeof(uid_t)));
-		group_uids[j-1] = user_pw_ptr->pw_uid;		
+		group_uids[j-1] = pwd_result->pw_uid;		
 	}
-	setpwent();
-	setgrent();
+	endpwent();
+
 	return group_uids;
 }
 
diff --git a/src/slurmd/slurmd/req.c b/src/slurmd/slurmd/req.c
index d5314fced80..96cbc4cb586 100644
--- a/src/slurmd/slurmd/req.c
+++ b/src/slurmd/slurmd/req.c
@@ -319,15 +319,15 @@ _send_slurmstepd_init(int fd, slurmd_step_type_t type, void *req,
 	Buf buffer = NULL;
 	slurm_msg_t msg;
 	uid_t uid = (uid_t)-1;
-	struct passwd pwd, *pwd_ptr;
-	char *pwd_buf;
-	size_t buf_size;
 	gids_t *gids = NULL;
 
 	int rank;
 	int parent_rank, children, depth, max_depth;
 	char *parent_alias = NULL;
 	slurm_addr parent_addr = {0};
+	size_t pwd_bufsize;
+	char *pwd_buffer;
+	struct passwd pwd, *pwd_result;
 
 	slurm_msg_t_init(&msg);
 	/* send type over to slurmstepd */
@@ -452,18 +452,20 @@ _send_slurmstepd_init(int fd, slurmd_step_type_t type, void *req,
 	
 	/* send cached group ids array for the relevant uid */
 	debug3("_send_slurmstepd_init: call to getpwuid_r");
-	buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
-	pwd_buf = xmalloc(buf_size);
-	if (getpwuid_r(uid, &pwd, pwd_buf, buf_size, &pwd_ptr)) {
-		xfree(pwd_buf);
+	pwd_bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+	pwd_buffer = xmalloc(pwd_bufsize);
+	if (getpwuid_r(uid, &pwd, pwd_buffer, pwd_bufsize, &pwd_result) ||
+	    (pwd_result == NULL)) {
 		error("_send_slurmstepd_init getpwuid_r: %m");
 		len = 0;
 		safe_write(fd, &len, sizeof(int));
+		xfree(pwd_buffer);
 		return -1;
 	}
 	debug3("_send_slurmstepd_init: return from getpwuid_r");
 
-	if ((gids = _gids_cache_lookup(pwd.pw_name, pwd.pw_gid))) {
+	if ((gids = _gids_cache_lookup(pwd_result->pw_name, 
+				       pwd_result->pw_gid))) {
 		int i;
 		uint32_t tmp32;
 		safe_write(fd, &gids->ngids, sizeof(int));
@@ -475,7 +477,7 @@ _send_slurmstepd_init(int fd, slurmd_step_type_t type, void *req,
 		len = 0;
 		safe_write(fd, &len, sizeof(int));
 	}
-	xfree(pwd_buf);
+	xfree(pwd_buffer);
 	return 0;
 
 rwfail:
-- 
GitLab