Commit message: TRQ-2885 - limit tm_adopt() to only adopt a session id that
is owned by the calling user.
CVE: CVE-2014-3684
CWE: CWE-264
Vulnerability description: The tm_adopt function in lib/Libifl/tm.c in Terascale Open-Source Resource and Queue Manager (aka TORQUE Resource Manager) 5.0.x, 4.5.x, 4.2.x, and earlier does not validate that the owner of the process also owns the adopted session id, which allows remote authenticated users to kill arbitrary processes via a crafted executable.

Project: torque

tm_alloc(char *resources, tm_event_t *event)
  {
  if (!init_done)
    return TM_BADINIT;

  return TM_ENOTIMPLEMENTED;
  }

Project: torque

int tm_taskinfo(

  tm_node_id  node,  /* in  */
  tm_task_id *tid_list, /* out */
  int         list_size, /* in  */
  int        *ntasks, /* out */
  tm_event_t *event)  /* out */

  {
  struct taskhold *thold;
  struct tcp_chan *chan = NULL;

  if (!init_done)
    return TM_BADINIT;

  if (tid_list == NULL || list_size == 0 || ntasks == NULL)
    return TM_EBADENVIRONMENT;

  *event = new_event();

  if (startcom(TM_TASKS, *event, &chan) != DIS_SUCCESS)
    return TM_ESYSTEM;

  if (diswsi(chan, node) != DIS_SUCCESS)
    {
    DIS_tcp_cleanup(chan);
    return TM_ESYSTEM;
    }

  DIS_tcp_wflush(chan);
  DIS_tcp_cleanup(chan);

  thold = (struct taskhold *)calloc(1, sizeof(struct taskhold));

  assert(thold != NULL);

  thold->list = tid_list;

  thold->size = list_size;

  thold->ntasks = ntasks;

  add_event(*event, node, TM_TASKS, (void *)thold);

  return TM_SUCCESS;
  }

Project: torque

int tm_notify(int tm_signal)
  {
  if (!init_done)
    return TM_BADINIT;

  return TM_ENOTIMPLEMENTED;
  }

Project: torque

tm_create_event(tm_event_t *event)
  {
  if (!init_done)
    return TM_BADINIT;

  return TM_ENOTIMPLEMENTED;
  }

Project: torque

int tm_init(

  void             *info,  /* in, currently unused */
  struct  tm_roots *roots) /* out */

  {
  tm_event_t  nevent, revent;
  char   *env, *hold;
  int   err;
  int   nerr = 0;
  struct tcp_chan *chan = NULL;

  if (init_done)
    {
    return(TM_BADINIT);
    }

  if ((tm_jobid = getenv("PBS_JOBID")) == NULL)
    {
    return(TM_EBADENVIRONMENT);
    }

  tm_jobid_len = strlen(tm_jobid);

  if ((tm_jobcookie = getenv("PBS_JOBCOOKIE")) == NULL)
    return TM_EBADENVIRONMENT;

  tm_jobcookie_len = strlen(tm_jobcookie);

  if ((env = getenv("PBS_NODENUM")) == NULL)
    return TM_EBADENVIRONMENT;

  tm_jobndid = (tm_node_id)strtol(env, &hold, 10);

  if (env == hold)
    return TM_EBADENVIRONMENT;

  if ((env = getenv("PBS_TASKNUM")) == NULL)
    return TM_EBADENVIRONMENT;

  if ((tm_jobtid = atoi(env)) == 0)
    return TM_EBADENVIRONMENT;

  if ((env = getenv("PBS_MOMPORT")) == NULL)
    return TM_EBADENVIRONMENT;

  if ((tm_momport = atoi(env)) == 0)
    return TM_EBADENVIRONMENT;

  init_done = 1;

  nevent = new_event();

  /*
   * send the following request:
   * header  (tm_init)
   * int  node number
   * int  task number
   */

  if (startcom(TM_INIT, nevent, &chan) != DIS_SUCCESS)
    return TM_ESYSTEM;

  DIS_tcp_wflush(chan);
  DIS_tcp_cleanup(chan);

  add_event(nevent, TM_ERROR_NODE, TM_INIT, (void *)roots);

  while (TRUE)
    {
    if ((err = tm_poll(TM_NULL_EVENT, &revent, 1, &nerr)) != TM_SUCCESS)
      return err;
    if (event_count == 0)
      break;
    }

  return nerr;
  }

Project: torque

int tm_publish(
  
  char       *name,  /* in  */
  void       *info,  /* in  */
  int         len,  /* in  */
  tm_event_t *event)  /* out */

  {
  int rc = TM_SUCCESS;
  struct tcp_chan *chan = NULL;

  if (!init_done)
    return TM_BADINIT;

  *event = new_event();

  if (startcom(TM_POSTINFO, *event, &chan) != DIS_SUCCESS)
    return TM_ESYSTEM;

  if (diswst(chan, name) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_publish_cleanup;
    }

  if (diswcs(chan, (char *)info, len) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_publish_cleanup;
    }

  DIS_tcp_wflush(chan);

  add_event(*event, TM_ERROR_NODE, TM_POSTINFO, NULL);

tm_publish_cleanup:
  if (chan != NULL)
    DIS_tcp_cleanup(chan);

  return rc;
  } /* tm_publish() */

Project: torque

int tm_adopt(
    
  char  *id,
  int    adoptCmd,
  pid_t  pid)

  {
  int rc = TM_SUCCESS;
  int status, ret;
  pid_t sid;
  char *env;
  struct tcp_chan *chan = NULL;

  sid = getsid(pid);

  /* do not adopt a sid not owned by caller */
  if (!ispidowner(sid))
    return(TM_EPERM);

  /* Must be the only call to call to tm and
     must only be called once */

  if (init_done) return TM_BADINIT;

  init_done = 1;

  /* Fabricate the tm state as best we can - not really needed */

  if ((tm_jobid = getenv("PBS_JOBID")) == NULL)
    tm_jobid = (char *)"ADOPT JOB";

  tm_jobid_len = strlen(tm_jobid);

  if ((tm_jobcookie = getenv("PBS_JOBCOOKIE")) == NULL)
    tm_jobcookie = (char *)"ADOPT COOKIE";

  tm_jobcookie_len = strlen(tm_jobcookie);

  /* We dont have the (right) node id or task id */
  tm_jobndid = 0;

  tm_jobtid = 0;

  /* Fallback is system default MOM port if not known */
  if ((env = getenv("PBS_MOMPORT")) == NULL || (tm_momport = atoi(env)) == 0)
    tm_momport = PBS_MANAGER_SERVICE_PORT;


  /* DJH 27 Feb 2002. two kinds of adoption now */
  if (adoptCmd != TM_ADOPT_ALTID && adoptCmd != TM_ADOPT_JOBID)
    return TM_EUNKNOWNCMD;

  if (startcom(adoptCmd, TM_NULL_EVENT, &chan) != DIS_SUCCESS)
    return TM_ESYSTEM;

  /* send session id */
  if (diswsi(chan, sid) != DIS_SUCCESS)
    {
    rc = TM_ENOTCONNECTED;
    goto tm_adopt_cleanup;
    }

  /* write the pid so the adopted process can be part of the cpuset if needed */
  if (diswsi(chan, pid) != DIS_SUCCESS)
    {
    rc =  TM_ENOTCONNECTED;
    goto tm_adopt_cleanup;
    }

  /* send job or alternative id */
  if (diswcs(chan, id, strlen(id)) != DIS_SUCCESS)
    {
    rc =  TM_ENOTCONNECTED;
    goto tm_adopt_cleanup;
    }

  DIS_tcp_wflush(chan);

  /* The mom should now attempt to adopt the task and will send back a
     status flag to indicate whether it was successful or not. */

  status = disrsi(chan, &ret);

  if (ret != DIS_SUCCESS)
    {
    rc = TM_ENOTCONNECTED;
    goto tm_adopt_cleanup;
    }

  /* Don't allow any more tm_* calls in this process. As well as
     closing an unused socket it also prevents any problems related to
     the fact that all adopted processes have a fake task id which
     might break the tm mechanism */
  tm_finalize();

  /* Since we're not using events, tm_finalize won't actually
     close the socket, so do it here. */
  if (local_conn > -1)
    {
    close(local_conn);
    local_conn = -1;
    }

  DIS_tcp_cleanup(chan);
  return (status == TM_OKAY ?

          TM_SUCCESS :
          TM_ENOTFOUND);

tm_adopt_cleanup:
  if (chan != NULL)
    DIS_tcp_cleanup(chan);
  return rc;
  }

Project: torque

int tm_poll(

  tm_event_t  poll_event,
  tm_event_t *result_event,
  int         wait,
  int        *tm_errno)

  {
  int  num, i;
  int  ret, mtype, nnodes;
  int  prot, protver;
  int  *obitvalp;
  event_info *ep = NULL;
  tm_task_id tid, *tidp;
  tm_event_t nevent;
  tm_node_id node;
  char  *jobid = NULL;
  char  *info = NULL;

  struct tm_roots *roots;

  struct taskhold *thold;

  struct infohold *ihold;

  struct reschold *rhold;
  extern time_t pbs_tcp_timeout;

  if (!init_done)
    {
    return(TM_BADINIT);
    }

  if (result_event == NULL)
    return(TM_EBADENVIRONMENT);

  *result_event = TM_ERROR_EVENT;

  if (poll_event != TM_NULL_EVENT)
    return(TM_ENOTIMPLEMENTED);

  if (tm_errno == NULL)
    return(TM_EBADENVIRONMENT);

  if (event_count == 0)
    {
    TM_DBPRT(("%s: no events waiting\n",
           __func__))

    return(TM_ENOTFOUND);
    }

  if (local_conn < 0)
    {
    TM_DBPRT(("%s: INTERNAL ERROR %d events but no connection (%d)\n",
           __func__, event_count, local_conn))

    if (static_chan != NULL)
      {
      DIS_tcp_cleanup(static_chan);
      static_chan = NULL;
      }
    return(TM_ENOTCONNECTED);
    }

  if ((static_chan == NULL) && ((static_chan = DIS_tcp_setup(local_conn)) == NULL))
    {
    TM_DBPRT(("%s: Error allocating memory for sock buffer %d", __func__, PBSE_MEM_MALLOC))
      return TM_BADINIT;
    }

  /*
  ** Setup tcp dis routines with a wait value appropriate for
  ** the value of wait the user set.
  */
  pbs_tcp_timeout = wait ? FOREVER : 1;

  prot = disrsi(static_chan, &ret);

  if (ret == DIS_EOD)
    {
    *result_event = TM_NULL_EVENT;
    DIS_tcp_cleanup(static_chan);
    static_chan = NULL;
    return TM_SUCCESS;
    }
  else if (ret != DIS_SUCCESS)
    {
    TM_DBPRT(("%s: protocol number dis error %d\n", __func__, ret))
    goto tm_poll_error;
    }

  if (prot != TM_PROTOCOL)
    {
    TM_DBPRT(("%s: bad protocol number %d\n", __func__, prot))
    goto tm_poll_error;
    }

  /*
  ** We have seen the start of a message.  Set the timeout value
  ** so we wait for the remaining data of a message.
  */
  pbs_tcp_timeout = FOREVER;

  protver = disrsi(static_chan, &ret);

  if (ret != DIS_SUCCESS)
    {
    TM_DBPRT(("%s: protocol version dis error %d\n", __func__, ret))
    goto tm_poll_error;
    }

  if (protver != TM_PROTOCOL_VER)
    {
    TM_DBPRT(("%s: bad protocol version %d\n", __func__, protver))
    goto tm_poll_error;
    }

  mtype = disrsi(static_chan, &ret);

  if (ret != DIS_SUCCESS)
    {
    TM_DBPRT(("%s: mtype dis error %d\n", __func__, ret))
    goto tm_poll_error;
    }

  nevent = disrsi(static_chan, &ret);

  if (ret != DIS_SUCCESS)
    {
    TM_DBPRT(("%s: event dis error %d\n", __func__, ret))
    goto tm_poll_error;
    }

  *result_event = nevent;

  TM_DBPRT(("%s: got event %d return %d\n", __func__, nevent, mtype))

  if ((ep = find_event(nevent)) == NULL)
    {
    TM_DBPRT(("%s: No event found for number %d\n", __func__, nevent));
    DIS_tcp_close(static_chan);
    static_chan = NULL;
    local_conn = -1;
    return TM_ENOEVENT;
    }

  if (mtype == TM_ERROR)   /* problem, read error num */
    {
    *tm_errno = disrsi(static_chan, &ret);
    TM_DBPRT(("%s: event %d error %d\n", __func__, nevent, *tm_errno));
    goto tm_poll_done;
    }

  *tm_errno = TM_SUCCESS;

  switch (ep->e_mtype)
    {

      /*
      ** auxiliary info (
      **  number of nodes int;
      **  nodeid[0] int;
      **  ...
      **  nodeid[n-1] int;
      **  parent jobid string;
      **  parent nodeid int;
      **  parent taskid int;
      ** )
      */

    case TM_INIT:
      nnodes = disrsi(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        TM_DBPRT(("%s: INIT failed nnodes\n", __func__))
        goto tm_poll_error;
        }

      node_table = (tm_node_id *)calloc(nnodes + 1,

                                        sizeof(tm_node_id));

      if (node_table == NULL)
        {
        perror("Memory allocation failed");
        goto tm_poll_error;
        }

      TM_DBPRT(("%s: INIT nodes %d\n", __func__, nnodes))

      for (i = 0; i < nnodes; i++)
        {
        node_table[i] = disrsi(static_chan, &ret);

        if (ret != DIS_SUCCESS)
          {
          TM_DBPRT(("%s: INIT failed nodeid %d\n", __func__, i))
          goto tm_poll_error;
          }
        }

      node_table[nnodes] = TM_ERROR_NODE;

      jobid = disrst(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        TM_DBPRT(("%s: INIT failed jobid\n", __func__))
        goto tm_poll_error;
        }

      TM_DBPRT(("%s: INIT daddy jobid %s\n", __func__, jobid))

      node = disrsi(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        TM_DBPRT(("%s: INIT failed parent nodeid\n", __func__))
        goto tm_poll_error;
        }

      TM_DBPRT(("%s: INIT daddy node %d\n", __func__, node))

      tid = disrsi(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        TM_DBPRT(("%s: INIT failed parent taskid\n", __func__))
        goto tm_poll_error;
        }

      TM_DBPRT(("%s: INIT daddy tid %lu\n", __func__, (unsigned long)tid))

      roots = (struct tm_roots *)ep->e_info;
      roots->tm_parent = new_task(jobid, node, tid);
      roots->tm_me = new_task(tm_jobid,
                              tm_jobndid,
                              tm_jobtid);
      roots->tm_nnodes = nnodes;
      roots->tm_ntasks = 0;  /* TODO */
      roots->tm_taskpoolid = -1; /* what? */
      roots->tm_tasklist = NULL; /* TODO */

      break;

    case TM_TASKS:
      thold = (struct taskhold *)ep->e_info;
      tidp = thold->list;
      num = thold->size;

      for (i = 0;; i++)
        {
        tid = disrsi(static_chan, &ret);

        if (tid == TM_NULL_TASK)
          break;

        if (ret != DIS_SUCCESS)
          goto tm_poll_error;

        if (i < num)
          {
          tidp[i] = new_task(tm_jobid,
                             ep->e_node, tid);
          }
        }

      if (i < num)
        tidp[i] = TM_NULL_TASK;

      *(thold->ntasks) = i;

      break;

    case TM_SPAWN:
      tid = disrsi(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        TM_DBPRT(("%s: SPAWN failed tid\n", __func__))
        goto tm_poll_error;
        }

      tidp = (tm_task_id *)ep->e_info;

      *tidp = new_task(tm_jobid, ep->e_node, tid);
      break;

    case TM_SIGNAL:
      break;

    case TM_OBIT:
      obitvalp = (int *)ep->e_info;
      *obitvalp = disrsi(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        TM_DBPRT(("%s: OBIT failed obitval\n", __func__))
        goto tm_poll_error;
        }

      break;

    case TM_POSTINFO:
      break;

    case TM_GETINFO:
      ihold = (struct infohold *)ep->e_info;
      info = disrcs(static_chan, (size_t *)ihold->info_len, &ret);

      if (ret != DIS_SUCCESS)
        {
        if (info != NULL)
          free(info);

        TM_DBPRT(("%s: GETINFO failed info\n", __func__))
        break;
        }

      memcpy(ihold->info, info, MIN(*ihold->info_len, ihold->len));

      free(info);
      break;

    case TM_RESOURCES:
      rhold = (struct reschold *)ep->e_info;
      info = disrst(static_chan, &ret);

      if (ret != DIS_SUCCESS)
        {
        if (info != NULL)
          free(info);

        break;
        }

      snprintf(rhold->resc, rhold->len, "%s", info);

      free(info);

      break;

    default:
      TM_DBPRT(("%s: unknown event command %d\n", __func__, ep->e_mtype))
      goto tm_poll_error;
    }

  DIS_tcp_wflush(static_chan);
tm_poll_done:

  if (jobid != NULL)
    free(jobid);

  del_event(ep);
  if (tcp_chan_has_data(static_chan) == FALSE)
    {
    DIS_tcp_cleanup(static_chan);
    static_chan = NULL;
    }

  return TM_SUCCESS;

tm_poll_error:

  if (jobid != NULL)
    free(jobid);

  if (ep)
    del_event(ep);

  close(local_conn);
  DIS_tcp_cleanup(static_chan);
  static_chan = NULL;
  local_conn = -1;

  return TM_ENOTCONNECTED;
  }

Project: torque

int tm_atnode(

  tm_task_id  tid,  /* in  */
  tm_node_id *node)  /* out */

  {
  task_info *tp;

  if (!init_done)
    return TM_BADINIT;

  if ((tp = find_task(tid)) == NULL)
    return TM_ENOTFOUND;

  *node = tp->t_node;

  return TM_SUCCESS;
  }

Project: torque

void del_event(
    
  event_info *ep)

  {
  /* unlink event from hash list */
  if (ep->e_prev)
    ep->e_prev->e_next = ep->e_next;
  else
    event_hash[ep->e_event % EVENT_HASH] = ep->e_next;

  if (ep->e_next)
    ep->e_next->e_prev = ep->e_prev;

  /*
  ** Free any memory saved with the event.  This depends
  ** on whay type of event it is.
  */
  switch (ep->e_mtype)
    {

    case TM_INIT:

    case TM_SPAWN:

    case TM_SIGNAL:

    case TM_OBIT:

    case TM_POSTINFO:
      break;

    case TM_TASKS:

    case TM_GETINFO:

    case TM_RESOURCES:
      free(ep->e_info);
      break;

    default:
      TM_DBPRT(("del_event: unknown event command %d\n", ep->e_mtype))
      break;
    }

  free(ep);

  if (--event_count == 0)
    {
    close(local_conn);
    local_conn = -1;
    }

  return;
  }

Project: torque

tm_task_id new_task(
    
  char       *jobid,
  tm_node_id  node,
  tm_task_id  task)

  {
  task_info  *tp, **head;

  TM_DBPRT(("%s: jobid=%s node=%d task=%lu\n",
         __func__, jobid, node, (unsigned long)task))

  if (jobid != tm_jobid && strcmp(jobid, tm_jobid) != 0)
    {
    TM_DBPRT(("%s: task job %s not my job %s\n",
           __func__, jobid, tm_jobid))
    return TM_NULL_TASK;
    }

  if (node == TM_ERROR_NODE)
    {
    TM_DBPRT(("%s: called with TM_ERROR_NODE\n", __func__))
    return TM_NULL_TASK;
    }

  if ((tp = find_task(task)) != NULL)
    {
    TM_DBPRT(("%s: task %lu found with node %d should be %d\n",
           __func__, (unsigned long)task, tp->t_node, node))
    return task;
    }

  if ((tp = (task_info *)calloc(1, sizeof(task_info))) == NULL)
    return TM_NULL_TASK;

  head = &task_hash[task % TASK_HASH];

  tp->t_jobid = tm_jobid;

  tp->t_task  = task;

  tp->t_node  = node;

  tp->t_next = *head;

  *head = tp;

  return task;
  }

Project: torque

int tm_nodeinfo(

  tm_node_id  **list,
  int          *nnodes)

  {
  tm_node_id *np;
  int  i;
  int  n = 0;

  if (!init_done)
    {
    return (TM_BADINIT);
    }

  if (node_table == NULL)
    {
    return (TM_ESYSTEM);
    }

  for (np = node_table; *np != TM_ERROR_NODE; np++)
    n++;  /* how many nodes */

  if ((np = (tm_node_id *)calloc(n,sizeof(tm_node_id))) == NULL)
    {
    /* FAILURE - cannot alloc memory */

    return(TM_ERROR);
    }

  for (i = 0; i < n; i++)
    np[i] = node_table[i];

  *list = np;

  *nnodes = i;

  return(TM_SUCCESS);
  }  /* END tm_nodeinfo() */

Project: torque

task_info *find_task(
    
  tm_task_id x)

  {
  task_info *tp;

  for (tp = task_hash[x % TASK_HASH]; tp; tp = tp->t_next)
    {
    if (tp->t_task == x)
      break;
    }

  return tp;
  }

Project: torque

static int localmom(void)

  {
  static int             have_addr = 0;
  static struct in_addr  hostaddr;
  struct addrinfo       *addr_info;

  int                    i;
  int                    sock;
  struct sockaddr_in     remote;

  struct linger         ltime;

  if (local_conn >= 0)
    {
    return(local_conn); /* already have open connection */
    }

  memset(&remote, 0, sizeof(remote));

  if (have_addr == 0)
    {
    /* lookup "localhost" and save address */

    if (pbs_getaddrinfo("localhost", NULL, &addr_info) != 0)
      {
      TM_DBPRT(("tm_init: localhost not found\n"))

      return(-1);
      }

    hostaddr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;

    have_addr = 1;

    }

  for (i = 0;i < 5;i++)
    {
    /* get socket */

    sock = socket(AF_INET, SOCK_STREAM, 0);

    if (sock < 0)
      {
      return(-1);
      }

#ifndef HAVE_POLL
    if (sock >= FD_SETSIZE)
      {
      close(sock);
      return(-1);
      }

#endif

    /* make sure data goes out */

    ltime.l_onoff = 1;

    ltime.l_linger = 5;

    setsockopt(sock, SOL_SOCKET, SO_LINGER, &ltime, sizeof(ltime));

    /* connect to specified local pbs_mom and port */

    remote.sin_addr = hostaddr;

    remote.sin_port = htons((unsigned short)tm_momport);

    remote.sin_family = AF_INET;

    if (connect(sock, (struct sockaddr *)&remote, sizeof(remote)) < 0)
      {
      switch (errno)
        {

        case EINTR:

        case EADDRINUSE:

        case ETIMEDOUT:

        case ECONNREFUSED:

          close(sock);

          sleep(1);

          continue;

          /*NOTREACHED*/

          break;

        default:

          close(sock);

          return(-1);

          /*NOTREACHED*/

          break;
        }
      }
    else
      {
      local_conn = sock;

      break;
      }
    }    /* END for (i) */

  return(local_conn);
  }  /* END localmom() */

Project: torque

static int startcom(

  int               com,
  tm_event_t        event,
  struct tcp_chan **pchan)

  {
  int     ret = DIS_SUCCESS;
  struct tcp_chan *chan = NULL;

  if (localmom() == -1)
    {
    return(-1);
    }

  if ((chan = DIS_tcp_setup(local_conn)) == NULL)
    goto done;

  ret = diswsi(chan, TM_PROTOCOL);

  if (ret != DIS_SUCCESS)
    goto done;

  ret = diswsi(chan, TM_PROTOCOL_VER);

  if (ret != DIS_SUCCESS)
    goto done;

  ret = diswcs(chan, tm_jobid, tm_jobid_len);

  if (ret != DIS_SUCCESS)
    goto done;

  ret = diswcs(chan, tm_jobcookie, tm_jobcookie_len);

  if (ret != DIS_SUCCESS)
    goto done;

  ret = diswsi(chan, com);

  if (ret != DIS_SUCCESS)
    goto done;

  ret = diswsi(chan, event);

  if (ret != DIS_SUCCESS)
    goto done;

  ret = diswui(chan, tm_jobtid);

  if (ret != DIS_SUCCESS)
    goto done;

  *pchan = chan;
  return(DIS_SUCCESS);

done:

  TM_DBPRT(("startcom: send error %s\n",
         dis_emsg[ret]))
  if (chan != NULL)
    DIS_tcp_close(chan);
  else
    close(local_conn);

  local_conn = -1;

  return(ret);
  }  /* END startcom() */

Project: torque

int tm_finalize(void)
  {
  event_info *e;
  int   i = 0;

  if (!init_done)
    return TM_BADINIT;

  while (event_count && (i < EVENT_HASH))
    {
    while ((e = event_hash[i]) != NULL)
      {
      del_event(e);
      }

    ++i; /* check next slot in hash table */
    }

  init_done = 0;

  return TM_SUCCESS; /* what else */
  }

Project: torque

int tm_obit(

  tm_task_id  tid,  /* in  */
  int        *obitval, /* out */
  tm_event_t *event)  /* out */

  {
  int rc = TM_SUCCESS;
  task_info *tp;
  struct tcp_chan *chan = NULL;

  if (!init_done)
    {
    rc = TM_BADINIT;
    goto tm_obit_cleanup;
    }

  if ((tp = find_task(tid)) == NULL)
    {
    rc = TM_ENOTFOUND;
    goto tm_obit_cleanup;
    }

  *event = new_event();

  if (startcom(TM_OBIT, *event, &chan) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_obit_cleanup;
    }

  if (diswsi(chan, tp->t_node) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_obit_cleanup;
    }

  if (diswsi(chan, tid) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_obit_cleanup;
    }

  DIS_tcp_wflush(chan);

  add_event(*event, tp->t_node, TM_OBIT, (void *)obitval);

tm_obit_cleanup:
  if (chan != NULL)
    DIS_tcp_cleanup(chan);
  return rc;
  }

Project: torque

tm_destroy_event(tm_event_t *event)
  {
  if (!init_done)
    return TM_BADINIT;

  return TM_ENOTIMPLEMENTED;
  }

Project: torque

int main(

  int    argc,
  char **argv) /* pbs_track */

  {
  int ArgIndex;
  int NumErrs = 0;

  char *Args[MAXARGS];
  int   aindex = 0;

  int   rc;
  int   pid;

  char tmpJobID[PBS_MAXCLTJOBID];        /* from the command line */

  char JobID[PBS_MAXCLTJOBID];  /* modified job ID for MOM/server consumption */
  char ServerName[MAXSERVERNAME];

  int  DoBackground = 0;

  tmpJobID[0] = '\0';

  /* USAGE: pbs_track [-j <JOBID>] -- a.out arg1 arg2 ... argN */

#define GETOPT_ARGS "bj:"

  while ((ArgIndex = getopt(argc, argv, GETOPT_ARGS)) != EOF)
    {
    switch (ArgIndex)
      {

      case 'b':

        /* background process */

        DoBackground = 1;

        break;

      case 'j':

        strncpy(tmpJobID, optarg, sizeof(tmpJobID));

        if (tmpJobID[PBS_MAXCLTJOBID-1] != '\0')
          {
          /* truncation occurred! */

          fprintf(stderr, "pbs_track: given job ID too large (> %d)\n",
                  PBS_MAXCLTJOBID);

          exit(-1);
          }

        break;

      default:

        NumErrs++;

        break;
      }
    }

  if ((NumErrs > 0) ||
      (optind >= argc) ||
      (tmpJobID[0] == '\0'))
    {
    static char Usage[] = "USAGE: pbs_track [-j <JOBID>] [-b] -- a.out arg1 arg2 ... argN\n";
    fprintf(stderr, "%s", Usage);
    exit(2);
    }

  if (getenv(NO_SERVER_SUFFIX) != NULL)
    {
    snprintf(JobID, sizeof(JobID), "%s", tmpJobID);
    }
  else
    {
    if (get_server(tmpJobID, JobID, sizeof(JobID), ServerName, sizeof(ServerName)))
      {
      fprintf(stderr, "pbs_track: illegally formed job identifier: '%s'\n", JobID);
      exit(1);
      }
    }

  /* gather a.out and other arguments */

  aindex = 0;

  for (;optind < argc;optind++)
    {
    Args[aindex++] = strdup(argv[optind]);
    printf("Got arg: %s\n",
           Args[aindex-1]);
    }

  Args[aindex] = NULL;

  /* decide if we should fork or not */

  pid = 1;

  if (DoBackground == 1)
    {
    printf("FORKING!\n");

    pid = fork();
    }

  if ((DoBackground == 0) || (pid == 0))
    {
    /* either parent or child, depending on the setting */

    /* call tm_adopt() to start tracking this process */

    rc = tm_adopt(JobID, TM_ADOPT_JOBID, getpid());

    switch (rc)
      {

      case TM_SUCCESS:

        /* success! */

        break;

      case TM_ENOTFOUND:

        fprintf(stderr, "pbs_track: MOM could not find job %s\n",
                JobID);

        break;

      case TM_ESYSTEM:

      case TM_ENOTCONNECTED:

        fprintf(stderr, "pbs_track: error occurred while trying to communication with pbs_mom: %s (%d)\n",
                pbse_to_txt(rc),
                rc);

        break;

      case TM_EPERM:

        fprintf(stderr, "pbs_track: permission denied: %s (%d)\n",
                pbse_to_txt(rc),
                rc);

      default:

        /* Unexpected error occurred */

        fprintf(stderr, "pbs_track: unexpected error %s (%d) occurred\n",
                pbse_to_txt(rc),
                rc);

        break;
      }  /* END switch(rc) */

    if (rc != TM_SUCCESS)
      {
      exit(-1);
      }

    /* do the exec */

    if (execvp(Args[0], Args) == -1)
      {
      fprintf(stderr,"execvp failed with error %d, message:\n%s\n",
        errno,
        strerror(errno));
      }
    }  /* END if ((DoBackground == 0) || (pid == 0)) */
  else if (pid > 0)
    {
    /* parent*/

    fclose(stdin);
    fclose(stdout);
    fclose(stderr);
    }
  else if (pid < 0)
    {
    fprintf(stderr, "pbs_track: could not fork (%d:%s)\n",
            errno,
            strerror(errno));
    }

  exit(0);
  }  /* END main() */

Project: torque

int tm_spawn(

  int          argc,  /* in  */
  char       **argv,  /* in  */
  char       **envp,  /* in  */
  tm_node_id   where, /* in  */
  tm_task_id  *tid,   /* out */
  tm_event_t  *event) /* out */

  {
  int rc = TM_SUCCESS;
  char *cp;
  int   i;
  struct tcp_chan *chan = NULL;

  /* NOTE: init_done is global */

  if (!init_done)
    {
    return(TM_BADINIT);
    }

  if ((argc <= 0) || (argv == NULL) || (argv[0] == NULL) || (*argv[0] == '\0'))
    {
    return(TM_ENOTFOUND);
    }

  *event = new_event();

  if (startcom(TM_SPAWN, *event, &chan) != DIS_SUCCESS)
    {
    return(TM_ENOTCONNECTED);
    }

  if (diswsi(chan, where) != DIS_SUCCESS) /* send where */
    {
    rc = TM_ENOTCONNECTED;
    goto tm_spawn_cleanup;
    }

  if (diswsi(chan, argc) != DIS_SUCCESS) /* send argc */
    {
     rc = TM_ENOTCONNECTED;
     goto tm_spawn_cleanup;
    }

  /* send argv strings across */

  for (i = 0;i < argc;i++)
    {
    cp = argv[i];

    if (diswcs(chan, cp, strlen(cp)) != DIS_SUCCESS)
      {
       rc = TM_ENOTCONNECTED;
       goto tm_spawn_cleanup;
      }
    }

  /* send envp strings across */

  if (getenv("PBSDEBUG") != NULL)
    {
    if (diswcs(chan, "PBSDEBUG=1", strlen("PBSDEBUG=1")) != DIS_SUCCESS)
      {
       rc = TM_ENOTCONNECTED;
       goto tm_spawn_cleanup;
      }
    }

  if (envp != NULL)
    {
    for (i = 0;(cp = envp[i]) != NULL;i++)
      {
      if (diswcs(chan, cp, strlen(cp)) != DIS_SUCCESS)
        {
         rc = TM_ENOTCONNECTED;
         goto tm_spawn_cleanup;
        }
      }
    }

  if (diswcs(chan, "", 0) != DIS_SUCCESS)
    {
     rc = TM_ENOTCONNECTED;
     goto tm_spawn_cleanup;
    }

  DIS_tcp_wflush(chan);

  add_event(*event, where, TM_SPAWN, (void *)tid);

tm_spawn_cleanup:
  if (chan != NULL)
    DIS_tcp_cleanup(chan);

  return(rc);
  }  /* END tm_spawn() */

Project: torque

tm_dealloc(tm_node_id node, tm_event_t *event)
  {
  if (!init_done)
    return TM_BADINIT;

  return TM_ENOTIMPLEMENTED;
  }

Project: torque

int tm_subscribe(
  
  tm_task_id  tid,     /* in  */
  char       *name,    /* in  */
  void       *info,    /* out */
  int         len,     /* in  */
  int        *info_len,/* out */
  tm_event_t *event)    /* out */
  
  {
  int              rc = TM_SUCCESS;
  task_info       *tp;
  struct tcp_chan *chan = NULL;

  struct infohold *ihold;

  if (!init_done)
    {
    rc = TM_BADINIT;
    goto tm_subscribe_cleanup;
    }

  if ((tp = find_task(tid)) == NULL)
    {
    rc = TM_ENOTFOUND;
    goto tm_subscribe_cleanup;
    }

  *event = new_event();

  if (startcom(TM_GETINFO, *event, &chan) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_subscribe_cleanup;
    }

  if (diswsi(chan, tp->t_node) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_subscribe_cleanup;
    }

  if (diswsi(chan, tid) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_subscribe_cleanup;
    }

  if (diswst(chan, name) != DIS_SUCCESS)
    {
    rc = TM_ESYSTEM;
    goto tm_subscribe_cleanup;
    }

  DIS_tcp_wflush(chan);

  ihold = (struct infohold *)calloc(1, sizeof(struct infohold));

  assert(ihold != NULL);

  ihold->info = info;

  ihold->len = len;

  ihold->info_len = info_len;

  add_event(*event, tp->t_node, TM_GETINFO, (void *)ihold);

tm_subscribe_cleanup:
  if (chan != NULL)
    DIS_tcp_cleanup(chan);

  return rc;
  }

Project: torque

bool ispidowner(pid_t pid)
  {
  char        path[MAXPATHLEN];
  struct stat sbuf;

  /* build path to pid */
  snprintf(path, sizeof(path), "/proc/%d", pid);

  /* do the stat */
  /*   if it fails, assume not owner */
  if (stat(path, &sbuf) != 0)
    return(FALSE);
 
  /* see if caller is the owner of pid */
  if (getuid() != sbuf.st_uid)
    return(FALSE);

  /* caller is owner */
  return(TRUE);
  }

Project: torque

int tm_rescinfo(

  tm_node_id  node,  /* in  */
  char       *resource, /* out */
  int         len,  /* in  */
  tm_event_t *event)  /* out */

  {
  struct reschold *rhold;
  struct tcp_chan *chan = NULL;

  if (!init_done)
    return TM_BADINIT;

  if (resource == NULL || len == 0)
    return TM_EBADENVIRONMENT;

  *event = new_event();

  if (startcom(TM_RESOURCES, *event, &chan) != DIS_SUCCESS)
    return TM_ESYSTEM;

  if (diswsi(chan, node) != DIS_SUCCESS)
    {
    DIS_tcp_cleanup(chan);
    return TM_ESYSTEM;
    }

  DIS_tcp_wflush(chan);
  DIS_tcp_cleanup(chan);

  rhold = (struct reschold *)calloc(1, sizeof(struct reschold));

  assert(rhold != NULL);

  rhold->resc = resource;

  rhold->len = len;

  add_event(*event, node, TM_RESOURCES, (void *)rhold);

  return TM_SUCCESS;
  } /* END tm_rescinfo() */

Project: torque

void add_event(
    
  tm_event_t  event,
  tm_node_id  node,
  int         type,
  void       *info)
  {
  event_info  *ep, **head;

  ep = (event_info *)calloc(1, sizeof(event_info));
  assert(ep != NULL);

  head = &event_hash[event % EVENT_HASH];
  ep->e_event = event;
  ep->e_node = node;
  ep->e_mtype = type;
  ep->e_info = info;
  ep->e_next = *head;
  ep->e_prev = NULL;

  if (*head)
    (*head)->e_prev = ep;

  *head = ep;

  event_count++;

  return;
  }

Project: torque

event_info *find_event(
    
  tm_event_t x)

  {
  event_info *ep;

  for (ep = event_hash[x % EVENT_HASH]; ep; ep = ep->e_next)
    {
    if (ep->e_event == x)
      break;
    }

  return ep;
  }

Project: torque

int tm_kill(

  tm_task_id  tid,  /* in  */
  int         sig,  /* in  */
  tm_event_t *event)  /* out */

  {
  int rc = TM_SUCCESS;
  task_info *tp;
  struct tcp_chan *chan = NULL;

  if (!init_done)
    {
    rc = TM_BADINIT;
    goto tm_kill_cleanup;
    }

  if ((tp = find_task(tid)) == NULL)
    {
    rc = TM_ENOTFOUND;
    goto tm_kill_cleanup;
    }

  *event = new_event();

  if (startcom(TM_SIGNAL, *event, &chan) != DIS_SUCCESS)
    {
    rc = TM_ENOTCONNECTED;
    goto tm_kill_cleanup;
    }

  if (diswsi(chan, tp->t_node) != DIS_SUCCESS)
    {
    rc = TM_ENOTCONNECTED;
    goto tm_kill_cleanup;
    }

  if (diswsi(chan, tid) != DIS_SUCCESS)
    {
    rc = TM_ENOTCONNECTED;
    goto tm_kill_cleanup;
    }

  if (diswsi(chan, sig) != DIS_SUCCESS)
    {
    rc = TM_ENOTCONNECTED;
    goto tm_kill_cleanup;
    }

  DIS_tcp_wflush(chan);

  add_event(*event, tp->t_node, TM_SIGNAL, NULL);

tm_kill_cleanup:
  if (chan != NULL)
    DIS_tcp_cleanup(chan);
  return rc;
  }

Project: torque

tm_event_t new_event(void)

  {
  static tm_event_t next_event = TM_NULL_EVENT + 1;
  event_info  *ep;
  tm_event_t  ret;

  if (next_event == INT_MAX)
    next_event = TM_NULL_EVENT + 1;

  for (;;)
    {
    ret = next_event++;

    for (ep = event_hash[ret % EVENT_HASH]; ep; ep = ep->e_next)
      {
      if (ep->e_event == ret)
        break; /* inner loop: this number is in use */
      }

    if (ep == NULL)
      break;  /* this number is not in use */
    }

  return ret;
  }

Project: torque

tm_register(tm_whattodo_t *what, tm_event_t *event)
  {
  if (!init_done)
    return TM_BADINIT;

  return TM_ENOTIMPLEMENTED;
  }