/***************************************************************************** * * Copyright (c) 2014 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * One option is added for salloc, sbatch, and srun: --krb5-propagate * which will attempt to preserve any valid tgt in the context of the * command and propagate it to the tasks being executed * **************************************************************************** * * $Source: /afs/pdc.kth.se/cluster/povel/src/spank_krb5_propagate/RCS/spank_krb5_propagate.c,v $ */ #include #include #include #include #include #include #include #include #include /* * All spank plugins must define this macro for the SLURM plugin loader. */ SPANK_PLUGIN(krb5_propagate, 1) #define NO_KRB5_PROPAGATE 1 static char* spank_krb5_propagate_realm = NULL; char* spank_krb5_propagate_kdeposit = NULL; char* spank_krb5_propagate_kdeposit_host = NULL; static int spank_krb5_propagate_opt_process (int val, const char *optarg, int remote); int spank_krb5_propagate_disable = 0; /* * Provide option for srun: */ struct spank_option spank_krb5_propagate_option_array[] = { { "no-krb5-propagate", NULL, "Don't propagate Kerberos 5 credentials", 0, NO_KRB5_PROPAGATE, (spank_opt_cb_f) spank_krb5_propagate_opt_process }, SPANK_OPTIONS_TABLE_END }; int slurm_spank_init(spank_t sp, int ac, char **av) { int res = ESPANK_SUCCESS; int i, c; spank_context_t ctx =spank_context(); // Process arguments - we need to know: // realm // where to find the kdeposit command // where to deposit the credentials. optind = 1; while ((c = getopt (ac, av, "r:k:h:")) != -1) { switch (c) { case 'r': if ((spank_krb5_propagate_realm = strdup(optarg)) == NULL) { slurm_error("Unable allocate memory for arguments: %s", strerror(errno)); res = ESPANK_ERROR; } break; case 'k': if ((spank_krb5_propagate_kdeposit = strdup(optarg)) == NULL) { slurm_error("Unable allocate memory for arguments: %s", strerror(errno)); res = ESPANK_ERROR; } break; case 'h': if ((spank_krb5_propagate_kdeposit_host = strdup(optarg)) == NULL) { slurm_error("Unable allocate memory for arguments: %s", strerror(errno)); res = ESPANK_ERROR; } break; default: slurm_error("Unable to parse command line"); res = ESPANK_ERROR; } } if (spank_krb5_propagate_realm == NULL || spank_krb5_propagate_kdeposit == NULL || spank_krb5_propagate_kdeposit_host == NULL) { slurm_error("Insufficient arguments - need realm, kdeposit command and kdeposit host"); res = ESPANK_ERROR; } if (res == ESPANK_ERROR) { return res; } // Options only valid for salloc/sbatch and srun (local context) if (ctx == S_CTX_ALLOCATOR || ctx == S_CTX_LOCAL) { for (i = 0; spank_krb5_propagate_option_array[i].name; i++) { res = spank_option_register(sp, &spank_krb5_propagate_option_array[i]); if (res != ESPANK_SUCCESS) { slurm_error("Could not register Spank option %s", spank_krb5_propagate_option_array[i].name); break; } } } else if (ctx == S_CTX_REMOTE) { // If AFS is present create unique pag for this task and afslog // For remote process in batch mode we must do afslog here // since slurm creates the I/O redirection files prior to // calling task_init char buf[1024]; char cmd[1024]; int s; res = spank_getenv(sp, "SPANK_KRB5CCNAME", buf, 1024); if (res == ESPANK_SUCCESS && k_hasafs()) { k_setpag(); snprintf(cmd, 1024, "/usr/heimdal/bin/afslog \"--cache=%s\"", buf); s = system(cmd); if (s < 0) { slurm_error("Unable to obtain AFS tokens: %s", strerror(errno)); res = ESPANK_ERROR; } else if (s > 0) { slurm_error("Failed to obtain AFS tokens running: %s", cmd); res = ESPANK_ERROR; } else { res = ESPANK_SUCCESS; } } } return res; } int spank_krb5_propagate(spank_t sp, int ac, char **av) { int res; int exitstatus; if (!spank_krb5_propagate_disable) { char cmd[1024]; char krb5_tag[1024]; res = spank_job_control_getenv (sp, "KRB5_TAG", krb5_tag, 1024); if (res != ESPANK_SUCCESS) { slurm_error("Unable to retrieve KRB5_TAG from job control environment: %s", spank_strerror(res)); } else { snprintf(cmd, sizeof(cmd), "%s -t %s -s %s", spank_krb5_propagate_kdeposit, krb5_tag, spank_krb5_propagate_kdeposit_host); res = system(cmd); if (res < 0) { slurm_error("Unable to deposit Kerberos tickets: %s", strerror(errno)); exitstatus = ESPANK_ERROR; } else if (res > 0) { slurm_error("Failed to deposit Kerberos tickets running: %s", cmd); exitstatus = ESPANK_ERROR; } else { exitstatus = ESPANK_SUCCESS; } } } else { exitstatus = ESPANK_SUCCESS; } return exitstatus; } /** * Called from start of step: */ int slurm_spank_task_init(spank_t sp, int ac, char **av) { int res = ESPANK_SUCCESS; int uid; int jid; int stepid; int taskid; spank_context_t ctx =spank_context(); if (ctx == S_CTX_REMOTE) { char buf[1024]; res = spank_getenv(sp, "SPANK_KRB5CCNAME", buf, 1024); if (res == ESPANK_SUCCESS) { res = spank_get_item(sp, S_JOB_UID, &uid); if (res != ESPANK_SUCCESS) { slurm_error("Unable to retrieve job uid: %s", spank_strerror(errno)); } res = spank_get_item(sp, S_JOB_ID, &jid); if (res != ESPANK_SUCCESS) { slurm_error("Unable to retrieve job id: %s", spank_strerror(errno)); } res = spank_get_item(sp, S_JOB_STEPID, &stepid); if (res != ESPANK_SUCCESS) { slurm_error("Unable to retrieve step id: %s", spank_strerror(errno)); } res = spank_get_item(sp, S_TASK_ID, &taskid); if (res != ESPANK_SUCCESS) { slurm_error("Unable to retrieve task id: %s", spank_strerror(errno)); } char ccname[1024]; snprintf(ccname, 1024, "FILE:/tmp/krb5cc-%d-%d-%d-%d", uid, jid, stepid, taskid); res = spank_setenv(sp, "KRB5CCNAME", ccname, 1); if (res != ESPANK_SUCCESS) { slurm_error("Unable to set KRB5CCNAME to value of \"%s\": %s", ccname, spank_strerror(errno)); } char cmd[1024]; snprintf(cmd, 1024, "/usr/heimdal/bin/kgetcred -c %s --out-cache=%s --forwardable krbtgt/%s@%s", buf, ccname, spank_krb5_propagate_realm, spank_krb5_propagate_realm); int s = system(cmd); if (s < 0) { slurm_error("Unable to copy Kerberos tickets: %s", strerror(errno)); res = ESPANK_ERROR; } else if (s > 0) { slurm_error("Failed to copy Kerberos tickets running: %s", cmd); res = ESPANK_ERROR; } else { res = ESPANK_SUCCESS; } /* If AFS is present create unique pag for this task and afslog*/ if(k_hasafs()) { k_setpag(); snprintf(cmd, 1024, "env KRB5CCNAME=%s /usr/heimdal/bin/afslog", ccname); s = system(cmd); if (s < 0) { slurm_error("Unable to obtain AFS tokens: %s", strerror(errno)); res = ESPANK_ERROR; } else if (s > 0) { slurm_error("Failed to obtain AFS tokens running: %s", cmd); res = ESPANK_ERROR; } else { res = ESPANK_SUCCESS; } } } } return res; } #define KRB5TAGLN 32 /* * Called from both srun and slurmd. */ int slurm_spank_init_post_opt (spank_t sp, int ac, char **av) { int res = ESPANK_SUCCESS; spank_context_t ctx =spank_context(); char krb5_tag[KRB5TAGLN]; // Options only valid for salloc/sbatch and srun (local // context) Note that srun can be called in two different // settings - job setting and non-job-setting. In the // job-setting case we do not want to propagate tickets as // those should already have been propagated during the // jobs allocation phase. if (ctx == S_CTX_ALLOCATOR || (ctx == S_CTX_LOCAL && getenv("SLURM_JOB_ID") == NULL)) { if (spank_krb5_propagate_disable) { slurm_debug("krb5_propagate disabled"); res = spank_job_control_setenv(sp, "KRB5_PROPAGATE", "0", 1); if (res != ESPANK_SUCCESS) { slurm_error("spank_setenv: %s", spank_strerror(res)); } } else { slurm_debug("krb5_propagate enabled"); res = spank_job_control_setenv(sp, "KRB5_PROPAGATE", "1", 1); if (res != ESPANK_SUCCESS) { slurm_error("Unable to add KRB5_PROPAGATE to job control environment: %s", spank_strerror(res)); } // Create random tag for ticket to be deposited. srandom((time(NULL)+1)*(getpid()+1)); snprintf(krb5_tag, KRB5TAGLN, "file%016x", random() & 0xFFFFFFFFFFFFFFFFl); res = spank_job_control_setenv(sp, "KRB5_TAG", krb5_tag, 1); if (res != ESPANK_SUCCESS) { slurm_error("Unable to add KRB5_TAG to job control environment: %s", spank_strerror(res)); } res = spank_krb5_propagate(sp, ac, av); if (res == ESPANK_SUCCESS) { // Add CC-name to job environment char buf[1024]; snprintf(buf, 1024, "/tmp/krb5cc_%d_%s", getuid(), krb5_tag); res = setenv("SPANK_KRB5CCNAME", buf, 1); if (res == -1) { slurm_error("Unable to add KRB5CCNAME to job environment: %s", strerror(errno)); } } } } return res; } static int spank_krb5_propagate_opt_process (int val, const char *optarg, int remote) { if (val == NO_KRB5_PROPAGATE) { spank_krb5_propagate_disable = 1; } return 0; }