| /*****************************************************************************\ | |
| * cred.c - Slurm job and sbcast credential functions | |
| ***************************************************************************** | |
| * Copyright (C) 2002-2007 The Regents of the University of California. | |
| * Copyright (C) 2008-2010 Lawrence Livermore National Security. | |
| * Copyright (C) SchedMD LLC. | |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | |
| * Written by Morris Jette <jette1@llnl.gov>. | |
| * CODE-OCEC-09-009. All rights reserved. | |
| * | |
| * This file is part of Slurm, a resource management program. | |
| * For details, see <https://slurm.schedmd.com/>. | |
| * Please also read the included file: DISCLAIMER. | |
| * | |
| * 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. | |
| * | |
| * In addition, as a special exception, the copyright holders give permission | |
| * to link the code of portions of this program with the OpenSSL library under | |
| * certain conditions as described in each individual source file, and | |
| * distribute linked combinations including the two. You must obey the GNU | |
| * General Public License in all respects for all of the code used other than | |
| * OpenSSL. If you modify file(s) with this exception, you may extend this | |
| * exception to your version of the file(s), but you are not obligated to do | |
| * so. If you do not wish to do so, delete this exception statement from your | |
| * version. If you delete this exception statement from all source files in | |
| * the program, then also delete it here. | |
| * | |
| * 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., | |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| \*****************************************************************************/ | |
| #include "config.h" | |
| #include <fcntl.h> | |
| #include <pthread.h> | |
| #include <stdarg.h> | |
| #include <stdlib.h> | |
| #include <sys/time.h> | |
| #include "slurm/slurm_errno.h" | |
| #include "src/common/bitstring.h" | |
| #include "src/common/group_cache.h" | |
| #include "src/common/identity.h" | |
| #include "src/common/job_resources.h" | |
| #include "src/common/list.h" | |
| #include "src/common/log.h" | |
| #include "src/common/macros.h" | |
| #include "src/common/plugin.h" | |
| #include "src/common/plugrack.h" | |
| #include "src/common/slurm_protocol_api.h" | |
| #include "src/common/slurm_protocol_pack.h" | |
| #include "src/common/slurm_time.h" | |
| #include "src/common/uid.h" | |
| #include "src/common/xassert.h" | |
| #include "src/common/xmalloc.h" | |
| #include "src/common/xstring.h" | |
| #include "src/interfaces/cred.h" | |
| #include "src/interfaces/gres.h" | |
| #include "src/interfaces/switch.h" | |
| typedef struct { | |
| slurm_cred_t *(*cred_create) (slurm_cred_arg_t *cred_arg, | |
| bool sign_it, | |
| uint16_t protocol_version); | |
| slurm_cred_t *(*cred_unpack) (buf_t *buffer, | |
| uint16_t protocol_version); | |
| char *(*create_net_cred) (void *addrs, | |
| uint16_t protocol_version); | |
| void *(*extract_net_cred) (char *net_cred, | |
| uint16_t protocol_version); | |
| sbcast_cred_t *(*sbcast_create) (sbcast_cred_arg_t *cred, | |
| uint16_t protocol_version); | |
| sbcast_cred_t *(*sbcast_unpack) (buf_t *buffer, bool verify, | |
| bool replay_okay, | |
| uint16_t protocol_version); | |
| char *(*cred_get_signature_key)(char *signature); | |
| } slurm_cred_ops_t; | |
| /* | |
| * These strings must be in the same order as the fields declared | |
| * for slurm_cred_ops_t. | |
| */ | |
| static const char *syms[] = { | |
| "cred_p_create", | |
| "cred_p_unpack", | |
| "cred_p_create_net_cred", | |
| "cred_p_extract_net_cred", | |
| "sbcast_p_create", | |
| "sbcast_p_unpack", | |
| "cred_p_get_signature_key", | |
| }; | |
| static slurm_cred_ops_t ops; | |
| static plugin_context_t *g_context = NULL; | |
| static pthread_mutex_t g_context_lock = PTHREAD_MUTEX_INITIALIZER; | |
| static time_t cred_restart_time = (time_t) 0; | |
| static int cred_expire = DEFAULT_EXPIRATION_WINDOW; | |
| static bool enable_nss_slurm = false; | |
| static bool enable_send_gids = true; | |
| /* Initialize the plugin. */ | |
| extern int cred_g_init(void) | |
| { | |
| char *tok; | |
| char *plugin_type = "cred"; | |
| int retval = SLURM_SUCCESS; | |
| char *type = NULL; | |
| /* | |
| * Avoid issues with configless if Slurm was built without MUNGE, | |
| * as the process that fetches the configs will still trigger | |
| * slurm_init(), which will default to cred/munge, which will | |
| * then fail to initialize as the plugin will be missing. | |
| */ | |
| if (getenv("SLURM_CONFIG_FETCH")) { | |
| xfree(slurm_conf.cred_type); | |
| goto done; | |
| } | |
| /* 123456789012 */ | |
| if ((tok = xstrstr(slurm_conf.authinfo, "cred_expire="))) { | |
| cred_expire = atoi(tok + 12); | |
| if (cred_expire < 5) { | |
| error("AuthInfo=cred_expire=%d invalid", cred_expire); | |
| cred_expire = DEFAULT_EXPIRATION_WINDOW; | |
| } | |
| } | |
| if (xstrcasestr(slurm_conf.launch_params, "enable_nss_slurm")) | |
| enable_nss_slurm = true; | |
| else if (xstrcasestr(slurm_conf.launch_params, "disable_send_gids")) | |
| enable_send_gids = false; | |
| /* allow the bare plugin name. also handle slurm type quirks */ | |
| type = slurm_conf.cred_type; | |
| if (!xstrncmp(type, "auth/", 5) || !xstrncmp(type, "cred/", 5)) | |
| type += 5; | |
| if (!xstrcmp(type, "slurm")) | |
| type = xstrdup("auth/slurm"); | |
| else | |
| type = xstrdup_printf("cred/%s", type); | |
| slurm_mutex_lock(&g_context_lock); | |
| if (cred_restart_time == (time_t) 0) | |
| cred_restart_time = time(NULL); | |
| if (g_context) | |
| goto done; | |
| g_context = plugin_context_create(plugin_type, type, | |
| (void **) &ops, syms, sizeof(syms)); | |
| if (!g_context) { | |
| error("cannot create %s context for %s", | |
| plugin_type, slurm_conf.cred_type); | |
| retval = SLURM_ERROR; | |
| goto done; | |
| } | |
| done: | |
| slurm_mutex_unlock(&g_context_lock); | |
| xfree(type); | |
| return(retval); | |
| } | |
| /* Terminate the plugin and release all memory. */ | |
| extern int cred_g_fini(void) | |
| { | |
| int rc; | |
| if (!g_context) | |
| return SLURM_SUCCESS; | |
| rc = plugin_context_destroy(g_context); | |
| g_context = NULL; | |
| return rc; | |
| } | |
| extern int cred_expiration(void) | |
| { | |
| return cred_expire; | |
| } | |
| extern slurm_cred_t *slurm_cred_create(slurm_cred_arg_t *arg, bool sign_it, | |
| uint16_t protocol_version) | |
| { | |
| slurm_cred_t *cred = NULL; | |
| int i = 0, sock_recs = 0; | |
| bool release_id = false; | |
| identity_t fake_id = { | |
| .uid = arg->uid, | |
| .gid = arg->gid, | |
| .pw_name = arg->username, | |
| .fake = true, | |
| }; | |
| xassert(arg); | |
| xassert(g_context); | |
| debug("%s: creating credential for %pI", __func__, &arg->step_id); | |
| if (arg->uid == SLURM_AUTH_NOBODY) { | |
| error("%s: refusing to create job %u credential for invalid user nobody", | |
| __func__, arg->step_id.job_id); | |
| return NULL; | |
| } | |
| if (arg->gid == SLURM_AUTH_NOBODY) { | |
| error("%s: refusing to create job %u credential for invalid group nobody", | |
| __func__, arg->step_id.job_id); | |
| return NULL; | |
| } | |
| if (arg->sock_core_rep_count) { | |
| for (i = 0; i < arg->job_nhosts; i++) { | |
| sock_recs += arg->sock_core_rep_count[i]; | |
| if (sock_recs >= arg->job_nhosts) | |
| break; | |
| } | |
| i++; | |
| } | |
| arg->core_array_size = i; | |
| if (!arg->id && (enable_nss_slurm || enable_send_gids) && | |
| (arg->uid != NO_VAL)) { | |
| release_id = true; | |
| if (!(arg->id = fetch_identity(arg->uid, arg->gid, | |
| enable_nss_slurm))) { | |
| error("%s: fetch_identity() failed", __func__); | |
| return NULL; | |
| } | |
| } else if (!arg->id) { | |
| arg->id = &fake_id; | |
| } | |
| identity_debug2(arg->id, __func__); | |
| cred = (*(ops.cred_create))(arg, sign_it, protocol_version); | |
| /* Release any values populated through _fill_cred_gids(). */ | |
| if (release_id) | |
| FREE_NULL_IDENTITY(arg->id); | |
| return cred; | |
| } | |
| extern slurm_cred_t *slurm_cred_job_create(slurm_cred_arg_t *arg, | |
| job_record_t *job_ptr, bool sign_it, | |
| uint16_t protocol_version) | |
| { | |
| list_t *job_orig, *step_orig, *job_copy, *step_copy; | |
| slurm_cred_t *cred; | |
| xassert(arg); | |
| if (!job_ptr || !job_ptr->node_bitmap) | |
| return slurm_cred_create(arg, sign_it, protocol_version); | |
| job_orig = arg->job_gres_list; | |
| step_orig = arg->step_gres_list; | |
| job_copy = NULL; | |
| step_copy = NULL; | |
| if (gres_list_needs_slurmd_indexes(job_orig, job_ptr->node_bitmap)) | |
| job_copy = gres_job_state_list_dup(job_orig); | |
| if (gres_list_needs_slurmd_indexes(step_orig, job_ptr->node_bitmap)) | |
| step_copy = gres_step_state_list_dup(step_orig); | |
| /* | |
| * Pack the copies. slurmd numbers only the devices it has, which | |
| * is the saved UUID order with the empty slots removed. A list | |
| * with no empty slot is already in slurmd's order and is packed | |
| * as is. | |
| */ | |
| if (job_copy) { | |
| gres_list_use_slurmd_indexes(job_copy, job_ptr->node_bitmap); | |
| arg->job_gres_list = job_copy; | |
| } | |
| if (step_copy) { | |
| gres_list_use_slurmd_indexes(step_copy, job_ptr->node_bitmap); | |
| arg->step_gres_list = step_copy; | |
| } | |
| cred = slurm_cred_create(arg, sign_it, protocol_version); | |
| if (job_copy) { | |
| FREE_NULL_LIST(job_copy); | |
| arg->job_gres_list = job_orig; | |
| } | |
| if (step_copy) { | |
| FREE_NULL_LIST(step_copy); | |
| arg->step_gres_list = step_orig; | |
| } | |
| return cred; | |
| } | |
| extern slurm_cred_t *slurm_cred_faker(slurm_cred_arg_t *arg) | |
| { | |
| /* | |
| * Force this on to ensure pw_name, ngid, gids are all populated. | |
| */ | |
| enable_send_gids = true; | |
| return slurm_cred_create(arg, true, SLURM_PROTOCOL_VERSION); | |
| } | |
| extern void slurm_cred_free_args(slurm_cred_arg_t *arg) | |
| { | |
| if (!arg) | |
| return; | |
| FREE_NULL_IDENTITY(arg->id); | |
| FREE_NULL_BITMAP(arg->job_core_bitmap); | |
| FREE_NULL_BITMAP(arg->step_core_bitmap); | |
| xfree(arg->cores_per_socket); | |
| xfree(arg->cpu_array); | |
| xfree(arg->cpu_array_reps); | |
| FREE_NULL_LIST(arg->job_gres_list); | |
| FREE_NULL_LIST(arg->job_hres_list); | |
| FREE_NULL_LIST(arg->step_gres_list); | |
| xfree(arg->step_hostlist); | |
| xfree(arg->job_account); | |
| xfree(arg->job_alias_list); | |
| xfree(arg->job_comment); | |
| xfree(arg->job_constraints); | |
| xfree(arg->job_extra); | |
| xfree(arg->job_layout); | |
| xfree(arg->job_licenses); | |
| xfree(arg->job_hostlist); | |
| xfree(arg->job_het_stepmgr_host); | |
| xfree(arg->sock_core_rep_count); | |
| xfree(arg->sockets_per_node); | |
| xfree(arg->job_mem_alloc); | |
| xfree(arg->job_mem_alloc_rep_count); | |
| xfree(arg->job_node_addrs); | |
| xfree(arg->job_partition); | |
| xfree(arg->job_qos); | |
| xfree(arg->job_reservation); | |
| xfree(arg->job_resolve_nodes); | |
| FREE_NULL_DATA(arg->job_runtime_data); | |
| xfree(arg->job_selinux_context); | |
| xfree(arg->job_std_err); | |
| xfree(arg->job_std_in); | |
| xfree(arg->job_std_out); | |
| xfree(arg->step_mem_alloc); | |
| xfree(arg->step_mem_alloc_rep_count); | |
| xfree(arg->username); | |
| switch_g_stepinfo_free(arg->switch_step); | |
| xfree(arg); | |
| } | |
| extern void slurm_cred_unlock_args(slurm_cred_t *cred) | |
| { | |
| slurm_rwlock_unlock(&cred->mutex); | |
| } | |
| /* | |
| * Caller *must* release lock. | |
| */ | |
| extern slurm_cred_arg_t *slurm_cred_get_args(slurm_cred_t *cred) | |
| { | |
| xassert(cred); | |
| slurm_rwlock_rdlock(&cred->mutex); | |
| return cred->arg; | |
| } | |
| extern void *slurm_cred_get(slurm_cred_t *cred, | |
| cred_data_enum_t cred_data_type) | |
| { | |
| void *rc = NULL; | |
| xassert(cred); | |
| slurm_rwlock_rdlock(&cred->mutex); | |
| if (!cred->arg) { | |
| slurm_rwlock_unlock(&cred->mutex); | |
| return NULL; | |
| } | |
| switch (cred_data_type) { | |
| case CRED_DATA_JOB_GRES_LIST: | |
| rc = (void *) cred->arg->job_gres_list; | |
| break; | |
| case CRED_DATA_JOB_ALIAS_LIST: | |
| rc = (void *) cred->arg->job_alias_list; | |
| break; | |
| case CRED_DATA_JOB_NODE_ADDRS: | |
| rc = (void *) cred->arg->job_node_addrs; | |
| break; | |
| case CRED_DATA_JOB_RESOLVE_NODES: | |
| rc = (void *) cred->arg->job_resolve_nodes; | |
| break; | |
| case CRED_DATA_STEP_GRES_LIST: | |
| rc = (void *) cred->arg->step_gres_list; | |
| break; | |
| case CRED_DATA_JOB_HRES_LIST: | |
| rc = (void *) cred->arg->job_hres_list; | |
| break; | |
| default: | |
| error("%s: Invalid arg type requested (%d)", __func__, | |
| cred_data_type); | |
| } | |
| slurm_rwlock_unlock(&cred->mutex); | |
| return rc; | |
| } | |
| /* | |
| * Returns NULL on error. | |
| * | |
| * On success, returns a pointer to the arg structure within the credential. | |
| * Caller *must* release the lock. | |
| */ | |
| extern slurm_cred_arg_t *slurm_cred_verify(slurm_cred_t *cred) | |
| { | |
| time_t now = time(NULL); | |
| int errnum; | |
| xassert(cred); | |
| xassert(g_context); | |
| slurm_rwlock_rdlock(&cred->mutex); | |
| xassert(cred->magic == CRED_MAGIC); | |
| /* NOTE: the verification checks that the credential was | |
| * created by SlurmUser or root */ | |
| if (!cred->verified) { | |
| errno = ESLURMD_INVALID_JOB_CREDENTIAL; | |
| goto error; | |
| } | |
| if (now > (cred->ctime + cred_expire)) { | |
| errno = ESLURMD_CREDENTIAL_EXPIRED; | |
| goto error; | |
| } | |
| /* coverity[missing_unlock] */ | |
| return cred->arg; | |
| error: | |
| errnum = errno; | |
| slurm_rwlock_unlock(&cred->mutex); | |
| errno = errnum; | |
| return NULL; | |
| } | |
| extern void slurm_cred_destroy(slurm_cred_t *cred) | |
| { | |
| if (cred == NULL) | |
| return; | |
| xassert(cred->magic == CRED_MAGIC); | |
| slurm_rwlock_wrlock(&cred->mutex); | |
| slurm_cred_free_args(cred->arg); | |
| FREE_NULL_BUFFER(cred->buffer); | |
| xfree(cred->signature); | |
| cred->magic = ~CRED_MAGIC; | |
| slurm_rwlock_unlock(&cred->mutex); | |
| slurm_rwlock_destroy(&cred->mutex); | |
| xfree(cred); | |
| } | |
| extern char *slurm_cred_get_signature(slurm_cred_t *cred) | |
| { | |
| char *sig = NULL; | |
| xassert(cred); | |
| slurm_rwlock_rdlock(&cred->mutex); | |
| sig = xstrdup(cred->signature); | |
| slurm_rwlock_unlock(&cred->mutex); | |
| return sig; | |
| } | |
| extern char *slurm_cred_get_signature_key(slurm_cred_t *cred) | |
| { | |
| char *key = NULL; | |
| xassert(cred); | |
| slurm_rwlock_rdlock(&cred->mutex); | |
| if (cred->signature) | |
| key = (*(ops.cred_get_signature_key))(cred->signature); | |
| slurm_rwlock_unlock(&cred->mutex); | |
| return key; | |
| } | |
| static int _get_rep_count_inx(uint32_t *rep_count, uint32_t rep_count_size, | |
| int inx, bool quiet) | |
| { | |
| if (!quiet) | |
| return slurm_get_rep_count_inx(rep_count, rep_count_size, inx); | |
| for (int i = 0; i < rep_count_size; i++) { | |
| if (!rep_count[i]) | |
| return -1; | |
| } | |
| return slurm_get_rep_count_inx(rep_count, rep_count_size, inx); | |
| } | |
| static bool _get_job_mem(slurm_cred_arg_t *cred, char *node_name, | |
| const char *func_name, uint64_t *job_mem_limit, | |
| bool quiet) | |
| { | |
| int node_id = -1, rep_idx = -1; | |
| if (!cred->job_hostlist || !cred->job_mem_alloc || | |
| !cred->job_mem_alloc_rep_count || !cred->job_mem_alloc_size) { | |
| if (!quiet) | |
| error("%s: job memory allocation data is incomplete", | |
| func_name); | |
| return false; | |
| } | |
| /* | |
| * Batch steps only have the job_hostlist set and will always be 0 here. | |
| */ | |
| if (cred->step_id.step_id == SLURM_BATCH_SCRIPT) { | |
| rep_idx = 0; | |
| } else if ((node_id = | |
| nodelist_find(cred->job_hostlist, node_name)) >= 0) { | |
| rep_idx = _get_rep_count_inx(cred->job_mem_alloc_rep_count, | |
| cred->job_mem_alloc_size, node_id, | |
| quiet); | |
| } else if (!quiet) { | |
| error("Unable to find %s in job hostlist: `%s'", | |
| node_name, cred->job_hostlist); | |
| } | |
| if (rep_idx < 0) { | |
| if (!quiet) | |
| error("%s: node_id=%d, not found in job_mem_alloc_rep_count requested job memory not reset.", | |
| func_name, node_id); | |
| return false; | |
| } | |
| *job_mem_limit = cred->job_mem_alloc[rep_idx]; | |
| return true; | |
| } | |
| extern bool slurm_cred_get_job_mem(slurm_cred_t *credential, char *node_name, | |
| uint64_t *job_mem_limit) | |
| { | |
| return _get_job_mem(credential->arg, node_name, NULL, job_mem_limit, | |
| true); | |
| } | |
| extern void slurm_cred_get_mem(slurm_cred_t *credential, char *node_name, | |
| const char *func_name, uint64_t *job_mem_limit, | |
| uint64_t *step_mem_limit) | |
| { | |
| slurm_cred_arg_t *cred = credential->arg; | |
| int rep_idx = -1; | |
| int node_id = -1; | |
| (void) _get_job_mem(cred, node_name, func_name, job_mem_limit, false); | |
| if (!step_mem_limit) { | |
| log_flag(CPU_BIND, "%s: Memory extracted from credential for %ps job_mem_limit= %"PRIu64, | |
| func_name, &cred->step_id, *job_mem_limit); | |
| return; | |
| } | |
| if (cred->step_mem_alloc) { | |
| rep_idx = -1; | |
| if ((node_id = | |
| nodelist_find(cred->step_hostlist, node_name)) >= 0) { | |
| rep_idx = slurm_get_rep_count_inx( | |
| cred->step_mem_alloc_rep_count, | |
| cred->step_mem_alloc_size, | |
| node_id); | |
| } else { | |
| error("Unable to find %s in step hostlist: `%s'", | |
| node_name, cred->step_hostlist); | |
| } | |
| if (rep_idx < 0) | |
| error("%s: node_id=%d, not found in step_mem_alloc_rep_count", | |
| func_name, node_id); | |
| else | |
| *step_mem_limit = cred->step_mem_alloc[rep_idx]; | |
| } | |
| /* | |
| * If we are not set or we were sent 0 go with the job_mem_limit value. | |
| */ | |
| if (!(*step_mem_limit)) | |
| *step_mem_limit = *job_mem_limit; | |
| log_flag(CPU_BIND, "Memory extracted from credential for %ps job_mem_limit=%"PRIu64" step_mem_limit=%"PRIu64, | |
| &cred->step_id, *job_mem_limit, *step_mem_limit); | |
| } | |
| /* Convert bitmap to string representation with brackets removed */ | |
| static char *_core_format(bitstr_t *core_bitmap) | |
| { | |
| char str[1024], *bracket_ptr; | |
| bit_fmt(str, sizeof(str), core_bitmap); | |
| if (str[0] != '[') | |
| return xstrdup(str); | |
| /* strip off brackets */ | |
| bracket_ptr = strchr(str, ']'); | |
| if (bracket_ptr) | |
| bracket_ptr[0] = '\0'; | |
| return xstrdup(str+1); | |
| } | |
| /* | |
| * Retrieve the set of cores that were allocated to the job and step then | |
| * format them in the List Format (e.g., "0-2,7,12-14"). Also return | |
| * job and step's memory limit. | |
| * | |
| * NOTE: caller must xfree the returned strings. | |
| */ | |
| extern void format_core_allocs(slurm_cred_t *credential, char *node_name, | |
| uint16_t cpus, char **job_alloc_cores, | |
| char **step_alloc_cores, uint64_t *job_mem_limit, | |
| uint64_t *step_mem_limit) | |
| { | |
| slurm_cred_arg_t *cred = credential->arg; | |
| bitstr_t *job_core_bitmap, *step_core_bitmap; | |
| hostlist_t *hset = NULL; | |
| int host_index = -1; | |
| uint32_t i, j, i_first_bit=0, i_last_bit=0; | |
| xassert(cred); | |
| xassert(job_alloc_cores); | |
| xassert(step_alloc_cores); | |
| if (!(hset = hostlist_create(cred->job_hostlist))) { | |
| error("Unable to create job hostlist: `%s'", | |
| cred->job_hostlist); | |
| return; | |
| } | |
| host_index = hostlist_find(hset, node_name); | |
| if ((host_index < 0) || (host_index >= cred->job_nhosts)) { | |
| error("Invalid host_index %d for job %u", | |
| host_index, cred->step_id.job_id); | |
| error("Host %s not in hostlist %s", | |
| node_name, cred->job_hostlist); | |
| hostlist_destroy(hset); | |
| return; | |
| } | |
| host_index++; /* change from 0-origin to 1-origin */ | |
| for (i=0; host_index; i++) { | |
| if (host_index > cred->sock_core_rep_count[i]) { | |
| i_first_bit += cred->sockets_per_node[i] * | |
| cred->cores_per_socket[i] * | |
| cred->sock_core_rep_count[i]; | |
| host_index -= cred->sock_core_rep_count[i]; | |
| } else { | |
| i_first_bit += cred->sockets_per_node[i] * | |
| cred->cores_per_socket[i] * | |
| (host_index - 1); | |
| i_last_bit = i_first_bit + | |
| cred->sockets_per_node[i] * | |
| cred->cores_per_socket[i]; | |
| break; | |
| } | |
| } | |
| job_core_bitmap = bit_alloc(i_last_bit - i_first_bit); | |
| step_core_bitmap = bit_alloc(i_last_bit - i_first_bit); | |
| for (i = i_first_bit, j = 0; i < i_last_bit; i++, j++) { | |
| if (bit_test(cred->job_core_bitmap, i)) | |
| bit_set(job_core_bitmap, j); | |
| if (bit_test(cred->step_core_bitmap, i)) | |
| bit_set(step_core_bitmap, j); | |
| } | |
| slurm_cred_get_mem(credential, node_name, __func__, job_mem_limit, | |
| step_mem_limit); | |
| *job_alloc_cores = _core_format(job_core_bitmap); | |
| *step_alloc_cores = _core_format(step_core_bitmap); | |
| FREE_NULL_BITMAP(job_core_bitmap); | |
| FREE_NULL_BITMAP(step_core_bitmap); | |
| hostlist_destroy(hset); | |
| } | |
| /* | |
| * Retrieve the job and step generic resources (gres) allocate to this job | |
| * on this node. | |
| * | |
| * NOTE: Caller must destroy the returned lists | |
| */ | |
| extern void get_cred_gres(slurm_cred_t *credential, char *node_name, | |
| list_t **job_gres_list, list_t **step_gres_list) | |
| { | |
| slurm_cred_arg_t *cred = credential->arg; | |
| hostlist_t *hset = NULL; | |
| int host_index = -1; | |
| xassert(cred); | |
| xassert(job_gres_list); | |
| xassert(step_gres_list); | |
| FREE_NULL_LIST(*job_gres_list); | |
| FREE_NULL_LIST(*step_gres_list); | |
| if ((cred->job_gres_list == NULL) && (cred->step_gres_list == NULL)) | |
| return; | |
| if (!(hset = hostlist_create(cred->job_hostlist))) { | |
| error("Unable to create job hostlist: `%s'", | |
| cred->job_hostlist); | |
| return; | |
| } | |
| host_index = hostlist_find(hset, node_name); | |
| hostlist_destroy(hset); | |
| if ((host_index < 0) || (host_index >= cred->job_nhosts)) { | |
| error("Invalid host_index %d for job %u", | |
| host_index, cred->step_id.job_id); | |
| error("Host %s not in credential hostlist %s", | |
| node_name, cred->job_hostlist); | |
| return; | |
| } | |
| *job_gres_list = gres_job_state_extract(cred->job_gres_list, | |
| host_index); | |
| *step_gres_list = gres_step_state_extract(cred->step_gres_list, | |
| host_index); | |
| return; | |
| } | |
| extern void slurm_cred_pack(slurm_cred_t *cred, buf_t *buffer, | |
| uint16_t protocol_version) | |
| { | |
| xassert(cred); | |
| xassert(cred->magic == CRED_MAGIC); | |
| slurm_rwlock_rdlock(&cred->mutex); | |
| xassert(cred->buffer); | |
| xassert(cred->buf_version == protocol_version); | |
| packbuf(cred->buffer, buffer); | |
| slurm_rwlock_unlock(&cred->mutex); | |
| } | |
| extern slurm_cred_t *slurm_cred_unpack(buf_t *buffer, uint16_t protocol_version) | |
| { | |
| return (*(ops.cred_unpack))(buffer, protocol_version); | |
| } | |
| extern slurm_cred_t *slurm_cred_alloc(bool alloc_arg) | |
| { | |
| slurm_cred_t *cred = xmalloc(sizeof(*cred)); | |
| /* Contents initialized to zero */ | |
| slurm_rwlock_init(&cred->mutex); | |
| if (alloc_arg) { | |
| cred->arg = xmalloc(sizeof(slurm_cred_arg_t)); | |
| cred->arg->uid = SLURM_AUTH_NOBODY; | |
| cred->arg->gid = SLURM_AUTH_NOBODY; | |
| } | |
| cred->verified = false; | |
| cred->magic = CRED_MAGIC; | |
| return cred; | |
| } | |
| /*****************************************************************************\ | |
| ***************** SBCAST CREDENTIAL FUNCTIONS ****************** | |
| \*****************************************************************************/ | |
| /* Create an sbcast credential for the specified job and nodes | |
| * including digital signature. | |
| * RET the sbcast credential or NULL on error */ | |
| extern sbcast_cred_t *create_sbcast_cred(sbcast_cred_arg_t *arg, | |
| uid_t uid, gid_t gid, | |
| uint16_t protocol_version) | |
| { | |
| sbcast_cred_t *sbcast_cred; | |
| bool release_id = false; | |
| identity_t fake_id = { .uid = uid, .gid = gid, .fake = true }; | |
| xassert(g_context); | |
| if (!arg->id && enable_send_gids) { | |
| release_id = true; | |
| if (!(arg->id = fetch_identity(uid, gid, false))) { | |
| error("%s: fetch_identity() failed", __func__); | |
| return NULL; | |
| } | |
| } else if (!arg->id) { | |
| arg->id = &fake_id; | |
| } | |
| if (!(sbcast_cred = (*(ops.sbcast_create))(arg, protocol_version))) | |
| error("%s: failed to create sbcast credential", __func__); | |
| if (release_id) | |
| FREE_NULL_IDENTITY(arg->id); | |
| return sbcast_cred; | |
| } | |
| /* Delete an sbcast credential created using create_sbcast_cred() or | |
| * unpack_sbcast_cred() */ | |
| extern void delete_sbcast_cred(sbcast_cred_t *sbcast_cred) | |
| { | |
| if (!sbcast_cred) | |
| return; | |
| FREE_NULL_IDENTITY(sbcast_cred->arg.id); | |
| xfree(sbcast_cred->arg.nodes); | |
| FREE_NULL_BUFFER(sbcast_cred->buffer); | |
| xfree(sbcast_cred->signature); | |
| xfree(sbcast_cred); | |
| } | |
| /* Pack an sbcast credential into a buffer including the digital signature */ | |
| extern void pack_sbcast_cred(sbcast_cred_t *sbcast_cred, buf_t *buffer, | |
| uint16_t protocol_version) | |
| { | |
| xassert(sbcast_cred); | |
| if (sbcast_cred->buffer) { | |
| /* already includes signature */ | |
| packbuf(sbcast_cred->buffer, buffer); | |
| } else { | |
| /* credential only uses signature */ | |
| packstr(sbcast_cred->signature, buffer); | |
| } | |
| } | |
| extern sbcast_cred_t *unpack_sbcast_cred(buf_t *buffer, void *msg, | |
| uint16_t protocol_version) | |
| { | |
| file_bcast_msg_t *bmsg = msg; | |
| bool verify = false, replay_okay = false; | |
| if (bmsg && (bmsg->block_no == 1)) { | |
| verify = true; | |
| /* | |
| * One credential covers the executable and every shared | |
| * object sent after it, so munged only sees it a second | |
| * time on the shared object transfers. | |
| */ | |
| replay_okay = (bmsg->flags & FILE_BCAST_SO); | |
| } | |
| return (*(ops.sbcast_unpack))(buffer, verify, replay_okay, | |
| protocol_version); | |
| } | |
| extern void print_sbcast_cred(sbcast_cred_t *sbcast_cred) | |
| { | |
| info("Sbcast_cred: JobId %u", sbcast_cred->arg.step_id.job_id); | |
| info("Sbcast_cred: HetJobId %u", sbcast_cred->arg.het_job_id); | |
| info("Sbcast_cred: StepId %u", sbcast_cred->arg.step_id.step_id); | |
| info("Sbcast_cred: Nodes %s", sbcast_cred->arg.nodes); | |
| info("Sbcast_cred: ctime %s", slurm_ctime2(&sbcast_cred->ctime)); | |
| info("Sbcast_cred: Expire %s", slurm_ctime2(&sbcast_cred->arg.expiration)); | |
| } | |
| extern char *create_net_cred(void *addrs, uint16_t protocol_version) | |
| { | |
| xassert(g_context); | |
| if (!addrs) { | |
| error("%s: addrs not provided", __func__); | |
| return NULL; | |
| } | |
| return (*(ops.create_net_cred))(addrs, protocol_version); | |
| } | |
| extern void *extract_net_cred(char *net_cred, uint16_t protocol_version) | |
| { | |
| xassert(g_context); | |
| if (!net_cred) { | |
| error("%s: net_cred not provided", __func__); | |
| return NULL; | |
| } | |
| return (*(ops.extract_net_cred))(net_cred, protocol_version); | |
| } | |
| extern void setup_cred_arg(slurm_cred_arg_t *cred_arg, job_record_t *job_ptr) | |
| { | |
| memset(cred_arg, 0, sizeof(slurm_cred_arg_t)); | |
| cred_arg->id = job_ptr->id; | |
| /* | |
| * Must be set before the job_ptr->details check below. The memset() | |
| * above leaves this at 0, and the pids controller reads pids.max=0 as | |
| * "no process may be created". | |
| */ | |
| cred_arg->job_max_npids = NO_VAL; | |
| cred_arg->gid = job_ptr->group_id; | |
| cred_arg->job_account = job_ptr->account; | |
| cred_arg->job_alias_list = job_ptr->alias_list; | |
| cred_arg->job_comment = job_ptr->comment; | |
| cred_arg->job_end_time = job_ptr->end_time; | |
| cred_arg->job_extra = job_ptr->extra; | |
| cred_arg->job_gres_list = job_ptr->gres_list_alloc; | |
| cred_arg->job_hres_list = job_ptr->hres_prep; | |
| cred_arg->job_layout = job_ptr->layout; | |
| cred_arg->job_licenses = job_ptr->licenses; | |
| cred_arg->job_node_addrs = job_ptr->node_addrs; | |
| cred_arg->job_reservation = job_ptr->resv_name; | |
| cred_arg->job_resolve_nodes = job_ptr->resolve_nodes; | |
| cred_arg->job_restart_cnt = job_ptr->restart_cnt; | |
| cred_arg->job_runtime_data = job_ptr->runtime_data; | |
| cred_arg->job_selinux_context = job_ptr->selinux_context; | |
| cred_arg->job_start_time = job_ptr->start_time; | |
| cred_arg->uid = job_ptr->user_id; | |
| cred_arg->username = job_ptr->user_name; | |
| /* | |
| * These helpers handle job_ptr->details == NULL internally and fall | |
| * through to the partition flags, so call them unconditionally so the | |
| * cred carries the partition's exclusive/oversubscribe state even | |
| * when details are unavailable. | |
| */ | |
| cred_arg->job_exclusive = get_job_exclusive_display_value(job_ptr); | |
| cred_arg->job_oversubscribe = get_job_oversubscribe_value(job_ptr); | |
| if (job_ptr->details) { | |
| cred_arg->job_constraints = job_ptr->details->features_use; | |
| cred_arg->job_core_spec = job_ptr->details->core_spec; | |
| cred_arg->job_max_npids = job_ptr->details->max_npids; | |
| cred_arg->job_ntasks = job_ptr->details->num_tasks; | |
| cred_arg->job_relay_io = job_ptr->details->relay_io; | |
| cred_arg->job_std_err = job_ptr->details->std_err; | |
| cred_arg->job_std_in = job_ptr->details->std_in; | |
| cred_arg->job_std_out = job_ptr->details->std_out; | |
| cred_arg->job_x11 = job_ptr->details->x11; | |
| } | |
| if (job_ptr->job_resrcs) { | |
| job_resources_t *resrcs = job_ptr->job_resrcs; | |
| cred_arg->cores_per_socket = resrcs->cores_per_socket; | |
| cred_arg->cpu_array_count = resrcs->cpu_array_cnt; | |
| cred_arg->cpu_array = resrcs->cpu_array_value; | |
| cred_arg->cpu_array_reps = resrcs->cpu_array_reps; | |
| cred_arg->job_core_bitmap = resrcs->core_bitmap; | |
| cred_arg->job_hostlist = resrcs->nodes; | |
| cred_arg->job_nhosts = resrcs->nhosts; | |
| cred_arg->sock_core_rep_count = resrcs->sock_core_rep_count; | |
| cred_arg->sockets_per_node = resrcs->sockets_per_node; | |
| } | |
| if (job_ptr->part_ptr) | |
| cred_arg->job_partition = job_ptr->part_ptr->name; | |
| if (job_ptr->qos_ptr) | |
| cred_arg->job_qos = job_ptr->qos_ptr->name; | |
| } |