XrdSecTLayer.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d S e c T L a y e r . c c                        */
00004 /*                                                                            */
00005 /*                                                                            */
00006 /* (c) 2008 by the Board of Trustees of the Leland Stanford, Jr., University  */
00007 /*                            All Rights Reserved                             */
00008 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00009 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00010 /******************************************************************************/
00011 
00012 #include <sys/types.h>
00013 #include <sys/socket.h>
00014 #include <errno.h>
00015 #include <fcntl.h>
00016 #include <poll.h>
00017 #include <stdio.h>
00018 #include <unistd.h>
00019 
00020 #include "XrdOuc/XrdOucErrInfo.hh"
00021 #include "XrdSec/XrdSecTLayer.hh"
00022 #include "XrdSys/XrdSysHeaders.hh"
00023 
00024 /******************************************************************************/
00025 /*                         S t a t i c   V a l u e s                          */
00026 /******************************************************************************/
00027 
00028 // Some compilers are incapable of optimizing away inline static const char's.
00029 //
00030 const char  XrdSecTLayer::TLayerRR::endData;
00031 const char  XrdSecTLayer::TLayerRR::xfrData;
00032   
00033 /******************************************************************************/
00034 /*                           C o n s t r u c t o r                            */
00035 /******************************************************************************/
00036 
00037 XrdSecTLayer::XrdSecTLayer(const char *pName, Initiator who1st)
00038              : XrdSecProtocol(pName),
00039                secTid(0), mySem(0), Starter(who1st), myFD(-1), urFD(-1),
00040                Tmax(275), Tcur(0), eCode(0), eText(0)
00041 {
00042 
00043 // Do the standard stuff
00044 //
00045    memset((void *)&Hdr, 0, sizeof(Hdr));
00046    strncpy(Hdr.protName,pName,sizeof(Hdr.protName)-1);
00047 }
00048   
00049 /******************************************************************************/
00050 /*               C l i e n t   O r i e n t e d   M e t h o d s                */
00051 /******************************************************************************/
00052 /******************************************************************************/
00053 /*                        g e t C r e d e n t i a l s                         */
00054 /******************************************************************************/
00055 
00056 XrdSecCredentials *XrdSecTLayer::getCredentials(XrdSecParameters *parm,
00057                                                 XrdOucErrInfo    *einfo)
00058 {
00059    char Buff[dataSz];
00060    int Blen = 0, wrLen = 0;
00061    char *bP, Req = TLayerRR::xfrData;
00062 
00063 // If this is the first time call, perform boot-up sequence and start the flow
00064 //
00065    eDest = einfo;
00066    if (!parm)
00067       {if (!bootUp(isClient)) return 0;
00068        if (Starter == isServer)
00069           {Hdr.protCode = TLayerRR::xfrData;
00070            bP = (char *)malloc(hdrSz);
00071            memcpy(bP, (char *)&Hdr, hdrSz);
00072            return new XrdSecCredentials(bP, hdrSz);
00073           }
00074       } else {
00075        if (parm->size < hdrSz) 
00076           {secError("Invalid parms length", EPROTO);
00077            return 0;
00078           }
00079        Req  = ((TLayerRR *)parm->buffer)->protCode;
00080        wrLen= parm->size - hdrSz;
00081       }
00082 
00083 // Perform required action
00084 // xfrData -> xfrData | endData if socket gets closed
00085 // endData -> endData           if socket still open else protocol error
00086 //
00087    switch(Req)
00088          {case TLayerRR::xfrData:
00089                if (wrLen > 0 && write(myFD, parm->buffer+hdrSz, wrLen) < 0)
00090                   {secError("Socket write failed", errno); return 0;}
00091                Blen = Read(myFD, Buff, dataSz);
00092                if (Blen < 0 && (Blen != -EPIPE) && (Blen != -ECONNRESET))
00093                   {secError("Socket read failed", -Blen); return 0;}
00094                break;
00095           case TLayerRR::endData:
00096                if (myFD < 0) {secError("Protocol violation", EPROTO); return 0;}
00097                Blen = -1;
00098                break;
00099           default: secError("Unknown parms request", EINVAL); return 0;
00100          }
00101 
00102 // Set correct protocol code based on value in Blen. On the client side we
00103 // check for proper completion upon socket close or when we get endData.
00104 // Note that we apply self-pacing here as well since either side can pace,
00105 //
00106         if (Blen < 0)      {if (!secDone()) return 0;
00107                             Blen = 0; Hdr.protCode = TLayerRR::endData;}
00108    else if (Blen || wrLen) {Tcur = 0; Hdr.protCode = TLayerRR::xfrData;}
00109    else if (++Tcur <= Tmax)           Hdr.protCode = TLayerRR::xfrData;
00110    else                    {Tcur = 0; Hdr.protCode = TLayerRR::endData;}
00111 
00112 // Return the credentials
00113 //
00114    bP = (char *)malloc(hdrSz+Blen);
00115    memcpy(bP, (char *)&Hdr, hdrSz);
00116    if (Blen) memcpy(bP+hdrSz, Buff, Blen);
00117    return new XrdSecCredentials(bP, hdrSz+Blen);
00118 }
00119 
00120 /******************************************************************************/
00121 /*               S e r v e r   O r i e n t e d   M e t h o d s                */
00122 /******************************************************************************/
00123   
00124 int XrdSecTLayer::Authenticate  (XrdSecCredentials  *cred,
00125                                  XrdSecParameters  **parms,
00126                                  XrdOucErrInfo      *einfo)
00127 {
00128    char Buff[dataSz];
00129    int Blen = 0, wrLen;
00130    char *bP, Req;
00131 
00132 // If this is the first time call, perform boot-up sequence and start the flow
00133 //
00134    eDest = einfo;
00135    if (myFD < 0 && !bootUp(isServer)) return -1;
00136 
00137 // Get the request code
00138 //
00139    if (cred->size < hdrSz) {secError("Invalid credentials",EBADMSG); return -1;}
00140    Req  = ((TLayerRR *)cred->buffer)->protCode;
00141    wrLen= cred->size - hdrSz;
00142 
00143 // Perform required action
00144 // xfrData -> xfrData | endData if socket gets closed
00145 // endData -> noresponse
00146 //
00147    switch(Req)
00148          {case TLayerRR::xfrData:
00149                if (wrLen > 0 && write(myFD, cred->buffer+hdrSz, wrLen) < 0)
00150                   {secError("Socket write failed", errno); return -1;}
00151                Blen = Read(myFD, Buff, dataSz);
00152                if (Blen < 0 && (Blen != -EPIPE) && (Blen != -ECONNRESET))
00153                   {secError("Socket read failed", -Blen); return 0;}
00154                break;
00155           case TLayerRR::endData: return (secDone() ? 0 : -1);
00156           default: secError("Unknown parms request", EINVAL); return -1;
00157          }
00158 
00159 // Set correct protocol code based on value in Blen and wrLen. Note that if
00160 // both are zero then we decrease the pace count and bail if it reaches zero.
00161 // Otherwise, we reset the pace count to it initial value. On the server side,
00162 // we defer the socket drain until we receive a endData notification.
00163 //
00164         if (Blen < 0)      {Blen = 0; Hdr.protCode = TLayerRR::endData;}
00165    else if (Blen || wrLen) {Tcur = 0; Hdr.protCode = TLayerRR::xfrData;}
00166    else if (++Tcur <= Tmax)           Hdr.protCode = TLayerRR::xfrData;
00167    else                    {Tcur = 0; Hdr.protCode = TLayerRR::endData;}
00168 
00169 // Return the credentials
00170 //
00171    bP = (char *)malloc(hdrSz+Blen);
00172    memcpy(bP, (char *)&Hdr, hdrSz);
00173    if (Blen) memcpy(bP+hdrSz, Buff, Blen);
00174    *parms = new XrdSecParameters(bP, hdrSz+Blen);
00175 
00176    return 1;
00177 }
00178 
00179 
00180 /******************************************************************************/
00181 /*                       P r i v a t e   M e t h o d s                        */
00182 /******************************************************************************/
00183 /******************************************************************************/
00184 /*                                b o o t U p                                 */
00185 /******************************************************************************/
00186 
00187 void *XrdSecTLayerBootUp(void *carg)
00188       {XrdSecTLayer *tP = (XrdSecTLayer *)carg;
00189        tP->secXeq();
00190        return (void *)0;
00191       }
00192 
00193 /******************************************************************************/
00194   
00195 int XrdSecTLayer::bootUp(Initiator whoami)
00196 {
00197    int sv[2];
00198 
00199 // Create a socket pair
00200 //
00201    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
00202       {secError("Unable to create socket pair", errno); return 0;}
00203    myFD = sv[0]; urFD = sv[1];
00204    Responder = whoami;
00205 
00206 // Make sure these sockets don't persist
00207 //
00208    fcntl(myFD, F_SETFD, FD_CLOEXEC);
00209    fcntl(urFD, F_SETFD, FD_CLOEXEC);
00210 
00211 // Start a thread to handle the socket interaction
00212 //
00213    if (XrdSysThread::Run(&secTid,XrdSecTLayerBootUp,(void *)this, XRDSYSTHREAD_HOLD))
00214       {int rc = errno;
00215        close(myFD); myFD = -1;
00216        close(urFD); urFD = -1;
00217        secError("Unable to create thread", rc);
00218        return 0;
00219       }
00220 
00221 // All done
00222 //
00223    return 1;
00224 }
00225 
00226 /******************************************************************************/
00227 /*                                  R e a d                                   */
00228 /******************************************************************************/
00229   
00230 int XrdSecTLayer::Read(int FD, char *Buff, int rdLen)
00231 {
00232    struct pollfd polltab = {FD, POLLIN|POLLRDNORM|POLLHUP, 0};
00233    int retc, xWt, Tlen = 0;
00234 
00235 // Read the data. We will employ a self-pacing read schedule where the
00236 // assumptioon is that should a read produce zero bytes after a small amount
00237 // of time then the data supplier needs additional data (i.e., writes) before
00238 // it can supply data to be read. This occurs because certain transport layer
00239 // protocols issue several writes in a row to complete the client/server
00240 // interaction. We cannot use a fixed schedule for this because streams may
00241 // coalesce adjacent writes, sigh.
00242 
00243 // Compute the actual poll wait time
00244 //
00245    if (Tcur) xWt = (Tcur+10)/10;
00246       else   xWt = 1;
00247 
00248 // Now do the interaction
00249 //
00250    do {do {retc = poll(&polltab, 1, xWt);} while(retc < 0 && errno == EINTR);
00251        if (retc <= 0) return (retc ? -errno : Tlen);
00252        do {retc = read(FD, Buff, rdLen);}  while(retc < 0 && errno == EINTR);
00253        if (retc <= 0) return (retc ? -errno : (Tlen ? Tlen : -EPIPE));
00254        Tlen += retc; Buff += retc; rdLen -= retc; xWt = 1;
00255       } while(rdLen > 0);
00256 
00257    return Tlen;
00258 }
00259 
00260 /******************************************************************************/
00261 /*                               s e c D o n e                                */
00262 /******************************************************************************/
00263 
00264 int XrdSecTLayer::secDone()
00265 {
00266 
00267 // First close the socket and wait for thread completion
00268 //
00269    secDrain();
00270 
00271 // Next, check if everything went well
00272 //
00273    if (!eCode) return 1;
00274 
00275 // Diagnose the problem and return failure
00276 //
00277    secError((eText ? eText : "?"), eCode, 0);
00278    return 0;
00279 }
00280   
00281 /******************************************************************************/
00282 /*                              s e c D r a i n                               */
00283 /******************************************************************************/
00284   
00285 void XrdSecTLayer::secDrain()
00286 {
00287    if (myFD >= 0)
00288       {close(myFD); myFD = -1;
00289        mySem.Wait();
00290       }
00291 }
00292 
00293 /******************************************************************************/
00294 /*                              s e c E r r n o                               */
00295 /******************************************************************************/
00296   
00297 const char *XrdSecTLayer::secErrno(int rc, char *buff)
00298 {
00299    sprintf(buff, "err %d", rc);
00300    return buff;
00301 }
00302 
00303 /******************************************************************************/
00304 /*                              s e c E r r o r                               */
00305 /******************************************************************************/
00306   
00307 void XrdSecTLayer::secError(const char *Msg, int rc, int iserrno)
00308 {
00309    char buff[32];
00310    const char *tlist[] = {"XrdSecProtocol", Hdr.protName, ": ", Msg, "; ", 
00311                           (iserrno ? strerror(rc) : secErrno(rc,buff))
00312                          };
00313    int i, n = sizeof(tlist)/sizeof(const char *);
00314 
00315    if (eDest) eDest->setErrInfo(rc, tlist, n);
00316       else {for (i = 0; i < n; i++) cerr <<tlist[i]; cerr <<endl;}
00317 
00318    secDrain();
00319 }
00320 
00321 /******************************************************************************/
00322 /*                                s e c X e q                                 */
00323 /******************************************************************************/
00324 
00325 void XrdSecTLayer::secXeq()
00326 {
00327    XrdOucErrInfo einfo;
00328    const char *Msg;
00329 
00330 // Initiate the protocol
00331 //
00332    if (Responder == XrdSecTLayer::isClient) secClient(urFD, &einfo);
00333       else secServer(urFD, &einfo);
00334 // Extract out the completion code
00335 //
00336    Msg = einfo.getErrText(eCode);
00337    if (eText) {free(eText); eText = 0;}
00338    if (eCode) eText = strdup(Msg ? Msg : "Authentication failed");
00339 
00340 // Indicate we are done
00341 //
00342    if (urFD>0) close(urFD);
00343    urFD = -1;
00344    mySem.Post();
00345 }

Generated on Tue Jul 5 14:46:58 2011 for ROOT_528-00b_version by  doxygen 1.5.1