diff --git a/slurm/slurm.h.in b/slurm/slurm.h.in index 42c6b142a96bca471087541b8b5c8df589540971..4d2dbb1ee93c97a12e8dbcb65c44e1431660bc71 100644 --- a/slurm/slurm.h.in +++ b/slurm/slurm.h.in @@ -138,13 +138,10 @@ enum node_states { * PROTOCOL DATA STRUCTURE DEFINITIONS \*****************************************************************************/ -typedef struct { - uint32_t job_id; /* job's id */ - uid_t user_id; /* user who job is running as */ - char *node_list; /* list of allocated nodes */ - time_t expiration_time; /* expiration of credential */ - char signature[SLURM_SSL_SIGNATURE_LENGTH]; -} slurm_job_credential_t; +#ifndef __slurm_cred_t_defined +# define __slurm_cred_t_defined + typedef struct slurm_job_credential * slurm_cred_t; +#endif typedef struct job_descriptor { /* For submit, allocate, and update requests */ uint16_t contiguous; /* 1 if job requires contiguous nodes, @@ -254,7 +251,7 @@ typedef struct job_step_specs { typedef struct job_step_create_response_msg { uint32_t job_step_id; /* assigned job step id */ char *node_list; /* list of allocated nodes */ - slurm_job_credential_t *credentials; + slurm_cred_t cred; /* slurm job credential */ #ifdef HAVE_LIBELAN3 qsw_jobinfo_t qsw_job; /* Elan3 switch context, opaque data structure */ #endif @@ -340,7 +337,7 @@ typedef struct resource_allocation_and_run_response_msg { slurm_addr *node_addr; /* network addresses */ uint32_t job_step_id; /* assigned step id */ - slurm_job_credential_t *credentials; + slurm_cred_t cred; /* slurm job credential */ #ifdef HAVE_LIBELAN3 qsw_jobinfo_t qsw_job; /* Elan3 switch context, opaque data structure */ #endif diff --git a/slurm/slurm_errno.h b/slurm/slurm_errno.h index 7166a97751fb54ea8a109fa25de57f8155e2ecd8..37ed30b2d4d67a1b3d8a03fcecd5c57ad7548f52 100644 --- a/slurm/slurm_errno.h +++ b/slurm/slurm_errno.h @@ -141,6 +141,7 @@ enum { ESLURMD_INVALID_JOB_CREDENTIAL, ESLURMD_CREDENTIAL_EXPIRED, ESLURMD_CREDENTIAL_REVOKED, + ESLURMD_CREDENTIAL_REPLAYED, ESLURMD_CREATE_BATCH_DIR_ERROR, ESLURMD_MODIFY_BATCH_DIR_ERROR, ESLURMD_CREATE_BATCH_SCRIPT_ERROR, diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 753db92a930ae8e96b7789ab7dd50a29e85db740..f115f05d41e49734e7fbe5b7434eac75052a4b25 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -60,10 +60,8 @@ libdaemonize_la_SOURCES = \ fd.c fd.h libcred_la_SOURCES = \ - credential_utils.c \ - credential_utils.h \ - signature_utils.c \ - signature_utils.h + slurm_cred.h \ + slurm_cred.c libhostlist_la_SOURCES = \ hostlist.c hostlist.h diff --git a/src/common/credential_utils.c b/src/common/credential_utils.c deleted file mode 100644 index ba554e11808fa6715cb31f04d9019f8536679643..0000000000000000000000000000000000000000 --- a/src/common/credential_utils.c +++ /dev/null @@ -1,404 +0,0 @@ -/*****************************************************************************\ - * credential_utils.c - slurm authentication credential management functions - * $Id$ - ***************************************************************************** - * Written by Kevin Tew <tewk@llnl.gov> - * - * 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 <stdio.h> -#include <string.h> -#include <openssl/rsa.h> -#include <openssl/evp.h> -#include <openssl/objects.h> -#include <openssl/x509.h> -#include <openssl/err.h> -#include <openssl/pem.h> -#include <openssl/ssl.h> - -#include <slurm/slurm_errno.h> - -#include "src/common/credential_utils.h" -#include "src/common/hostlist.h" -#include "src/common/list.h" -#include "src/common/log.h" -#include "src/common/pack.h" -#include "src/common/signature_utils.h" -#include "src/common/slurm_protocol_api.h" -#include "src/common/slurm_protocol_pack.h" -#include "src/common/xmalloc.h" - -#define MAX_NAME_LEN 1024 - -/* global variables */ - -/* prototypes */ - -static int _clear_expired_revoked_credentials(List list); -static int _is_credential_still_valid(slurm_job_credential_t *, List); -static void _free_credential_state(void *credential_state); -static int _insert_credential_state(slurm_job_credential_t *l, List); -static int _insert_revoked_credential_state(revoke_credential_msg_t *, List); -static void _pack_one_cred(credential_state_t *, Buf); -static int _unpack_one_cred(credential_state_t *, Buf); - -static int _init_credential_state( credential_state_t *, - slurm_job_credential_t *); - -int -sign_credential(slurm_ssl_key_ctx_t * ctx, slurm_job_credential_t * cred) -{ - Buf buffer; - int length, rc; - int sigsize = SLURM_SSL_SIGNATURE_LENGTH; - - buffer = init_buf(4096); - pack_job_credential(cred, buffer); - length = get_buf_offset(buffer) - SLURM_SSL_SIGNATURE_LENGTH; - - rc = slurm_ssl_sign(ctx, get_buf_data(buffer), length, - cred->signature, &sigsize); - free_buf(buffer); - - if (rc != 0) - return SLURM_ERROR; - - if (sigsize != SLURM_SSL_SIGNATURE_LENGTH) - error("signature size not correct in ssl_sign!"); - - return SLURM_SUCCESS; -} - - -int -verify_credential(slurm_ssl_key_ctx_t * ctx, slurm_job_credential_t * cred, - List cred_state_list) -{ - int rc; - time_t now = time(NULL); - int length; - Buf buffer; - - buffer = init_buf(4096); - pack_job_credential(cred, buffer); - length = get_buf_offset(buffer) - SLURM_SSL_SIGNATURE_LENGTH; - - rc = slurm_ssl_verify(ctx, get_buf_data(buffer), length, - cred->signature, SLURM_SSL_SIGNATURE_LENGTH); - free_buf(buffer); - - if (rc) { - error("Invalid credential submitted"); - slurm_seterrno_ret(ESLURMD_INVALID_JOB_CREDENTIAL); - } - - if (cred->expiration_time < now) { - error("credential has expired expiration=%lx now=%lx", - (long)cred->expiration_time , (long)now); - slurm_seterrno_ret(ESLURMD_CREDENTIAL_EXPIRED); - } - -#if WE_WANT_TO_CONFIRM_NODELIST_IN_CREDENTIAL - /* FIXME:XXX: if so desired */ - char this_node_name[MAX_NAME_LEN]; - if ((rc = getnodename(this_node_name, MAX_NAME_LEN))) - fatal("slurmd: getnodename: %m"); - - if ( verify_node_name_list ( this_node_name , - credential->node_list ) ) - slurm_seterrno_ret( - ESLURMD_NODE_NAME_NOT_PRESENT_IN_CREDENTIAL); -#endif - - /* XXX: - * need code to check to make sure that only the specified - * number of procs per node are used to launch tasks and not more - */ - - if ((rc = _is_credential_still_valid(cred, cred_state_list))) { - slurm_seterrno_ret(rc); - } - - return SLURM_SUCCESS; -} - -void -print_credential(slurm_job_credential_t * cred) -{ - int i, j = 0; - long long_tmp; - char sig_str[SLURM_SSL_SIGNATURE_LENGTH*4]; - - for (i=0; i<SLURM_SSL_SIGNATURE_LENGTH; i+=sizeof(long)) { - memcpy(&long_tmp, &cred->signature[i], sizeof(long)); - sprintf(&sig_str[(j++)*9], "%8lx ", long_tmp); - } - - info("cred uid:%u job_id:%u time:%lx", - cred->user_id, cred->job_id, (long)cred->expiration_time); - info("cred signature:%s", sig_str); -} - -int -revoke_credential(revoke_credential_msg_t * msg, List list) -{ - time_t now = time(NULL); - uint32_t jobid = msg->job_id; - ListIterator i = NULL; - credential_state_t *state = NULL; - - i = list_iterator_create(list); - - while ( (state = list_next(i)) && (state->job_id != jobid) ) {;} - - list_iterator_destroy(i); - - if (state) { - state->revoked = true; - state->revoke_time = now; - } else - _insert_revoked_credential_state(msg, list); - - return SLURM_SUCCESS; -} - - - -static int -_is_credential_still_valid(slurm_job_credential_t * credential, List list) -{ - uint32_t jobid = credential->job_id; - ListIterator i = NULL; - credential_state_t *state = NULL; - - _clear_expired_revoked_credentials(list); - - i = list_iterator_create(list); - - while ( (state = list_next(i)) && (state->job_id != jobid)) {;} - - list_iterator_destroy(i); - - if (!state) - _insert_credential_state(credential, list); - else if (state->revoked) - return ESLURMD_CREDENTIAL_REVOKED; - - return SLURM_SUCCESS; -} - -void -clear_expired_credentials(List l) -{ - _clear_expired_revoked_credentials(l); -} - -/* - * This function is not thread-safe. However, it should only - * be used from _clear_expired_revoked_credentials(), below, - * which is only called from a single thread. - */ -static char * -_cred_string(uint32_t jobid) -{ - static char buf[256]; - snprintf(buf, sizeof(buf), "job%d", jobid); - return buf; -} - -static void -_print_expired_list(hostlist_t hl) -{ - char buf[1024]; - - xassert(hl != NULL); - - if (!hostlist_count(hl)) - return; - - hostlist_ranged_string(hl, sizeof(buf), buf); - debug2("expired credentials for: %s", buf); -} - -static int -_clear_expired_revoked_credentials(List list) -{ - time_t now = time(NULL); - ListIterator iterator; - credential_state_t *s; - hostlist_t hl = hostlist_create(NULL); - - debug2("clearing expired credentials"); - - iterator = list_iterator_create(list); - while ((s = list_next(iterator))) { - if (now > (s->expiration + EXPIRATION_WINDOW) ) { - hostlist_push(hl, _cred_string(s->job_id)); - list_delete(iterator); - } - } - list_iterator_destroy(iterator); - - _print_expired_list(hl); - hostlist_destroy(hl); - - return SLURM_SUCCESS; -} - -bool -credential_is_cached(List list, uint32_t jobid) -{ - ListIterator i; - credential_state_t *state; - - debug2("checking for cached credential for job %u", jobid); - - i = list_iterator_create(list); - while ( (state = list_next(i)) && (state->job_id != jobid) ) {;} - list_iterator_destroy(i); - - return (state != NULL); -} - -int -initialize_credential_state_list(List * list) -{ - *list = list_create((ListDelF) _free_credential_state); - return SLURM_SUCCESS; -} - -int -destroy_credential_state_list(List list) -{ - list_destroy(list); - return SLURM_SUCCESS; -} - -static int -_init_credential_state(credential_state_t * credential_state, - slurm_job_credential_t * credential) -{ - credential_state->job_id = credential->job_id; - credential_state->expiration = credential->expiration_time; - credential_state->revoked = false; - return SLURM_SUCCESS; -} - -static void -_free_credential_state(void *state) -{ - if (state) { - xfree(state); - } -} - -static int -_insert_credential_state(slurm_job_credential_t * credential, List list) -{ - credential_state_t *s = xmalloc(sizeof(*s)); - - _init_credential_state(s, credential); - list_append(list, s); - - return SLURM_SUCCESS; -} - -int -_insert_revoked_credential_state(revoke_credential_msg_t *msg, List list) -{ - time_t now = time(NULL); - credential_state_t *s = xmalloc(sizeof(*s)); - - s->job_id = msg->job_id; - s->expiration = msg->expiration_time; - s->revoked = true; - s->revoke_time = now; - - list_append(list, s); - return SLURM_SUCCESS; -} - -/* pack_credential_list - * pack a list of credentials into a machine independent format buffer - * IN list - list to credentials to pack - * IN/OUT buffer - existing buffer into which the credential - * information should be stored - */ -void -pack_credential_list(List list, Buf buffer) -{ - ListIterator i = NULL; - credential_state_t *s = NULL; - - i = list_iterator_create(list); - while ((s = list_next(i))) - _pack_one_cred(s, buffer); - list_iterator_destroy(i); -} - -/* unpack_credential_list - * unpack a list of credentials from a machine independent format buffer - * IN/OUT list - existing list onto which the records in - * the buffer are added - * IN buffer - existing buffer from which the credential - * information should be read - * RET int - zero or error code - */ -int -unpack_credential_list(List list, Buf buffer) -{ - credential_state_t *s = NULL; - - do { - s = xmalloc(sizeof(slurm_job_credential_t)); - if (_unpack_one_cred(s, buffer)) { - xfree(s); - return SLURM_ERROR; - } else - list_append(list, s); - } while (remaining_buf(buffer)); - - return SLURM_SUCCESS; -} - -static void -_pack_one_cred(credential_state_t *state, Buf buffer) -{ - pack32(state->job_id, buffer); - pack16(state->revoked, buffer); - pack16(state->procs_allocated, buffer); - pack16(state->total_procs, buffer); - pack_time(state->revoke_time, buffer); - pack_time(state->expiration, buffer); -} - -static int -_unpack_one_cred(credential_state_t *state, Buf buffer) -{ - safe_unpack32(&state->job_id, buffer); - safe_unpack16(&state->revoked, buffer); - safe_unpack16(&state->procs_allocated, buffer); - safe_unpack16(&state->total_procs, buffer); - unpack_time(&state->revoke_time, buffer); - unpack_time(&state->expiration, buffer); - return SLURM_SUCCESS; - - unpack_error: - return SLURM_ERROR; -} diff --git a/src/common/credential_utils.h b/src/common/credential_utils.h deleted file mode 100644 index 9aa76d34b14e9117e0964e3dafbf5e82fd9dc0c7..0000000000000000000000000000000000000000 --- a/src/common/credential_utils.h +++ /dev/null @@ -1,138 +0,0 @@ -/*****************************************************************************\ - * credential_utils.h - slurm authentication credential management functions - ***************************************************************************** - * Written by Kevin Tew <tewk@llnl.gov>, et. al. - * - * 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 _CREDENTIAL_UTILS_H -#define _CREDENTIAL_UTILS_H - -#include <stdint.h> -#include <stdio.h> -#include <openssl/rsa.h> -#include <openssl/evp.h> -#include <openssl/objects.h> -#include <openssl/x509.h> -#include <openssl/err.h> -#include <openssl/pem.h> -#include <openssl/ssl.h> - -#include "src/common/list.h" -#include "src/common/pack.h" -#include "src/common/signature_utils.h" -#include "src/common/slurm_protocol_api.h" - -typedef struct credential_state { - uint32_t job_id; /* job_id this credential corresponds to */ - uint16_t revoked; /* boolean true/false */ - uint16_t procs_allocated; /* number of credential procs running */ - uint16_t total_procs; /* number of procs in credential */ - time_t revoke_time; /* time of revoke - this is informational only - * not used */ - time_t expiration; /* expiration date set at credential creation - * time */ -} credential_state_t; - -/* time to wait after expiration_time before removing credential_state - * from credential_state_list, time in seconds */ -#define EXPIRATION_WINDOW 600 - -/* function prototypes */ -/* initialize_credential_state_list - * called from slurmd_init initializes the List structure pointed to by list - * IN list - type List - * RET int - zero or error code - */ -int initialize_credential_state_list(List * list); - -/* destroy_credential_state_list - * destroys a initialized list - * IN list - type List - * RET int - zero or error code - */ -int destroy_credential_state_list(List list); - -/* print_credential - * log a credential using info() function - */ -void print_credential(slurm_job_credential_t * cred); - -/* verify_credential - * given a credential message and a verify_ctx containing the public key - * this method verifies the credential and creates the necessary state - * objectin the credential_state_list - * IN ctx - slurm ssl public key ctx - * IN cred - credential to verify - * IN l - list to add credential state object to - * RET int - zero or error code - */ -int verify_credential(slurm_ssl_key_ctx_t *ctx, slurm_job_credential_t *cred, - List l); - -/* sign_credential - * signs a credential before transmit - * used by slurmctld - * IN sign_ctx - slurm ssl private key ctx - * IN credential - credential to sign - * RET int - zero or error code - */ -extern int sign_credential(slurm_ssl_key_ctx_t * sign_ctx, - slurm_job_credential_t * credential); - -/* revoke_credential - * expires a credential in the credential_state_list - * IN msg - revoke rpc message - * IN list - list to revoke credential state object in - * RET int - zero or error code - */ -extern int revoke_credential(revoke_credential_msg_t * msg, List list); - -/* pack_credential_list - * pack a list of credentials into a machine independent format buffer - * IN list - list to credentials to pack - * IN/OUT buffer - existing buffer into which the credential - * information should be stored - */ -extern void pack_credential_list(List list, Buf buffer); - -/* unpack_credential_list - * unpack a list of credentials from a machine independent format buffer - * IN/OUT list - existing list into which the credential records - * from the buffer are added - * IN buffer - existing buffer from which the credential - * information should be read - * RET int - zero or error code - */ -extern int unpack_credential_list(List list, Buf buffer); - -/* - * Returns true if credential for job id jobid is already cached in the - * credential state list - */ -bool credential_is_cached(List state_list, uint32_t jobid); - -/* - * Force expiration of expired credentials from the - * state list (l). - */ -void clear_expired_credentials(List l); - -#endif /* !_CREDENTIAL_UTILS_H */ - diff --git a/src/common/pack.h b/src/common/pack.h index 13c1a081135eecd3fcfb3b753ee4d7820bac3c0f..44c6a179feff4f5577a5a091c0272202a363ec3a 100644 --- a/src/common/pack.h +++ b/src/common/pack.h @@ -43,6 +43,7 @@ #include <assert.h> #include <time.h> +#include <string.h> #define BUF_MAGIC 0x42554545 diff --git a/src/common/signature_utils.c b/src/common/signature_utils.c deleted file mode 100644 index 881b4353fd244159464a3dae5a2cd6abb2fab8be..0000000000000000000000000000000000000000 --- a/src/common/signature_utils.c +++ /dev/null @@ -1,152 +0,0 @@ -/*****************************************************************************\ - * signature_utils.c - functions related to job cred signatures - * $Id$ - ***************************************************************************** - * Copyright (C) 2002 The Regents of the University of California. - * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). - * Written by Kevin Tew <tewk@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. -\*****************************************************************************/ -#if HAVE_CONFIG_H -# include "config.h" -#endif - -#include <stdio.h> -#include <openssl/rsa.h> -#include <openssl/evp.h> -#include <openssl/objects.h> -#include <openssl/x509.h> -#include <openssl/err.h> -#include <openssl/pem.h> -#include <openssl/ssl.h> - -#include <slurm/slurm_errno.h> - -#include "src/common/credential_utils.h" -#include "src/common/log.h" -#include "src/common/signature_utils.h" -#include "src/common/slurm_protocol_api.h" -#include "src/common/xmalloc.h" - - -int slurm_ssl_init() -{ - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); - return SLURM_SUCCESS; -} - -int slurm_ssl_destroy() -{ - EVP_cleanup(); - ERR_free_strings(); - return SLURM_SUCCESS; -} - -int slurm_init_signer(slurm_ssl_key_ctx_t * ctx, char *path) -{ - FILE *fp = NULL; - EVP_PKEY *pk = NULL; - int rc = SLURM_SUCCESS; - - if (!(fp = fopen(path, "r"))) { - error ("can't open key file '%s' : %m", path); - return SLURM_ERROR; - }; - - if (PEM_read_PrivateKey(fp, &pk, NULL, NULL)) - ctx->key.private = pk; - else { - error ("PEM_read_PrivateKey [%s]: %m", path); - rc = SLURM_ERROR; - } - fclose(fp); - - if (pk && (EVP_PKEY_size(pk) > SLURM_SSL_SIGNATURE_LENGTH)) { - error ("slurm_ssl_sign: key size too large"); - rc = SLURM_ERROR; - } - - return rc; -} - -int slurm_init_verifier(slurm_ssl_key_ctx_t * ctx, char *path) -{ - FILE *fp = NULL; - int rc = SLURM_SUCCESS; - - if ((fp = fopen(path, "r")) == NULL) { - error ("can't open certificate file '%s' : %m ", path); - return SLURM_ERROR; - } - - ctx->key.public = NULL; - if (!PEM_read_PUBKEY(fp, &ctx->key.public, NULL, NULL)) { - error("PEM_read_PUBKEY[%s]: %m",path); - rc = SLURM_ERROR; - } - fclose(fp); - - return rc; -} - -int slurm_destroy_ssl_key_ctx(slurm_ssl_key_ctx_t * ctx) -{ - if (ctx) EVP_PKEY_free(ctx->key.private); - return SLURM_SUCCESS; -} - - -int -slurm_ssl_sign(slurm_ssl_key_ctx_t *ctx, - char *data, int datalen, char *sig, int *siglen ) -{ - EVP_MD_CTX ectx; - - - EVP_SignInit(&ectx, EVP_sha1()); - - EVP_SignUpdate(&ectx, data, datalen); - - if (!EVP_SignFinal(&ectx, sig, siglen, ctx->key.private)) { - ERR_print_errors_fp(log_fp()); - return SLURM_ERROR; - } - - return SLURM_SUCCESS; -} - -int -slurm_ssl_verify(slurm_ssl_key_ctx_t * ctx, - char *data, int datalen, char *sig, int siglen) -{ - EVP_MD_CTX ectx; - - EVP_VerifyInit(&ectx, EVP_sha1()); - - EVP_VerifyUpdate(&ectx, data, datalen); - - if (!EVP_VerifyFinal(&ectx, sig, siglen, ctx->key.public)) { - error("EVP_VerifyFinal: %s", - ERR_error_string(ERR_get_error(), NULL)); - return SLURM_ERROR; - } - return SLURM_SUCCESS; -} diff --git a/src/common/signature_utils.h b/src/common/signature_utils.h deleted file mode 100644 index b2acbcbdd95fb13cdc8656287bc361b7498c018a..0000000000000000000000000000000000000000 --- a/src/common/signature_utils.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _SIGNATURE_UTILS_H -#define _SIGNATURE_UTILS_H -#include <stdio.h> -#include <openssl/rsa.h> -#include <openssl/evp.h> -#include <openssl/objects.h> -#include <openssl/x509.h> -#include <openssl/err.h> -#include <openssl/pem.h> -#include <openssl/ssl.h> - -#include "src/common/slurm_protocol_api.h" - -enum key_type { SIGNER_PRIVATE_KEY, VERIFIER_PUBLIC_KEY }; -enum { SLURM_OPENSSL_SIGNED = 1 }; -enum { SLURM_OPENSSL_VERIFIED = 1 }; - -typedef struct slurm_ssl_key_ctx { - enum key_type key_type; - unsigned int key_length; - union key { - EVP_PKEY *private; - EVP_PKEY *public; - } key; -} slurm_ssl_key_ctx_t; - -/* slurm_ssl_init - * calls the approriate ssl init functions for crypto functions - * should be called once before using other slurm_ssl functions - * RET - return code - */ -int slurm_ssl_init(); - -/* slurm_ssl_destroy - * calls the approriate ssl destroy fucntions for crypto functions - * should be called right before exit - * RET - return code - */ -int slurm_ssl_destroy(); - -/* slurm_init_signer - * loads a private key to later be used to sign messages - * OUT ctx - context to initialize - * IN path - path to private key - * RET - return code - */ -int slurm_init_signer(slurm_ssl_key_ctx_t * ctx, char *path); - -/* slurm_init_verifier - * loads a public key out of a X509 cert to verify signed messages - * OUT ctx - context to initialize - * IN path - path to certificate - * RET - return code - */ -int slurm_init_verifier(slurm_ssl_key_ctx_t * ctx, char *path); - - -/* slurm_destroy_ssl_key_ctx - * destroys an initialezed ssl_key_ctx - * IN ctx - context to destroy - * RET - return code - */ -int slurm_destroy_ssl_key_ctx(slurm_ssl_key_ctx_t * ctx); - -/* slurm_ssl_sign - * using a private key ctx and a buffer creates a signature in buffer - * - * IN ctx - private key ctx - * IN data_buffer - buffer to sign - * IN data_length - length of data buffer - * OUT signature_buffer - signature - * OUT signature_length - signature length - * RET - return code - */ -int slurm_ssl_sign(slurm_ssl_key_ctx_t * ctx, char *data_buffer, - int data_length, char *signature_buffer, - int *signature_length); - -/* slurm_ssl_verify - * using a public key ctx and a buffer verifies a signature in buffer - * IN ctx - private key ctx - * IN data_buffer - buffer to verify - * IN data_length - length of data buffer - * OUT signature_buffer - signature - * OUT signature_length - signature length - * RET - return code - */ -int slurm_ssl_verify(slurm_ssl_key_ctx_t * ctx, char *data_buffer, - int data_length, char *signature_buffer, - int signature_length); - -#endif diff --git a/src/common/slurm_cred.c b/src/common/slurm_cred.c new file mode 100644 index 0000000000000000000000000000000000000000..49a7e21cf72d8666623020a2c568538a64cdc33f --- /dev/null +++ b/src/common/slurm_cred.c @@ -0,0 +1,1037 @@ +/*****************************************************************************\ + * src/common/slurm_cred.c - SLURM job credential functions + * $Id$ + ***************************************************************************** + * Copyright (C) 2002 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Mark A. 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. +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <slurm/slurm_errno.h> + +#include <stdarg.h> + +/* + * OpenSSL includes + */ +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/err.h> + +#include "src/common/macros.h" +#include "src/common/list.h" +#include "src/common/log.h" +#include "src/common/xmalloc.h" +#include "src/common/xassert.h" +#include "src/common/xstring.h" + +#include "src/common/slurm_cred.h" + +/* + * Default credential information expiration window: + */ +#define DEFAULT_EXPIRATION_WINDOW 600 + +/* + * slurm job credential state + * + */ +typedef struct { + uint32_t jobid; /* SLURM job id for this credential */ + uint32_t stepid; /* SLURM step id for this credential */ + time_t expiration; /* Time at which cred is no longer good */ +} cred_state_t; + +/* + * slurm job state information + * tracks jobids for which all future credentials have been revoked + * + */ +typedef struct { + uint32_t jobid; + bool revoked; /* True if all creds for jobid are revoked */ + time_t ctime; /* Time that this entry was created */ + time_t expiration; /* Time at which credentials were revoked */ +} job_state_t; + + +/* + * Completion of slurm credential context + */ +enum ctx_type { + SLURM_CRED_CREATOR, + SLURM_CRED_VERIFIER +}; + +struct slurm_cred_context { +#ifndef NDEBUG +# define CRED_CTX_MAGIC 0x0c0c0c + int magic; +#endif + enum ctx_type type; /* type of context (creator or verifier) */ + EVP_PKEY *key; /* private or public key */ + List job_list; /* List of used jobids (for verifier) */ + List state_list; /* List of cred states (for verifier) */ + + int expiry_window; /* expiration window for cached creds */ + + EVP_PKEY *exkey; /* Old public key if key is updated */ + time_t exkey_exp; /* Old key expiration time */ +}; + +/* + * Completion of slurm job credential type: + * + */ +struct slurm_job_credential { + uint32_t jobid; /* Job ID associated with this credential */ + uint32_t stepid; /* Job step ID for this credential */ + uid_t uid; /* user for which this cred is valid */ + time_t ctime; /* time of credential creation */ + char *nodes; /* list of hostnames for which the cred is ok*/ + + unsigned char *signature; /* credential signature */ + int siglen; /* signature length in bytes */ +}; + + + +/* + * Static prototypes: + */ + +static slurm_cred_ctx_t _slurm_cred_ctx_alloc(void); +static slurm_cred_t _slurm_cred_alloc(void); + +static int _ctx_update_private_key(slurm_cred_ctx_t ctx, const char *path); +static int _ctx_update_public_key(slurm_cred_ctx_t ctx, const char *path); +static bool _exkey_is_valid(slurm_cred_ctx_t ctx); + +static cred_state_t * _cred_state_create(slurm_cred_ctx_t ctx, slurm_cred_t c); +static job_state_t * _job_state_create(slurm_cred_t c); +static void _cred_state_destroy(cred_state_t *cs); +static void _job_state_destroy(job_state_t *js); + +static job_state_t * _find_job_state(slurm_cred_ctx_t ctx, uint32_t jobid); + +static void _insert_cred_state(slurm_cred_ctx_t ctx, slurm_cred_t cred); +static void _insert_job_state(slurm_cred_ctx_t ctx, slurm_cred_t cred); +static void _clear_expired_job_states(slurm_cred_ctx_t ctx); +static void _clear_expired_credential_states(slurm_cred_ctx_t ctx); +static void _verifier_ctx_init(slurm_cred_ctx_t ctx); + +static bool _credential_replayed(slurm_cred_ctx_t ctx, slurm_cred_t cred); +static bool _credential_revoked(slurm_cred_ctx_t ctx, slurm_cred_t cred); + +static EVP_PKEY * _read_private_key(const char *path); +static EVP_PKEY * _read_public_key(const char *path); + +static int _slurm_cred_sign(slurm_cred_ctx_t ctx, slurm_cred_t cred); +static int _slurm_cred_verify_signature(slurm_cred_ctx_t ctx, slurm_cred_t c); + +static job_state_t * _job_state_unpack_one(Buf buffer); +static cred_state_t * _cred_state_unpack_one(Buf buffer); + +static void _pack_cred(slurm_cred_t cred, Buf buffer); +static void _job_state_unpack(slurm_cred_ctx_t ctx, Buf buffer); +static void _job_state_pack(slurm_cred_ctx_t ctx, Buf buffer); +static void _cred_state_unpack(slurm_cred_ctx_t ctx, Buf buffer); +static void _cred_state_pack(slurm_cred_ctx_t ctx, Buf buffer); +static void _job_state_pack_one(job_state_t *j, Buf buffer); +static void _cred_state_pack_one(cred_state_t *s, Buf buffer); + + + +slurm_cred_ctx_t +slurm_cred_creator_ctx_create(const char *path) +{ + slurm_cred_ctx_t ctx = NULL; + + xassert(path != NULL); + + ctx = _slurm_cred_ctx_alloc(); + + ctx->type = SLURM_CRED_CREATOR; + + if (!(ctx->key = _read_private_key(path))) + goto fail; + + return ctx; + + fail: + xfree(ctx); + return NULL; +} + + +slurm_cred_ctx_t +slurm_cred_verifier_ctx_create(const char *path) +{ + slurm_cred_ctx_t ctx = NULL; + + xassert(path != NULL); + + ctx = _slurm_cred_ctx_alloc(); + ctx->type = SLURM_CRED_VERIFIER; + + if (!(ctx->key = _read_public_key(path))) + goto fail; + + _verifier_ctx_init(ctx); + return ctx; + + fail: + xfree(ctx); + return NULL; +} + + +void +slurm_cred_ctx_destroy(slurm_cred_ctx_t ctx) +{ + if (ctx == NULL) + return; + + xassert(ctx->magic == CRED_CTX_MAGIC); + + if (ctx->key) + EVP_PKEY_free(ctx->key); + if (ctx->job_list) + list_destroy(ctx->job_list); + if (ctx->state_list) + list_destroy(ctx->state_list); + + xassert(ctx->magic = ~CRED_CTX_MAGIC); + + xfree(ctx); + + return; +} + +int +slurm_cred_ctx_set(slurm_cred_ctx_t ctx, slurm_cred_opt_t opt, ...) +{ + int rc = SLURM_SUCCESS; + va_list ap; + + va_start(ap, opt); + + switch (opt) { + case SLURM_CRED_OPT_EXPIRY_WINDOW: + ctx->expiry_window = va_arg(ap, int); + break; + default: + slurm_seterrno(EINVAL); + rc = SLURM_ERROR; + break; + } + + va_end(ap); + + return rc; +} + +int +slurm_cred_ctx_get(slurm_cred_ctx_t ctx, slurm_cred_opt_t opt, ...) +{ + int rc = SLURM_SUCCESS; + va_list ap; + int *intp; + + va_start(ap, opt); + + switch (opt) { + case SLURM_CRED_OPT_EXPIRY_WINDOW: + intp = va_arg(ap, int *); + *intp = ctx->expiry_window; + break; + default: + slurm_seterrno(EINVAL); + rc = SLURM_ERROR; + break; + } + + va_end(ap); + + return rc; +} + +int +slurm_cred_ctx_key_update(slurm_cred_ctx_t ctx, const char *path) +{ + if (ctx->type == SLURM_CRED_CREATOR) + return _ctx_update_private_key(ctx, path); + else + return _ctx_update_public_key(ctx, path); + +} + + +slurm_cred_t +slurm_cred_create(slurm_cred_ctx_t ctx, slurm_cred_arg_t *arg) +{ + slurm_cred_t cred = NULL; + + xassert(ctx != NULL); + xassert(arg != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_CREATOR); + + cred = _slurm_cred_alloc(); + + cred->jobid = arg->jobid; + cred->stepid = arg->stepid; + cred->uid = arg->uid; + cred->nodes = xstrdup(arg->hostlist); + cred->ctime = time(NULL); + + if (_slurm_cred_sign(ctx, cred) < 0) + goto fail; + + return cred; + + fail: + slurm_cred_destroy(cred); + return NULL; +} + + +int +slurm_cred_verify(slurm_cred_ctx_t ctx, slurm_cred_t cred, + slurm_cred_arg_t *arg) +{ + time_t now = time(NULL); + + xassert(ctx != NULL); + xassert(cred != NULL); + xassert(arg != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_VERIFIER); + + if (_slurm_cred_verify_signature(ctx, cred) < 0) + slurm_seterrno_ret(ESLURMD_INVALID_JOB_CREDENTIAL); + + if (now > (cred->ctime + ctx->expiry_window)) + slurm_seterrno_ret(ESLURMD_CREDENTIAL_EXPIRED); + + if (_credential_revoked(ctx, cred)) + slurm_seterrno_ret(ESLURMD_CREDENTIAL_REVOKED); + + if (_credential_replayed(ctx, cred)) + slurm_seterrno_ret(ESLURMD_CREDENTIAL_REPLAYED); + + /* + * set arguments to cred contents + */ + arg->jobid = cred->jobid; + arg->stepid = cred->stepid; + arg->uid = cred->uid; + arg->hostlist = xstrdup(cred->nodes); + + return SLURM_SUCCESS; +} + + +void +slurm_cred_destroy(slurm_cred_t cred) +{ + if (cred == NULL) + return; + + if (cred->nodes) + xfree(cred->nodes); + if (cred->signature) + xfree(cred->signature); + xfree(cred); +} + + +bool +slurm_cred_jobid_cached(slurm_cred_ctx_t ctx, uint32_t jobid) +{ + xassert(ctx != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_VERIFIER); + + _clear_expired_job_states(ctx); + + /* + * Return true if we find a cached job state for job id `jobid' + */ + return (_find_job_state(ctx, jobid) != NULL); +} + + +int +slurm_cred_revoke(slurm_cred_ctx_t ctx, uint32_t jobid) +{ + job_state_t *j = NULL; + + xassert(ctx != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_VERIFIER); + + _clear_expired_job_states(ctx); + + if (!(j = _find_job_state(ctx, jobid))) + slurm_seterrno_ret(ESRCH); + + j->revoked = true; + j->expiration = time(NULL) + ctx->expiry_window; + + return SLURM_SUCCESS; +} + +int +slurm_cred_get_signature(slurm_cred_t cred, char *data, int *datalen) +{ + data = cred->signature; + *datalen = cred->siglen; + return SLURM_SUCCESS; +} + +void +slurm_cred_pack(slurm_cred_t cred, Buf buffer) +{ + _pack_cred(cred, buffer); + packmem(cred->signature, (uint16_t) cred->siglen, buffer); + return; +} + +slurm_cred_t +slurm_cred_unpack(Buf buffer) +{ + uint16_t len; + slurm_cred_t cred = NULL; + char **sigp; + + xassert(buffer != NULL); + + cred = _slurm_cred_alloc(); + + sigp = (char **) &cred->signature; + + safe_unpack32( &cred->jobid, buffer); + safe_unpack32( &cred->stepid, buffer); + safe_unpack32( &cred->uid, buffer); + safe_unpackstr_xmalloc( &cred->nodes, &len, buffer); + safe_unpack_time( &cred->ctime, buffer); + safe_unpackmem_xmalloc( sigp, &len, buffer); + + cred->siglen = len; + + return cred; + + unpack_error: + slurm_cred_destroy(cred); + return NULL; +} + +int +slurm_cred_ctx_pack(slurm_cred_ctx_t ctx, Buf buffer) +{ + _job_state_pack(ctx, buffer); + _cred_state_pack(ctx, buffer); + + return SLURM_SUCCESS; +} + +int +slurm_cred_ctx_unpack(slurm_cred_ctx_t ctx, Buf buffer) +{ + xassert(ctx != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_VERIFIER); + + /* + * Unpack job state list and cred state list from buffer + * appening them onto ctx->state_list and ctx->job_list. + */ + _job_state_unpack(ctx, buffer); + _cred_state_unpack(ctx, buffer); + + return SLURM_SUCCESS; +} + +void +slurm_cred_print(slurm_cred_t cred) +{ + if (cred == NULL) + return; + + info("Cred: Jobid %u", cred->jobid ); + info("Cred: Stepid %u", cred->jobid ); + info("Cred: UID %lu", cred->uid ); + info("Cred: Nodes %s", cred->nodes ); + info("Cred: ctime %s", ctime(&cred->ctime) ); + info("Cred: siglen %d", cred->siglen ); + +} + + +static EVP_PKEY * +_read_private_key(const char *path) +{ + FILE *fp = NULL; + EVP_PKEY *pk = NULL; + + xassert(path != NULL); + + if (!(fp = fopen(path, "r"))) { + error ("can't open key file '%s' : %m", path); + return NULL; + } + + if (!PEM_read_PrivateKey(fp, &pk, NULL, NULL)) + error ("PEM_read_PrivateKey [%s]: %m", path); + + fclose(fp); + + return pk; +} + + +static EVP_PKEY * +_read_public_key(const char *path) +{ + FILE *fp = NULL; + EVP_PKEY *pk = NULL; + + xassert(path != NULL); + + if ((fp = fopen(path, "r")) == NULL) { + error ("can't open public key '%s' : %m ", path); + return NULL; + } + + if (!PEM_read_PUBKEY(fp, &pk, NULL, NULL)) + error("PEM_read_PUBKEY[%s]: %m", path); + + fclose(fp); + + return pk; +} + + +static void +_verifier_ctx_init(slurm_cred_ctx_t ctx) +{ + xassert(ctx != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_VERIFIER); + + ctx->job_list = list_create((ListDelF) _job_state_destroy); + ctx->state_list = list_create((ListDelF) _cred_state_destroy); + + return; +} + + +static int +_ctx_update_private_key(slurm_cred_ctx_t ctx, const char *path) +{ + EVP_PKEY *pk = NULL; + EVP_PKEY *tmpk = NULL; + + xassert(ctx != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_CREATOR); + + if (!(pk = _read_private_key(path))) + return SLURM_ERROR; + + tmpk = ctx->key; + ctx->key = pk; + + EVP_PKEY_free(tmpk); + + return SLURM_SUCCESS; +} + + +static int +_ctx_update_public_key(slurm_cred_ctx_t ctx, const char *path) +{ + EVP_PKEY *pk = NULL; + + xassert(ctx != NULL); + xassert(ctx->magic == CRED_CTX_MAGIC); + xassert(ctx->type == SLURM_CRED_VERIFIER); + + if (!(pk = _read_public_key(path))) + return SLURM_ERROR; + + if (ctx->exkey) + EVP_PKEY_free(ctx->exkey); + + ctx->exkey = ctx->key; + ctx->key = pk; + + /* + * exkey expires in expiry_window seconds. + * This should be long enough to capture any keys in-flight. + */ + ctx->exkey_exp = time(NULL) + ctx->expiry_window; + + return SLURM_SUCCESS; +} + + +static bool +_exkey_is_valid(slurm_cred_ctx_t ctx) +{ + time_t now = time(NULL); + + if (!ctx->exkey) return false; + + if (now > ctx->exkey_exp) { + EVP_PKEY_free(ctx->exkey); + ctx->exkey = NULL; + return false; + } + + return true; +} + + +static slurm_cred_ctx_t +_slurm_cred_ctx_alloc(void) +{ + slurm_cred_ctx_t ctx = xmalloc(sizeof(*ctx)); + + ctx->key = NULL; + ctx->job_list = NULL; + ctx->state_list = NULL; + ctx->expiry_window = DEFAULT_EXPIRATION_WINDOW; + + ctx->exkey = NULL; + ctx->exkey_exp = (time_t) -1; + + xassert(ctx->magic = CRED_CTX_MAGIC); + + return ctx; +} + +static slurm_cred_t +_slurm_cred_alloc(void) +{ + slurm_cred_t cred = xmalloc(sizeof(*cred)); + + cred->jobid = 0; + cred->stepid = 0; + cred->uid = (uid_t) -1; + cred->nodes = NULL; + cred->signature = NULL; + cred->siglen = 0; + + return cred; +} + +static const char * +_ssl_error(void) +{ + return ERR_reason_error_string(ERR_get_error()); +} + +static void +_print_data(char *data, int datalen) +{ + char buf[1024]; + size_t len = 0; + int i; + + for (i = 0; i < datalen; i += sizeof(char)) + len += sprintf(buf+len, "%02x", data[i]); +} + +static int +_slurm_cred_sign(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + EVP_MD_CTX ectx; + Buf buffer; + int rc = SLURM_SUCCESS; + int *lenp = &cred->siglen; + int ksize = EVP_PKEY_size(ctx->key); + + /* + * Allocate memory for signature: at most EVP_PKEY_size() bytes + */ + cred->signature = xmalloc(ksize * sizeof(unsigned char)); + + buffer = init_buf(4096); + _pack_cred(cred, buffer); + + EVP_SignInit(&ectx, EVP_sha1()); + EVP_SignUpdate(&ectx, get_buf_data(buffer), get_buf_offset(buffer)); + + if (!(EVP_SignFinal(&ectx, cred->signature, lenp, ctx->key))) { + ERR_print_errors_fp(log_fp()); + rc = SLURM_ERROR; + } + + free_buf(buffer); + + return rc; +} + +static int +_slurm_cred_verify_signature(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + EVP_MD_CTX ectx; + Buf buffer; + int rc; + unsigned char *sig = cred->signature; + int siglen = cred->siglen; + + buffer = init_buf(4096); + _pack_cred(cred, buffer); + + EVP_VerifyInit(&ectx, EVP_sha1()); + EVP_VerifyUpdate(&ectx, get_buf_data(buffer), get_buf_offset(buffer)); + + if (!(rc = EVP_VerifyFinal(&ectx, sig, siglen, ctx->key))) { + /* + * Check against old key if one exists and is valid + */ + if (_exkey_is_valid(ctx)) + rc = EVP_VerifyFinal(&ectx, sig, siglen, ctx->exkey); + } + + if (!rc) { + ERR_load_crypto_strings(); + error("EVP_VerifyFinal: %s", _ssl_error()); + ERR_free_strings(); + rc = SLURM_ERROR; + } else + rc = SLURM_SUCCESS; + + free_buf(buffer); + + return rc; +} + + +static void +_pack_cred(slurm_cred_t cred, Buf buffer) +{ + pack32( cred->jobid, buffer); + pack32( cred->stepid, buffer); + pack32( cred->uid, buffer); + packstr( cred->nodes, buffer); + pack_time( cred->ctime, buffer); +} + + +static bool +_credential_replayed(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + ListIterator i = NULL; + cred_state_t *s = NULL; + + _clear_expired_credential_states(ctx); + + i = list_iterator_create(ctx->state_list); + + while ((s = list_next(i))) { + if ((s->jobid == cred->jobid) && (s->stepid == cred->stepid)) + break; + } + + list_iterator_destroy(i); + + /* + * If we found a match, this credential is being replayed. + */ + if (s) return true; + + /* + * Otherwise, save the credential state + */ + _insert_cred_state(ctx, cred); + return false; +} + + +static bool +_credential_revoked(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + job_state_t *j = NULL; + + _clear_expired_job_states(ctx); + + if (!(j = _find_job_state(ctx, cred->jobid))) + _insert_job_state(ctx, cred); + else if (j->revoked) + return true; + + return false; +} + + +static job_state_t * +_find_job_state(slurm_cred_ctx_t ctx, uint32_t jobid) +{ + ListIterator i = NULL; + job_state_t *j = NULL; + + i = list_iterator_create(ctx->job_list); + while ((j = list_next(i)) && (j->jobid != jobid)) {;} + list_iterator_destroy(i); + return j; +} + + +static void +_insert_job_state(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + job_state_t *j = _job_state_create(cred); + list_append(ctx->job_list, j); +} + + +static job_state_t * +_job_state_create(slurm_cred_t cred) +{ + job_state_t *j = xmalloc(sizeof(*j)); + + j->jobid = cred->jobid; + j->revoked = false; + j->ctime = time(NULL); + j->expiration = (time_t) -1; + + return j; +} + +static void +_job_state_destroy(job_state_t *j) +{ + xfree(j); +} + + +static void +_clear_expired_job_states(slurm_cred_ctx_t ctx) +{ + time_t now = time(NULL); + ListIterator i = NULL; + job_state_t *j = NULL; + + i = list_iterator_create(ctx->job_list); + + while ((j = list_next(i))) { + if (j->revoked && (now > j->expiration)) + list_delete(i); + } + + list_iterator_destroy(i); +} + + +static void +_clear_expired_credential_states(slurm_cred_ctx_t ctx) +{ + time_t now = time(NULL); + ListIterator i = NULL; + cred_state_t *s = NULL; + + i = list_iterator_create(ctx->state_list); + + while ((s = list_next(i))) { + if (now > s->expiration) + list_delete(i); + } + + list_iterator_destroy(i); +} + + +static void +_insert_cred_state(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + cred_state_t *s = _cred_state_create(ctx, cred); + list_append(ctx->state_list, s); +} + + +static cred_state_t * +_cred_state_create(slurm_cred_ctx_t ctx, slurm_cred_t cred) +{ + cred_state_t *s = xmalloc(sizeof(*s)); + + s->jobid = cred->jobid; + s->stepid = cred->stepid; + s->expiration = cred->ctime + ctx->expiry_window; + + return s; +} + +static void +_cred_state_destroy(cred_state_t *s) +{ + xfree(s); +} + + +static void +_cred_state_pack_one(cred_state_t *s, Buf buffer) +{ + pack32(s->jobid, buffer); + pack32(s->stepid, buffer); + pack_time(s->expiration, buffer); +} + + +static cred_state_t * +_cred_state_unpack_one(Buf buffer) +{ + cred_state_t *s = xmalloc(sizeof(*s)); + + safe_unpack32(&s->jobid, buffer); + safe_unpack32(&s->stepid, buffer); + safe_unpack_time(&s->expiration, buffer); + return s; + + unpack_error: + _cred_state_destroy(s); + return NULL; +} + + +static void +_job_state_pack_one(job_state_t *j, Buf buffer) +{ + pack32(j->jobid, buffer); + pack16((uint16_t) j->revoked, buffer); + pack_time(j->ctime, buffer); + pack_time(j->expiration, buffer); + + _print_data(buffer->head, buffer->processed); +} + + +static job_state_t * +_job_state_unpack_one(Buf buffer) +{ + uint16_t revoked = 0; + job_state_t *j = xmalloc(sizeof(*j)); + + safe_unpack32( &j->jobid, buffer); + safe_unpack16( &revoked, buffer); + safe_unpack_time( &j->ctime, buffer); + safe_unpack_time( &j->expiration, buffer); + + if (revoked) j->revoked = true; + + return j; + + unpack_error: + _job_state_destroy(j); + return NULL; +} + + +static void +_cred_state_pack(slurm_cred_ctx_t ctx, Buf buffer) +{ + ListIterator i = NULL; + cred_state_t *s = NULL; + + pack32(list_count(ctx->state_list), buffer); + + i = list_iterator_create(ctx->state_list); + while ((s = list_next(i))) + _cred_state_pack_one(s, buffer); + list_iterator_destroy(i); +} + + +static void +_cred_state_unpack(slurm_cred_ctx_t ctx, Buf buffer) +{ + time_t now = time(NULL); + int n = 0; + int i = 0; + cred_state_t *s = NULL; + + safe_unpack32(&n, buffer); + + for (i = 0; i < n; i++) { + if (!(s = _cred_state_unpack_one(buffer))) + goto unpack_error; + + if (now < s->expiration) + list_append(ctx->state_list, s); + } + + return; + + unpack_error: + error("Unable to unpack job credential state information"); + return; +} + + +static void +_job_state_pack(slurm_cred_ctx_t ctx, Buf buffer) +{ + ListIterator i = NULL; + job_state_t *j = NULL; + + pack32((uint32_t) list_count(ctx->job_list), buffer); + + + i = list_iterator_create(ctx->job_list); + while ((j = list_next(i))) + _job_state_pack_one(j, buffer); + list_iterator_destroy(i); +} + + +static void +_job_state_unpack(slurm_cred_ctx_t ctx, Buf buffer) +{ + time_t now = time(NULL); + uint32_t n = 0; + int i = 0; + job_state_t *j = NULL; + + safe_unpack32(&n, buffer); + + for (i = 0; i < n; i++) { + if (!(j = _job_state_unpack_one(buffer))) + goto unpack_error; + + if (j->revoked && (now < j->expiration)) + list_append(ctx->job_list, j); + } + + return; + + unpack_error: + error("Unable to unpack job state information"); + return; +} + + diff --git a/src/common/slurm_cred.h b/src/common/slurm_cred.h new file mode 100644 index 0000000000000000000000000000000000000000..78e585699c71cbf3c3abafce11cf1489e447ac31 --- /dev/null +++ b/src/common/slurm_cred.h @@ -0,0 +1,183 @@ +/*****************************************************************************\ + * src/common/slurm_cred.h - SLURM job credential operations + * $Id$ + ***************************************************************************** + * Copyright (C) 2002 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by AUTHOR <AUTHOR@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 _HAVE_SLURM_CRED_H +#define _HAVE_SLURM_CRED_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include "src/common/pack.h" + +/* + * The incomplete slurm_cred_t type is also defined in slurm.h for + * users of the api, so check to ensure that this header has not been + * included after slurm.h: + */ +#ifndef __slurm_cred_t_defined +# define __slurm_cred_t_defined + typedef struct slurm_job_credential * slurm_cred_t; +#endif + +/* + * The slurm_cred_ctx_t incomplete type + */ +typedef struct slurm_cred_context * slurm_cred_ctx_t; + + +/* + * Initialize current process for slurm credential creation. + * + * `privkey' contains the absolute path to the slurmctld private + * key, which needs to be readable by the current process. + * + * Returns 0 for success, -1 on failure and sets errno to reason. + * + * + */ +slurm_cred_ctx_t slurm_cred_creator_ctx_create(const char *privkey); + +/* + * Initialize current process for slurm credential verification. + * `pubkey' contains the absolute path to the slurmctld public key. + * + * Returns 0 for success, -1 on failure. + */ +slurm_cred_ctx_t slurm_cred_verifier_ctx_create(const char *pubkey); + +/* + * Set and get credential context options + * + */ +typedef enum { + SLURM_CRED_OPT_EXPIRY_WINDOW /* expiration time of creds (int ); */ +} slurm_cred_opt_t; + +int slurm_cred_ctx_set(slurm_cred_ctx_t ctx, slurm_cred_opt_t opt, ...); +int slurm_cred_ctx_get(slurm_cred_ctx_t ctx, slurm_cred_opt_t opt, ...); + +/* + * Update the context's current key. + */ +int slurm_cred_ctx_key_update(slurm_cred_ctx_t ctx, const char *keypath); + + +/* + * Destroy a credential context, freeing associated memory. + */ +void slurm_cred_ctx_destroy(slurm_cred_ctx_t ctx); + +/* + * Pack and unpack slurm credential context. + * + * On pack() ctx is packed in machine-independent format into the + * buffer, on unpack() the contents of the buffer are used to + * intialize the state of the context ctx. + */ +int slurm_cred_ctx_pack(slurm_cred_ctx_t ctx, Buf buffer); +int slurm_cred_ctx_unpack(slurm_cred_ctx_t ctx, Buf buffer); + + +/* + * Container for SLURM credential create and verify arguments: + */ +typedef struct { + uint32_t jobid; + uint32_t stepid; + uid_t uid; + char *hostlist; +} slurm_cred_arg_t; + +/* + * Create a slurm credential using the values in `arg.' + * The credential is signed using the creators public key. + * + * `arg' must be non-NULL and have valid values. The arguments + * will be copied as is into the slurm job credential. + * + * Returns NULL on failure. + */ +slurm_cred_t slurm_cred_create(slurm_cred_ctx_t ctx, slurm_cred_arg_t *arg); + +/* + * Verify the signed credential `cred,' and return cred contents in + * the cred_arg structure. The credential is cached and cannot be reused. + * + */ +int slurm_cred_verify(slurm_cred_ctx_t ctx, slurm_cred_t cred, + slurm_cred_arg_t *arg); + +/* + * Revoke all credentials for job id jobid + */ +int slurm_cred_revoke(slurm_cred_ctx_t ctx, uint32_t jobid); + + +/* + * Returns true if the credential context has a cached state for + * job id jobid. + */ +bool slurm_cred_jobid_cached(slurm_cred_ctx_t ctx, uint32_t jobid); + + +/* Free memory associated with slurm credential `cred.' + */ +void slurm_cred_destroy(slurm_cred_t cred); + +/* + * Pack a slurm credential for network transmission + */ +void slurm_cred_pack(slurm_cred_t cred, Buf buffer); + +/* + * Unpack a slurm job credential + */ +slurm_cred_t slurm_cred_unpack(Buf buffer); + +/* + * Get a pointer to the slurm credential signature + * (used by slurm IO connections to verify connecting agent) + */ +int slurm_cred_get_signature(slurm_cred_t cred, char *data, int *len); + + +/* + * Print a slurm job credential using the info() call + */ +void slurm_cred_print(slurm_cred_t cred); + + +#endif /* _HAVE_SLURM_CREDS_H */ diff --git a/src/common/slurm_errno.c b/src/common/slurm_errno.c index 978eeeb80694282af344dac8890c0f9eb5a1b0bf..0f9d9326c84c21fa9ea2ab9d0d27533174d68f94 100644 --- a/src/common/slurm_errno.c +++ b/src/common/slurm_errno.c @@ -181,7 +181,11 @@ static slurm_errtab_t slurm_errtab[] = { { ESLURMD_INVALID_JOB_CREDENTIAL, "Invalid job credential" }, { ESLURMD_CREDENTIAL_REVOKED, - "Job credential revoked" }, + "Job credential revoked" }, + { ESLURMD_CREDENTIAL_EXPIRED, + "Job credential expired" }, + { ESLURMD_CREDENTIAL_REPLAYED, + "Job credential replayed" }, { ESLURMD_CREATE_BATCH_DIR_ERROR, "Slurmd could not create a batch directory" }, { ESLURMD_MODIFY_BATCH_DIR_ERROR, diff --git a/src/common/slurm_protocol_defs.c b/src/common/slurm_protocol_defs.c index 80e71f486f98c1ed4e37ed7e1d42d1bd50df3fe8..975f15c863597a9db3bfa6a1579cd2f681a74534 100644 --- a/src/common/slurm_protocol_defs.c +++ b/src/common/slurm_protocol_defs.c @@ -37,6 +37,7 @@ #include <stdio.h> #include "src/common/log.h" +#include "src/common/slurm_cred.h" #include "src/common/slurm_protocol_defs.h" #include "src/common/xmalloc.h" @@ -233,32 +234,35 @@ void slurm_free_task_exit_msg(task_exit_msg_t * msg) void slurm_free_launch_tasks_request_msg(launch_tasks_request_msg_t * msg) { int i; - if (msg) { - xfree(msg->credential); - if (msg->env) { - for (i = 0; i < msg->envc; i++) { - xfree(msg->env[i]); - } - xfree(msg->env); + if (msg == NULL) + return; + + + slurm_cred_destroy(msg->cred); + + if (msg->env) { + for (i = 0; i < msg->envc; i++) { + xfree(msg->env[i]); } - xfree(msg->cwd); - if (msg->argv) { - for (i = 0; i < msg->argc; i++) { - xfree(msg->argv[i]); - } - xfree(msg->argv); + xfree(msg->env); + } + xfree(msg->cwd); + if (msg->argv) { + for (i = 0; i < msg->argc; i++) { + xfree(msg->argv[i]); } - xfree(msg->global_task_ids); - xfree(msg->ofname); - xfree(msg->ofname); - xfree(msg->ofname); + xfree(msg->argv); + } + xfree(msg->global_task_ids); + xfree(msg->ofname); + xfree(msg->ofname); + xfree(msg->ofname); -# ifdef HAVE_LIBELAN3 - qsw_free_jobinfo(msg->qsw_job); -# endif +# ifdef HAVE_LIBELAN3 + qsw_free_jobinfo(msg->qsw_job); +# endif - xfree(msg); - } + xfree(msg); } void slurm_free_reattach_tasks_request_msg(reattach_tasks_request_msg_t *msg) diff --git a/src/common/slurm_protocol_defs.h b/src/common/slurm_protocol_defs.h index f9d6a3940492d5555cda68f1ffba76cf93b56cc2..cafb33c440ac436c3c952fd3f13c27d57533277c 100644 --- a/src/common/slurm_protocol_defs.h +++ b/src/common/slurm_protocol_defs.h @@ -256,7 +256,7 @@ typedef struct launch_tasks_request_msg { int32_t slurmd_debug; /* remote slurmd debug level */ - slurm_job_credential_t *credential; /* job credential */ + slurm_cred_t cred; /* job credential */ #ifdef HAVE_LIBELAN3 qsw_jobinfo_t qsw_job; /* Elan3 switch context */ @@ -287,7 +287,6 @@ typedef struct revoke_credential_msg { uint32_t job_id; uint32_t job_uid; time_t expiration_time; - char signature[SLURM_SSL_SIGNATURE_LENGTH]; } revoke_credential_msg_t; typedef struct job_time_msg { diff --git a/src/common/slurm_protocol_pack.c b/src/common/slurm_protocol_pack.c index a28087b6e408611ac999d83ae31b68bfd8ee82d8..a9208e026634f6254891d696629f585eb88e44d3 100644 --- a/src/common/slurm_protocol_pack.c +++ b/src/common/slurm_protocol_pack.c @@ -37,6 +37,7 @@ #include "src/common/log.h" #include "src/common/pack.h" #include "src/common/slurm_auth.h" +#include "src/common/slurm_cred.h" #include "src/common/slurm_protocol_api.h" #include "src/common/slurm_protocol_defs.h" #include "src/common/slurm_protocol_pack.h" @@ -889,7 +890,7 @@ static void pack16(msg->node_cnt, buffer); _pack_slurm_addr_array(msg->node_addr, msg->node_cnt, buffer); - pack_job_credential(msg->credentials, buffer); + slurm_cred_pack(msg->cred, buffer); #ifdef HAVE_LIBELAN3 qsw_pack_jobinfo(msg->qsw_job, buffer); #endif @@ -938,7 +939,7 @@ static int } else tmp_ptr->node_addr = NULL; - if (unpack_job_credential(&tmp_ptr->credentials, buffer)) + if (!(tmp_ptr->cred = slurm_cred_unpack(buffer))) goto unpack_error; #ifdef HAVE_LIBELAN3 qsw_alloc_jobinfo(&tmp_ptr->qsw_job); @@ -1157,8 +1158,6 @@ _pack_revoke_credential_msg(revoke_credential_msg_t * msg, Buf buffer) pack32(msg->job_id, buffer); pack32(msg->job_uid, buffer); pack_time(msg->expiration_time, buffer); - packmem_array(msg->signature, - (uint32_t) SLURM_SSL_SIGNATURE_LENGTH, buffer); } static int @@ -1168,14 +1167,12 @@ _unpack_revoke_credential_msg(revoke_credential_msg_t ** msg, Buf buffer) /* alloc memory for structure */ assert(msg); - tmp_ptr = xmalloc(sizeof(slurm_job_credential_t)); + tmp_ptr = xmalloc(sizeof(*tmp_ptr)); *msg = tmp_ptr; safe_unpack32(&(tmp_ptr->job_id), buffer); safe_unpack32(&(tmp_ptr->job_uid), buffer); safe_unpack_time(& (tmp_ptr->expiration_time), buffer); - safe_unpackmem_array(tmp_ptr->signature, - (uint32_t) SLURM_SSL_SIGNATURE_LENGTH, buffer); return SLURM_SUCCESS; @@ -1214,58 +1211,6 @@ _unpack_update_job_time_msg(job_time_msg_t ** msg, Buf buffer) return SLURM_ERROR; } -/* pack_job_credential - * packs a slurm job credential - * IN cred - pointer to the credential - * IN/OUT buffer - destination of the pack, contains pointers that are - * automatically updated - */ -void -pack_job_credential(slurm_job_credential_t * cred, Buf buffer) -{ - assert(cred != NULL); - - pack32(cred->job_id, buffer); - pack16((uint16_t) cred->user_id, buffer); - packstr(cred->node_list, buffer); - pack_time(cred->expiration_time, buffer); - packmem_array(cred->signature, - (uint32_t) SLURM_SSL_SIGNATURE_LENGTH, buffer); -} - -/* unpack_job_credential - * unpacks a slurm job credential - * OUT cred - pointer to the credential pointer - * IN/OUT buffer - source of the unpack, contains pointers that are - * automatically updated - * RET 0 or error code - */ -int -unpack_job_credential(slurm_job_credential_t ** cred, Buf buffer) -{ - uint16_t uint16_tmp; - slurm_job_credential_t *tmp_ptr; - - /* alloc memory for structure */ - tmp_ptr = xmalloc(sizeof(slurm_job_credential_t)); - *cred = tmp_ptr; - - safe_unpack32(&(tmp_ptr->job_id), buffer); - safe_unpack16((uint16_t *) & (tmp_ptr->user_id), buffer); - safe_unpackstr_xmalloc(&(tmp_ptr->node_list), &uint16_tmp, buffer); - safe_unpack_time(&(tmp_ptr->expiration_time), buffer); - safe_unpackmem_array(tmp_ptr->signature, - (uint32_t) SLURM_SSL_SIGNATURE_LENGTH, buffer); - - return SLURM_SUCCESS; - - unpack_error: - xfree(tmp_ptr->node_list); - xfree(tmp_ptr); - *cred = NULL; - return SLURM_ERROR; -} - static void _pack_job_step_create_response_msg(job_step_create_response_msg_t * msg, Buf buffer) @@ -1274,7 +1219,7 @@ _pack_job_step_create_response_msg(job_step_create_response_msg_t * msg, pack32(msg->job_step_id, buffer); packstr(msg->node_list, buffer); - pack_job_credential(msg->credentials, buffer); + slurm_cred_pack(msg->cred, buffer); #ifdef HAVE_LIBELAN3 qsw_pack_jobinfo(msg->qsw_job, buffer); #endif @@ -1295,7 +1240,7 @@ _unpack_job_step_create_response_msg(job_step_create_response_msg_t ** msg, safe_unpack32(&tmp_ptr->job_step_id, buffer); safe_unpackstr_xmalloc(&tmp_ptr->node_list, &uint16_tmp, buffer); - if (unpack_job_credential(&tmp_ptr->credentials, buffer)) + if (!(tmp_ptr->cred = slurm_cred_unpack(buffer))) goto unpack_error; #ifdef HAVE_LIBELAN3 @@ -2061,7 +2006,7 @@ _pack_launch_tasks_request_msg(launch_tasks_request_msg_t * msg, Buf buffer) pack32(msg->nprocs, buffer); pack32(msg->uid, buffer); pack32(msg->srun_node_id, buffer); - pack_job_credential(msg->credential, buffer); + slurm_cred_pack(msg->cred, buffer); pack32(msg->tasks_to_launch, buffer); packstr_array(msg->env, msg->envc, buffer); packstr(msg->cwd, buffer); @@ -2097,7 +2042,7 @@ _unpack_launch_tasks_request_msg(launch_tasks_request_msg_t ** safe_unpack32(&msg->nprocs, buffer); safe_unpack32(&msg->uid, buffer); safe_unpack32(&msg->srun_node_id, buffer); - if (unpack_job_credential(&msg->credential, buffer)) + if (!(msg->cred = slurm_cred_unpack(buffer))) goto unpack_error; safe_unpack32(&msg->tasks_to_launch, buffer); safe_unpackstr_array(&msg->env, &msg->envc, buffer); diff --git a/src/common/slurm_protocol_pack.h b/src/common/slurm_protocol_pack.h index 1a76d1bc4d35b104d2c590efa10f36986deffc6a..d8d7f9ccd77359e0aa60fb5271b45e5941da6634 100644 --- a/src/common/slurm_protocol_pack.h +++ b/src/common/slurm_protocol_pack.h @@ -125,7 +125,7 @@ extern int unpack_msg ( slurm_msg_t * msgi , Buf buffer ); * IN/OUT buffer - destination of the pack, contains pointers that are * automatically updated */ -void pack_job_credential ( slurm_job_credential_t* cred , Buf buffer ) ; +/* void pack_job_credential ( slurm_job_credential_t* cred , Buf buffer ) ;*/ /* unpack_job_credential * unpacks a slurm job credential @@ -134,7 +134,7 @@ void pack_job_credential ( slurm_job_credential_t* cred , Buf buffer ) ; * automatically updated * RET 0 or error code */ -int unpack_job_credential( slurm_job_credential_t** cred , Buf buffer ) ; +/* int unpack_job_credential( slurm_job_credential_t** cred , Buf buffer ) ;*/ /* pack_job_step_info * packs a slurm job steps info diff --git a/src/common/slurm_protocol_util.c b/src/common/slurm_protocol_util.c index c7f78673905f3e8e87861ab5dda23e8a19bcc948..c6a4040c2a8a9d58aa30616df6fe6dd5bca311dc 100644 --- a/src/common/slurm_protocol_util.c +++ b/src/common/slurm_protocol_util.c @@ -239,16 +239,6 @@ int write_io_stream_header2(slurm_io_stream_header_t * header, slurm_fd fd) return SLURM_SUCCESS; } -/* log the supplied slurm credential as debug3() level */ -void slurm_print_job_credential(slurm_job_credential_t * credential) -{ - debug3("credential.job_id: %i", credential->job_id); - debug3("credential.user_id: %i", credential->user_id); - debug3("credential.node_list: %s", credential->node_list); - debug3("credential.expiration_time: %lu", - credential->expiration_time); - debug3("credential.signature: %#x", credential->signature); -} /* log the supplied slurm task launch message as debug3() level */ void slurm_print_launch_task_msg(launch_tasks_request_msg_t * msg) @@ -258,7 +248,6 @@ void slurm_print_launch_task_msg(launch_tasks_request_msg_t * msg) debug3("job_id: %i", msg->job_id); debug3("job_step_id: %i", msg->job_step_id); debug3("uid: %i", msg->uid); - slurm_print_job_credential(msg->credential); debug3("tasks_to_launch: %i", msg->tasks_to_launch); debug3("envc: %i", msg->envc); for (i = 0; i < msg->envc; i++) { diff --git a/src/common/slurm_protocol_util.h b/src/common/slurm_protocol_util.h index 8150009e23d071c9be40aceb39c58bf81136a660..2b22c10520c20778173079538303d7f305525169 100644 --- a/src/common/slurm_protocol_util.h +++ b/src/common/slurm_protocol_util.h @@ -122,7 +122,7 @@ extern int read_io_stream_header2(slurm_io_stream_header_t * header, slurm_fd fd extern int write_io_stream_header(slurm_io_stream_header_t * header, slurm_fd fd); /* log the supplied slurm credential as debug3() level */ -extern void slurm_print_job_credential(slurm_job_credential_t * credential); +/* extern void slurm_print_job_credential(slurm_job_credential_t * credential);*/ /* * write an i/o stream header to the supplied slurm stream