diff --git a/NEWS b/NEWS index 6c140036c642b23b0ab0cda7519147772624433c..603041731e85b100136c44db6b6eb753eed1f5a3 100644 --- a/NEWS +++ b/NEWS @@ -5,16 +5,21 @@ documents those changes that are of interest to users and admins. ======================== -- Set SLURM_TASKS_PER_NODE env var for batch jobs (and LAM/MPI). -- Fix for slurmd spinning when stdin buffers full (gnats:434) - -- Change some slurmctld malloc sizes to reduce demand for realloc - calls, improves performance and eliminates realloc failure on - RH EL3 under extremely heavy workload apparently due to memory - fragmentation. + -- Change some slurmctld malloc sizes to reduce demand for realloc calls, + improves performance and eliminates realloc failure on RH EL3 under + extremely heavy workload apparently due to memory fragmentation. -- Fix scheduling logic for heterogeneous processor count. -- Modify security_2_2 test to function with release 0.3 -- Fix broken rpm build when libslurm not already installed. -- New slurmd option -M to mlock() slurmd process into memory. - -- Fix node processing if state change requested via scontrol - prior to initial node registration. + -- New srun option --no-shell causes srun to exit instead of spawning + shell when using --allocate, -A. + -- Modify srun --uid=user and --gid=group options to maintain invoking + user's credentials until after nodes have been allocated to requested + user/group (allows root to run jobs and allocate nodes for other users + in a RootOnly partition). + -- Fix node processing if state change requested via scontrol prior to + initial node registration. * Changes in SLURM 0.3.0 ======================== diff --git a/doc/man/man1/srun.1 b/doc/man/man1/srun.1 index 579dfdf5ba0189feba5e6d3c5edb47bdf6a4b577..98833feb9aae0a52701a2418a38b4c48f4dd53d9 100644 --- a/doc/man/man1/srun.1 +++ b/doc/man/man1/srun.1 @@ -238,10 +238,13 @@ Quiet operation. Suppress informational messages. Errors will still be displayed. .TP \fB\-\-uid\fR=\fIuser\fR -If -.B srun -is run as root, submit the job with \fIuser\fR's access permissions. -\fIuser\fR may be the user name or the numerical user ID. +Attempt to submit and/or run a job as \fIuser\fR instead of the +invoking user id. The invoking user's credentials will be used +to check access permissions for the target partition. User root +may use this option to run jobs as a normal user in a RootOnly +partition for example. If run as root, \fBsrun\fR will drop +its permissions to the uid specified after node allocation is +successful. \fIuser\fR may be the user name or numerical user ID. .TP \fB\-\-gid\fR=\fIgroup\fR If \fBsrun\fR is run as root, and the \fB\-\-gid\fR option is used, @@ -261,6 +264,10 @@ allocate resources and spawn a shell. When \fB\-\-allocate\fR is specified to \fBsrun\fR, no remote tasks are started. Instead a subshell is started that has access to the allocated resources. Multiple jobs can then be run on the same cpus from within this subshell. See \fBAllocate Mode\fR below. +.TP +\fB\-\-no\-shell\fR +immediately exit after allocating resources instead of spawning a +shell when used with the \fB\-A\fR, \fB\-\-allocate\fR option. .PP Attach to running job: .TP diff --git a/src/common/uid.c b/src/common/uid.c index e5e5d433866b7a21c72f0a3aac0b5a6dc5d92f6e..749671e445979eb65485850e2a45b618237c2bbe 100644 --- a/src/common/uid.c +++ b/src/common/uid.c @@ -1,3 +1,30 @@ +/*****************************************************************************\ + * src/common/uid.c - uid/gid lookup utility functions + * $Id$ + ***************************************************************************** + * Copyright (C) 2002 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Mark Grondona <mgrondona@llnl.gov>. + * UCRL-CODE-2002-040. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +\*****************************************************************************/ + #include <stdlib.h> #include <pwd.h> #include <grp.h> @@ -5,28 +32,33 @@ #include "uid.h" -int -is_digit_string( char *str ) +uid_t +uid_from_string (char *name) { - char *p; + struct passwd *pwd = NULL; + char *p = NULL; + uid_t uid = (uid_t) strtoul (name, &p, 10); - for ( p = str; *p; ++p ) { - if ( ! isdigit( *p ) ) return 0; - } - return 1; -} + if (*p != '\0') + pwd = getpwnam (name); + else + pwd = getpwuid (uid); -uid_t -uid_from_name( char *name ) -{ - struct passwd *p = getpwnam( name ); - return p ? p->pw_uid : NFS_NOBODY; + return pwd ? pwd->pw_uid : (uid_t) -1; } gid_t -gid_from_name( char *name ) +gid_from_string (char *name) { - struct group *g = getgrnam( name ); - return g ? g->gr_gid : NFS_NOBODY; + struct group *g = NULL; + char *p = NULL; + 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; } diff --git a/src/common/uid.h b/src/common/uid.h index c672917056701532290989cabeba3bae302face7..4c1be538b015f2aeeba38bae636c70b8e9781836 100644 --- a/src/common/uid.h +++ b/src/common/uid.h @@ -1,10 +1,45 @@ +/*****************************************************************************\ + * src/common/uid.h - uid/gid lookup utility functions + * $Id$ + ***************************************************************************** + * Copyright (C) 2002 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Mark Grondona <mgrondona@llnl.gov>. + * UCRL-CODE-2002-040. + * + * This file is part of SLURM, a resource management program. + * For details, see <http://www.llnl.gov/linux/slurm/>. + * + * SLURM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with SLURM; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +\*****************************************************************************/ + #ifndef __SLURM_UID_UTILITY_H__ #define __SLURM_UID_UTILITY_H__ -#define NFS_NOBODY 65534 +/* + * Return validated uid_t for string in ``name'' which contains + * either the UID number or user name + * + * Returns uid after verifying presence in /etc/passwd, or + * (uid_t) -1 on failure. + */ +uid_t uid_from_string (char *name); -int is_digit_string( char *str ); -uid_t uid_from_name( char *name ); -gid_t gid_from_name( char *name ); +/* + * Same as uid_from_name(), but for group name/id. + */ +gid_t gid_from_string (char *name); #endif /*__SLURM_UID_UTILITY_H__*/ diff --git a/src/srun/allocate.c b/src/srun/allocate.c index c1b7126f8d2999ba4a563e24d48339ccac3ae4a5..57f67a66eccae096b7dc90bbb6da91878c1b2340 100644 --- a/src/srun/allocate.c +++ b/src/srun/allocate.c @@ -230,7 +230,11 @@ job_desc_msg_create(void) j->min_nodes = opt.min_nodes; j->num_tasks = opt.nprocs; j->user_id = opt.uid; - j->group_id = getgid(); + + if (opt.egid == (gid_t) -1) + j->group_id = getgid (); + else + j->group_id = opt.egid; if (opt.hold) j->priority = 0; @@ -255,10 +259,11 @@ job_desc_msg_create(void) if (opt.share) j->shared = 1; - if (slurmctld_comm_addr.port) { + j->port = slurmctld_comm_addr.port; + if (slurmctld_comm_addr.hostname) j->host = xstrdup(slurmctld_comm_addr.hostname); - j->port = slurmctld_comm_addr.port; - } + else + j->host = NULL; return (j); } diff --git a/src/srun/msg.c b/src/srun/msg.c index 6d99ac8692f50c944523105f2618721ed4a370a3..016d2f4fc7b728f96f83b8108a3ec2eef5ca6fbe 100644 --- a/src/srun/msg.c +++ b/src/srun/msg.c @@ -775,6 +775,13 @@ extern void slurmctld_msg_init(void) slurm_addr slurm_address; char hostname[64]; uint16_t port; + + slurmctld_fd = -1; + slurmctld_comm_addr.hostname = NULL; + slurmctld_comm_addr.port = 0; + + if (opt.allocate && opt.noshell) + return; if ((slurmctld_fd = slurm_init_msg_engine_port(0)) < 0) fatal("slurm_init_msg_engine_port error %m"); diff --git a/src/srun/opt.c b/src/srun/opt.c index 83d6b72c9419b6b2820662b1ab26d72ee21bf9bb..d3fb2a83d553218417e487a901906c4ebc114ce3 100644 --- a/src/srun/opt.c +++ b/src/srun/opt.c @@ -102,6 +102,7 @@ #define LONG_OPT_GID 0x10b #define LONG_OPT_MPI 0x10c #define LONG_OPT_CORE 0x10e +#define LONG_OPT_NOSHELL 0x10f /*---- forward declarations of static functions ----*/ @@ -132,9 +133,6 @@ static void _opt_list(void); /* verify options sanity */ static bool _opt_verify(void); -/* demote to regular user */ -static uid_t _become_user( char *uid_string, char *gid_string ); - static void _print_version(void); static void _process_env_var(env_vars_t *e, const char *val); @@ -409,6 +407,7 @@ static void _opt_default() opt.immediate = false; opt.allocate = false; + opt.noshell = false; opt.attach = NULL; opt.join = false; opt.max_wait = slurm_get_wait_time(); @@ -433,8 +432,8 @@ static void _opt_default() opt.max_exit_timeout= 60; /* Warn user 60 seconds after task exit */ opt.msg_timeout = 5; /* Default launch msg timeout */ - opt.euid = NULL; - opt.egid = NULL; + opt.euid = (uid_t) -1; + opt.egid = (gid_t) -1; mode = MODE_NORMAL; @@ -644,6 +643,7 @@ static void _opt_args(int argc, char **argv) {"mincpus", required_argument, 0, LONG_OPT_MINCPU}, {"mem", required_argument, 0, LONG_OPT_MEM}, {"mpi", required_argument, 0, LONG_OPT_MPI}, + {"no-shell", no_argument, 0, LONG_OPT_NOSHELL}, {"tmp", required_argument, 0, LONG_OPT_TMP}, {"jobid", required_argument, 0, LONG_OPT_JOBID}, {"msg-timeout", required_argument, 0, LONG_OPT_TIMEO}, @@ -847,6 +847,9 @@ static void _opt_args(int argc, char **argv) if (strncasecmp(optarg, "lam", 3) == 0) opt.mpi_type = MPI_LAM; break; + case LONG_OPT_NOSHELL: + opt.noshell = true; + break; case LONG_OPT_TMP: opt.tmpdisk = _to_bytes(optarg); if (opt.tmpdisk < 0) { @@ -870,16 +873,14 @@ static void _opt_args(int argc, char **argv) _get_int(optarg, "max-exit-timeout"); break; case LONG_OPT_UID: - xfree( opt.euid ); - opt.euid = xstrdup( optarg ); - if ( getuid() ) - info( "UID ignored for non-root user" ); + opt.euid = uid_from_string (optarg); + if (opt.euid == (uid_t) -1) + fatal ("--uid=\"%s\" invalid", optarg); break; case LONG_OPT_GID: - xfree( opt.egid ); - opt.egid = xstrdup( optarg ); - if ( getuid() ) - info( "GID ignored for non-root user" ); + opt.egid = gid_from_string (optarg); + if (opt.egid == (gid_t) -1) + fatal ("--gid=\"%s\" invalid", optarg); break; case LONG_OPT_HELP: _help(); @@ -924,7 +925,6 @@ static void _opt_args(int argc, char **argv) static bool _opt_verify(void) { bool verified = true; - uid_t euid; /* * Do not set slurmd debug level higher than DEBUG2, @@ -941,22 +941,6 @@ static bool _opt_verify(void) verified = false; } - /* - * If we are root and have been asked to submit as another - * user, become that user now. - */ - if ( getuid() == 0 ) { - if ( opt.euid ) { - euid = _become_user( opt.euid, opt.egid ); - if ( euid != NFS_NOBODY ) { - opt.uid = euid; - strncpy( opt.user, opt.euid, MAX_USERNAME ); - } else { - verified = false; - } - } - } - if (opt.no_alloc && !opt.nodelist) { error("must specify a node list with -Z, --no-allocate."); verified = false; @@ -1078,6 +1062,14 @@ static bool _opt_verify(void) if (opt.time_limit == 0) opt.time_limit = INFINITE; + if ((opt.euid != (uid_t) -1) && (opt.euid != opt.uid)) + opt.uid = opt.euid; + + if (opt.noshell && !opt.allocate) { + error ("--no-shell only valid with -A (--allocate)"); + verified = false; + } + return verified; } @@ -1155,54 +1147,6 @@ _search_path(char *cmd, bool check_current_dir, int access_mode) } -static uid_t -_become_user( char *uid_string, char *gid_string ) -{ - uid_t euid = 0; - gid_t egid = 0; - - /* - * The group is not strictly necessary but we have to change - * the group before we change the user, else we lose the - * ability to change the group after having become a normal - * user. - */ - if ( gid_string ) { - - /* Resolve group name/ID to numerical form. */ - if ( is_digit_string( gid_string ) ) { - egid = atoi( gid_string ); - } else { - egid = gid_from_name( gid_string ); - } - - /* Assume this group. */ - if ( egid ) { - if ( setregid( egid, egid ) < 0 ) { - error( "can't assume group %s", gid_string ); - } - } - } - - /* Resolve user name/ID to numerical form. */ - if ( is_digit_string( uid_string ) ) { - euid = atoi( uid_string ); - } else { - euid = uid_from_name( uid_string ); - } - - /* Become this user. */ - if ( euid ) { - if ( setreuid( euid, euid ) < 0 ) { - error( "can't become user %s", uid_string ); - return 0; - } - } - - return euid; -} - - /* helper function for printing options * * warning: returns pointer to memory allocated on the stack. @@ -1351,6 +1295,7 @@ Parallel run options:\n\ \n\ Allocate only:\n\ -A, --allocate allocate resources and spawn a shell\n\ + --no-shell don't spawn shell in allocate mode\n\ \n\ Attach to running job:\n\ -a, --attach=jobid attach to running job with specified id\n\ diff --git a/src/srun/opt.h b/src/srun/opt.h index 338a8cbd261b592b63fb14a260c250ecf49c25a9..54b0f3b8d1953beed6a8e10ce7df7ef5485b6ece 100644 --- a/src/srun/opt.h +++ b/src/srun/opt.h @@ -87,8 +87,8 @@ typedef struct srun_options { char *progname; /* argv[0] of this program */ char user[MAX_USERNAME];/* local username */ uid_t uid; /* local uid */ - char *euid; /* effective user --uid=user */ - char *egid; /* effective group --gid=group */ + uid_t euid; /* effective user --uid=user */ + gid_t egid; /* effective group --gid=group */ char *cwd; /* current working directory */ int nprocs; /* --nprocs=n, -n n */ @@ -126,6 +126,7 @@ typedef struct srun_options { bool labelio; /* --label-output, -l */ bool unbuffered; /* --unbuffered, -u */ bool allocate; /* --allocate, -A */ + bool noshell; /* --noshell */ bool overcommit; /* --overcommit, -O */ bool batch; /* --batch, -b */ bool no_kill; /* --no-kill, -k */ diff --git a/src/srun/srun.c b/src/srun/srun.c index 4e52b9582590c35386c2001ee5bea304299b03ca..52128f7817935835b080edd3697c2e44d1ac35b3 100644 --- a/src/srun/srun.c +++ b/src/srun/srun.c @@ -51,6 +51,7 @@ #include <signal.h> #include <unistd.h> #include <fcntl.h> +#include <grp.h> #include "src/common/fd.h" #include "src/common/log.h" @@ -96,6 +97,7 @@ static int _set_batch_script_env(job_t *job); static int _set_rlimit_env(void); static char *_sprint_task_cnt(job_t *job); static void _switch_standalone(job_t *job); +static int _become_user (void); int srun(int ac, char **av) { @@ -159,6 +161,12 @@ int srun(int ac, char **av) sig_setup_sigmask(); if ( !(resp = allocate_nodes()) ) exit(1); + if (opt.noshell) { + fprintf (stdout, "SLURM_JOBID=%u\n", resp->job_id); + exit (0); + } + if (_become_user () < 0) + info ("Warning: unable to assume uid=%lu\n", opt.uid); if (_verbose) _print_job_information(resp); job = job_create_allocation(resp); @@ -186,6 +194,12 @@ int srun(int ac, char **av) slurm_free_resource_allocation_response_msg(resp); } + /* + * Become --uid user + */ + if (_become_user () < 0) + info ("Warning: Unable to assume uid=%lu\n", opt.uid); + /* job structure should now be filled in */ /* @@ -840,3 +854,21 @@ static void _run_job_script (job_t *job) } } + +static int _become_user (void) +{ + struct passwd *pwd = getpwuid (opt.uid); + + if (opt.uid == getuid ()) + return (0); + + if ((opt.egid != (gid_t) -1) && (setgid (opt.egid) < 0)) + return (error ("setgid: %m")); + + initgroups (pwd->pw_name, pwd->pw_gid); /* Ignore errors */ + + if (setuid (opt.uid) < 0) + return (error ("setuid: %m")); + + return (0); +}