/* * OpenPBS (Portable Batch System) v2.3 Software License * * Copyright (c) 1999-2000 Veridian Information Solutions, Inc. * All rights reserved. * * --------------------------------------------------------------------------- * For a license to use or redistribute the OpenPBS software under conditions * other than those described below, or to purchase support for this software, * please contact Veridian Systems, PBS Products Department ("Licensor") at: * * www.OpenPBS.org +1 650 967-4675 sales@OpenPBS.org * 877 902-4PBS (US toll-free) * --------------------------------------------------------------------------- * * This license covers use of the OpenPBS v2.3 software (the "Software") at * your site or location, and, for certain users, redistribution of the * Software to other sites and locations. Use and redistribution of * OpenPBS v2.3 in source and binary forms, with or without modification, * are permitted provided that all of the following conditions are met. * After December 31, 2001, only conditions 3-6 must be met: * * 1. Commercial and/or non-commercial use of the Software is permitted * provided a current software registration is on file at www.OpenPBS.org. * If use of this software contributes to a publication, product, or * service, proper attribution must be given; see www.OpenPBS.org/credit.html * * 2. Redistribution in any form is only permitted for non-commercial, * non-profit purposes. There can be no charge for the Software or any * software incorporating the Software. Further, there can be no * expectation of revenue generated as a consequence of redistributing * the Software. * * 3. Any Redistribution of source code must retain the above copyright notice * and the acknowledgment contained in paragraph 6, this list of conditions * and the disclaimer contained in paragraph 7. * * 4. Any Redistribution in binary form must reproduce the above copyright * notice and the acknowledgment contained in paragraph 6, this list of * conditions and the disclaimer contained in paragraph 7 in the * documentation and/or other materials provided with the distribution. * * 5. Redistributions in any form must be accompanied by information on how to * obtain complete source code for the OpenPBS software and any * modifications and/or additions to the OpenPBS software. The source code * must either be included in the distribution or be available for no more * than the cost of distribution plus a nominal fee, and all modifications * and additions to the Software must be freely redistributable by any party * (including Licensor) without restriction. * * 6. All advertising materials mentioning features or use of the Software must * display the following acknowledgment: * * "This product includes software developed by NASA Ames Research Center, * Lawrence Livermore National Laboratory, and Veridian Information * Solutions, Inc. * Visit www.OpenPBS.org for OpenPBS software support, * products, and information." * * 7. DISCLAIMER OF WARRANTY * * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT * ARE EXPRESSLY DISCLAIMED. * * IN NO EVENT SHALL VERIDIAN CORPORATION, ITS AFFILIATED COMPANIES, OR THE * U.S. GOVERNMENT OR ANY OF ITS AGENCIES BE LIABLE FOR ANY DIRECT OR 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. * * This license will be governed by the laws of the Commonwealth of Virginia, * without reference to its choice of law rules. */ #include /* the master config generated by configure */ #include #include #include "libpbs.h" #include "string.h" #include "list_link.h" #include "attribute.h" #include "server_limits.h" #include "server.h" #include "pbs_job.h" #include "credential.h" #include "batch_request.h" #include "pbs_error.h" #include "log.h" #include "../lib/Liblog/pbs_log.h" #include "../lib/Liblog/log_event.h" #include "svrfunc.h" #include "mcom.h" #include "utils.h" #include "svr_func.h" /* get_svr_attr_* */ #include "net_cache.h" #include "../lib/Libnet/lib_net.h" #include "ji_mutex.h" /* Global Data */ extern int LOGLEVEL; extern struct credential conn_credent[PBS_NET_MAX_CONNECTIONS]; extern char *pbs_o_host; extern char server_host[]; extern char *msg_permlog; extern char server_localhost[]; extern char *PJobState[]; extern int site_allow_u(char *, char *); int svr_chk_owner_generic(struct batch_request *preq, char *owner, char *submit_host); int svr_authorize_req(struct batch_request *preq, char *owner, char *submit_host); /* * svr_chk_owner - compare a user name from a request and the name of * the user who owns the job. * * Return 0 if same, non 0 if user is not the job owner */ int svr_chk_owner( struct batch_request *preq, /* I */ job *pjob) /* I */ { char owner[PBS_MAXUSER + 1]; get_jobowner(pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, owner); return svr_chk_owner_generic(preq, owner, get_variable(pjob, pbs_o_host)); } /* END svr_chk_owner() */ int svr_chk_owner_generic( struct batch_request *preq, char *owner, char *submit_host) { char *pu; char rmtuser[PBS_MAXUSER + 1]; /* map user@host to "local" name */ pu = site_map_user(preq->rq_user, preq->rq_host); if (pu == NULL) { /* FAILURE */ return(-1); } snprintf(rmtuser, sizeof(rmtuser), "%s", pu); pu = site_map_user(owner, submit_host); return(strcmp(rmtuser, pu)); } /* * svr_authorize_jobreq - determine if requestor is authorized to make * request against the job. This is only called for batch requests * against jobs, not manager requests against queues or the server. * * Returns 0 if authorized (job owner, operator, administrator) * -1 if not authorized. */ int svr_authorize_jobreq( struct batch_request *preq, /* I */ job *pjob) /* I */ { char owner[PBS_MAXUSER + 1]; get_jobowner(pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, owner); return svr_authorize_req(preq, owner, get_variable(pjob, pbs_o_host)); } /* END svr_authorize_jobreq() */ int svr_authorize_req( struct batch_request *preq, char *owner, char *submit_host) { /* does requestor have special privileges? */ if ((preq->rq_perm & (ATR_DFLAG_OPRD | ATR_DFLAG_OPWR | ATR_DFLAG_MGRD | ATR_DFLAG_MGWR)) != 0) { /* request authorized */ return(0); } /* is requestor the job owner? */ if (svr_chk_owner_generic(preq, owner, submit_host) == 0) { /* request authorized */ return(0); } /* not authorized */ return(-1); } /* * svr_get_privilege - get privilege level of a user. * * Privilege is granted to a user at a host. A user is automatically * granted "user" privilege. The user@host pair must appear in * the server's administrator attribute list to be granted "manager" * privilege and/or appear in the operators attribute list to be * granted "operator" privilege. If either acl is unset, then root * on the server machine is granted that privilege. * * If "PBS_ROOT_ALWAYS_ADMIN" is defined, then root always has privilege * even if not in the list. * * The returns are based on the access permissions of attributes, see * attribute.h. */ int svr_get_privilege( char *user, /* I */ char *host) /* I */ { int is_root = 0; int priv = (ATR_DFLAG_USRD | ATR_DFLAG_USWR); int num_host_chars; char uh[PBS_MAXUSER + PBS_MAXHOSTNAME + 2]; char host_no_port[PBS_MAXHOSTNAME+1]; char *colon_loc = NULL; char log_buf[LOCAL_LOG_BUF_SIZE]; char *other_host; int other_priv = 0; int my_err; pbs_net_t server_addr; pbs_net_t connect_addr; #ifndef __CYGWIN__ pbs_net_t local_server_addr; #endif if (!user) { sprintf(log_buf, "Invalid user: %s", "null"); log_record(PBSEVENT_SECURITY, PBS_EVENTCLASS_SERVER, __func__, log_buf); return(0); } /* user name cannot be longer than PBS_MAXUSER*/ if (strlen(user) > PBS_MAXUSER) { sprintf(log_buf, "Invalid user: %s", user); log_record(PBSEVENT_SECURITY, PBS_EVENTCLASS_SERVER, __func__, log_buf); return(0); } if (!host) return(0); colon_loc = strchr(host, ':'); /* if the request host has port information in it, we want to strip it out */ if (colon_loc == NULL) { /* no colon found */ num_host_chars = strlen(host); sprintf(host_no_port, "%s", host); } else { num_host_chars = colon_loc - host; /* actually remove the colon for host_no_port */ *colon_loc = '\0'; sprintf(host_no_port,"%s",host); *colon_loc = ':'; } /* num_host_chars cannot be more than PBS_MAXHOSTNAME */ if (num_host_chars > PBS_MAXHOSTNAME) { snprintf(log_buf, sizeof(log_buf), "Invalid host: %s", host); log_record(PBSEVENT_SECURITY, PBS_EVENTCLASS_SERVER, __func__, log_buf); return(0); } sprintf(uh, "%s@%s", user, host); server_addr = get_hostaddr(&my_err, server_host); connect_addr = get_hostaddr(&my_err, host_no_port); #ifdef __CYGWIN__ if ((IamAdminByName(user)) && (server_addr == connect_addr)) { return(priv | ATR_DFLAG_MGRD | ATR_DFLAG_MGWR | ATR_DFLAG_OPRD | ATR_DFLAG_OPWR); } #else /* __CYGWIN__ */ local_server_addr = get_hostaddr(&my_err, server_localhost); if ((strcmp(user, PBS_DEFAULT_ADMIN) == 0) && ((connect_addr == server_addr) || (connect_addr == local_server_addr))) { is_root = 1; #ifdef PBS_ROOT_ALWAYS_ADMIN if (is_root) { /* This statement allows us to compile with gcc-warnings */ /* if PBS_ROOT_ALWAYS_ADMIN is true is_root is assigned but never used */ ; } return(priv | ATR_DFLAG_MGRD | ATR_DFLAG_MGWR | ATR_DFLAG_OPRD | ATR_DFLAG_OPWR); #endif } #endif /* __CYGWIN__ */ pthread_mutex_lock(server.sv_attr_mutex); if (!(server.sv_attr[SRV_ATR_managers].at_flags & ATR_VFLAG_SET)) { #ifndef PBS_ROOT_ALWAYS_ADMIN if (is_root) priv |= (ATR_DFLAG_MGRD | ATR_DFLAG_MGWR); #endif } else if (acl_check(&server.sv_attr[SRV_ATR_managers], uh, ACL_User)) { priv |= (ATR_DFLAG_MGRD | ATR_DFLAG_MGWR); } if (!(server.sv_attr[SRV_ATR_operators].at_flags & ATR_VFLAG_SET)) { #ifndef PBS_ROOT_ALWAYS_ADMIN if (is_root) priv |= (ATR_DFLAG_OPRD | ATR_DFLAG_OPWR); #endif } else if (acl_check(&server.sv_attr[SRV_ATR_operators], uh, ACL_User)) { priv |= (ATR_DFLAG_OPRD | ATR_DFLAG_OPWR); } pthread_mutex_unlock(server.sv_attr_mutex); /* resolve using the other hostname (if available) and give the higher privilege */ other_host = get_cached_fullhostname(host, NULL); if ((other_host != NULL) && (strcmp(host, other_host))) other_priv = svr_get_privilege(user, other_host); if (other_priv > priv) priv = other_priv; return(priv); } /* END svr_get_privilege() */ /* * authenticate_user - authenticate user by checking name against credential * provided on connection via Authenticate User request. * * Returns 0 if user is who s/he claims, non-zero error code if not */ int authenticate_user( struct batch_request *preq, /* I */ struct credential *pcred, char **autherr) /* O */ { int rc; char uath[PBS_MAXUSER + PBS_MAXHOSTNAME + 1]; time_t time_now = time(NULL); char error_msg[1024]; long acl_enabled = FALSE; #ifdef MUNGE_AUTH if (strncmp(preq->rq_user, pcred->username, PBS_MAXUSER)) { /* extra check for munge */ struct array_strings *my_acl = NULL; char uh[PBS_MAXUSER + PBS_MAXHOSTNAME + 2]; sprintf(uh, "%s@%s", preq->rq_user, pcred->hostname); get_svr_attr_arst(SRV_ATR_authusers, &my_acl); if ((acl_check_my_array_string(my_acl, uh, ACL_User_Host)) == 0) { *autherr = strdup("User not in authorized user list."); sprintf(error_msg, "%s Requested user %s: requested from host %s", *autherr, preq->rq_user, preq->rq_host); log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, __func__, error_msg); return(PBSE_BADCRED); } } #else if (strncmp(preq->rq_user, pcred->username, PBS_MAXUSER)) { *autherr = strdup("Users do not match"); sprintf(error_msg, "%s: Requested user %s: credential user %s: requested from host %s", *autherr, preq->rq_user, pcred->username, preq->rq_host); log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, __func__, error_msg); return(PBSE_BADCRED); } #endif if (strncmp(preq->rq_host, pcred->hostname, PBS_MAXHOSTNAME)) { struct sockaddr_in *sai1; struct sockaddr_in *sai2; struct addrinfo *addr_info1 = NULL; struct addrinfo *addr_info2 = NULL; sai1 = get_cached_addrinfo(preq->rq_host); sai2 = get_cached_addrinfo(pcred->hostname); if ((sai1 == NULL) && (pbs_getaddrinfo(preq->rq_host, NULL, &addr_info1) == PBSE_NONE)) { sai1 = (struct sockaddr_in *)addr_info1->ai_addr; insert_addr_name_info(addr_info1,preq->rq_host); } if ((sai2 == NULL) && (pbs_getaddrinfo(pcred->hostname, NULL, &addr_info2) == PBSE_NONE)) { sai2 = (struct sockaddr_in *)addr_info2->ai_addr; insert_addr_name_info(addr_info2,pcred->hostname); } if ((sai1 == NULL) || (sai2 == NULL) || (memcmp(sai1, sai2, sizeof(struct sockaddr_in)))) { *autherr = strdup("Hosts do not match"); sprintf(error_msg, "%s: Requested host %s: credential host: %s", *autherr, preq->rq_host, pcred->hostname); log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, __func__, error_msg); return(PBSE_BADCRED); } } if (pcred->timestamp) { long lifetime = 0; if (get_svr_attr_l(SRV_ATR_CredentialLifetime, &lifetime) == PBSE_NONE) { /* use configured value if set */ } else { /* if not use the default */ lifetime = CREDENTIAL_LIFETIME; } /* negative values mean that credentials have an infinite lifetime */ if (lifetime > -1) { if ((pcred->timestamp - CREDENTIAL_TIME_DELTA > time_now) || (pcred->timestamp + lifetime < time_now)) { return(PBSE_EXPIRED); } } } /* If Server's Acl_User enabled, check if user in list */ get_svr_attr_l(SRV_ATR_AclUserEnabled, &acl_enabled); if (acl_enabled) { struct array_strings *acl_users = NULL; snprintf(uath, sizeof(uath), "%s@%s", preq->rq_user, preq->rq_host); get_svr_attr_arst(SRV_ATR_AclUsers, &acl_users); if (acl_check_my_array_string(acl_users, uath, ACL_User) == 0) { int my_err; pbs_net_t connect_addr = get_hostaddr(&my_err, preq->rq_host); pbs_net_t server_addr = get_hostaddr(&my_err, server_host); #ifdef __CYGWIN__ if ((!IamAdminByName(preq->rq_user)) || (connect_addr != server_addr)) { return(PBSE_PERM); } #else /* __CYGWIN__ */ #ifdef PBS_ROOT_ALWAYS_ADMIN if ((strcmp(preq->rq_user, PBS_DEFAULT_ADMIN) != 0) || (connect_addr != server_addr)) { return(PBSE_PERM); } #else /* PBS_ROOT_ALWAYS_ADMIN */ return(PBSE_PERM); #endif /* PBS_ROOT_ALWAYS_ADMIN */ #endif /* __CYGWIN__ */ } } /* A site stub for additional checking */ rc = site_allow_u(preq->rq_user, preq->rq_host); return(rc); } /* END authenticate_user() */ void chk_job_req_permissions( job **pjob_ptr, /* M */ struct batch_request *preq) /* I */ { job *pjob = *pjob_ptr; char tmpLine[MAXLINE]; char log_buf[LOCAL_LOG_BUF_SIZE]; if (svr_authorize_jobreq(preq, pjob) == -1) { sprintf(log_buf, msg_permlog, preq->rq_type, "Job", pjob->ji_qs.ji_jobid, preq->rq_user, preq->rq_host); log_event(PBSEVENT_SECURITY,PBS_EVENTCLASS_JOB,pjob->ji_qs.ji_jobid,log_buf); req_reject(PBSE_PERM, 0, preq, NULL, "operation not permitted"); unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); *pjob_ptr = NULL; } else if (pjob->ji_qs.ji_state >= JOB_STATE_EXITING) { /* job has completed */ switch (preq->rq_type) { case PBS_BATCH_Rerun: /* allow re-run to be executed for completed jobs */ /* NO-OP */ break; default: sprintf(log_buf, "%s %s", pbse_to_txt(PBSE_BADSTATE), PJobState[pjob->ji_qs.ji_state]); log_event(PBSEVENT_DEBUG,PBS_EVENTCLASS_JOB,pjob->ji_qs.ji_jobid,log_buf); snprintf(tmpLine, sizeof(tmpLine), "invalid state for job - %s", PJobState[pjob->ji_qs.ji_state]); req_reject(PBSE_BADSTATE, 0, preq, NULL, tmpLine); unlock_ji_mutex(pjob, __func__, "2", LOGLEVEL); *pjob_ptr = NULL; break; } /* END switch (preq->rq_type) */ } /* END if (pjob->ji_qs.ji_state >= JOB_STATE_EXITING) */ /* SUCCESS - request is valid */ } /* END chk_job_req_permissions() */ /* * chk_job_request - check legality of a request against a job * * this checks the most conditions common to most job batch requests. * It also returns a pointer to the job if found and the tests pass. */ job *chk_job_request( char *jobid, /* I */ struct batch_request *preq) /* I */ { job *pjob = NULL; if ((pjob = svr_find_job(jobid, FALSE)) == NULL) { log_event( PBSEVENT_DEBUG, PBS_EVENTCLASS_JOB, jobid, pbse_to_txt(PBSE_UNKJOBID)); req_reject(PBSE_UNKJOBID, 0, preq, NULL, "cannot locate job"); return(NULL); } /* if we aren't authorized, pjob will be set to NULL in chk_job_req_permissions */ chk_job_req_permissions(&pjob,preq); return(pjob); } /* END chk_job_request() */