XrdSecProtocolssl.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                 X r d S e c P r o t o c o l s s l . c c                    */
00004 /*                                                                            */
00005 /* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010 
00011 //       $Id: XrdSecProtocolssl.cc 38011 2011-02-08 18:35:57Z ganis $
00012 
00013 
00014 const char *XrdSecProtocolsslCVSID = "$Id: XrdSecProtocolssl.cc 38011 2011-02-08 18:35:57Z ganis $";
00015 
00016 #include "XrdSecProtocolssl.hh"
00017 
00018 char*  XrdSecProtocolssl::sslcadir=0;
00019 char*  XrdSecProtocolssl::sslvomsdir=0;
00020 char*  XrdSecProtocolssl::procdir=(char*)"";
00021 XrdSecProtocolsslProc* XrdSecProtocolssl::proc=(XrdSecProtocolsslProc*)0;
00022 int    XrdSecProtocolssl::verifydepth=10;
00023 int    XrdSecProtocolssl::verifyindex=0;
00024 int    XrdSecProtocolssl::sslselecttimeout=10;
00025 int    XrdSecProtocolssl::sslsessioncachesize=2000;
00026 char*  XrdSecProtocolssl::sslkeyfile=0;
00027 char*  XrdSecProtocolssl::sslserverkeyfile=0;
00028 char   XrdSecProtocolssl::sslserverexportpassword[EXPORTKEYSTRENGTH+1];
00029 char*  XrdSecProtocolssl::sslcertfile=0;
00030 char*  XrdSecProtocolssl::sslproxyexportdir=(char*)0;
00031 bool   XrdSecProtocolssl::sslproxyexportplain=1;
00032 int    XrdSecProtocolssl::debug=0;
00033 time_t XrdSecProtocolssl::sslsessionlifetime=86400;
00034 bool   XrdSecProtocolssl::isServer=0;
00035 bool   XrdSecProtocolssl::forwardProxy=0;
00036 bool   XrdSecProtocolssl::allowSessions=0;
00037 char*  XrdSecProtocolssl::SessionIdContext = (char*)"xrootdssl"; 
00038 char*  XrdSecProtocolssl::gridmapfile = (char*) "/etc/grid-security/grid-mapfile";
00039 bool   XrdSecProtocolssl::mapuser  = false;
00040 bool   XrdSecProtocolssl::mapnobody  = false;
00041 char*  XrdSecProtocolssl::vomsmapfile = (char*) "/etc/grid-security/voms-mapfile";
00042 bool   XrdSecProtocolssl::mapgroup = false;
00043 bool   XrdSecProtocolssl::mapcerncertificates = false;
00044 int    XrdSecProtocolssl::threadsinuse=0;
00045 int    XrdSecProtocolssl::errortimeout=0;
00046 int    XrdSecProtocolssl::errorverify=0;
00047 int    XrdSecProtocolssl::errorqueue=0;
00048 int    XrdSecProtocolssl::erroraccept=0;
00049 int    XrdSecProtocolssl::errorread=0;
00050 int    XrdSecProtocolssl::errorabort=0;
00051 int    XrdSecProtocolssl::forwardedproxies=0;
00052 X509_STORE*    XrdSecProtocolssl::store=0;
00053 X509_LOOKUP*   XrdSecProtocolssl::lookup=0;
00054 SSL_CTX*       XrdSecProtocolssl::ctx=0;
00055 XrdSysError    XrdSecProtocolssl::ssleDest(0, "secssl_");
00056 XrdSysLogger   XrdSecProtocolssl::Logger;
00057 time_t         XrdSecProtocolssl::storeLoadTime;
00058 
00059 XrdSysMutex XrdSecsslSessionLock::sessionmutex;
00060 XrdOucHash<XrdOucString> XrdSecProtocolssl::gridmapstore;
00061 XrdOucHash<XrdOucString> XrdSecProtocolssl::vomsmapstore;
00062 XrdOucHash<XrdOucString> XrdSecProtocolssl::stringstore;
00063 XrdSysMutex              XrdSecProtocolssl::StoreMutex;           
00064 XrdSysMutex              XrdSecProtocolssl::GridMapMutex;
00065 XrdSysMutex              XrdSecProtocolssl::VomsMapMutex;
00066 XrdSysMutex*             XrdSecProtocolssl::CryptoMutexPool[PROTOCOLSSL_MAX_CRYPTO_MUTEX];
00067 XrdSysMutex              XrdSecProtocolssl::ThreadsInUseMutex;
00068 XrdSysMutex              XrdSecProtocolssl::ErrorMutex;
00069 
00070 XrdSysMutex SSLTRACEMUTEX;
00071 
00072 /******************************************************************************/
00073 /*             T h r e a d - S a f e n e s s   F u n c t i o n s              */
00074 /******************************************************************************/
00075 static unsigned long protocolssl_id_callback(void) {
00076   return (unsigned long)XrdSysThread::ID();
00077 }
00078 
00079 void protocolssl_lock(int mode, int n, const char *file, int line)
00080 {
00081   if (mode & CRYPTO_LOCK) {
00082     if (XrdSecProtocolssl::CryptoMutexPool[n]) {
00083       XrdSecProtocolssl::CryptoMutexPool[n]->Lock();
00084     }
00085   } else {
00086     if (XrdSecProtocolssl::CryptoMutexPool[n]) {
00087       XrdSecProtocolssl::CryptoMutexPool[n]->UnLock();
00088     }
00089   }
00090 }
00091 
00092 
00093 /******************************************************************************/
00094 /*             C l i e n t   O r i e n t e d   F u n c t i o n s              */
00095 /******************************************************************************/
00096 
00097 int secprotocolssl_pem_cb(char *buf, int size, int rwflag, void *password)
00098 {
00099   memset(buf,0,size);
00100   memcpy(buf,XrdSecProtocolssl::sslserverexportpassword,EXPORTKEYSTRENGTH+1);
00101   return EXPORTKEYSTRENGTH;
00102 }
00103 
00104 void XrdSecProtocolssl::GetEnvironment() {
00105   EPNAME("GetEnvironment");
00106   // default the cert/key file to the standard proxy locations
00107   char proxyfile[1024];
00108   sprintf(proxyfile,"/tmp/x509up_u%d",(int)geteuid());
00109 
00110   if (sslproxyexportdir) {
00111     sprintf(proxyfile,"%s/x509up_u%d",sslproxyexportdir,(int)geteuid()); 
00112   }
00113 
00114   if (XrdSecProtocolssl::sslcertfile) { free (XrdSecProtocolssl::sslcertfile); }
00115   if (XrdSecProtocolssl::sslkeyfile) { free (XrdSecProtocolssl::sslkeyfile); }
00116 
00117   XrdSecProtocolssl::sslcertfile = strdup(proxyfile);
00118   XrdSecProtocolssl::sslkeyfile  = strdup(proxyfile);
00119 
00120   char *cenv = getenv("XrdSecDEBUG");
00121   // debug
00122   if (cenv)
00123     if (cenv[0] >= 49 && cenv[0] <= 57) XrdSecProtocolssl::debug = atoi(cenv);
00124 
00125   // directory with CA certificates
00126   cenv = getenv("XrdSecSSLCADIR");
00127   if (cenv) {
00128     if (XrdSecProtocolssl::sslcadir) { free (XrdSecProtocolssl::sslcadir); }
00129     XrdSecProtocolssl::sslcadir = strdup(cenv);
00130   }
00131   else {
00132     // accept X509_CERT_DIR 
00133     cenv = getenv("X509_CERT_DIR");
00134     if (cenv) {
00135       if (XrdSecProtocolssl::sslcadir) { free (XrdSecProtocolssl::sslcadir); }
00136       XrdSecProtocolssl::sslcadir = strdup(cenv);
00137     }
00138   }
00139   // directory with VOMS certificates
00140   cenv = getenv("XrdSecSSLVOMSDIR");
00141   if (cenv) {
00142     if (XrdSecProtocolssl::sslvomsdir) { free (XrdSecProtocolssl::sslvomsdir); }
00143     XrdSecProtocolssl::sslvomsdir = strdup(cenv);
00144   }
00145 
00146 
00147   // file with user cert
00148   cenv = getenv("XrdSecSSLUSERCERT");
00149   if (cenv) {
00150     if (XrdSecProtocolssl::sslcertfile) { free (XrdSecProtocolssl::sslcertfile); }
00151     XrdSecProtocolssl::sslcertfile = strdup(cenv);  
00152   } else {
00153     // accept X509_USER_CERT
00154     cenv = getenv("X509_USER_CERT");
00155     if (cenv) {
00156       if (XrdSecProtocolssl::sslcertfile) { free (XrdSecProtocolssl::sslcertfile); }
00157       XrdSecProtocolssl::sslcertfile = strdup(cenv);
00158     } else {
00159       // accept X509_USER_PROXY
00160       cenv = getenv("X509_USER_PROXY");
00161       if (cenv) {
00162         if (XrdSecProtocolssl::sslcertfile) { free (XrdSecProtocolssl::sslcertfile); }
00163         XrdSecProtocolssl::sslcertfile = strdup(cenv);
00164       }
00165     }
00166   }
00167 
00168   cenv = getenv("XrdSecSSLSELECTTIMEOUT");
00169   if (cenv) {
00170     XrdSecProtocolssl::sslselecttimeout = atoi(cenv);
00171     if ( XrdSecProtocolssl::sslselecttimeout < 5) {
00172       XrdSecProtocolssl::sslselecttimeout = 5;
00173     }
00174   }
00175 
00176   // file with user key
00177   cenv = getenv("XrdSecSSLUSERKEY");
00178   if (cenv) {
00179     if (XrdSecProtocolssl::sslkeyfile) { free (XrdSecProtocolssl::sslkeyfile); }    
00180       XrdSecProtocolssl::sslkeyfile = strdup(cenv);
00181   } else {
00182     // accept X509_USER_KEY
00183     cenv = getenv("X509_USER_KEY");
00184     if (cenv) {
00185       if (XrdSecProtocolssl::sslkeyfile) { free (XrdSecProtocolssl::sslkeyfile); }    
00186       XrdSecProtocolssl::sslkeyfile = strdup(cenv);
00187     } else {
00188       // accept X509_USER_PROXY
00189       cenv = getenv("X509_USER_PROXY");
00190       if (cenv) {
00191         if (XrdSecProtocolssl::sslkeyfile) { free (XrdSecProtocolssl::sslkeyfile); }    
00192         XrdSecProtocolssl::sslkeyfile = strdup(cenv);
00193       }
00194     }
00195   }
00196   // verify depth
00197   cenv = getenv("XrdSecSSLVERIFYDEPTH");
00198   if (cenv)
00199     XrdSecProtocolssl::verifydepth = atoi(cenv);
00200     
00201   // proxy forwarding
00202   cenv = getenv("XrdSecSSLPROXYFORWARD");
00203   if (cenv)
00204     XrdSecProtocolssl::forwardProxy = atoi(cenv);
00205 
00206   // ssl session reuse
00207   cenv = getenv("XrdSecSSLSESSION");
00208   if (cenv)
00209     XrdSecProtocolssl::allowSessions = atoi(cenv);
00210   
00211   TRACE(Authen,"====> debug         = " << XrdSecProtocolssl::debug);
00212   TRACE(Authen,"====> cadir         = " << XrdSecProtocolssl::sslcadir);
00213   TRACE(Authen,"====> keyfile       = " << XrdSecProtocolssl::sslkeyfile);
00214   TRACE(Authen,"====> certfile      = " << XrdSecProtocolssl::sslcertfile);
00215   TRACE(Authen,"====> verify depth  = " << XrdSecProtocolssl::verifydepth);
00216   TRACE(Authen,"====> timeout       = " << XrdSecProtocolssl::sslselecttimeout);
00217 }
00218 
00219 int XrdSecProtocolssl::Fatal(XrdOucErrInfo *erp, const char *msg, int rc)
00220 {
00221   const char *msgv[8];
00222   int k, i = 0;
00223   
00224   msgv[i++] = "Secssl: ";    //0
00225   msgv[i++] = msg;            //1
00226 
00227   if (erp) erp->setErrInfo(rc, msgv, i);
00228   else {for (k = 0; k < i; k++) cerr <<msgv[k];
00229     cerr <<endl;
00230   }
00231   
00232   if (XrdSecProtocolssl::proc) {
00233     XrdSecProtocolsslProcFile* pf;
00234     char ErrorInfo[16384];
00235     sprintf(ErrorInfo,"errortimeout  = %d\nerrorverify   = %d\nerrorqueue    = %d\nerroraccept   = %d\nerrorread     = %d\nerrorabort    = %d", errortimeout, errorverify, errorqueue, erroraccept, errorread, errorabort); 
00236     pf= XrdSecProtocolssl::proc->Handle("error"); pf && pf->Write(ErrorInfo);
00237   }
00238 
00239   return -1;
00240 }
00241 
00242 
00243 int ssl_select(int fd) {
00244 
00245   if (fd<0)
00246     return -1;
00247 
00248   fd_set read_mask;
00249 
00250   struct timeval timeout;
00251     
00252   timeout.tv_sec = 0;
00253   timeout.tv_usec = 100000;
00254     
00255   FD_ZERO(&read_mask);
00256   FD_SET(fd, &read_mask);
00257 
00258   int result = select(fd + 1, &read_mask, 0, 0, &timeout);
00259     
00260   if ( (result < 0 ) && (errno == EINTR || errno == EAGAIN))
00261     return 0;
00262 
00263   if (result < 0)
00264     return -1;
00265 
00266   return 1;
00267 }
00268 
00269 
00270 int ssl_continue(SSL* ssl, int err) {
00271   switch (SSL_get_error(ssl,err)) {
00272   case SSL_ERROR_NONE:
00273     return 0;
00274   case SSL_ERROR_WANT_WRITE:
00275     return 1;
00276   case SSL_ERROR_WANT_READ:
00277     return 1;
00278   case SSL_ERROR_WANT_X509_LOOKUP:
00279     return 1;
00280   case SSL_ERROR_SYSCALL:
00281   case SSL_ERROR_SSL:
00282     if (errno == EAGAIN)
00283       return 1;
00284   case SSL_ERROR_ZERO_RETURN:
00285     return -1;
00286   }
00287   return -1;
00288 }
00289 
00290 /******************************************************************************/
00291 /*                        g e t C r e d e n t i a l s                         */
00292 /******************************************************************************/
00293 
00294 
00295 void   
00296 XrdSecProtocolssl::secClient(int theFD, XrdOucErrInfo      *error) {
00297   
00298   EPNAME("secClient");
00299 
00300   XrdSecsslThreadInUse ThreadInUse();
00301 
00302   char *nossl = getenv("XrdSecNoSSL");
00303   if (nossl) {
00304     error->setErrInfo(ENOENT,"SSL is disabled by force");
00305     return ;
00306   }
00307 
00308   XrdSecProtocolssl::GetEnvironment();
00309 
00310   error->setErrInfo(0,"");
00311   SSLMutex.Lock();
00312 
00313   int err=0;
00314   char*    str;
00315   SSL_METHOD *meth;
00316   SSL_SESSION *session=0;
00317 
00318   SSL_load_error_strings();  
00319   SSLeay_add_ssl_algorithms();
00320   meth = (SSL_METHOD*) TLSv1_client_method();
00321 
00322   ERR_load_crypto_strings();
00323 
00324   XrdOucString sslsessionfile="";
00325   XrdOucString sslsessionid="";
00326   
00327   sslsessionfile = "/tmp/xssl_";
00328   sslsessionid += (int)geteuid();
00329   sslsessionid += ":";
00330   sslsessionid += host.c_str();
00331   sslsessionfile += sslsessionid;
00332 
00333   XrdSecsslSessionLock sessionlock;
00334   sessionlock.SoftLock();
00335 
00336   if (allowSessions) {
00337     struct stat sessionstat;
00338 
00339     if (!stat(sslsessionfile.c_str(),&sessionstat)) {
00340       // session exists ... I try to read it
00341       FILE* fp = fopen(sslsessionfile.c_str(), "r");
00342       if (fp) {
00343         if (sessionlock.HardLock(sslsessionfile.c_str())) {
00344           session = PEM_read_SSL_SESSION(fp, NULL, NULL, NULL);
00345           fclose(fp);
00346           sessionlock.HardUnLock();
00347         }
00348       }
00349       
00350       if (session) {
00351         
00352         DEBUG("Info: ("<<__FUNCTION__<<") Session loaded from " << sslsessionfile.c_str());
00353         char session_id[1024];
00354         for (int i=0; i< (int)session->session_id_length; i++) {
00355           sprintf(session_id+(i*2),"%02x",session->session_id[i]);
00356         }
00357         
00358         unsigned char buf[5],*p;
00359         unsigned long l;
00360         
00361         p=buf;
00362         l=session->cipher_id;
00363         l2n(l,p);
00364 
00365         DEBUG("Info: ("<<__FUNCTION__<<") Session Id: "<< session_id << " Verify: " << session->verify_result << " (" << X509_verify_cert_error_string(session->verify_result) << ")");
00366       } else {
00367         DEBUG("Info: ("<<__FUNCTION__<<") Session load failed from " << sslsessionfile.c_str());
00368         ERR_print_errors_fp(stderr);
00369       }
00370     }
00371   }
00372 
00373   clientctx = SSL_CTX_new (meth);
00374 
00375 
00376   SSL_CTX_set_options(clientctx,  SSL_OP_ALL | SSL_OP_NO_SSLv2);
00377 
00378   if (!clientctx) {
00379     Fatal(error,"Cannot do SSL_CTX_new",-1);
00380     exit(2);
00381   }
00382   
00383   if (!XrdSecProtocolssl::sslproxyexportplain) {
00384     // set a password callback here
00385     SSL_CTX_set_default_passwd_cb(clientctx, secprotocolssl_pem_cb);
00386     SSL_CTX_set_default_passwd_cb_userdata(clientctx, XrdSecProtocolssl::sslserverexportpassword);
00387   }
00388 
00389   if (SSL_CTX_use_certificate_chain_file(clientctx, sslcertfile) <= 0) {
00390     ERR_print_errors_fp(stderr);
00391     Fatal(error,"Cannot use certificate file",-1);
00392     if (clientctx) SSL_CTX_free (clientctx);
00393     SSLMutex.UnLock();
00394     return;
00395   }
00396 
00397   if (SSL_CTX_use_PrivateKey_file(clientctx, sslkeyfile, SSL_FILETYPE_PEM) <= 0) {
00398     ERR_print_errors_fp(stderr);
00399     Fatal(error,"Cannot use private key file",-1);
00400     if (clientctx) SSL_CTX_free (clientctx);
00401     SSLMutex.UnLock();
00402     return;
00403   }
00404 
00405 
00406   if (!SSL_CTX_check_private_key(clientctx)) {
00407     fprintf(stderr,"Error: (%s) Private key does not match the certificate public key\n",__FUNCTION__);
00408     Fatal(error,"Private key does not match the certificate public key",-1);
00409     if (clientctx) SSL_CTX_free (clientctx);
00410     SSLMutex.UnLock();
00411     return;
00412   } else {
00413     DEBUG("Private key check passed ...");
00414   }
00415   SSL_CTX_load_verify_locations(clientctx, NULL,sslcadir);
00416   SSL_CTX_set_verify(clientctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,  GRST_callback_SSLVerify_wrapper);
00417 
00418   SSL_CTX_set_cert_verify_callback(clientctx, GRST_verify_cert_wrapper, (void *) NULL);
00419 
00420   grst_cadir   = sslcadir;
00421   grst_vomsdir = sslvomsdir;
00422 
00423   grst_depth=verifydepth;
00424   SSL_CTX_set_verify_depth(clientctx, verifydepth);
00425 
00426   if (session) {
00427     SSL_CTX_add_session(clientctx,session);
00428   }
00429 
00430 
00431   ssl = SSL_new (clientctx);            
00432   SSL_set_purpose(ssl,X509_PURPOSE_ANY);
00433   if (session) {
00434     SSL_set_session(ssl, session);
00435   }
00436 
00437   sessionlock.SoftUnLock();
00438   sessionlock.HardUnLock();
00439 
00440   if (!ssl) {
00441     Fatal(error,"Cannot do SSL_new",-1);
00442     exit(6);
00443   }
00444 
00445   SSL_set_fd (ssl, theFD);
00446 
00447   /* make socket non-blocking */
00448   int flags;
00449 
00450   /* Set socket to non-blocking */
00451   if ((flags = fcntl(theFD, F_GETFL, 0)) < 0) {
00452     /* Handle error */
00453     fprintf(stderr,"Error: (%s) failed to make socket non-blocking\n",__FUNCTION__);
00454   } else {
00455     if (fcntl(theFD, F_SETFL, flags | O_NONBLOCK) < 0) {
00456       /* Handle error */
00457       fprintf(stderr,"Error: (%s) failed to make socket non-blocking\n",__FUNCTION__);
00458     }
00459   }
00460 
00461   time_t now= time(NULL);
00462   
00463   do {
00464     if ( (time(NULL)-now) > XrdSecProtocolssl::sslselecttimeout ) {
00465       ErrorMutex.Lock();erroraccept++;errortimeout++; ErrorMutex.UnLock();
00466       /* timeout */
00467       Fatal(error,"authenticate - handshake time out",-ETIMEDOUT);
00468       TRACE(Authen,"Error: ("<<__FUNCTION__<<") handshake timedout in SSL_connect");
00469       SSLMutex.UnLock();
00470       return;
00471     }
00472 
00473     int set = ssl_select(theFD);
00474     if (set < 1)
00475       continue;
00476     err = SSL_connect (ssl);
00477     if (err>0)
00478       break;
00479   } while ( (ssl_continue(ssl,err))==1);
00480 
00481 
00482 
00483   if (err!=1) {
00484     // we want to see the error message from the server side
00485     ERR_print_errors_fp(stderr);
00486     if (clientctx) SSL_CTX_free (clientctx);
00487     SSLMutex.UnLock();
00488     return;
00489   }
00490 
00491   /* I am not sure, if this is actually needed at all */
00492   if (!session)
00493     session = SSL_get1_session(ssl);
00494   
00495   /* Get the cipher - opt */
00496   
00497   TRACE(Authen,"SSL connection uses cipher: "<<SSL_get_cipher (ssl));
00498   
00499   /* Get server's certificate (note: beware of dynamic allocation) - opt */
00500   
00501   server_cert = SSL_get_peer_certificate (ssl);       
00502 
00503   if (!server_cert) {
00504     TRACE(Authen,"Server didn't provide certificate");
00505   }
00506 
00507   XrdOucString rdn;
00508   
00509   str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
00510   rdn = str;
00511   TRACE(Authen,"Server certificate subject:\t" << str);
00512   OPENSSL_free (str);
00513   
00514   str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
00515   TRACE(Authen,"Server certificate  issuer: \t" << str);
00516   OPENSSL_free (str);
00517   
00518   X509_free (server_cert);
00519   server_cert=0;
00520 
00521 
00522   /******************************************/
00523   /* this is called only to cleanup objects */
00524   /******************************************/
00525 
00526   /* get the grst_chain  */
00527   GRSTx509Chain *grst_chain = (GRSTx509Chain*) SSL_get_app_data(ssl);
00528   SSL_set_app_data(ssl,0);
00529   
00530   if (grst_chain) {
00531     GRST_print_ssl_creds((void*) grst_chain);
00532     char* vr = GRST_get_voms_roles_and_free((void*) grst_chain);
00533     if (vr) {
00534       free(vr);
00535     }
00536   }
00537 
00538 
00539   if (forwardProxy) {
00540     if (!strcmp(sslkeyfile,sslcertfile)) {
00541       // this is a cert & key in one file atleast ... looks like proxy
00542       int fd = open(sslkeyfile,O_RDONLY);
00543       if (fd>=0) {
00544         int nread = read(fd,proxyBuff, sizeof(proxyBuff));
00545         if (nread>=0) {
00546           TRACE(Authen,"Uploading my Proxy ...\n");
00547 
00548 
00549           do {
00550             if ( (time(NULL)-now) > XrdSecProtocolssl::sslselecttimeout ) {
00551               ErrorMutex.Lock();errorread++;errortimeout++; ErrorMutex.UnLock();
00552               /* timeout */
00553               Fatal(error,"authenticate - handshake time out",-ETIMEDOUT);
00554               TRACE(Authen,"Error: ("<<__FUNCTION__<<") handshake timedout in SSL_read");
00555               ERR_remove_state(0);
00556               SSLMutex.UnLock();
00557               return;
00558             }
00559             
00560             int set = ssl_select(theFD);
00561             if (set < 1)
00562               continue;
00563             err = SSL_write(ssl, proxyBuff,nread);
00564           } while ( (ssl_continue(ssl,err)) == 1);
00565 
00566 
00567           if (err!= nread) {
00568             Fatal(error,"Cannot forward proxy",-1);
00569             if (clientctx) SSL_CTX_free (clientctx);
00570             if (session) SSL_SESSION_free(session);
00571             SSLMutex.UnLock();
00572             return;
00573           }
00574           
00575           char ok[16];
00576 
00577           do {
00578             if ( (time(NULL)-now) > XrdSecProtocolssl::sslselecttimeout ) {
00579               ErrorMutex.Lock();errorread++;errortimeout++; ErrorMutex.UnLock();
00580               /* timeout */
00581               Fatal(error,"authenticate - handshake time out",-ETIMEDOUT);
00582               TRACE(Authen,"Error: ("<<__FUNCTION__<<") handshake timedout in SSL_read");
00583               ERR_remove_state(0);
00584               SSLMutex.UnLock();
00585               return;
00586             }
00587             
00588             int set = ssl_select(theFD);
00589             if (set < 1)
00590               continue;
00591             err = SSL_read(ssl,ok, 3);
00592           } while ( (ssl_continue(ssl,err)) == 1);
00593           
00594           if (err != 3) {
00595             Fatal(error,"Didn't receive OK",-1);
00596             if (clientctx) SSL_CTX_free (clientctx);
00597             if (session) SSL_SESSION_free(session);
00598             SSLMutex.UnLock();
00599             return;
00600           } 
00601         } else {
00602           close(fd);
00603           Fatal(error,"Cannot read proxy file to forward",-1);
00604           if (clientctx) SSL_CTX_free (clientctx);
00605           if (session) SSL_SESSION_free(session);
00606           SSLMutex.UnLock();
00607           return;
00608         }
00609       } else {
00610         Fatal(error,"Cannot read proxy file to forward",-1);
00611         if (clientctx) SSL_CTX_free (clientctx);
00612         if (session) SSL_SESSION_free(session);
00613         SSLMutex.UnLock();
00614         return;
00615       }
00616       close(fd);
00617     }
00618   }
00619 
00620   if (allowSessions && session) {
00621     char session_id[1024];
00622     for (int i=0; i< (int)session->session_id_length; i++) {
00623       sprintf(session_id+(i*2),"%02x",session->session_id[i]);
00624     }
00625     
00626     if (session->cipher) {
00627       DEBUG("Info: ("<<__FUNCTION__<<") Session Id: "<< session_id << " Cipher: " << session->cipher->name  << " Verify: " << session->verify_result << " (" << X509_verify_cert_error_string(session->verify_result) << ")");
00628     } else {
00629       DEBUG("Info: ("<<__FUNCTION__<<") Session Id: "<< session_id << " Verify: " << session->verify_result << " (" << X509_verify_cert_error_string(session->verify_result) << ")");
00630     }
00631     // write out the session
00632     FILE* fp = fopen((const char*)(sslsessionfile.c_str()),"w+");
00633     if (fp) {
00634       if (sessionlock.HardLock(sslsessionfile.c_str())) {
00635         PEM_write_SSL_SESSION(fp, session);
00636       }
00637       fclose(fp);
00638       sessionlock.HardUnLock();
00639       DEBUG("Info: ("<<__FUNCTION__<<") Session stored to " << sslsessionfile.c_str());
00640       if (chmod(sslsessionfile.c_str(),S_IRUSR| S_IWUSR)) {
00641         Fatal(error,"secure session file (chmod 600 failed) ",-errno);
00642       }
00643     }
00644   }
00645 
00646   do {
00647     err = SSL_shutdown(ssl);
00648   } while (ssl_continue(ssl,err) || (!err));
00649   
00650   if (ssl) {
00651     SSL_free(ssl);ssl = 0;
00652   }
00653 
00654   if (clientctx) SSL_CTX_free (clientctx);
00655 
00656   if (session) {
00657     SSL_SESSION_free(session);
00658   }
00659 
00660   SSLMutex.UnLock();
00661   return;
00662 }
00663 
00664 /******************************************************************************/
00665 /*               S e r v e r   O r i e n t e d   M e t h o d s                */
00666 /******************************************************************************/
00667 
00668 
00669 
00670 /*----------------------------------------------------------------------------*/
00671 /* this helps to avoid memory leaks by strdup                                 */
00672 /* we maintain a string hash to keep all used user ids/group ids etc.         */
00673 
00674 char* 
00675 STRINGSTORE(const char* __charptr__) {
00676   XrdOucString* yourstring;
00677   if (!__charptr__ ) return (char*)"";
00678 
00679   XrdSecProtocolssl::StoreMutex.Lock();
00680   yourstring = XrdSecProtocolssl::stringstore.Find(__charptr__);
00681   XrdSecProtocolssl::StoreMutex.UnLock();
00682 
00683   if (yourstring) {
00684     return (char*)yourstring->c_str();
00685   } else {
00686     XrdOucString* newstring = new XrdOucString(__charptr__);
00687     XrdSecProtocolssl::StoreMutex.Lock();
00688     XrdSecProtocolssl::stringstore.Add(__charptr__,newstring);
00689     XrdSecProtocolssl::StoreMutex.UnLock();
00690     return (char*)newstring->c_str();
00691   } 
00692 }
00693 
00694 /*----------------------------------------------------------------------------*/
00695 void MyGRSTerrorLogFunc (char *lfile, int lline, int llevel, char *fmt, ...) {
00696   EPNAME("grst");
00697   va_list args;
00698   char fullmessage[4096];
00699   fullmessage[0] = 0;
00700 
00701   va_start(args, fmt);
00702   vsprintf(fullmessage,fmt,args);
00703   va_end(args);
00704 
00705   // just remove linefeeds
00706   XrdOucString sfullmessage = fullmessage;
00707   sfullmessage.replace("\n","");
00708 
00709   if (llevel <= GRST_LOG_WARNING) {
00710     TRACE(Authen," ("<< lfile << ":" << lline <<"): " << sfullmessage);    
00711   } else if (llevel <= GRST_LOG_INFO) {
00712     TRACE(Authen, " ("<< lfile << ":" << lline <<"): " << sfullmessage);    
00713   } else {
00714     DEBUG(" ("<< lfile << ":" << lline <<"): " << sfullmessage);
00715   }
00716 }
00717 
00718 /*----------------------------------------------------------------------------*/
00719 void
00720 XrdSecProtocolssl::secServer(int theFD, XrdOucErrInfo      *error) {
00721   int err=0;
00722 
00723   char*    str;
00724 
00725   SSLMutex.Lock();
00726 
00727 
00728   EPNAME("secServer");
00729 
00730   XrdSecsslThreadInUse ThreadInUse;
00731 
00732   if ((debug>=4)) {
00733     TRACE(Identity,"Info: having " << threadsinuse << " threads running SSL authentication");
00734   }
00735 
00736   XrdSecsslSessionLock sessionlock;
00737 
00738   /* check if we should reload the store */
00739   GridMapMutex.Lock();
00740   if ((time(NULL)-storeLoadTime) > 3600) {
00741     if (store) {
00742       TRACE(Authen,"Reloading X509 Store from " << sslcadir);
00743       X509_STORE_free(store);
00744       store = SSL_X509_STORE_create(NULL, sslcadir);
00745       X509_STORE_set_flags(XrdSecProtocolssl::store,0);
00746       storeLoadTime = time(NULL);
00747     }
00748   }
00749   GridMapMutex.UnLock();
00750 
00751   if (XrdSecProtocolssl::sslsessioncachesize) {
00752     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); // enable autoclear every 255 connections | SSL_SESS_CACHE_NO_AUTO_CLEAR );
00753   } else {
00754     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
00755   }
00756 
00757   ssl = SSL_new (ctx);
00758   SSL_set_purpose(ssl,X509_PURPOSE_ANY);
00759 
00760 
00761   TRACE(Authen,"Info: ("<<__FUNCTION__<<") Session Cache has size: " <<SSL_CTX_sess_get_cache_size(ctx));
00762 
00763   if (!ssl) {
00764     fprintf(stderr,"Error: (%s) failed to create context\n",__FUNCTION__);
00765     TRACE(Authen,"Error: ("<<__FUNCTION__<<") failed to create context");
00766     exit(5);
00767   }
00768 
00769   SSL_set_app_data(ssl,0);
00770 
00771   SSL_set_fd (ssl, theFD);
00772 
00773   /* make socket non-blocking */
00774   int flags;
00775 
00776   /* Set socket to non-blocking */
00777   if ((flags = fcntl(theFD, F_GETFL, 0)) < 0) {
00778     /* Handle error */
00779     fprintf(stderr,"Error: (%s) failed to make socket non-blocking\n",__FUNCTION__);
00780   } else {
00781     if (fcntl(theFD, F_SETFL, flags | O_NONBLOCK) < 0) {
00782       /* Handle error */
00783       fprintf(stderr,"Error: (%s) failed to make socket non-blocking\n",__FUNCTION__);
00784     }
00785   }
00786 
00787   TRACE(Authen,"Before:: SSL accept loop");
00788   time_t now= time(NULL);
00789   do {
00790     if (terminate) {
00791       ErrorMutex.Lock();erroraccept++;errorabort++; ErrorMutex.UnLock();
00792       /* timeout */
00793       Fatal(error,"authenticate - handshake abort from client",-ETIMEDOUT);
00794       TRACE(Authen,"Error: ("<<__FUNCTION__<<") aborted SSL_accept");
00795       ERR_remove_state(0);
00796       SSLMutex.UnLock();
00797       return;
00798     }
00799     
00800     if ( (time(NULL)-now) > XrdSecProtocolssl::sslselecttimeout ) {
00801       ErrorMutex.Lock();erroraccept++;errortimeout++; ErrorMutex.UnLock();
00802       /* timeout */
00803       Fatal(error,"authenticate - handshake time out",-ETIMEDOUT);
00804       TRACE(Authen,"Error: ("<<__FUNCTION__<<") handshake timedout in SSL_accept");
00805       SSLMutex.UnLock();
00806       return;
00807     }
00808 
00809     int set = ssl_select(theFD);
00810     if (set < 1)
00811       continue;
00812     TRACE(Authen,"Before:: SSL accept");
00813     err = SSL_accept (ssl);
00814     TRACE(Authen,"After :: SSL accept");
00815     if (err>0)
00816       break;
00817   } while ( (ssl_continue(ssl,err))==1);
00818 
00819   TRACE(Authen,"After :: SSL accept loop");
00820   
00821   if (err!=1) {
00822     long verifyresult = SSL_get_verify_result(ssl);
00823     if (verifyresult != X509_V_OK) {
00824       ErrorMutex.Lock();erroraccept++;errorverify++; ErrorMutex.UnLock();
00825       Fatal(error,X509_verify_cert_error_string(verifyresult),verifyresult);
00826       TRACE(Authen,"Error: ("<<__FUNCTION__<<") failed SSL_accept ");
00827     } else {
00828       ErrorMutex.Lock();erroraccept++;errorqueue++; ErrorMutex.UnLock();
00829       Fatal(error,"do SSL_accept",-1);
00830       unsigned long lerr;
00831       while ((lerr=ERR_get_error())) {TRACE(Authen,"SSL Queue error: err=" << lerr << " msg=" <<
00832                                           ERR_error_string(lerr, NULL));Fatal(error,ERR_error_string(lerr,NULL),-1);}
00833     }
00834 
00835     GRSTx509Chain *grst_chain = (GRSTx509Chain*) SSL_get_app_data(ssl);
00836     SSL_set_app_data(ssl,0);
00837     
00838     if (grst_chain) {
00839       GRST_free_chain((void*)grst_chain);
00840     }
00841     ERR_remove_state(0);
00842     SSLMutex.UnLock();
00843     return;
00844   }
00845 
00846   TRACE(Authen,"Before:: SSL get session");
00847 
00848   SSL_SESSION* session = SSL_get1_session(ssl);
00849 
00850   TRACE(Authen,"After :: SSL get session");
00851   if (session) {
00852     char session_id[1024];
00853     TRACE(Authen,"Doing :: SSL Print session");
00854     for (int i=0; i< (int)session->session_id_length; i++) {
00855       sprintf(session_id+(i*2),"%02x",session->session_id[i]);
00856     }
00857     
00858     DEBUG("Info: ("<<__FUNCTION__<<") Session Id: "<< session_id << " Verify: " << session->verify_result << " (" << X509_verify_cert_error_string(session->verify_result) << ")");
00859     DEBUG("Info: ("<<__FUNCTION__<<") cache items             : " << SSL_CTX_sess_number(ctx));
00860     DEBUG("Info: ("<<__FUNCTION__<<") client connects         : " << SSL_CTX_sess_connect(ctx));
00861     DEBUG("Info: ("<<__FUNCTION__<<") client renegotiates     : " << SSL_CTX_sess_connect_renegotiate(ctx));
00862     DEBUG("Info: ("<<__FUNCTION__<<") client connect finished : " << SSL_CTX_sess_connect_good(ctx));
00863     DEBUG("Info: ("<<__FUNCTION__<<") server accepts          : " << SSL_CTX_sess_accept(ctx));
00864     DEBUG("Info: ("<<__FUNCTION__<<") server renegotiates     : " << SSL_CTX_sess_accept_renegotiate(ctx));
00865     DEBUG("Info: ("<<__FUNCTION__<<") server accepts finished : " << SSL_CTX_sess_accept_good(ctx));
00866     DEBUG("Info: ("<<__FUNCTION__<<") session cache hits      : " << SSL_CTX_sess_hits(ctx));
00867     DEBUG("Info: ("<<__FUNCTION__<<") session cache misses    : " << SSL_CTX_sess_misses(ctx));
00868     DEBUG("Info: ("<<__FUNCTION__<<") session cache timeouts  : " << SSL_CTX_sess_timeouts(ctx));
00869     DEBUG("Info: ("<<__FUNCTION__<<") callback cache hits     : " << SSL_CTX_sess_cb_hits(ctx));
00870     DEBUG("Info: ("<<__FUNCTION__<<") cache full overflows    : " << SSL_CTX_sess_cache_full(ctx) << " allowed: " << SSL_CTX_sess_get_cache_size(ctx));
00871 
00872     if (XrdSecProtocolssl::proc) {
00873       XrdSecProtocolsslProcFile* pf;
00874       char CacheInfo[16384];
00875       sprintf(CacheInfo,"items                 = %ld\nclientconnects        = %ld\nclientrenegotiates    = %ld\nclientconnectfinished = %ld\nserveraccept          = %ld\nserverrenegotiates    = %ld\nserveracceptfinished  = %ld\nsessioncachehits      = %ld\nsessioncachemisses    = %ld\nsessioncachetimeouts  = %ld\ncallbackcachehits     = %ld\ncachefulloverflows    = %ld\ncachesize             = %ld\nhandshakethreads      = %d\nforwardedproxies      = %d\n",  SSL_CTX_sess_number(ctx),  SSL_CTX_sess_connect(ctx),SSL_CTX_sess_connect_renegotiate(ctx),SSL_CTX_sess_connect_good(ctx), SSL_CTX_sess_accept(ctx), SSL_CTX_sess_accept_renegotiate(ctx), SSL_CTX_sess_accept_good(ctx), SSL_CTX_sess_hits(ctx), SSL_CTX_sess_misses(ctx), SSL_CTX_sess_timeouts(ctx),SSL_CTX_sess_cb_hits(ctx), SSL_CTX_sess_cache_full(ctx),  SSL_CTX_sess_get_cache_size(ctx), XrdSecProtocolssl::threadsinuse, XrdSecProtocolssl::forwardedproxies);
00876 
00877       pf= XrdSecProtocolssl::proc->Handle("cache"); pf && pf->Write(CacheInfo);
00878       
00879       char ErrorInfo[16384];
00880       sprintf(ErrorInfo,"errortimeout  = %d\nerrorverify   = %d\nerrorqueue    = %d\nerroraccept   = %d\nerrorread     = %d\nerrorabort    = %d", errortimeout, errorverify, errorqueue, erroraccept, errorread, errorabort); 
00881       pf= XrdSecProtocolssl::proc->Handle("error"); pf && pf->Write(ErrorInfo);
00882     }
00883   }
00884 
00885   
00886   SSL_SESSION_free(session);
00887 
00888   /* get the grst_chain  */
00889   GRSTx509Chain *grst_chain = (GRSTx509Chain*) SSL_get_app_data(ssl);
00890   SSL_set_app_data(ssl,0);
00891   
00892   XrdOucString vomsroles="";
00893   XrdOucString clientdn="";
00894   
00895   if (grst_chain) {
00896     GRST_print_ssl_creds((void*) grst_chain);
00897     char* vr = GRST_get_voms_roles_and_free((void*) grst_chain);
00898     if (vr) {
00899       vomsroles = vr;
00900       free(vr);
00901     }
00902   }
00903   
00904   TRACE(Authen,"Authenticated with VOMS roles: "<<vomsroles);
00905   
00906   long verifyresult = SSL_get_verify_result(ssl);
00907   
00908   TRACE(Authen,"Verify result is = "<<verifyresult);
00909   
00910   /* Get the cipher - opt */
00911   
00912   DEBUG("SSL connection uses cipher " << SSL_get_cipher(ssl));
00913   
00914   /* Get client's certificate (note: beware of dynamic allocation) - opt */
00915   
00916   client_cert = SSL_get_peer_certificate (ssl);
00917 
00918 
00919   if (client_cert != NULL) {
00920     str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
00921     if (str) {
00922       TRACE(Authen,"client certificate subject: "<< str);
00923       clientdn = str;
00924       OPENSSL_free (str);
00925     } else {
00926       TRACE(Authen,"client certificate subject: none");
00927     }
00928     
00929     str = X509_NAME_oneline (X509_get_issuer_name  (client_cert), 0, 0);
00930     
00931     if (str) {
00932       TRACE(Authen,"client certificate issuer : "<<str);
00933       TRACE(Authen,"Setting dn="<<clientdn<<" roles="<<vomsroles);
00934       OPENSSL_free (str);
00935     } else {
00936       TRACE(Authen,"client certificate issuer : none");
00937       Fatal(error,"no client issuer",-1);
00938       ERR_remove_state(0);
00939       SSLMutex.UnLock();
00940       return;
00941     }
00942   } else {
00943     TRACE(Authen,"Client does not have certificate.");
00944     Fatal(error,"no client certificate",-1);
00945     ERR_remove_state(0);
00946     SSLMutex.UnLock();
00947     return;
00948   }
00949 
00950   /* receive client proxy - if he send's one */
00951   
00952   do {
00953     if (terminate) {
00954       ErrorMutex.Lock();errorabort++; ErrorMutex.UnLock();
00955       /* timeout */
00956       Fatal(error,"authenticate - handshake abort from client",-ECONNABORTED);
00957       TRACE(Authen,"Error: ("<<__FUNCTION__<<") aborted SSL_read client proxy");
00958       ERR_remove_state(0);
00959       SSLMutex.UnLock();
00960       return;
00961     }
00962 
00963     if ( (time(NULL)-now) > XrdSecProtocolssl::sslselecttimeout ) {
00964       ErrorMutex.Lock();errorread++;errortimeout++; ErrorMutex.UnLock();
00965       /* timeout */
00966       Fatal(error,"authenticate - handshake time out",-ETIMEDOUT);
00967       TRACE(Authen,"Error: ("<<__FUNCTION__<<") handshake timedout in SSL_read");
00968       ERR_remove_state(0);
00969       SSLMutex.UnLock();
00970       return;
00971     }
00972 
00973     int set = ssl_select(theFD);
00974     if (set < 1)
00975       continue;
00976     err = SSL_read(ssl,proxyBuff, sizeof(proxyBuff));
00977   } while ( (ssl_continue(ssl,err)) == 1);
00978 
00979   if (err>0) {
00980     ErrorMutex.Lock();forwardedproxies++; ErrorMutex.UnLock();
00981     TRACE(Authen,"Received proxy buffer with " << err << " bytes");
00982     proxyBuff[err] = 0; //0 terminate the proxy buffer
00983     Entity.endorsements = proxyBuff;
00984     err = SSL_write(ssl,"OK\n",3);
00985     if (err!=3) {
00986       ErrorMutex.Lock();errorread++; ErrorMutex.UnLock();
00987       Fatal(error,"could not send end of handshake OK",-1);
00988       ERR_remove_state(0);
00989       SSLMutex.UnLock();
00990       return;
00991     }
00992     //    err = SSL_read(ssl,dummy, sizeof(dummy));
00993     //    ;
00994   } else {
00995     TRACE(Authen,"Received no proxy");
00996   }
00997 
00998   struct timeval tv1, tv2;
00999   struct timezone tz;
01000 
01001   gettimeofday(&tv1,&tz);
01002 
01003   do {
01004     if (terminate) {
01005       break;
01006     }
01007     gettimeofday(&tv2,&tz);
01008     if ( ((((tv2.tv_sec-tv1.tv_sec)*1000)) + (((tv2.tv_usec-tv1.tv_usec))/1000)) > 500) {
01009       // old client versions don't shut down the ssl connection, so we leave only 500ms grace time to shutdown
01010       TRACE(Authen,"Warning: ("<<__FUNCTION__<<") shutdown timed out");
01011       SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
01012       break;
01013     }
01014     err = SSL_shutdown(ssl);
01015   } while (ssl_continue(ssl,err) || (!err));
01016 
01017   strncpy(Entity.prot,"ssl", sizeof(Entity.prot));
01018 
01019   /*----------------------------------------------------------------------------*/
01020   /* mapping interface                                                          */
01021   /*----------------------------------------------------------------------------*/
01022      
01023   if (!mapuser && !mapcerncertificates) { 
01024     // no mapping put the DN
01025     Entity.name = strdup(clientdn.c_str());
01026   } else {
01027     bool mapped=false;
01028     // map user from grid map file
01029     if (mapcerncertificates) {
01030       // map from CERN DN
01031       if ( (mapcerncertificates) && (clientdn.beginswith("/DC=ch/DC=cern/OU=Organic Units/OU=Users/CN="))) {
01032         XrdOucString certsubject = clientdn;
01033         certsubject.erasefromstart(strlen("/DC=ch/DC=cern/OU=Organic Units/OU=Users/CN="));
01034         int pos=certsubject.find('/');                               
01035         if (pos != STR_NPOS)                                         
01036           certsubject.erase(pos);                                       
01037         Entity.name = strdup(certsubject.c_str());
01038         mapped=true;
01039         TRACE(Authen,"Found CERN certificate - mapping to AFS account " << certsubject);
01040       }
01041     }
01042     if (!mapped) {
01043       if (mapuser) {
01044         // treatment of old proxy
01045         XrdOucString certsubject = clientdn;
01046         certsubject.replace("/CN=proxy","");                           
01047         // treatment of new proxy - leave only the first CN=, cut the rest
01048         int pos = certsubject.find("CN=");
01049         int pos2 = certsubject.find("/",pos);
01050         if (pos2>0) certsubject.erase(pos2);
01051         XrdOucString* gridmaprole;                                     
01052         ReloadGridMapFile();
01053         GridMapMutex.Lock();                             
01054         
01055         if ((gridmaprole = gridmapstore.Find(certsubject.c_str()))) { 
01056           Entity.name = strdup(gridmaprole->c_str());      
01057           Entity.role = 0;
01058         }  else {
01059           Entity.name = strdup((char*)"nobody");
01060           Entity.role = 0;
01061           if (!XrdSecProtocolssl::mapnobody) {
01062             Fatal(error,"user cannot be mapped",-1);
01063           }
01064         }
01065         GridMapMutex.UnLock();
01066       } else {
01067         Entity.name = strdup((char*)"nobody");
01068         Entity.role = 0;
01069         if (!XrdSecProtocolssl::mapnobody) {
01070           Fatal(error,"user cannot be mapped",-1);
01071         }
01072       }
01073     }
01074   }
01075   
01076   
01077   if (!mapgroup) {
01078     if (vomsroles.length()) {
01079       // no mapping put the VOMS groups and role
01080       Entity.grps = strdup(vomsroles.c_str());
01081       
01082       XrdOucString vomsrole = vomsroles.c_str();
01083       
01084       if (vomsroles.length()) {
01085         int dp = vomsrole.find(":");
01086         if (dp != STR_NPOS) {
01087           vomsrole.assign(vomsroles,0,dp-1);
01088         }
01089         Entity.role = strdup(vomsrole.c_str());
01090       } else {
01091         Entity.role = strdup("");
01092       }
01093     } else {
01094       // map the group from the passwd/group file
01095       struct passwd* pwd;
01096       struct group*  grp;
01097       StoreMutex.Lock();
01098       if ( (pwd = getpwnam(Entity.name)) && (grp = getgrgid(pwd->pw_gid))) {
01099         Entity.grps   = strdup(grp->gr_name);
01100         Entity.role   = strdup(grp->gr_name);
01101       }
01102       StoreMutex.UnLock();
01103     }
01104   } else {
01105     // map groups & role from VOMS mapfile
01106     XrdOucString defaultgroup="";                                     
01107     XrdOucString allgroups="";  
01108 
01109     // map the group from the passwd/group file at first place
01110     struct passwd* pwd;
01111     struct group*  grp;
01112     StoreMutex.Lock();
01113     if ( (pwd = getpwnam(Entity.name)) && (grp = getgrgid(pwd->pw_gid))) {
01114       Entity.grps   = strdup(grp->gr_name);
01115       Entity.role   = strdup(grp->gr_name);
01116     }
01117     StoreMutex.UnLock();
01118 
01119     if (vomsroles.length()) {
01120       if (VomsMapGroups(vomsroles.c_str(), allgroups,defaultgroup)) {
01121         // allow mapping from VOMS role to uid
01122         if (defaultgroup.beginswith("uid:")) {
01123           defaultgroup.erase(0,4);
01124           if (Entity.name) {
01125             free(Entity.name);
01126           }
01127           Entity.name = strdup(defaultgroup.c_str());
01128           allgroups=":";
01129         }
01130         if (!strcmp(allgroups.c_str(),":")) {
01131           // map the group from the passwd/group file
01132           struct passwd* pwd;
01133           struct group*  grp;
01134           StoreMutex.Lock();
01135           if ( (pwd = getpwnam(Entity.name)) && (grp = getgrgid(pwd->pw_gid))) {
01136             allgroups    = grp->gr_name;
01137             defaultgroup = grp->gr_name;
01138           }
01139           StoreMutex.UnLock();
01140         }
01141         Entity.grps   = strdup(allgroups.c_str());
01142         Entity.role   = strdup(defaultgroup.c_str());
01143       }
01144     }
01145   }
01146 
01147 
01148   /*----------------------------------------------------------------------------*/
01149   /* proxy forwarding                                                           */
01150   /*----------------------------------------------------------------------------*/
01151 
01152   if (sslproxyexportdir && Entity.endorsements) {
01153     StoreMutex.Lock();
01154     // get the UID of the entity name
01155     struct passwd* pwd;
01156     XrdOucString outputproxy = sslproxyexportdir; outputproxy+="/x509up_u"; 
01157     if ( (pwd = getpwnam(Entity.name)) ) {
01158       outputproxy += (int)pwd->pw_uid;
01159     } else {
01160       outputproxy += Entity.name;
01161     }
01162     XrdOucString outputproxytmp = outputproxy;
01163     outputproxytmp += (int) rand();
01164 
01165     if (XrdSecProtocolssl::sslproxyexportplain) {
01166       int fd = open (outputproxytmp.c_str(),O_CREAT| O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
01167       if (fd>0) {
01168         if ( ((int)write(fd,Entity.endorsements,strlen(Entity.endorsements))) != (int)strlen(Entity.endorsements)) {
01169           unlink(outputproxytmp.c_str());
01170           Fatal(error,"cannot export(write) user proxy",-1);
01171         } else {
01172           TRACE(Identity,"Exported proxy buffer of " << Entity.name << " to file " << outputproxy.c_str());
01173         }
01174         if ( rename(outputproxytmp.c_str(),outputproxy.c_str()) ) {
01175           unlink(outputproxytmp.c_str());
01176           Fatal(error,"cannot rename temporary export proxy",-1);
01177         }
01178         close(fd);
01179       } else {
01180         Fatal(error,"cannot export(open) user proxy",-1);
01181       }
01182     } else {
01183       EVP_PKEY* pkey=NULL;
01184       X509* x509=NULL;
01185       // we protect the private key with our session password
01186       BIO* bp = BIO_new_mem_buf( (void *)Entity.endorsements, strlen(Entity.endorsements)+1);
01187       FILE* fout = fopen (outputproxytmp.c_str(),"w+");
01188       if (!fout) {
01189         Fatal(error,"cannot export user proxy - unable to open proxy file",-1);
01190       } else {
01191         if (bp) {
01192           pkey = PEM_read_bio_PrivateKey(bp, &pkey,0,0);
01193           BIO_free(bp);
01194           if (!pkey) {
01195             Fatal(error,"cannot export user proxy - unable to read key/cert from BIO",-1);
01196           } else {
01197             int wk = PEM_write_PrivateKey(fout, pkey, EVP_des_ede3_cbc(),(unsigned char*)XrdSecProtocolssl::sslserverexportpassword,EXPORTKEYSTRENGTH,0,0);
01198             EVP_PKEY_free(pkey);
01199             
01200             if (!wk) {
01201               Fatal(error,"cannot export user proxy - unable to write private key",-1);
01202             } else {
01203               // deal with the certificates
01204               char* certificatebuffer = 0;
01205               certificatebuffer = Entity.endorsements;
01206               while ((certificatebuffer = strstr(certificatebuffer,"-----BEGIN CERTIFICATE-----"))) {
01207                 // we point to the next certificate to export in memory
01208                 BIO* bp = BIO_new_mem_buf( (void *)certificatebuffer, strlen(certificatebuffer)+1);
01209                 if (bp) {
01210                   x509 = NULL;
01211                   x509 = PEM_read_bio_X509(bp, &x509,0,0);
01212                   BIO_free(bp);
01213                   if (x509)  {
01214                     int wc = PEM_write_X509(fout,x509);
01215                     X509_free(x509);
01216                     if (!wc) {
01217                       Fatal(error,"cannto export user proxy - unable to write certificate",-1);
01218                       break;
01219                     }
01220                   }
01221                 } else {
01222                   Fatal(error,"cannot export user proxy - unable to allocate BIO to read private key",-1);
01223                 }
01224                 certificatebuffer++;
01225               }
01226             }
01227           }
01228         } else {
01229           Fatal(error,"cannot export user proxy - unable to allocate BIO to read private key",-1);
01230         }
01231         
01232         fclose(fout);
01233         if ( rename(outputproxytmp.c_str(),outputproxy.c_str()) ) {
01234           unlink(outputproxytmp.c_str());
01235           Fatal(error,"cannot rename temporary export proxy",-1);
01236         }
01237       }
01238     }
01239     
01240     StoreMutex.UnLock();
01241   }
01242 
01243 
01244   TRACE(Identity,"[usermapping] name=|" << Entity.name << "| role=|" << (Entity.role?Entity.role:"-") << "| grps=|"<< (Entity.grps?Entity.grps:"-") << "| DN=|" << clientdn.c_str() << "| VOMS=|" << vomsroles.c_str() << "|");
01245 
01246   if (ssl) {
01247     SSL_free(ssl);ssl = 0;
01248   }
01249 
01250   ERR_remove_state(0);
01251   SSLMutex.UnLock();
01252   return;
01253 }
01254 
01255 int 
01256 XrdSecProtocolssl::GenerateSession(const SSL* ssl, unsigned char *id, unsigned int *id_len) {
01257   EPNAME("GenerateSession");
01258   unsigned int count = 0;
01259   do      {
01260     RAND_pseudo_bytes(id, *id_len);
01261     /* Prefix the session_id with the required prefix. NB: If our
01262      * prefix is too long, clip it - but there will be worse effects
01263      * anyway, eg. the server could only possibly create 1 session
01264      * ID (ie. the prefix!) so all future session negotiations will
01265      * fail due to conflicts. */
01266     memcpy(id, "xrootdssl",
01267            (strlen("xrootdssl") < *id_len) ?
01268            strlen("xrootdssl") : *id_len);
01269    TRACE(Authen,"Generated SSID **********************");
01270   }
01271   while(SSL_has_matching_session_id(ssl, id, *id_len) &&
01272         (++count < MAX_SESSION_ID_ATTEMPTS));
01273   if(count >= MAX_SESSION_ID_ATTEMPTS)
01274     return 0;
01275   return 1;
01276 }
01277 
01278 int 
01279 XrdSecProtocolssl::NewSession(SSL* ssl, SSL_SESSION *session) {
01280   EPNAME("NewSession");
01281   TRACE(Authen,"Creating new Session");
01282   char session_id[1024];
01283   for (int i=0; i< (int)session->session_id_length; i++) {
01284     sprintf(session_id+(i*2),"%02x",session->session_id[i]);
01285   }
01286   DEBUG("Info: ("<<__FUNCTION__<<") Session Id: "<< session_id << " Verify: " << session->verify_result << " (" << X509_verify_cert_error_string(session->verify_result) << ")");
01287   
01288   SSL_set_timeout(session, sslsessionlifetime);
01289   return 0;
01290 }
01291 
01292 /*----------------------------------------------------------------------------*/
01293 void 
01294 XrdSecProtocolssl::ReloadGridMapFile()
01295 { 
01296   EPNAME("ReloadGridMapFile");
01297 
01298   static time_t         GridMapMtime=0;
01299   static time_t         GridMapCheckTime=0;
01300   int now = time(NULL);
01301 
01302   if ((!GridMapCheckTime) || ((now >GridMapCheckTime + 60)) ) {
01303     // load it for the first time or again
01304     struct stat buf;
01305     if (!::stat(gridmapfile,&buf)) {
01306       if (buf.st_mtime != GridMapMtime) {
01307         GridMapMutex.Lock();
01308         // store the last modification time
01309         GridMapMtime = buf.st_mtime;
01310         // store the current time of the check
01311         GridMapCheckTime = now;
01312         // dump the current table
01313         gridmapstore.Purge();
01314         // open the gridmap file
01315         FILE* mapin = fopen(gridmapfile,"r");
01316         if (!mapin) {
01317           // error no grid map possible
01318           TRACE(Authen,"Unable to open gridmapfile " << XrdOucString(gridmapfile) << " - no mapping!");
01319         } else {
01320           char userdnin[4096];
01321           char usernameout[4096];
01322           int nitems;
01323           // parse it
01324           while ( (nitems = fscanf(mapin,"\"%[^\"]\" %s\n", userdnin,usernameout)) == 2) {
01325             XrdOucString dn = userdnin;
01326             dn.replace("\"","");
01327             // leave only the first CN=, cut the rest
01328             int pos = dn.find("CN=");
01329             int pos2 = dn.find("/",pos);
01330             if (pos2>0) dn.erase(pos2);
01331 
01332             if (!gridmapstore.Find(dn.c_str())) {
01333               gridmapstore.Add(dn.c_str(), new XrdOucString(usernameout));
01334               TRACE(Authen, "gridmapfile Mapping Added: " << dn.c_str() << " |=> " << usernameout);
01335             }
01336           }
01337           fclose(mapin);
01338         }
01339         GridMapMutex.UnLock();
01340       } else {
01341         // the file didn't change, we don't do anything
01342       }
01343     } else {
01344       TRACE(Authen,"Unable to stat gridmapfile " << XrdOucString(gridmapfile) << " - no mapping!");
01345     }
01346   }
01347 }
01348 
01349 /*----------------------------------------------------------------------------*/
01350 
01351 void 
01352 XrdSecProtocolssl::ReloadVomsMapFile()
01353 {
01354   EPNAME("ReloadVomsMapFile");
01355 
01356   static time_t         VomsMapMtime=0;
01357   static time_t         VomsMapCheckTime=0;
01358   int now = time(NULL);
01359 
01360   if ((!VomsMapCheckTime) || ((now >VomsMapCheckTime + 60 )) ) {
01361     // load it for the first time or again
01362     struct stat buf;
01363     if (!::stat(vomsmapfile,&buf)) {
01364       if (buf.st_mtime != VomsMapMtime) {
01365         VomsMapMutex.Lock();
01366         // store the last modification time
01367         VomsMapMtime = buf.st_mtime;
01368         // store the current time of the check
01369         VomsMapCheckTime = now;
01370         // dump the current table
01371         vomsmapstore.Purge();
01372         // open the vomsmap file
01373         FILE* mapin = fopen(vomsmapfile,"r");
01374         if (!mapin) {
01375           // error no voms map possible
01376           TRACE(Authen,"Unable to open vomsmapfile " << XrdOucString(vomsmapfile) << " - no mapping!");
01377         } else {
01378           char userdnin[4096];
01379           char usernameout[4096];
01380           int nitems;
01381           // parse it
01382           while ( (nitems = fscanf(mapin,"\"%[^\"]\" %s\n", userdnin,usernameout)) == 2) {
01383             XrdOucString dn = userdnin;
01384             dn.replace("\"","");
01385             if (!vomsmapstore.Find(dn.c_str())) {
01386               vomsmapstore.Add(dn.c_str(), new XrdOucString(usernameout));
01387               TRACE(Authen,"vomsmapfile Mapping Added: " << dn.c_str() << " |=> " << usernameout);
01388             }
01389           }
01390           fclose(mapin);
01391         }
01392         VomsMapMutex.UnLock();
01393       } else {
01394         // the file didn't change, we don't do anything
01395       }
01396     } else {
01397       TRACE(Authen,"Unable to stat vomsmapfile " << XrdOucString(vomsmapfile) << " - no mapping!");
01398     }
01399   }
01400 }
01401 
01402 /*----------------------------------------------------------------------------*/
01403 
01404 bool
01405 XrdSecProtocolssl::VomsMapGroups(const char* groups, XrdOucString& allgroups, XrdOucString& defaultgroup) 
01406 {
01407   EPNAME("VomsMapGroups");
01408   ReloadVomsMapFile();
01409   // loop over all VOMS groups and replace them according to the mapping
01410   XrdOucString vomsline = groups;
01411   allgroups = ":";
01412   defaultgroup = "";
01413   vomsline.replace(":","\n");
01414   XrdOucTokenizer vomsgroups((char*)vomsline.c_str());
01415   const char* stoken;
01416   int ntoken=0;
01417   XrdOucString* vomsmaprole;                                     
01418   while( (stoken = vomsgroups.GetLine())) {
01419     if ((vomsmaprole = XrdSecProtocolssl::vomsmapstore.Find(stoken))) { 
01420       allgroups += vomsmaprole->c_str();
01421       allgroups += ":";
01422       if (ntoken == 0) {
01423         defaultgroup = vomsmaprole->c_str();
01424       }
01425       ntoken++;
01426     } else {
01427       // scan for a wildcard rule
01428       XrdOucString vomsattribute = stoken;
01429       int rpos=STR_NPOS;
01430       while ((rpos = vomsattribute.rfind("/",rpos))!=STR_NPOS) {
01431         rpos--;
01432         XrdOucString wildcardattribute = vomsattribute;
01433         wildcardattribute.erase(rpos+2);
01434         wildcardattribute += "*";
01435         if ((vomsmaprole = XrdSecProtocolssl::vomsmapstore.Find(wildcardattribute.c_str()))) {
01436           allgroups += vomsmaprole->c_str();
01437           allgroups += ":";
01438           if (ntoken == 0) {
01439             defaultgroup = vomsmaprole->c_str();
01440           }
01441           ntoken++;
01442           break; // leave the wildcard loop
01443         }
01444         if ( rpos < 0) {
01445           break;
01446         }
01447       }
01448     }
01449   }
01450 
01451   if (allgroups == ":") {
01452     TRACE(Authen,"No VOMS mapping found for " << XrdOucString(stoken) << " using default group");
01453     return false;
01454   }
01455   return true;
01456 }
01457 
01458 /******************************************************************************/
01459 /*                X r d S e c p r o t o c o l u n i x I n i t                 */
01460 /******************************************************************************/
01461   
01462 extern "C"
01463 {
01464 char  *XrdSecProtocolsslInit(const char     mode,
01465                               const char    *parms,
01466                               XrdOucErrInfo *erp)
01467 {
01468   EPNAME("ProtocolsslInit");
01469   // Initiate error logging and tracing
01470   XrdSecProtocolssl::ssleDest.logger(&XrdSecProtocolssl::Logger);
01471   
01472   GRSTerrorLogFunc = &MyGRSTerrorLogFunc;
01473   static bool serverinitialized = false;
01474 
01475   // create the tracer
01476   if (!SSLxTrace)
01477     SSLxTrace = new XrdOucTrace(&XrdSecProtocolssl::ssleDest);
01478 
01479   for (int i=0; i< PROTOCOLSSL_MAX_CRYPTO_MUTEX; i++) {
01480     XrdSecProtocolssl::CryptoMutexPool[i] = new XrdSysMutex();
01481   }
01482 
01483 
01484   // read the configuration options
01485   if ( (mode == 's') && (!serverinitialized) )  {
01486     XrdSecProtocolssl::sslcertfile = strdup("/etc/grid-security/hostcert.pem");
01487     XrdSecProtocolssl::sslkeyfile  = strdup("/etc/grid-security/hostkey.pem");
01488     XrdSecProtocolssl::sslcadir    = strdup("/etc/grid-security/certificates");
01489     XrdSecProtocolssl::sslvomsdir  = (char*)"/etc/grid-security/vomsdir";
01490     
01491     XrdSecProtocolssl::isServer = 1;
01492     serverinitialized = true;
01493     if (parms){
01494       // Duplicate the parms
01495       char parmbuff[1024];
01496       strlcpy(parmbuff, parms, sizeof(parmbuff));
01497       //
01498       // The tokenizer
01499       XrdOucTokenizer inParms(parmbuff);
01500       char *op;
01501 
01502       while (inParms.GetLine()) { 
01503         while ((op = inParms.GetToken())) {
01504           if (!strncmp(op, "-d:",3)) {
01505             XrdSecProtocolssl::debug = atoi(op+3);
01506           } else if (!strncmp(op, "-cadir:",7)) {
01507             XrdSecProtocolssl::sslcadir = strdup(op+7);
01508           } else if (!strncmp(op, "-vomsdir:",6)) {
01509             XrdSecProtocolssl::sslvomsdir = strdup(op+6);
01510           } else if (!strncmp(op, "-cert:",6)) {
01511             XrdSecProtocolssl::sslcertfile = strdup(op+6);
01512           } else if (!strncmp(op, "-key:",5)) {
01513             XrdSecProtocolssl::sslkeyfile = strdup(op+5);
01514           } else if (!strncmp(op, "-ca:",4)) {
01515             XrdSecProtocolssl::verifydepth = atoi(op+4);
01516           } else if (!strncmp(op, "-t:",3)) {
01517             XrdSecProtocolssl::sslsessionlifetime = atoi(op+3);
01518           } else if (!strncmp(op, "-export:",8)) {
01519             XrdSecProtocolssl::sslproxyexportdir = strdup(op+8);
01520           } else if (!strncmp(op, "-gridmapfile:",13)) {
01521             XrdSecProtocolssl::gridmapfile = strdup(op+13);
01522           } else if (!strncmp(op, "-vomsmapfile:",13)) {
01523             XrdSecProtocolssl::vomsmapfile = strdup(op+13);
01524           } else if (!strncmp(op, "-mapuser:",9)) {
01525             XrdSecProtocolssl::mapuser = (bool) atoi(op+9);
01526           } else if (!strncmp(op, "-mapnobody:",11)) {
01527             XrdSecProtocolssl::mapnobody = (bool) atoi(op+11);
01528           } else if (!strncmp(op, "-mapgroup:",10)) {
01529             XrdSecProtocolssl::mapgroup = (bool) atoi(op+10);
01530           } else if (!strncmp(op, "-mapcernuser:",13)) {
01531             XrdSecProtocolssl::mapcerncertificates = (bool) atoi(op+13);
01532           } else if (!strncmp(op, "-sessioncachesize:", 18)) {
01533             XrdSecProtocolssl::sslsessioncachesize = atoi(op+18);
01534           } else if (!strncmp(op, "-selecttimeout:", 15)) {
01535             XrdSecProtocolssl::sslselecttimeout = atoi(op + 15);
01536             if ( XrdSecProtocolssl::sslselecttimeout < 5) {
01537               XrdSecProtocolssl::sslselecttimeout = 5;
01538             }
01539           } else if (!strncmp(op, "-procdir:",9)) {
01540             XrdSecProtocolssl::procdir = strdup(op+9);
01541             XrdSecProtocolssl::proc = new XrdSecProtocolsslProc(XrdSecProtocolssl::procdir, false);
01542             if (XrdSecProtocolssl::proc) {
01543               if (!XrdSecProtocolssl::proc->Open()) {
01544                 delete XrdSecProtocolssl::proc;
01545                 XrdSecProtocolssl::proc = NULL;
01546               }
01547             }
01548             time_t now = time(NULL);
01549 
01550             if (XrdSecProtocolssl::proc) {
01551               XrdSecProtocolsslProcFile* pf;
01552               XrdOucString ID = XrdSecProtocolsslCVSID;
01553               ID+="\n";
01554               pf= XrdSecProtocolssl::proc->Handle("version"); pf && pf->Write(ID.c_str());
01555               pf= XrdSecProtocolssl::proc->Handle("start"); pf && pf->Write(ctime(&now));
01556             }
01557           }
01558         }
01559       }
01560     }
01561   } else {
01562     if ( (mode == 'c') || (serverinitialized)) {
01563       if (mode == 'c') {
01564         for (int i=0; i< PROTOCOLSSL_MAX_CRYPTO_MUTEX; i++) {
01565           XrdSecProtocolssl::CryptoMutexPool[i] = 0;
01566         }
01567         XrdSecProtocolssl::sslcertfile = strdup("/etc/grid-security/hostcert.pem");
01568         XrdSecProtocolssl::sslkeyfile  = strdup("/etc/grid-security/hostkey.pem");
01569         XrdSecProtocolssl::sslcadir    = strdup("/etc/grid-security/certificates");
01570         XrdSecProtocolssl::sslvomsdir  = (char*)"/etc/grid-security/vomsdir";
01571       }
01572       XrdSecProtocolssl::GetEnvironment();
01573       XrdSecProtocolssl::isServer = 0;
01574       if (serverinitialized) {
01575         XrdSecProtocolssl::sslproxyexportplain = 0;
01576       }
01577     }
01578   }
01579 
01580   if (XrdSecProtocolssl::debug >= 4) {
01581     SSLxTrace->What = TRACE_ALL | TRACE_Debug;
01582   } else if (XrdSecProtocolssl::debug == 3 ) {
01583     SSLxTrace->What |= TRACE_Authen;
01584     SSLxTrace->What |= TRACE_Debug;
01585     SSLxTrace->What |= TRACE_Identity;
01586   } else if (XrdSecProtocolssl::debug == 2) {
01587     SSLxTrace->What = TRACE_Debug;
01588   } else if (XrdSecProtocolssl::debug == 1) {
01589     SSLxTrace->What = TRACE_Identity;
01590   } else SSLxTrace->What = 0;
01591 
01592   // thread-saftey
01593   if (PROTOCOLSSL_MAX_CRYPTO_MUTEX < CRYPTO_num_locks() ) {
01594     fprintf(stderr,"Error: (%s) I don't have enough crypto mutexes as required by crypto_ssl [recompile increasing PROTOCOLSSL_MAX_CRYPTO_MUTEX to %d] \n",__FUNCTION__,CRYPTO_num_locks());
01595     TRACE(Authen,"Error: I don't have enough crypto mutexes as required by crypto_ssl [recompile increasing PROTOCOLSSL_MAX_CRYPTO_MUTEX to " << (int)CRYPTO_num_locks() << "]");
01596   } else {
01597     TRACE(Authen,"====> SSL requires " << (int)CRYPTO_num_locks() << " mutexes for thread-safety");
01598   }
01599 
01600 #if defined(OPENSSL_THREADS)
01601   // thread support enabled
01602   TRACE(Authen,"====> SSL with thread support!");
01603 #else
01604   fprintf(stderr,"Error: (%s) SSL lacks thread support: Abort!");
01605   TRACE(Authen,"Error: SSL lacks thread support: Abort!");
01606 #endif
01607 
01608   // set callback functions
01609   CRYPTO_set_locking_callback(protocolssl_lock);
01610   CRYPTO_set_id_callback(protocolssl_id_callback);
01611 
01612 
01613 
01614 
01615   if (XrdSecProtocolssl::isServer) {
01616     TRACE(Authen,"====> debug            = " << XrdSecProtocolssl::debug);
01617     TRACE(Authen,"====> cadir            = " << XrdSecProtocolssl::sslcadir);
01618     TRACE(Authen,"====> keyfile          = " << XrdSecProtocolssl::sslkeyfile);
01619     TRACE(Authen,"====> certfile         = " << XrdSecProtocolssl::sslcertfile);
01620     TRACE(Authen,"====> verify depth     = " << XrdSecProtocolssl::verifydepth);
01621     TRACE(Authen,"====> sess.lifetime    = " << XrdSecProtocolssl::sslsessionlifetime);
01622     TRACE(Authen,"====> gridmapfile      = " << XrdSecProtocolssl::gridmapfile);
01623     TRACE(Authen,"====> vomsmapfile      = " << XrdSecProtocolssl::vomsmapfile);
01624     TRACE(Authen,"====> mapuser          = " << XrdSecProtocolssl::mapuser);
01625     TRACE(Authen,"====> mapnobody        = " << XrdSecProtocolssl::mapnobody);
01626     TRACE(Authen,"====> mapgroup         = " << XrdSecProtocolssl::mapgroup);
01627     TRACE(Authen,"====> mapcernuser      = " << XrdSecProtocolssl::mapcerncertificates);
01628     TRACE(Authen,"====> selecttimeout    = " << XrdSecProtocolssl::sslselecttimeout);
01629     TRACE(Authen,"====> sessioncachesize = " << XrdSecProtocolssl::sslsessioncachesize);
01630     TRACE(Authen,"====> procdir       = " << XrdSecProtocolssl::procdir);
01631     char Info[16384];
01632     sprintf(Info,"debug         = %d\ncadir         = %s\nkeyfile       = %s\ncertfile      = %s\nverify depth  = %d\nsess.lifetime = %ld\ngridmapfile   = %s\nvomsmapfile   = %s\nmapuser       = %d\nmapnobody     = %d\nmapgroup      = %d\nmapcernuser   = %d\nselecttimeout = %d\nprocdir       = %s\nsessioncachesz = %d\n",XrdSecProtocolssl::debug,XrdSecProtocolssl::sslcadir, XrdSecProtocolssl::sslkeyfile, XrdSecProtocolssl::sslcertfile, XrdSecProtocolssl::verifydepth, XrdSecProtocolssl::sslsessionlifetime, XrdSecProtocolssl::gridmapfile, XrdSecProtocolssl::vomsmapfile, XrdSecProtocolssl::mapuser,  XrdSecProtocolssl::mapnobody, XrdSecProtocolssl::mapgroup, XrdSecProtocolssl::mapcerncertificates, XrdSecProtocolssl::sslselecttimeout,  XrdSecProtocolssl::procdir, XrdSecProtocolssl::sslsessioncachesize);
01633     if (XrdSecProtocolssl::proc) {
01634       XrdSecProtocolsslProcFile* pf;
01635       pf= XrdSecProtocolssl::proc->Handle("info"); pf && pf->Write(Info);
01636     }
01637   } else {
01638     if (XrdSecProtocolssl::debug) {
01639       TRACE(Authen,"====> debug         = " << XrdSecProtocolssl::debug);
01640       TRACE(Authen,"====> cadir         = " << XrdSecProtocolssl::sslcadir);
01641       TRACE(Authen,"====> keyfile       = " << XrdSecProtocolssl::sslkeyfile);
01642       TRACE(Authen,"====> certfile      = " << XrdSecProtocolssl::sslcertfile);
01643       TRACE(Authen,"====> verify depth  = " << XrdSecProtocolssl::verifydepth);
01644     }
01645   }
01646 
01647   if (XrdSecProtocolssl::isServer) {
01648     XrdSecProtocolssl::sslproxyexportplain=0; // for security reasons a server should not export plain private keys
01649     // check if we can map with a grid map file
01650     if (XrdSecProtocolssl::mapuser && access(XrdSecProtocolssl::gridmapfile,R_OK)) {
01651       fprintf(stderr,"Error: (%s) cannot access gridmapfile %s\n",__FUNCTION__,XrdSecProtocolssl::gridmapfile);
01652       TRACE(Authen,"Error: cannot access gridmapfile "<< XrdOucString(XrdSecProtocolssl::gridmapfile));
01653       return 0;
01654     }
01655     // check if we can map with a voms map file
01656     if (XrdSecProtocolssl::mapgroup && access(XrdSecProtocolssl::vomsmapfile,R_OK)) {
01657       fprintf(stderr,"Error: (%s) cannot access vomsmapfile %s\n",__FUNCTION__,XrdSecProtocolssl::vomsmapfile);
01658       TRACE(Authen,"Error: cannot access vomsmapfile "<< XrdOucString(XrdSecProtocolssl::vomsmapfile));
01659       return 0;
01660     }
01661     // check if we can export proxies
01662     XrdOucString exportplain=XrdSecProtocolssl::sslproxyexportdir;
01663     // if the export file starts with plain: we don't write the proxy with a passphrase
01664     if (exportplain.beginswith("plain:")) {
01665       XrdSecProtocolssl::sslproxyexportdir+=6;
01666       XrdSecProtocolssl::sslproxyexportplain=true;
01667       TRACE(Authen,"====> export plain proxy (warning: can be re-used out of daemon context) to dir: " << XrdSecProtocolssl::sslproxyexportdir);
01668     }
01669     if (XrdSecProtocolssl::sslproxyexportdir && access(XrdSecProtocolssl::sslproxyexportdir,R_OK | W_OK)) {
01670       fprintf(stderr,"Error: (%s) cannot read/write proxy export directory %s\n",__FUNCTION__,XrdSecProtocolssl::sslproxyexportdir);
01671       TRACE(Authen,"Error: cannot access proxyexportdir "<< XrdOucString(XrdSecProtocolssl::sslproxyexportdir));
01672       return 0;
01673     }
01674   }
01675 
01676   if (XrdSecProtocolssl::isServer) {
01677     SSL_METHOD *meth;
01678     // initialize openssl until the context is created 
01679     SSL_load_error_strings();
01680     SSLeay_add_ssl_algorithms();
01681     
01682     meth = (SSL_METHOD*)SSLv23_server_method();
01683 
01684     XrdSecProtocolssl::ctx = SSL_CTX_new (meth);
01685     if (!XrdSecProtocolssl::ctx) {
01686       ERR_print_errors_fp(stderr);
01687       return 0;
01688     }
01689       
01690     if (SSL_CTX_use_certificate_file(XrdSecProtocolssl::ctx, XrdSecProtocolssl::sslcertfile, SSL_FILETYPE_PEM) <= 0) {
01691       ERR_print_errors_fp(stderr);
01692       return 0;
01693     }
01694     
01695     if (SSL_CTX_use_PrivateKey_file(XrdSecProtocolssl::ctx,XrdSecProtocolssl::sslkeyfile, SSL_FILETYPE_PEM) <= 0) {
01696       ERR_print_errors_fp(stderr);
01697       return 0;
01698     }
01699       
01700     if (!SSL_CTX_check_private_key(XrdSecProtocolssl::ctx)) {
01701       fprintf(stderr,"Private key does not match the certificate public key\n");
01702       return 0;
01703     }
01704 
01705     XrdSecProtocolssl::sslserverkeyfile=XrdSecProtocolssl::sslkeyfile;
01706     // use the private server key as password for proxy private key export
01707     memset(XrdSecProtocolssl::sslserverexportpassword,0,EXPORTKEYSTRENGTH); 
01708 
01709     unsigned int seed = (unsigned int) (time(NULL) + (unsigned int) random());
01710     srand(seed);
01711     char rexportkey[16384];
01712     rexportkey[0]=0;
01713     for (int i=0; i < EXPORTKEYSTRENGTH; i++) {
01714       XrdSecProtocolssl::sslserverexportpassword[i] = (unsigned char)(rand()%256);
01715       if (!XrdSecProtocolssl::sslserverexportpassword[i]) XrdSecProtocolssl::sslserverexportpassword[i]++;
01716       sprintf(rexportkey,"%s%x",rexportkey,XrdSecProtocolssl::sslserverexportpassword[i]);
01717     }
01718     XrdSecProtocolssl::sslserverexportpassword[EXPORTKEYSTRENGTH] = 0;
01719     sprintf((char*)XrdSecProtocolssl::sslserverexportpassword,"1234567890");
01720     // debug 
01721     DEBUG("Created random export key: "<< rexportkey);
01722     SSL_CTX_load_verify_locations(XrdSecProtocolssl::ctx, NULL,XrdSecProtocolssl::sslcadir);  
01723     
01724     // create the store
01725     if (!XrdSecProtocolssl::store) {
01726       DEBUG("Created SSL CRL store: " << XrdSecProtocolssl::store);
01727       XrdSecProtocolssl::store = SSL_X509_STORE_create(NULL,XrdSecProtocolssl::sslcadir);
01728       X509_STORE_set_flags(XrdSecProtocolssl::store,0);
01729       XrdSecProtocolssl::storeLoadTime = time(NULL);
01730     }
01731     
01732     XrdSecProtocolssl::ctx->verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
01733 
01734     grst_cadir   = XrdSecProtocolssl::sslcadir;
01735     grst_vomsdir = XrdSecProtocolssl::sslvomsdir;
01736     grst_depth   = XrdSecProtocolssl::verifydepth;
01737     
01738     SSL_CTX_set_cert_verify_callback(XrdSecProtocolssl::ctx,
01739                                      GRST_verify_cert_wrapper,
01740                                      (void *) NULL);
01741     
01742     SSL_CTX_set_verify(XrdSecProtocolssl::ctx, XrdSecProtocolssl::ctx->verify_mode,GRST_callback_SSLVerify_wrapper);
01743     SSL_CTX_set_verify_depth(XrdSecProtocolssl::ctx, XrdSecProtocolssl::verifydepth + 1);
01744 
01745     if(!SSL_CTX_set_generate_session_id(XrdSecProtocolssl::ctx, XrdSecProtocolssl::GenerateSession)) {
01746       TRACE(Authen,"Cannot set session generator");
01747       return 0;
01748     }
01749 
01750     SSL_CTX_set_options(XrdSecProtocolssl::ctx,  SSL_OP_ALL | SSL_OP_NO_SSLv2);
01751     
01752     SSL_CTX_sess_set_cache_size(XrdSecProtocolssl::ctx,XrdSecProtocolssl::sslsessioncachesize);
01753 
01754     if (XrdSecProtocolssl::sslsessioncachesize) {
01755       SSL_CTX_set_session_cache_mode(XrdSecProtocolssl::ctx, SSL_SESS_CACHE_BOTH); // | SSL_SESS_CACHE_NO_AUTO_CLEAR );
01756     } else {
01757       SSL_CTX_set_session_cache_mode(XrdSecProtocolssl::ctx, SSL_SESS_CACHE_OFF | SSL_SESS_CACHE_NO_INTERNAL );
01758       
01759     }
01760 
01761     SSL_CTX_set_session_id_context(XrdSecProtocolssl::ctx,(const unsigned char*) XrdSecProtocolssl::SessionIdContext,  strlen(XrdSecProtocolssl::SessionIdContext));
01762     SSL_CTX_sess_set_new_cb(XrdSecProtocolssl::ctx, XrdSecProtocolssl::NewSession);
01763   }
01764   return (char *)"";
01765 }
01766 }
01767 
01768 /******************************************************************************/
01769 /*              X r d S e c P r o t o c o l u n i x O b j e c t               */
01770 /******************************************************************************/
01771   
01772 extern "C"
01773 {
01774 XrdSecProtocol *XrdSecProtocolsslObject(const char              mode,
01775                                          const char             *hostname,
01776                                          const struct sockaddr  &netaddr,
01777                                          const char             *parms,
01778                                                XrdOucErrInfo    *erp)
01779 {
01780    XrdSecProtocolssl *prot;
01781 
01782 // Return a new protocol object
01783 //
01784    if (!(prot = new XrdSecProtocolssl(hostname, &netaddr)))
01785       {const char *msg = "Secssl: Insufficient memory for protocol.";
01786        if (erp) erp->setErrInfo(ENOMEM, msg);
01787           else cerr <<msg <<endl;
01788        return (XrdSecProtocol *)0;
01789       }
01790    
01791 // All done
01792 //
01793    return prot;
01794 }
01795 }
01796 

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