[torquedev] patch: gssapi: support integrity protection on authenticated connections

Sergio Gelato Sergio.Gelato at astro.su.se
Wed May 30 07:07:02 MDT 2007


The patches below add integrity (and optional confidentiality)
protection to authenticated GSSAPI connections. They've passed
my initial testing.

The first patch is not GSSAPI-specific and may be also of interest for
the trunk. It adds a function DIS_tcp_release(fd) to be called when a
TCP connection is closed. In the GSSAPI case this will be extended to
release the security context as soon as it is no longer needed. I'm not
yet entirely confident that this new function is called from *all* the
right places; please audit.

The second patch adds the machinery to wrap and unwrap messages that
are sent on the wire. It depends on the first patch. Sorry if it doesn't
look elegant, but for a first cut I wanted to keep the code changes as
localised as possible.

The third patch makes use of the new machinery to actually wrap traffic
after authentication. Only integrity protection (GSS_C_INTEG_FLAG) is
explicitly required; confidentiality (GSS_C_CONF_FLAG) is used if
the security context supports it (that was the case in my tests).
-------------- next part --------------
diff -ru old/src/include/dis.h new/src/include/dis.h
--- old/src/include/dis.h	2007-02-16 20:40:47.000000000 +0100
+++ new/src/include/dis.h	2007-05-30 14:31:42.975040778 +0200
@@ -249,6 +249,7 @@
 extern int  DIS_tcp_wflush A_((int fd));
 extern void DIS_tcp_settimeout A_((long timeout));
 extern int  DIS_tcp_istimeout A_((int fd));
+extern void DIS_tcp_release A_((int fd));
 
 extern int  PConnTimeout(int);
 
diff -ru old/src/lib/Libifl/pbsD_connect.c new/src/lib/Libifl/pbsD_connect.c
--- old/src/lib/Libifl/pbsD_connect.c	2007-02-08 21:50:06.000000000 +0100
+++ new/src/lib/Libifl/pbsD_connect.c	2007-05-30 14:31:42.975040778 +0200
@@ -575,6 +575,8 @@
 
     connection[out].ch_inuse = 0;
 
+    DIS_tcp_release(connection[out].ch_socket);
+
     pbs_errno = PBSE_PERM;
 
     if (getenv("PBSDEBUG"))
@@ -646,6 +648,8 @@
 	
   close(sock);
 
+  DIS_tcp_release(sock);
+
   if (connection[connect].ch_errtxt != (char *)NULL) 
     free(connection[connect].ch_errtxt);
 
diff -ru old/src/lib/Libifl/tcp_dis.c new/src/lib/Libifl/tcp_dis.c
--- old/src/lib/Libifl/tcp_dis.c	2007-02-16 20:41:14.000000000 +0100
+++ new/src/lib/Libifl/tcp_dis.c	2007-05-30 14:31:42.975040778 +0200
@@ -80,6 +80,7 @@
 
 
 #include <pbs_config.h>   /* the master config generated by configure */
+#include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -775,6 +776,21 @@
   }  /* END DIS_tcp_setup() */
 
 
+/*
+ * DIS_tcp_release - release data structures for the given fd
+ */
+void DIS_tcp_release(
+
+  int fd)
+
+  {
+  assert (fd >= 0);
+  if (fd >= tcparraymax || tcparray[fd] == NULL)
+    return;	/* Might be an RPP connection */
+
+  free(tcparray[fd]);
+  tcparray[fd] = NULL;
+  }  /* END DIS_tcp_release() */
 
 /* END tcp_dis.c */
 
diff -ru old/src/lib/Libnet/net_server.c new/src/lib/Libnet/net_server.c
--- old/src/lib/Libnet/net_server.c	2007-02-16 20:41:20.000000000 +0100
+++ new/src/lib/Libnet/net_server.c	2007-05-30 14:31:42.976040847 +0200
@@ -332,7 +332,6 @@
   fd_set selset;
 
   struct timeval timeout;
-  void close_conn();
 
   long OrigState=0;
 
@@ -576,6 +575,8 @@
 
   FD_CLR(sd,&readset);
 
+  DIS_tcp_release(sd);	/* FIXME: only do this on TCP sockets */
+
   svr_conn[sd].cn_addr = 0;
   svr_conn[sd].cn_handle = -1;
   svr_conn[sd].cn_active = Idle;
-------------- next part --------------
diff -ru old/src/include/dis.h new/src/include/dis.h
--- old/src/include/dis.h	2007-05-30 14:31:42.000000000 +0200
+++ new/src/include/dis.h	2007-05-30 14:32:41.663087704 +0200
@@ -90,6 +90,10 @@
 #define FALSE	0
 #endif
 
+#ifdef GSSAPI
+#include "pbsgss.h"
+#endif
+
 /*
  * Integer function return values from Data-is-Strings reading calls
  */
@@ -250,6 +254,9 @@
 extern void DIS_tcp_settimeout A_((long timeout));
 extern int  DIS_tcp_istimeout A_((int fd));
 extern void DIS_tcp_release A_((int fd));
+#ifdef GSSAPI
+extern void DIS_tcp_set_gss A_((int fd, gss_ctx_id_t ctx, OM_uint32 flags));
+#endif
 
 extern int  PConnTimeout(int);
 
@@ -264,16 +271,26 @@
   char *tdis_leadp;
   char *tdis_trailp;
   char *tdis_eod;
+  size_t bufsize;
   char  tdis_thebuf[THE_BUF_SIZE];
   };
 
 struct tcp_chan {
   struct tcpdisbuf readbuf;
   struct tcpdisbuf writebuf;
+#ifdef GSSAPI
+  struct tcpdisbuf gssrdbuf;   /* incoming wrapped data */
+  gss_buffer_desc  unwrapped;  /* release after copying to readbuf */
+  gss_ctx_id_t     gssctx;
+#endif
 
   int              IsTimeout;  /* (boolean)  1 - true */
   int              ReadErrno;
   int              SelectErrno;
+#ifdef GSSAPI
+  int              AtEOF;		/* (boolean) */
+  int              Confidential;	/* (boolean) */
+#endif
   };
 
 #endif	/* DATA_IS_STRINGS_ */
diff -ru old/src/lib/Libifl/tcp_dis.c new/src/lib/Libifl/tcp_dis.c
--- old/src/lib/Libifl/tcp_dis.c	2007-05-30 14:31:42.000000000 +0200
+++ new/src/lib/Libifl/tcp_dis.c	2007-05-30 14:32:41.664087773 +0200
@@ -185,9 +185,10 @@
  *		-2 if EOF (stream closed)
  */
 
-static int tcp_read(
+static int tcp_readbuf(
 
-  int fd)  /* I */
+  int               fd, /* I */
+  struct tcpdisbuf *tp)	/* I */
  
   {
   int               i;
@@ -198,9 +199,6 @@
   fd_set            readset;
   struct timeval    timeout;
 #endif
-  struct tcpdisbuf *tp;
-
-  tp = &tcparray[fd]->readbuf;
 
   /* must compact any uncommitted data into bottom of buffer */
 
@@ -291,6 +289,104 @@
   tp->tdis_eod += i;
  
   return(i);
+  }  /* END tcp_readbuf() */
+
+static int tcp_read(
+
+  int fd)	/* I */
+
+  {
+  struct tcpdisbuf *tp;
+#ifdef GSSAPI
+  OM_uint32 minor;
+  size_t l, f;
+#endif
+
+#ifdef GSSAPI
+  if (tcparray[fd]->gssctx == GSS_C_NO_CONTEXT)
+#endif
+    {
+    tp = &tcparray[fd]->readbuf;
+    return tcp_readbuf(fd, tp);
+    }
+
+#ifdef GSSAPI
+leftover:
+  if ((l = tcparray[fd]->unwrapped.length) > 0)
+    {
+    tp = &tcparray[fd]->readbuf;
+    tcp_pack_buff(tp);
+    f = THE_BUF_SIZE - (tp->tdis_eod - tp->tdis_thebuf);
+    if (f < l)
+      {
+      memcpy(tp->tdis_eod, tcparray[fd]->unwrapped.value, f);
+      tp->tdis_eod += f;
+      memmove(tcparray[fd]->unwrapped.value, 
+	      tcparray[fd]->unwrapped.value+f,
+	      l-f);
+      tcparray[fd]->unwrapped.length = l-f;
+      return f;	/* readbuf is now full */
+      }
+    else
+      {
+      memcpy(tp->tdis_eod, tcparray[fd]->unwrapped.value, l);
+      tp->tdis_eod += l;
+      gss_release_buffer(&minor, &tcparray[fd]->unwrapped);
+      return l;	/* for simplicity */
+      }
+    }
+
+readmore:
+  if (tcparray[fd]->AtEOF)
+    return(-2);
+  tp = &tcparray[fd]->gssrdbuf;
+  f = tcp_readbuf(fd, tp);
+  tcparray[fd]->AtEOF = (f == -2);
+
+  if (tp->tdis_eod - tp->tdis_leadp >= 4)
+    {
+    int i;
+    for (i=0, l=0; i<4; i++)
+      l = l<<8 | (*tp->tdis_leadp++ & 0xff);
+    if (l<0 || l+4>THE_BUF_SIZE)
+      {
+      return(-2);	/* FIXME: this is fatal; how to clean up? */
+      }
+    if (tp->tdis_eod - tp->tdis_leadp >= l)
+      {
+      OM_uint32 major, minor;
+      gss_buffer_desc msg_in;
+      msg_in.length = l;
+      msg_in.value = tp->tdis_leadp;
+      major = gss_unwrap(&minor,
+		         tcparray[fd]->gssctx,
+			 &msg_in,
+			 &tcparray[fd]->unwrapped,
+			 NULL,
+			 NULL);
+      tp->tdis_leadp += l;
+      tp->tdis_trailp = tp->tdis_leadp;	/* commit */
+      if (major != GSS_S_COMPLETE)
+        {
+	if (getenv("PBSDEBUG") != NULL)
+	  pbsgss_display_status("gss_unwrap", major, minor);
+	gss_release_buffer(&minor, &tcparray[fd]->unwrapped);
+	tcparray[fd]->ReadErrno = 0;
+	return(-1);
+        }
+      if (tcparray[fd]->unwrapped.length > 0)
+        goto leftover;
+      }
+    else
+      {
+      tp->tdis_leadp = tp->tdis_trailp;	/* uncommit */
+      if (!tcparray[fd]->IsTimeout)
+        goto readmore;
+      }
+    }
+  return (f<0 ? f : 0);
+
+#endif
   }  /* END tcp_read() */
 
 
@@ -314,12 +410,68 @@
   int	 i;
   char	*pb;
   struct tcpdisbuf *tp;
+#ifdef GSSAPI
+  OM_uint32 major, minor;
+  gss_buffer_desc msg_in, msg_out;
+  int conf_state;
+  unsigned char nct[4];
+#endif
 
   tp = &tcparray[fd]->writebuf;
   pb = tp->tdis_thebuf;
 
   ct = tp->tdis_trailp - tp->tdis_thebuf;
 
+#ifdef GSSAPI
+  msg_out.value = NULL;
+  msg_out.length = 0;
+  if (tcparray[fd]->gssctx != GSS_C_NO_CONTEXT)
+  {
+    msg_in.value  = pb;
+    msg_in.length = ct;
+    major = gss_wrap(&minor,
+		     tcparray[fd]->gssctx,
+		     tcparray[fd]->Confidential,
+		     GSS_C_QOP_DEFAULT,
+		     &msg_in,
+		     &conf_state,
+		     &msg_out);
+    if (major != GSS_S_COMPLETE)
+      {
+      if (getenv("PBSDEBUG") != NULL)
+	pbsgss_display_status("gss_wrap", major, minor);
+      gss_release_buffer(&minor, &msg_out);
+      return(-1);
+      }
+    if (tcparray[fd]->Confidential && !conf_state)
+      {
+      if (getenv("PBSDEBUG") != NULL)
+        fprintf(stderr, "gss_wrap() failed to encrypt as requested\n");
+      gss_release_buffer(&minor, &msg_out);
+      return(-1);
+      }
+    pb = msg_out.value;
+    ct = msg_out.length;
+    for (i=sizeof(nct); i>0; ct>>=8)
+      nct[--i] = ct & 0xff;
+    while ((i = write(fd,nct,sizeof(nct))) != sizeof(nct))
+      {
+      if (i == -1)
+        {
+	if (errno == EINTR)
+	  continue;
+        if (getenv("PBSDEBUG") != NULL)
+          {
+          fprintf(stderr,"TCP write of message length failed, errno=%ld (%s)\n",
+          (long)errno,
+          strerror(errno));
+          }
+	}
+      }
+    ct = msg_out.length;
+  }
+#endif
+
   while ((i = write(fd,pb,ct)) != (ssize_t)ct) 
     {
     if (i == -1)  
@@ -333,13 +485,16 @@
 
       if (getenv("PBSDEBUG") != NULL)
         {
-        fprintf(stderr,"TCP write of %d bytes (%.32s) failed, errno=%d (%s)\n",
-          ct,
+        fprintf(stderr,"TCP write of %ld bytes (%.32s) failed, errno=%ld (%s)\n",
+          (long)ct,
           pb,
-          errno,
+          (long)errno,
           strerror(errno));
         }
 
+#ifdef GSSAPI
+      gss_release_buffer(&minor, &msg_out);
+#endif
       return(-1);
       }  /* END if (i == -1) */
 
@@ -348,6 +503,10 @@
     }  /* END while (i) */
  
   /* SUCCESS */
+
+#ifdef GSSAPI
+  gss_release_buffer(&minor, &msg_out);
+#endif
  
   tp->tdis_eod = tp->tdis_leadp;
 
@@ -592,24 +751,24 @@
 
   tp = &tcparray[fd]->writebuf;
 
-  /* NOTE:  currently, failures may occur if THE_BUF_SIZE is not large enough */
+  /* NOTE:  currently, failures may occur if tp->bufsize is not large enough. */
   /*        this should be changed to allow proper operation with degraded    */
   /*        performance (how?) */
 
-  if ((tp->tdis_thebuf + THE_BUF_SIZE - tp->tdis_leadp) < (ssize_t)ct) 
+  if ((tp->tdis_thebuf + tp->bufsize - tp->tdis_leadp) < (ssize_t)ct) 
     {
     /* not enough room, try to flush committed data */
 
     if ((DIS_tcp_wflush(fd) < 0) ||
-       ((tp->tdis_thebuf + THE_BUF_SIZE - tp->tdis_leadp) < (ssize_t)ct))
+       ((tp->tdis_thebuf + tp->bufsize - tp->tdis_leadp) < (ssize_t)ct))
       {
       /* FAILURE */
 
-      DBPRT(("%s: error!  out of space in buffer and cannot commit message (bufsize=%d, buflen=%d, ct=%d)\n",
+      DBPRT(("%s: error!  out of space in buffer and cannot commit message (bufsize=%ld, buflen=%ld, ct=%ld)\n",
         id,
-        THE_BUF_SIZE,
-        (int)(tp->tdis_leadp - tp->tdis_thebuf),
-        (int)ct))
+        (long)tp->bufsize,
+        (long)(tp->tdis_leadp - tp->tdis_thebuf),
+        (long)ct))
 
       return(-1);	
       }
@@ -765,10 +924,22 @@
     {
     tcp = tcparray[fd] =
       (struct tcp_chan *)malloc(sizeof(struct tcp_chan));
+#ifdef GSSAPI
+    tcp->unwrapped.length = 0;
+    tcp->unwrapped.value = NULL;
+    tcp->gssctx = GSS_C_NO_CONTEXT;
+    tcp->gssrdbuf.bufsize = THE_BUF_SIZE;
+#endif
+    tcp->readbuf.bufsize = THE_BUF_SIZE;
+    tcp->writebuf.bufsize = THE_BUF_SIZE;
     }
 
   /* initialize read and write buffers */
 
+#ifdef GSSAPI
+  assert (tcp->unwrapped.value == NULL);
+  DIS_tcp_clear(&tcp->gssrdbuf);
+#endif
   DIS_tcp_clear(&tcp->readbuf);
   DIS_tcp_clear(&tcp->writebuf);
   
@@ -784,14 +955,49 @@
   int fd)
 
   {
+#ifdef GSSAPI
+  OM_uint32 minor;
+#endif
+
   assert (fd >= 0);
   if (fd >= tcparraymax || tcparray[fd] == NULL)
     return;	/* Might be an RPP connection */
 
+#ifdef GSSAPI
+  if (tcparray[fd]->gssctx != GSS_C_NO_CONTEXT)
+    gss_delete_sec_context (&minor, &tcparray[fd]->gssctx, GSS_C_NO_BUFFER);
+  if (tcparray[fd]->unwrapped.value)
+    gss_release_buffer (&minor, &tcparray[fd]->unwrapped);
+#endif
   free(tcparray[fd]);
   tcparray[fd] = NULL;
   }  /* END DIS_tcp_release() */
 
+#ifdef GSSAPI
+/*
+ * DIS_tcp_set_gss - associate GSSAPI information with a TCP channel
+ */
+void DIS_tcp_set_gss(
+
+  int          fd,    /* I */
+  gss_ctx_id_t ctx,   /* I */
+  OM_uint32    flags) /* I */
+
+  {
+  OM_uint32 major, minor, bufsize;
+
+  assert (fd >= 0 && fd < tcparraymax && tcparray[fd]);
+  assert (tcparray[fd]->gssctx == GSS_C_NO_CONTEXT);
+  tcparray[fd]->gssctx = ctx;
+  tcparray[fd]->AtEOF = 0;
+  tcparray[fd]->Confidential = (flags & GSS_C_CONF_FLAG);
+  major = gss_wrap_size_limit (&minor, ctx, (flags & GSS_C_CONF_FLAG),
+                             GSS_C_QOP_DEFAULT, THE_BUF_SIZE, &bufsize);
+  if (major == GSS_S_COMPLETE)
+    tcparray[fd]->writebuf.bufsize = bufsize;
+  } /* END DIS_tcp_set_gss */
+#endif
+
 /* END tcp_dis.c */
 
 
-------------- next part --------------
diff -ru old/src/include/pbsgss.h new/src/include/pbsgss.h
--- old/src/include/pbsgss.h	2007-05-30 14:27:51.000000000 +0200
+++ new/src/include/pbsgss.h	2007-05-30 14:33:23.197951767 +0200
@@ -31,7 +31,10 @@
 				    OM_uint32 gss_flags,
 				    gss_ctx_id_t *gss_context,
 				    OM_uint32 *ret_flags);
-int pbsgss_client_authenticate(char *hostname, int psock, int delegate);
+int pbsgss_client_authenticate(char *hostname, 
+		               int psock, 
+			       int delegate,
+			       int wrap);
 int pbsgss_server_establish_context(int s,
 				    gss_cred_id_t server_creds, 
 				    gss_cred_id_t *client_creds,
@@ -50,6 +53,7 @@
 char *ccname_for_job(char *jobnamem, char *prefix);
 int authenticate_as_job(char *username,char *jobname,int setpag);
 int pbsgss_renew_creds (char *jobname, char *prefix);
+void pbsgss_save_sec_context(gss_ctx_id_t *context, OM_uint32 flags, int fd);
 
 /* Token types */
 #define TOKEN_NOOP		(1<<0)
diff -ru old/src/lib/Libgss/pbsgss.c new/src/lib/Libgss/pbsgss.c
--- old/src/lib/Libgss/pbsgss.c	2007-05-30 14:27:51.000000000 +0200
+++ new/src/lib/Libgss/pbsgss.c	2007-05-30 14:33:23.197951767 +0200
@@ -733,7 +733,10 @@
   return system(cmd);
 }
 
-int pbsgss_client_authenticate(char *hostname, int psock, int delegate) {
+int pbsgss_client_authenticate(char *hostname, 
+		               int psock, 
+			       int delegate,
+			       int wrap) {
   char *service_name;
   OM_uint32 gss_flags, ret_flags, maj_stat, min_stat;
   gss_OID oid;
@@ -798,7 +801,8 @@
   service_name = malloc(sizeof(char) * (1 + strlen(hostname) + strlen("host@")));
   sprintf(service_name,"host@%s",hostname);
 
-  gss_flags = GSS_C_MUTUAL_FLAG | (delegate ? GSS_C_DELEG_FLAG : 0);
+  gss_flags = GSS_C_MUTUAL_FLAG | (delegate ? GSS_C_DELEG_FLAG : 0)
+	      | (wrap ? GSS_C_INTEG_FLAG : 0);
   oid = GSS_C_NULL_OID;
   retval = pbsgss_client_establish_context(psock,
 					   service_name,
@@ -814,17 +818,21 @@
   if (name != GSS_C_NO_NAME) {
     gss_release_name(&min_stat,&name);
   }
-  gss_delete_sec_context(&min_stat,&gss_context,GSS_C_NO_BUFFER);
   if (retval < 0) {    
     if (retry < 3) {
       retry++;
       DIS_tcp_setup(psock);
-      return pbsgss_client_authenticate(hostname, psock, delegate);      
+      gss_delete_sec_context(&min_stat,&gss_context,GSS_C_NO_BUFFER);
+      return pbsgss_client_authenticate(hostname, psock, delegate, wrap);      
     } else {
       return retval;
     }
   }
   retry = 0;
+  if (wrap)
+    pbsgss_save_sec_context(&gss_context,ret_flags,psock);
+  else
+    gss_delete_sec_context(&min_stat,&gss_context,GSS_C_NO_BUFFER);
   return retval;
 }
 
@@ -959,3 +967,22 @@
   free(service_name);
   return princname;
 }
+
+/* If the context supports integrity, save it for later use by gss_wrap()
+ * and gss_unwrap(). Otherwise delete it.
+ */
+void pbsgss_save_sec_context(gss_ctx_id_t *context,
+			     OM_uint32 flags,
+			     int fd)
+{
+  OM_uint32 major, minor;
+
+  if (flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) {
+    DIS_tcp_set_gss(fd, *context, flags);
+  } else if (*context != GSS_C_NO_CONTEXT) {
+    major = gss_delete_sec_context(&minor, context, GSS_C_NO_BUFFER);
+    if (major != GSS_S_COMPLETE) {
+      pbsgss_display_status("deleting context", major, minor);
+    }
+  }
+}
diff -ru old/src/lib/Libifl/pbsD_connect.c new/src/lib/Libifl/pbsD_connect.c
--- old/src/lib/Libifl/pbsD_connect.c	2007-05-30 14:31:42.000000000 +0200
+++ new/src/lib/Libifl/pbsD_connect.c	2007-05-30 14:33:23.198951836 +0200
@@ -543,7 +543,7 @@
       neediff = 1;
     } else {
       DIS_tcp_wflush(connection[out].ch_socket);
-      if (pbsgss_client_authenticate(server,connection[out].ch_socket,1) != 0) {
+      if (pbsgss_client_authenticate(server,connection[out].ch_socket,1,1) != 0) {
 	neediff = 1;
 	if (getenv("PBSDEBUG")) {
 	  fprintf(stderr,"ERROR:  cannot authenticate connection, errno=%d (%s)\n",
diff -ru old/src/server/gss/req_gssauthenuser.c new/src/server/gss/req_gssauthenuser.c
--- old/src/server/gss/req_gssauthenuser.c	2007-05-22 08:50:45.000000000 +0200
+++ new/src/server/gss/req_gssauthenuser.c	2007-05-30 14:33:23.198951836 +0200
@@ -131,7 +131,14 @@
   svr_conn[sock].principal[client_name.length] = '\0';
   memcpy(&(svr_conn[sock].creds),&client_creds,sizeof(client_creds));
   svr_conn[sock].cn_authen = PBS_NET_CONN_GSSAPIAUTH;
-  gss_delete_sec_context(&ret_flags,&context,GSS_C_NO_BUFFER);
+  if (!(ret_flags & GSS_C_INTEG_FLAG)) {
+    log_event(PBSEVENT_DEBUG,
+	      PBS_EVENTCLASS_SERVER,
+	      "req_gssauthenuser",
+	      "Integrity protection not available on connection.");
+    req_reject(PBSE_SYSTEM,0,preq,NULL,"no integrity protection");
+  }
+  pbsgss_save_sec_context(&context,ret_flags,sock);
   log_event(PBSEVENT_DEBUG,
 	    PBS_EVENTCLASS_SERVER,"req_gssauthenuser calling con_credent","");
   return gss_conn_credent(preq,sock);
diff -ru old/src/server/svr_movejob.c new/src/server/svr_movejob.c
--- old/src/server/svr_movejob.c	2007-05-22 08:50:46.000000000 +0200
+++ new/src/server/svr_movejob.c	2007-05-30 14:33:23.198951836 +0200
@@ -875,7 +875,7 @@
 	exit(1);
       }
       retries = 0;
-      while ((i = pbsgss_client_authenticate(hostname, connection[con].ch_socket,1)) != 0) {
+      while ((i = pbsgss_client_authenticate(hostname, connection[con].ch_socket,1,0)) != 0) {
 	fprintf(stderr,"send job failed: Couldn't authenticate as user to %s:%d : %d\n",hostname,con,i);      
 	if (retries++ > 2) {
 	  exit(1);


More information about the torquedev mailing list