XRootD
XrdSecProtocolgsi.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S e c P r o t o c o l g s i . c c */
4 /* */
5 /* (c) 2005 G. Ganis / CERN */
6 /* */
7 /* This file is part of the XRootD software suite. */
8 /* */
9 /* XRootD is free software: you can redistribute it and/or modify it under */
10 /* the terms of the GNU Lesser General Public License as published by the */
11 /* Free Software Foundation, either version 3 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
15 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
16 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
17 /* License for more details. */
18 /* */
19 /* You should have received a copy of the GNU Lesser General Public License */
20 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
21 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
22 /* */
23 /* The copyright holder's institutional names and contributor's names may not */
24 /* be used to endorse or promote products derived from this software without */
25 /* specific prior written permission of the institution or contributor. */
26 /* */
27 /******************************************************************************/
28 
29 #include <unistd.h>
30 #include <cctype>
31 #include <cerrno>
32 #include <cstdlib>
33 #include <strings.h>
34 #include <cstdio>
35 #include <sys/param.h>
36 #include <pwd.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <dirent.h>
41 #include <iostream>
42 
43 #include "XrdVersion.hh"
44 
45 #include "XrdNet/XrdNetAddr.hh"
47 #include "XrdSys/XrdSysHeaders.hh"
48 #include "XrdSys/XrdSysLogger.hh"
49 #include "XrdSys/XrdSysError.hh"
51 #include "XrdOuc/XrdOucStream.hh"
52 #include "XrdOuc/XrdOucEnv.hh"
53 
54 #include "XrdSut/XrdSutAux.hh"
55 
59 
62 
63 /******************************************************************************/
64 /* T r a c i n g I n i t O p t i o n s */
65 /******************************************************************************/
66 #ifndef NODEBUG
67 //#define POPTS(t,y) {if (t) {t->Beg(epname); std::cerr <<y; t->End();}}
68 #define POPTS(t,y) {if (t) {std::cerr <<"Secgsi" <<y <<'\n' << std::flush;}}
69 #else
70 #define POPTS(t,y)
71 #endif
72 
73 /******************************************************************************/
74 /* S t a t i c D a t a */
75 /******************************************************************************/
76 
77 static String Prefix = "xrd";
80 
81 static const char *gsiClientSteps[] = {
82  "kXGC_none",
83  "kXGC_certreq",
84  "kXGC_cert",
85  "kXGC_sigpxy",
86  "kXGC_reserved"
87 };
88 
89 static const char *gsiServerSteps[] = {
90  "kXGS_none",
91  "kXGS_init",
92  "kXGS_cert",
93  "kXGS_pxyreq",
94  "kXGS_reserved"
95 };
96 
97 static const char *gGSErrStr[] = {
98  "ErrParseBuffer", // 10000
99  "ErrDecodeBuffer", // 10001
100  "ErrLoadCrypto", // 10002
101  "ErrBadProtocol", // 10003
102  "ErrCreateBucket", // 10004
103  "ErrDuplicateBucket", // 10005
104  "ErrCreateBuffer", // 10006
105  "ErrSerialBuffer", // 10007
106  "ErrGenCipher", // 10008
107  "ErrExportPuK", // 10009
108  "ErrEncRndmTag", // 10010
109  "ErrBadRndmTag", // 10011
110  "ErrNoRndmTag", // 10012
111  "ErrNoCipher", // 10013
112  "ErrNoCreds", // 10014
113  "ErrBadOpt", // 10015
114  "ErrMarshal", // 10016
115  "ErrUnmarshal", // 10017
116  "ErrSaveCreds", // 10018
117  "ErrNoBuffer", // 10019
118  "ErrRefCipher", // 10020
119  "ErrNoPublic", // 10021
120  "ErrAddBucket", // 10022
121  "ErrFinCipher", // 10023
122  "ErrInit", // 10024
123  "ErrBadCreds", // 10025
124  "ErrError" // 10026
125 };
126 
127 // One day in secs
128 static const int kOneDay = 86400;
129 // Default proxy location template
130 static const char *gUsrPxyDef = "/tmp/x509up_u";
131 // Tag for pad support
132 static const char *gNoPadTag = "nopad";
133 // static const char *gPadTag = "&pad";
134 
135 
136 /******************************************************************************/
137 /* S t a t i c C l a s s D a t a */
138 /******************************************************************************/
139 
140 XrdSysMutex XrdSecProtocolgsi::gsiContext;
141 String XrdSecProtocolgsi::CAdir = "/etc/grid-security/certificates/";
142 String XrdSecProtocolgsi::CRLdir = "/etc/grid-security/certificates/";
143 String XrdSecProtocolgsi::DefCRLext= ".r0";
144 String XrdSecProtocolgsi::GMAPFile = "/etc/grid-security/grid-mapfile";
145 String XrdSecProtocolgsi::SrvCert = "/etc/grid-security/xrd/xrdcert.pem";
146 String XrdSecProtocolgsi::SrvKey = "/etc/grid-security/xrd/xrdkey.pem";
147 String XrdSecProtocolgsi::UsrProxy;
148 String XrdSecProtocolgsi::UsrCert = "/.globus/usercert.pem";
149 String XrdSecProtocolgsi::UsrKey = "/.globus/userkey.pem";
150 String XrdSecProtocolgsi::PxyValid = "12:00";
151 int XrdSecProtocolgsi::DepLength= 0;
152 int XrdSecProtocolgsi::DefBits = XrdCryptoDefRSABits;
153 int XrdSecProtocolgsi::CACheck = caVerifyss;
154 int XrdSecProtocolgsi::CRLCheck = crlTry; // 1
155 int XrdSecProtocolgsi::CRLDownload = 0;
156 int XrdSecProtocolgsi::CRLRefresh = 86400;
157 int XrdSecProtocolgsi::GMAPOpt = 1;
158 bool XrdSecProtocolgsi::GMAPuseDNname = 0;
159 String XrdSecProtocolgsi::DefCrypto= "ssl";
160 String XrdSecProtocolgsi::DefCipher= "aes-128-cbc:bf-cbc:des-ede3-cbc";
161 String XrdSecProtocolgsi::DefMD = "sha256";
162 String XrdSecProtocolgsi::DefError = "invalid credentials ";
163 int XrdSecProtocolgsi::PxyReqOpts = 0;
164 int XrdSecProtocolgsi::AuthzPxyWhat = -1;
165 int XrdSecProtocolgsi::AuthzPxyWhere = -1;
166 int XrdSecProtocolgsi::AuthzAlways = 1;
167 XrdSecgsiGMAP_t XrdSecProtocolgsi::GMAPFun = 0;
168 XrdSecgsiAuthz_t XrdSecProtocolgsi::AuthzFun = 0;
169 XrdSecgsiAuthzKey_t XrdSecProtocolgsi::AuthzKey = 0;
170 int XrdSecProtocolgsi::AuthzCertFmt = -1;
171 int XrdSecProtocolgsi::GMAPCacheTimeOut = -1;
172 int XrdSecProtocolgsi::AuthzCacheTimeOut = 43200; // 12h, default
173 String XrdSecProtocolgsi::SrvAllowedNames;
174 int XrdSecProtocolgsi::VOMSAttrOpt = vatIgnore; // Was '1' or extract
175 XrdSecgsiAuthz_t XrdSecProtocolgsi::VOMSFun = 0;
176 int XrdSecProtocolgsi::VOMSCertFmt = -1;
177 int XrdSecProtocolgsi::MonInfoOpt = 0;
178 bool XrdSecProtocolgsi::HashCompatibility = 1;
179 bool XrdSecProtocolgsi::TrustDNS = false;
180 bool XrdSecProtocolgsi::ShowDN = false;
181 //
182 // Crypto related info
183 int XrdSecProtocolgsi::ncrypt = 0; // Number of factories
184 XrdCryptoFactory *XrdSecProtocolgsi::cryptF[XrdCryptoMax] = {0}; // their hooks
185 int XrdSecProtocolgsi::cryptID[XrdCryptoMax] = {0}; // their IDs
186 String XrdSecProtocolgsi::cryptName[XrdCryptoMax] = {0}; // their names
187 XrdCryptoCipher *XrdSecProtocolgsi::refcip[XrdCryptoMax] = {0}; // ref for session ciphers
188 //
189 // Caches
190 XrdSutCache XrdSecProtocolgsi::cacheCA; // Server certificates info cache (default size 144)
191 XrdSutCache XrdSecProtocolgsi::cacheCert(8,13); // Server certificates info cache (Fibonacci-based sizes)
192 XrdSutCache XrdSecProtocolgsi::cachePxy(8,13); // Client proxies cache (Fibonacci-based sizes)
193 XrdSutCache XrdSecProtocolgsi::cacheGMAPFun; // Entries mapped by GMAPFun (default size 144)
194 XrdSutCache XrdSecProtocolgsi::cacheAuthzFun; // Entities filled by AuthzFun (default size 144)
195 //
196 // Services
197 XrdOucGMap *XrdSecProtocolgsi::servGMap = 0; // Grid map service
198 //
199 // CA and CRL stacks
200 GSIStack<XrdCryptoX509Chain> XrdSecProtocolgsi::stackCA; // Stack of CA in use
201 std::unique_ptr<GSIStack<XrdCryptoX509Crl>> XrdSecProtocolgsi::stackCRL( new GSIStack<XrdCryptoX509Crl>() ); // Stack of CRL in use
202 //
203 // GMAP control vars
204 time_t XrdSecProtocolgsi::lastGMAPCheck = -1; // Time of last check
205 XrdSysMutex XrdSecProtocolgsi::mutexGMAP; // Mutex to control GMAP reloads
206 //
207 // Running options / settings
208 int XrdSecProtocolgsi::Debug = 0; // [CS] Debug level
209 bool XrdSecProtocolgsi::Server = 1; // [CS] If server mode
210 int XrdSecProtocolgsi::TimeSkew = 300; // [CS] Allowed skew in secs for time stamps
211 //
212 // Debug an tracing
213 XrdSysError XrdSecProtocolgsi::eDest(0, "secgsi_");
214 XrdSysLogger XrdSecProtocolgsi::Logger;
215 XrdOucTrace *XrdSecProtocolgsi::GSITrace = 0;
216 
218 
219 /******************************************************************************/
220 /* S t a t i c F u n c t i o n s */
221 /******************************************************************************/
222 //_____________________________________________________________________________
223 static const char *ClientStepStr(int kclt)
224 {
225  // Return string with client step
226  static const char *ukn = "Unknown";
227 
228  kclt = (kclt < 0) ? 0 : kclt;
229  kclt = (kclt > kXGC_reserved) ? 0 : kclt;
230  kclt = (kclt >= kXGC_certreq) ? (kclt - kXGC_certreq + 1) : kclt;
231 
232  if (kclt < 0 || kclt > (kXGC_reserved - kXGC_certreq + 1))
233  return ukn;
234  else
235  return gsiClientSteps[kclt];
236 }
237 
238 //_____________________________________________________________________________
239 static const char *ServerStepStr(int ksrv)
240 {
241  // Return string with server step
242  static const char *ukn = "Unknown";
243 
244  ksrv = (ksrv < 0) ? 0 : ksrv;
245  ksrv = (ksrv > kXGS_reserved) ? 0 : ksrv;
246  ksrv = (ksrv >= kXGS_init) ? (ksrv - kXGS_init + 1) : ksrv;
247 
248  if (ksrv < 0 || ksrv > (kXGS_reserved - kXGS_init + 1))
249  return ukn;
250  else
251  return gsiServerSteps[ksrv];
252 }
253 
254 
255 /******************************************************************************/
256 /* D u m p o f H a n d s h a k e v a r i a b l e s */
257 /******************************************************************************/
258 
259 //_____________________________________________________________________________
261 {
262  // Dump content
263  EPNAME("HSVars::Dump");
264 
265  PRINT("----------------------------------------------------------------");
266  PRINT("protocol instance: "<<p);
267  PRINT("this: "<<this);
268  PRINT(" ");
269  PRINT("Time stamp: "<<TimeStamp);
270  PRINT("Crypto mod: "<<CryptoMod);
271  PRINT("Remote version: "<<RemVers);
272  PRINT("Ref cipher: "<<Rcip);
273  PRINT("Cipher padding: "<<HasPad);
274  PRINT("Bucket for exp cert: "<<Cbck);
275  PRINT("Handshake ID: "<<ID);
276  PRINT("Cache reference: "<<Cref);
277  PRINT("Relevant file entry: "<<Pent);
278  PRINT("Chain pointer: "<<Chain);
279  PRINT("CRL pointer: "<<Crl);
280  PRINT("Proxy chain: "<<PxyChain);
281  PRINT("Rndm tag checked: "<<RtagOK);
282  PRINT("Last step: "<<LastStep);
283  PRINT("Options: "<<Options);
284  PRINT("----------------------------------------------------------------");
285 }
286 
287 /******************************************************************************/
288 /* P r o t o c o l I n i t i a l i z a t i o n M e t h o d s */
289 /******************************************************************************/
290 
291 
292 //_____________________________________________________________________________
294  XrdNetAddrInfo &endPoint,
295  const char *parms) : XrdSecProtocol("gsi")
296 {
297  // Default constructor
298  EPNAME("XrdSecProtocolgsi");
299 
300  if (QTRACE(Authen)) { PRINT("constructing: "<<this); }
301 
302  // Create instance of the handshake vars
303  if ((hs = new gsiHSVars())) {
304  // Update time stamp
305  hs->TimeStamp = time(0);
306  // Local handshake variables
307  hs->Tty = (isatty(0) == 0 || isatty(1) == 0) ? 0 : 1;
308  } else {
309  PRINT("could not create handshake vars object");
310  }
311 
312  // Set host name and address
313  // The hostname is critical for the GSI protocol; it must match the potential
314  // names on the remote EEC. We default to the hostname requested by the user to
315  // the client (or proxy). However, as we may have been redirected to an IP
316  // address instead of an actual hostname, we must fallback to a reverse DNS lookup.
317  // As of time of testing (June 2018), EOS will redirect to an IP address to handle
318  // metadata commands and rely on the reverse DNS lookup for GSI security to function.
319  // Hence, this fallback likely needs to be kept for some time.
320  //
321  // We provide servers a switch and clients an environment variable to override all
322  // usage of DNS (processed on XrdSecProtocolgsiInit).
323  // Default is to fallback to DNS lookups in limited
324  // cases for backward compatibility.
325  expectedHost = NULL;
326  if (TrustDNS) {
327  if (!hname || !XrdNetAddrInfo::isHostName(hname)) {
328  Entity.host = strdup(endPoint.Name(""));
329  } else {
330  // At this point, hname still may possibly be a non-qualified domain name.
331  // If there is a '.' character, then we assume it is a qualified domain name --
332  // otherwise, we use DNS.
333  //
334  // NOTE: We can definitively test whether this is a qualified domain name by
335  // simply appending a '.' to `hname` and performing a lookup. However, this
336  // causes DNS to be used by every lookup - meaning we rely on the security
337  // of DNS for all cases; we want to avoid this.
338  if (strchr(hname, '.')) {
339  // We have a valid hostname; proceed.
340  Entity.host = strdup(hname);
341  } else {
342  XrdNetAddr xrd_addr;
343  char canonname[256];
344  if (!xrd_addr.Set(hname) || (xrd_addr.Format(canonname, 256, XrdNetAddrInfo::fmtName, XrdNetAddrInfo::noPort) <= 0)) {
345  Entity.host = strdup(hname);
346  } else {
347  Entity.host = strdup(canonname);
348  }
349  }
350  }
351  } else {
352  // We have been told via environment variable to not trust DNS; use the exact
353  // hostname provided by the user.
354 // char dnBuff[256];
355 // getdomainname(dnBuff, sizeof(dnBuff));
356  Entity.host = strdup(hname);
357  expectedHost = strdup(hname);
358  }
359  epAddr = endPoint;
360  Entity.addrInfo = &epAddr;
361 
362  // Init session variables
363  sessionCF = 0;
364  sessionKey = 0;
365  bucketKey = 0;
366  sessionMD = 0;
367  sessionKsig = 0;
368  sessionKver = 0;
369  sessionKver = 0;
370  proxyChain = 0;
371  useIV = false;
372 
373  //
374  // Notify, if required
375  DEBUG("constructing: host: "<< Entity.host);
376  DEBUG("p: "<<XrdSecPROTOIDENT<<", plen: "<<XrdSecPROTOIDLEN);
377  //
378  // basic settings
379  options = opts;
380  srvMode = 0;
381 
382  //
383  // Mode specific initializations
384  if (Server) {
385  srvMode = 1;
386  DEBUG("mode: server");
387  } else {
388  DEBUG("mode: client");
389  //
390  // Decode received buffer
391  if (parms) {
392  XrdOucString p("&P=gsi,");
393  p += parms;
394  hs->Parms = new XrdSutBuffer(p.c_str(), p.length());
395  }
396  }
397 
398  // We are done
399  String vers = Version;
400  vers.insert('.',vers.length()-2);
401  vers.insert('.',vers.length()-5);
402  DEBUG("object created: v"<<vers.c_str());
403 }
404 
405 //_____________________________________________________________________________
407 {
408  // Static method to the configure the static part of the protocol
409  // Called once by XrdSecProtocolgsiInit
410  EPNAME("Init");
411  char *Failure = 0, *Parms = 0;
412 
413  //
414  // Debug an tracing
415  Debug = (opt.debug > -1) ? opt.debug : Debug;
416 
417  // We must have the tracing object at this point
418  // (initialized in XrdSecProtocolgsiInit)
419  if (!gsiTrace) {
420  ErrF(erp,kGSErrInit,"tracing object (gsiTrace) not initialized! cannot continue");
421  return Failure;
422  }
423  // Set debug mask ... also for auxilliary libs
424  int trace = 0, traceSut = 0, traceCrypto = 0;
425  if (Debug >= 3) {
426  trace = cryptoTRACE_Dump;
427  traceSut = sutTRACE_Dump;
428  traceCrypto = cryptoTRACE_Dump;
429  GSITrace->What = TRACE_ALL;
430  } else if (Debug >= 2) {
431  trace = cryptoTRACE_Debug;
432  traceSut = sutTRACE_Debug;
433  traceCrypto = cryptoTRACE_Debug;
434  GSITrace->What = TRACE_Debug;
435  GSITrace->What |= TRACE_Authen;
436  } else if (Debug >= 1) {
437  trace = cryptoTRACE_Debug;
438  traceSut = sutTRACE_Notify;
439  traceCrypto = cryptoTRACE_Notify;
440  GSITrace->What = TRACE_Debug;
441  }
442 
443  // ... also for auxilliary libs
444  XrdSutSetTrace(traceSut);
445  XrdCryptoSetTrace(traceCrypto);
446 
447  // Name hashing algorithm compatibility
448  if (opt.hashcomp == 0) HashCompatibility = 0;
449 
450  //
451  // Operation mode
452  Server = (opt.mode == 's');
453 
454  //
455  // CA verification level
456  //
457  // 0 do not verify
458  // 1 verify if self-signed; warn if not
459  // 2 verify in all cases; fail if not possible
460  //
461  if (opt.ca >= caNoVerify && opt.ca <= caVerify)
462  CACheck = opt.ca;
463  DEBUG("option CACheck: "<<getOptName(caVerOpts,CACheck));
464 
465  //
466  // Check existence of CA directory
467  struct stat st;
468  if (opt.certdir) {
469  DEBUG("testing CA dir(s): "<<opt.certdir);
470  String CAtmp;
471  String tmp = opt.certdir;
472  String dp;
473  int from = 0;
474  while ((from = tmp.tokenize(dp, from, ',')) != -1) {
475  if (dp.length() > 0) {
476  if (XrdSutExpand(dp) == 0) {
477  if (stat(dp.c_str(),&st) == -1) {
478  if (errno == ENOENT) {
479  ErrF(erp,kGSErrError,"CA directory non existing",dp.c_str());
480  PRINT(erp->getErrText());
481  } else {
482  ErrF(erp,kGSErrError,"cannot stat CA directory",dp.c_str());
483  PRINT(erp->getErrText());
484  }
485  } else {
486  if (!(dp.endswith('/'))) dp += '/';
487  if (!(CAtmp.endswith(','))) CAtmp += ',';
488  CAtmp += dp;
489  }
490  } else {
491  PRINT("Warning: could not expand: "<<dp);
492  }
493  }
494  }
495  if (CAtmp.length() > 0)
496  CAdir = CAtmp;
497  }
498  DEBUG("using CA dir(s): "<<CAdir);
499 
500  //
501  // CRL check level
502  //
503  // 0 do not care
504  // 1 use if available
505  // 2 require
506  // 3 require not expired
507  // 12 require; try download if missing
508  // 13 require not expired; try download if missing
509  //
510  const char *cocrl[] = { "do-not-care", "use-if-available", "require", "require-not-expired" };
511  const char *codwld[] = { "no", "yes"};
512  if (opt.crl >= crlUpdate) {
513  CRLDownload = 1;
514  opt.crl %= 10;
515  }
516  if (opt.crl >= crlIgnore && opt.crl <= crlRequire)
517  CRLCheck = opt.crl;
518  DEBUG("option CRLCheck: "<<CRLCheck<<" ('"<<cocrl[CRLCheck]<<"'; download? "<<
519  codwld[CRLDownload]<<")");
520 
521  //
522  // Check existence of CRL directory
523  if (opt.crldir) {
524 
525  DEBUG("testing CRL dir(s): "<<opt.crldir);
526  String CRLtmp;
527  String tmp = opt.crldir;
528  String dp;
529  int from = 0;
530  while ((from = tmp.tokenize(dp, from, ',')) != -1) {
531  if (dp.length() > 0) {
532  if (XrdSutExpand(dp) == 0) {
533  if (stat(dp.c_str(),&st) == -1) {
534  if (errno == ENOENT) {
535  ErrF(erp,kGSErrError,"CRL directory non existing:",dp.c_str());
536  PRINT(erp->getErrText());
537  } else {
538  ErrF(erp,kGSErrError,"cannot stat CRL directory:",dp.c_str());
539  PRINT(erp->getErrText());
540  }
541  } else {
542  if (!(dp.endswith('/'))) dp += '/';
543  if (!(CRLtmp.endswith(','))) CRLtmp += ',';
544  CRLtmp += dp;
545  }
546  } else {
547  PRINT("Warning: could not expand: "<<dp);
548  }
549  }
550  }
551  if (CRLtmp.length() > 0)
552  CRLdir = CRLtmp;
553 
554  } else {
555  // Use CAdir
556  CRLdir = CAdir;
557  }
558  if (CRLCheck > 0)
559  DEBUG("using CRL dir(s): "<<CRLdir);
560 
561  //
562  // Default extension for CRL files
563  if (opt.crlext)
564  DefCRLext = opt.crlext;
565 
566  //
567  // Refresh or expiration time for CRLs
568  if (opt.crlrefresh)
569  CRLRefresh = opt.crlrefresh;
570  DEBUG("CRL information refreshed every "<<CRLRefresh<<" secs");
571 
572  //
573  // Honour trust / unstrust DNS settings (switch or env)
574  TrustDNS = opt.trustdns;
575  DEBUG("trust DNS option: "<<TrustDNS);
576 
577  //
578  // Enable/disable displaying the DN
579  ShowDN = opt.showDN;
580  DEBUG("show DN option: "<<ShowDN);
581 
582  //
583  // Server specific options
584  if (Server) {
585  //
586  // List of supported / wanted crypto modules
587  if (opt.clist)
588  DefCrypto = opt.clist;
589  //
590  // List of crypto modules
591  String cryptlist;
592  String crypts(DefCrypto,0,-1,64);
593  //
594  // Load crypto modules
595  XrdSutPFEntry ent;
596  XrdCryptoFactory *cf = 0;
597  if (crypts.length()) {
598  String ncpt = "";
599  int from = 0;
600  while ((from = crypts.tokenize(ncpt, from, '|')) != -1) {
601  if (ncpt.length() > 0 && ncpt[0] != '-') {
602  // Try loading
603  if ((cf = XrdCryptoFactory::GetCryptoFactory(ncpt.c_str()))) {
604  // Add it to the list
605  cryptF[ncrypt] = cf;
606  cryptID[ncrypt] = cf->ID();
607  cryptName[ncrypt].insert(cf->Name(),0,strlen(cf->Name())+1);
608  cf->SetTrace(trace);
609  cf->Notify();
610  // Ref cipher
611  if (!(refcip[ncrypt] = cf->Cipher(0,0,0))) {
612  PRINT("ref cipher for module "<<ncpt<<
613  " cannot be instantiated : disable");
614  from -= ncpt.length();
615  } else {
616  ncrypt++;
617  if (ncrypt >= XrdCryptoMax) {
618  PRINT("max number of crypto modules ("
619  << XrdCryptoMax <<") reached ");
620  break;
621  }
622  if (cryptlist.length()) cryptlist += ":";
623  cryptlist += ncpt;
624  if (!cf->HasPaddingSupport()) cryptlist += gNoPadTag;
625  }
626  } else {
627  PRINT("cannot instantiate crypto factory "<<ncpt<<
628  ": disable");
629  from -= ncpt.length();
630  }
631  }
632  }
633  }
634  //
635  // We need at least one valid crypto module
636  if (ncrypt <= 0) {
637  ErrF(erp,kGSErrInit,"could not find any valid crypto module");
638  PRINT(erp->getErrText());
639  return Failure;
640  }
641  //
642  // List of supported / wanted ciphers
643  if (opt.cipher)
644  DefCipher = opt.cipher;
645  // make sure we support all of them
646  String cip = "";
647  int from = 0;
648  while ((from = DefCipher.tokenize(cip, from, ':')) != -1) {
649  if (cip.length() > 0) {
650  int i = 0;
651  for (; i < ncrypt; i++) {
652  if (!(cryptF[i]->SupportedCipher(cip.c_str()))) {
653  // Not supported: drop from the list
654  DEBUG("cipher type not supported ("<<cip<<") - disabling");
655  from -= cip.length();
656  DefCipher.erase(cip);
657  }
658  }
659  }
660  }
661 
662  //
663  // List of supported / wanted Message Digest
664  if (opt.md)
665  DefMD = opt.md;
666  // make sure we support all of them
667  String md = "";
668  from = 0;
669  while ((from = DefMD.tokenize(md, from, ':')) != -1) {
670  if (md.length() > 0) {
671  int i = 0;
672  for (; i < ncrypt; i++) {
673  if (!(cryptF[i]->SupportedMsgDigest(md.c_str()))) {
674  // Not supported: drop from the list
675  PRINT("MD type not supported ("<<md<<") - disabling");
676  from -= md.length();
677  DefMD.erase(md);
678  }
679  }
680  }
681  }
682 
683  //
684  // Load server certificate and key
685  if (opt.cert) {
686  String TmpCert = opt.cert;
687  if (XrdSutExpand(TmpCert) == 0) {
688  SrvCert = TmpCert;
689  } else {
690  PRINT("Could not expand: "<<opt.cert<<": use default");
691  }
692  }
693  if (opt.key) {
694  String TmpKey = opt.key;
695  if (XrdSutExpand(TmpKey) == 0) {
696  SrvKey = TmpKey;
697  } else {
698  PRINT("Could not expand: "<<opt.key<<": use default");
699  }
700  }
701  //
702  // Check if we can read the certificate key
703  if (access(SrvKey.c_str(), R_OK)) {
704  PRINT("WARNING: process has no permission to read the certificate key file: "<<SrvKey);
705  }
706  int i = 0;
707  String certcalist = ""; // list of CA for server certificates
708  XrdSutCERef ceref;
709  for (; i<ncrypt; i++) {
710  if (!GetSrvCertEnt(ceref, cryptF[i], time(0), certcalist)) {
711  PRINT("problems loading srv cert");
712  ceref.UnLock();
713  continue;
714  }
715  }
716  // Rehash cache
717  ceref.UnLock();
718  //
719  // We must have got at least one valid certificate
720  if (cacheCert.Num() <= 0) {
721  ErrF(erp,kGSErrError,"no valid server certificate found");
722  PRINT(erp->getErrText());
723  return Failure;
724  }
725 
726  DEBUG("CA list: "<<certcalist);
727 
728  //
729  // GRID map check option
730  //
731  // 0 do not use (DN hash will be used as identifier)
732  // 1 use if available; otherwise as 0
733  // 2 require
734  // 10 do not use (DN name will be used as identifier)
735  // 11 use if available; otherwise as 10
736  const char *cogmap[] = { "do-not-use", "use-if-available", "require" };
737  const char *codnnm[] = { "DN hash", "DN name"};
738  if (opt.ogmap >= 10) {
739  GMAPuseDNname = 1;
740  opt.ogmap %= 10;
741  }
742  if (opt.ogmap >= 0 && opt.ogmap <= 2)
743  GMAPOpt = opt.ogmap;
744  DEBUG("user mapping file option: "<<cogmap[GMAPOpt]);
745  if (GMAPOpt < 2)
746  DEBUG("default option for entity name if no mapping available: "<<codnnm[(int)GMAPuseDNname]);
747 
748  //
749  // Check existence of GRID map file
750  if (opt.gridmap) {
751  String GMAPTmp = opt.gridmap;
752  if (XrdSutExpand(GMAPTmp) == 0) {
753  GMAPFile = GMAPTmp;
754  } else {
755  PRINT("Could not expand: "<<opt.gridmap<<": use default");
756  }
757  }
758  bool hasgmap = 0;
759  if (GMAPOpt > 0) {
760  // Initialize the GMap service
761  //
762  String pars;
763  if (Debug) pars += "dbg|";
764  if (opt.gmapto > 0) { pars += "to="; pars += (int)opt.gmapto; }
765  if (!(servGMap = XrdOucgetGMap(&eDest, GMAPFile.c_str(), pars.c_str()))) {
766  if (GMAPOpt > 1) {
767  ErrF(erp,kGSErrError,"error loading grid map file",GMAPFile.c_str());
768  PRINT(erp->getErrText());
769  return Failure;
770  } else {
771  NOTIFY("Grid map file: "<<GMAPFile<<" cannot be 'access'ed: do not use");
772  }
773  } else {
774  DEBUG("using grid map file: "<<GMAPFile);
775  hasgmap = 1;
776  }
777  }
778  //
779  // Load function be used to map DN to usernames, if specified
780  bool hasgmapfun = 0;
781  if (opt.gmapfun && GMAPOpt > 0) {
782  if (!(GMAPFun = LoadGMAPFun((const char *) opt.gmapfun,
783  (const char *) opt.gmapfunparms))) {
784  ErrF(erp, kGSErrError, "GMAP plug-in could not be loaded", opt.gmapfun);
785  PRINT(erp->getErrText());
786  return Failure;
787  } else {
788  hasgmapfun = 1;
789  }
790  }
791  //
792  // Disable GMAP if neither a grid mapfile nor a GMAP function are available
793  if (!hasgmap && !hasgmapfun) {
794  if (GMAPOpt > 1) {
795  ErrF(erp,kGSErrError,"User mapping required, but neither a grid mapfile"
796  " nor a mapping function are available");
797  PRINT(erp->getErrText());
798  return Failure;
799  }
800  GMAPOpt = 0;
801  }
802  //
803  // Authentication function
804  bool hasauthzfun = 0;
805  AuthzAlways = opt.authzcall;
806  if (opt.authzfun) {
807  if (!(AuthzFun = LoadAuthzFun((const char *) opt.authzfun,
808  (const char *) opt.authzfunparms, AuthzCertFmt))) {
809  ErrF(erp, kGSErrError, "Authz plug-in could not be loaded", opt.authzfun);
810  PRINT(erp->getErrText());
811  return Failure;
812  } else {
813  hasauthzfun = 1;
814  // Notify certificate format
815  if (AuthzCertFmt >= 0 && AuthzCertFmt <= 1) {
816  const char *ccfmt[] = { "raw", "PEM base64" };
817  DEBUG("authzfun: proxy certificate format: "<<ccfmt[AuthzCertFmt]);
818  } else {
819  NOTIFY("authzfun: proxy certificate format: unknown (code: "<<AuthzCertFmt<<")");
820  }
821  // Expiration of Authz related cache entries
822  if (opt.authzto > 0) {
823  AuthzCacheTimeOut = opt.authzto;
824  DEBUG("grid-map cache entries expire after "<<AuthzCacheTimeOut<<" secs");
825  }
826  }
827  }
828  //
829  // Expiration of GRIDMAP related cache entries
830  if (GMAPOpt > 0 && !hasauthzfun && opt.gmapto > 0) {
831  GMAPCacheTimeOut = opt.gmapto;
832  DEBUG("grid-map cache entries expire after "<<GMAPCacheTimeOut<<" secs");
833  }
834 
835  //
836  // Request for proxy export for authorization
837  // authzpxy = opt_what*10 + opt_where
838  // opt_what = 0 full chain
839  // 1 last proxy only
840  // opt_where = 1 Entity.creds
841  // 2 Entity.endorsements
842  if (opt.authzpxy) {
843  AuthzPxyWhat = opt.authzpxy / 10;
844  AuthzPxyWhere = opt.authzpxy % 10;
845  // Some notification
846  const char *capxy_what = (AuthzPxyWhat == 1) ? "'last proxy only'"
847  : "'full proxy chain'";
848  const char *capxy_where = (AuthzPxyWhere == 1) ? "XrdSecEntity.creds"
849  : "XrdSecEntity.endorsements";
850  DEBUG("Export proxy for authorization in '"<<capxy_where<<"': "<<capxy_what);
851  if (hasauthzfun) {
852  // Warn user about possible overwriting of Entity.creds or Entity.endorsements
853  PRINT("WARNING: proxy export for authz enabled: be aware that any setting of '"<<capxy_what<<
854  "' done by '"<<opt.authzfun<<"' will get overwritten with "<<capxy_what);
855  }
856  }
857 
858  //
859  // Handle delegated proxies options
860  if (opt.dlgpxy == -1) {
861  // Will not accept any delegated proxies
862  DEBUG("Will not accept delegated proxies");
863  } else {
864  // Ask the client to sign a delegated proxy; client may decide to forward its proxy
865  if (opt.dlgpxy == dlgReqSign)
866  PxyReqOpts |= kOptsSrvReq;
867 
868  // Exporting options (default none: delegated proxy kept in memory, in proxyChain)
869  if (opt.exppxy) {
870  if (!strcmp(opt.exppxy, "=creds")) {
871  // register the delegated proxy in Entity.creds (in HEX format)
872  PxyReqOpts |= kOptsPxCred;
873  DEBUG("Delegated proxy saved in Entity.creds ");
874  } else {
875  String TmpProxy = gUsrPxyDef;
876  if (strcmp(opt.exppxy, "=default"))
877  TmpProxy = opt.exppxy;
878  if (XrdSutExpand(TmpProxy) == 0) {
879  UsrProxy = TmpProxy;
880  } else {
881  UsrProxy = gUsrPxyDef;
882  UsrProxy += "u<uid>";
883  }
884  PxyReqOpts |= kOptsPxFile;
885  DEBUG("File template for delegated proxy: "<<UsrProxy);
886  }
887  }
888  DEBUG("Delegated proxies options: "<<PxyReqOpts);
889  }
890 
891  //
892  // VOMS attributes switch
893  // vomsat = 0 do not look for
894  // 1 extract if any (fill 'vorg', 'role'; the full string in 'endorsements');
895  // 2 require (fill 'vorg', 'role'; the full string in 'endorsements');
896  VOMSAttrOpt = (opt.vomsat <= vatRequire && opt.vomsat >= vatIgnore)
897  ? opt.vomsat : VOMSAttrOpt;
898 
899  //
900  // Alternative VOMS extraction function
901  if (opt.vomsfun) {
902  if (!(VOMSFun = LoadVOMSFun((const char *) opt.vomsfun,
903  (const char *) opt.vomsfunparms, VOMSCertFmt))) {
904  ErrF(erp, kGSErrError, "VOMS plug-in loading failed", opt.vomsfun);
905  PRINT(erp->getErrText());
906  return Failure;
907  } else {
908  // Notify certificate format
909  if (VOMSCertFmt >= 0 && VOMSCertFmt <= 1) {
910  const char *ccfmt[] = { "raw", "PEM base64" };
911  DEBUG("vomsfun: proxy certificate format: "<<ccfmt[VOMSCertFmt]);
912  } else {
913  char fbuff[64];
914  snprintf(fbuff, sizeof(fbuff), "%d", VOMSCertFmt);
915  ErrF(erp, kGSErrError, "VOMS plug-in returned invalid cert "
916  "format", fbuff);
917  PRINT(erp->getErrText());
918  return Failure;
919  }
920  }
921  } else opt.authzcall = AuthzAlways = 1;
922  DEBUG("VOMS attributes options: "<<getOptName(vomsatOpts, VOMSAttrOpt));
923 
924  //
925  // Default moninfo option
926  // 0 nothing
927  // 1 DN
928  MonInfoOpt = opt.moninfo;
929  const char *cmoninfo = (MonInfoOpt == 1) ? "DN" : "none";
930  DEBUG("Monitor information options: "<<cmoninfo);
931 
932  // Make sure we have a calist as the client can't do anything without it.
933  // If the cryptlist is empty the client will use the default one.
934  //
935  if (certcalist.length() == 0)
936  {ErrF(erp,kGSErrInit,"unable to generate ca cert hash list!");
937  PRINT(erp->getErrText());
938  return Failure;
939  }
940 
941  //
942  // Parms in the form:
943  // &P=gsi,v:<version>,c:<cryptomod>,ca:<list_of_srv_cert_ca>
944  Parms = new char[cryptlist.length()+3+12+certcalist.length()+5];
945  if (Parms) {
946  sprintf(Parms,"v:%d,c:%s,ca:%s",
947  Version,cryptlist.c_str(),certcalist.c_str());
948  } else {
949  ErrF(erp,kGSErrInit,"no system resources for 'Parms'");
950  PRINT(erp->getErrText());
951  return Failure;
952  }
953 
954  // Some notification
955  DEBUG("available crypto modules: "<<cryptlist);
956  DEBUG("issuer CAs of server certs (hashes): "<<certcalist);
957  }
958 
959  //
960  // Client specific options
961  if (!Server) {
962  // use default dir $(HOME)/.<prefix>
963  struct passwd *pw = getpwuid(getuid());
964  if (!pw) {
965  NOTIFY("WARNING: cannot get user information (uid:"<<getuid()<<")");
966  }
967  //
968  // Define user proxy file
969  UsrProxy = gUsrPxyDef;
970  if (opt.proxy) {
971  String TmpProxy = opt.proxy;
972  if (XrdSutExpand(TmpProxy) == 0) {
973  UsrProxy = TmpProxy;
974  } else {
975  PRINT("Could not expand: "<<opt.proxy<<": use default");
976  }
977  } else {
978  if (pw)
979  UsrProxy += (int)(pw->pw_uid);
980  }
981  // Define user certificate file
982  if (opt.cert) {
983  String TmpCert = opt.cert;
984  if (XrdSutExpand(TmpCert) == 0) {
985  UsrCert = TmpCert;
986  } else {
987  PRINT("Could not expand: "<<opt.cert<<": use default");
988  }
989  } else {
990  if (pw)
991  UsrCert.insert(XrdSutHome(),0);
992  }
993  // Define user private key file
994  if (opt.key) {
995  String TmpKey = opt.key;
996  if (XrdSutExpand(TmpKey) == 0) {
997  UsrKey = TmpKey;
998  } else {
999  PRINT("Could not expand: "<<opt.key<<": use default");
1000  }
1001  } else {
1002  if (pw)
1003  UsrKey.insert(XrdSutHome(),0);
1004  }
1005  // Define proxy validity at renewal
1006  if (opt.valid)
1007  PxyValid = opt.valid;
1008  // Set depth of signature path
1009  if (opt.deplen != DepLength)
1010  DepLength = opt.deplen;
1011  // Set number of bits for proxy key
1012  if (opt.bits > DefBits)
1013  DefBits = opt.bits;
1014  //
1015  // Delegate proxy options
1016  if (opt.dlgpxy > dlgIgnore) {
1017  PxyReqOpts |= kOptsSigReq;
1018  if (opt.dlgpxy == dlgSendpxy) {
1019  PxyReqOpts |= kOptsFwdPxy;
1020  } else {
1021  PxyReqOpts |= kOptsDlgPxy;
1022  }
1023  }
1024  //
1025  // No proxy options
1026  if (opt.createpxy) {
1027  PxyReqOpts |= kOptsCreatePxy;
1028  }
1029  //
1030  // Define valid CNs for the server certificates; default is null, which means that
1031  // the server CN must be in the form "*/<hostname>"
1032  if (opt.srvnames)
1033  SrvAllowedNames = opt.srvnames;
1034  //
1035  // Notify
1036  TRACE(Authen, "using certificate file: "<<UsrCert);
1037  TRACE(Authen, "using private key file: "<<UsrKey);
1038  TRACE(Authen, "proxy: file: "<<UsrProxy);
1039  TRACE(Authen, "proxy: validity: "<<PxyValid);
1040  TRACE(Authen, "proxy: depth of signature path: "<<DepLength);
1041  TRACE(Authen, "proxy: bits in key: "<<DefBits);
1042  TRACE(Authen, "server cert: allowed names: "<<SrvAllowedNames);
1043  if (!(PxyReqOpts & kOptsCreatePxy)) {
1044  TRACE(Authen, "allowing for pure cert/key authentication (no proxy) ");
1045  }
1046 
1047  // We are done
1048  Parms = (char *)"";
1049  }
1050 
1051  // We are done
1052  return Parms;
1053 }
1054 
1055 /******************************************************************************/
1056 /* D e l e t e */
1057 /******************************************************************************/
1059 {
1060  // Deletes the protocol
1061  SafeFree(Entity.name);
1062  SafeFree(Entity.host);
1063  SafeFree(Entity.vorg);
1064  SafeFree(Entity.role);
1065  SafeFree(Entity.grps);
1066  SafeFree(Entity.caps);
1068  if (Entity.creds && Entity.credslen > 0) {
1070  } else {
1071  Entity.creds = 0;
1072  }
1073  Entity.credslen = 0;
1075  // Cleanup the handshake variables, if still there
1076  SafeDelete(hs);
1077  // Cleanup any other instance specific to this protocol
1078  SafeDelete(sessionKey); // Session Key (result of the handshake)
1079  SafeDelete(bucketKey); // Bucket with the key in export form
1080  SafeDelete(sessionMD); // Message Digest instance
1081  SafeDelete(sessionKsig); // RSA key to sign
1082  SafeDelete(sessionKver); // RSA key to verify
1083  if (proxyChain) proxyChain->Cleanup();
1084  SafeDelete(proxyChain); // Chain with delegated proxies
1085  SafeFree(expectedHost);
1086 
1087  delete this;
1088 }
1089 
1090 
1091 /******************************************************************************/
1092 /* E n c r y p t i o n R e l a t e d M e t h o d s */
1093 /******************************************************************************/
1094 
1095 //_____________________________________________________________________________
1096 int XrdSecProtocolgsi::Encrypt(const char *inbuf, // Data to be encrypted
1097  int inlen, // Length of data in inbuff
1098  XrdSecBuffer **outbuf) // Returns encrypted data
1099 {
1100  // Encrypt data in inbuff and place it in outbuff.
1101  //
1102  // Returns: < 0 Failed, the return value is -errno of the reason. Typically,
1103  // -EINVAL - one or more arguments are invalid.
1104  // -ENOTSUP - encryption not supported by the protocol
1105  // -EOVERFLOW - outbuff is too small to hold result
1106  // -ENOENT - Context not initialized
1107  // = 0 Success, outbuff contains a pointer to the encrypted data.
1108  //
1109  EPNAME("Encrypt");
1110 
1111  // We must have a key
1112  if (!sessionKey)
1113  return -ENOENT;
1114 
1115  // And something to encrypt
1116  if (!inbuf || inlen <= 0 || !outbuf)
1117  return -EINVAL;
1118 
1119  // Regenerate IV
1120  int liv = 0;
1121  char *iv = 0;
1122  if (useIV) {
1123  iv = sessionKey->RefreshIV(liv); // no need to call sessionKeySetIV as
1124  // RefreshIV will set the internal value
1125  }
1126 
1127  // Get output buffer
1128  char *buf = (char *)malloc(sessionKey->EncOutLength(inlen) + liv);
1129  if (!buf)
1130  return -ENOMEM;
1131  // IV at beginning
1132  if (liv > 0 && iv)
1133  memcpy(buf, iv, liv);
1134 
1135  // Encrypt
1136  int len = sessionKey->Encrypt(inbuf, inlen, buf + liv) + liv; // the size of initialization vector which is being appended at
1137  // the beginning of the output buffer has to be taken into account
1138  if (len <= 0) {
1139  SafeFree(buf);
1140  return -EINVAL;
1141  }
1142 
1143  // Create and fill output buffer
1144  *outbuf = new XrdSecBuffer(buf, len);
1145 
1146  // We are done
1147  DEBUG("encrypted buffer has "<<len<<" bytes");
1148  return 0;
1149 }
1150 
1151 //_____________________________________________________________________________
1152 int XrdSecProtocolgsi::Decrypt(const char *inbuf, // Data to be decrypted
1153  int inlen, // Length of data in inbuff
1154  XrdSecBuffer **outbuf) // Returns decrypted data
1155 {
1156  // Decrypt data in inbuff and place it in outbuff.
1157  //
1158  // Returns: < 0 Failed,the return value is -errno (see Encrypt).
1159  // = 0 Success, outbuff contains a pointer to the encrypted data.
1160  EPNAME("Decrypt");
1161 
1162  // We must have a key
1163  if (!sessionKey)
1164  return -ENOENT;
1165 
1166  // And something to decrypt
1167  if (!inbuf || inlen <= 0 || !outbuf)
1168  return -EINVAL;
1169 
1170  // Size
1171  int liv = (useIV) ? sessionKey->MaxIVLength() : 0;
1172  int sz = inlen - liv;
1173  // Get output buffer
1174  char *buf = (char *)malloc(sessionKey->DecOutLength(sz) + liv);
1175  if (!buf)
1176  return -ENOMEM;
1177 
1178  // Get and set IV
1179  if (useIV) {
1180  char *iv = new char[liv];
1181  memcpy(iv, inbuf, liv);
1182  sessionKey->SetIV(liv, iv);
1183  delete[] iv;
1184  }
1185 
1186  // Decrypt
1187  int len = sessionKey->Decrypt(inbuf + liv, sz, buf);
1188  if (len <= 0) {
1189  SafeFree(buf);
1190  return -EINVAL;
1191  }
1192 
1193  // Create and fill output buffer
1194  *outbuf = new XrdSecBuffer(buf, len);
1195 
1196  // We are done
1197  DEBUG("decrypted buffer has "<<len<<" bytes");
1198  return 0;
1199 }
1200 
1201 //_____________________________________________________________________________
1202 int XrdSecProtocolgsi::Sign(const char *inbuf, // Data to be signed
1203  int inlen, // Length of data to be signed
1204  XrdSecBuffer **outbuf) // Buffer for the signature
1205 {
1206  // Sign data in inbuff and place the signature in outbuf.
1207  //
1208  // Returns: < 0 Failed, returned value is -errno (see Encrypt).
1209  // = 0 Success, the return value is the length of the signature
1210  // placed in outbuf.
1211  //
1212  EPNAME("Sign");
1213 
1214  // We must have a PKI and a digest
1215  if (!sessionKsig || !sessionMD)
1216  return -ENOENT;
1217 
1218  // And something to sign
1219  if (!inbuf || inlen <= 0 || !outbuf)
1220  return -EINVAL;
1221 
1222  // Reset digest
1223  sessionMD->Reset(0);
1224 
1225  // Calculate digest
1226  sessionMD->Update(inbuf, inlen);
1227  sessionMD->Final();
1228 
1229  // Output length
1230  int lmax = sessionKsig->GetOutlen(sessionMD->Length());
1231  char *buf = (char *)malloc(lmax);
1232  if (!buf)
1233  return -ENOMEM;
1234 
1235  // Sign
1236  int len = sessionKsig->EncryptPrivate(sessionMD->Buffer(),
1237  sessionMD->Length(),
1238  buf, lmax);
1239  if (len <= 0) {
1240  SafeFree(buf);
1241  return -EINVAL;
1242  }
1243 
1244  // Create and fill output buffer
1245  *outbuf = new XrdSecBuffer(buf, len);
1246 
1247  // We are done
1248  DEBUG("signature has "<<len<<" bytes");
1249  return 0;
1250 }
1251 
1252 //_____________________________________________________________________________
1253 int XrdSecProtocolgsi::Verify(const char *inbuf, // Data to be verified
1254  int inlen, // Length of data in inbuf
1255  const char *sigbuf, // Buffer with signature
1256  int siglen) // Length of signature
1257 {
1258  // Verify a signature
1259  //
1260  // Returns: < 0 Failed, returned value is -errno (see Encrypt).
1261  // = 0 Signature matches the value in inbuff.
1262  // > 0 Failed to verify, signature does not match inbuff data.
1263  //
1264  EPNAME("Verify");
1265 
1266  // We must have a PKI and a digest
1267  if (!sessionKver || !sessionMD)
1268  return -ENOENT;
1269 
1270  // And something to verify
1271  if (!inbuf || inlen <= 0 || !sigbuf || siglen <= 0)
1272  return -EINVAL;
1273 
1274  // Reset digest
1275  sessionMD->Reset(0);
1276 
1277  // Calculate digest
1278  sessionMD->Update(inbuf, inlen);
1279  sessionMD->Final();
1280 
1281  // Output length
1282  int lmax = sessionKver->GetOutlen(siglen);
1283  char *buf = new char[lmax];
1284  if (!buf)
1285  return -ENOMEM;
1286 
1287  // Decrypt signature
1288  int len = sessionKver->DecryptPublic(sigbuf, siglen, buf, lmax);
1289  if (len <= 0) {
1290  delete[] buf;
1291  return -EINVAL;
1292  }
1293 
1294  // Verify signature
1295  bool bad = 1;
1296  if (len == sessionMD->Length()) {
1297  if (!strncmp(buf, sessionMD->Buffer(), len)) {
1298  // Signature matches
1299  bad = 0;
1300  DEBUG("signature successfully verified");
1301  }
1302  }
1303 
1304  // Cleanup
1305  if (buf) delete[] buf;
1306 
1307  // We are done
1308  return ((bad) ? 1 : 0);
1309 }
1310 
1311 //_____________________________________________________________________________
1312 int XrdSecProtocolgsi::getKey(char *kbuf, int klen)
1313 {
1314  // Get the current encryption key
1315  //
1316  // Returns: < 0 Failed, returned value if -errno (see Encrypt)
1317  // >= 0 The size of the encyption key. The supplied buffer of length
1318  // size hold the key. If the buffer address is 0, only the
1319  // size of the key is returned.
1320  //
1321  EPNAME("getKey");
1322 
1323  // Check if we have to serialize the key
1324  if (!bucketKey) {
1325 
1326  // We must have a key for that
1327  if (!sessionKey)
1328  // Invalid call
1329  return -ENOENT;
1330  // Create bucket
1331  bucketKey = sessionKey->AsBucket();
1332  }
1333 
1334  // Prepare output now, if we have any
1335  if (bucketKey) {
1336  // If are asked only the size, we are done
1337  if (kbuf == 0)
1338  return bucketKey->size;
1339 
1340  // Check the size of the buffer
1341  if (klen < bucketKey->size)
1342  // Too small
1343  return -EOVERFLOW;
1344 
1345  // Copy the buffer
1346  memcpy(kbuf, bucketKey->buffer, bucketKey->size);
1347 
1348  // We are done
1349  DEBUG("session key exported");
1350  return bucketKey->size;
1351  }
1352 
1353  // Key exists but we could export it in bucket format
1354  return -ENOMEM;
1355 }
1356 
1357 //_____________________________________________________________________________
1358 int XrdSecProtocolgsi::setKey(char *kbuf, int klen)
1359 {
1360  // Set the current encryption key
1361  //
1362  // Returns: < 0 Failed, returned value if -errno (see Encrypt)
1363  // 0 The new key has been set.
1364  //
1365  EPNAME("setKey");
1366 
1367  // Make sur that we can initialize the new key
1368  if (!kbuf || klen <= 0)
1369  // Invalid inputs
1370  return -EINVAL;
1371 
1372  if (!sessionCF)
1373  // Invalid context
1374  return -ENOENT;
1375 
1376  // Put the buffer key into a bucket
1377  XrdSutBucket *bck = new XrdSutBucket();
1378  if (!bck)
1379  // Cannot get buffer: out-of-resources?
1380  return -ENOMEM;
1381  // Set key buffer
1382  bck->SetBuf(kbuf, klen);
1383 
1384  // Init a new cipher from the bucket
1385  XrdCryptoCipher *newKey = sessionCF->Cipher(bck);
1386  if (!newKey) {
1387  SafeDelete(bck);
1388  return -ENOMEM;
1389  }
1390 
1391  // Delete current key
1392  SafeDelete(sessionKey);
1393 
1394  // Set the new key
1395  sessionKey = newKey;
1396 
1397  // Cleanup
1398  SafeDelete(bck);
1399 
1400  // Ok
1401  DEBUG("session key update");
1402  return 0;
1403 }
1404 
1405 /******************************************************************************/
1406 /* C l i e n t O r i e n t e d F u n c t i o n s */
1407 /******************************************************************************/
1408 /******************************************************************************/
1409 /* g e t C r e d e n t i a l s */
1410 /******************************************************************************/
1411 
1413  XrdOucErrInfo *ei)
1414 {
1415  // Query client for the password; remote username and host
1416  // are specified in 'parm'. File '.rootnetrc' is checked.
1417  EPNAME("getCredentials");
1418 
1419  // If we are a server the only reason to be here is to get the forwarded
1420  // or saved client credentials
1421  if (srvMode) {
1422  XrdSecCredentials *creds = 0;
1423  if (proxyChain) {
1424  // Export the proxy chain into a bucket
1425  XrdCryptoX509ExportChain_t ExportChain = sessionCF->X509ExportChain();
1426  if (ExportChain) {
1427  XrdSutBucket *bck = (*ExportChain)(proxyChain, 1);
1428  if (bck) {
1429  // We need to duplicate it because XrdSecCredentials uses
1430  // {malloc, free} instead of {new, delete}
1431  char *nbuf = (char *) malloc(bck->size);
1432  if (nbuf) {
1433  memcpy(nbuf, bck->buffer, bck->size);
1434  // Import the buffer in a XrdSecCredentials object
1435  creds = new XrdSecCredentials(nbuf, bck->size);
1436  }
1437  delete bck;
1438  }
1439  }
1440  }
1441  return creds;
1442  }
1443 
1444  // Handshake vars container must be initialized at this point
1445  if (!hs)
1446  return ErrC(ei,0,0,0,kGSErrError,
1447  "handshake var container missing","getCredentials");
1448  //
1449  // Nothing to do if buffer is empty
1450  if ((!parm && !hs->Parms) || (parm && (!(parm->buffer) || parm->size <= 0))) {
1451  if (hs->Iter == 0)
1452  return ErrC(ei,0,0,0,kGSErrNoBuffer,"missing parameters","getCredentials");
1453  else
1454  return (XrdSecCredentials *)0;
1455  }
1456 
1457  // We support passing the user {proxy, cert, key} paths via Url parameter
1458  char *upp = (ei && ei->getEnv()) ? ei->getEnv()->Get("xrd.gsiusrpxy") : 0;
1459  if (upp) urlUsrProxy = upp;
1460  upp = (ei && ei->getEnv()) ? ei->getEnv()->Get("xrd.gsiusrcrt") : 0;
1461  if (upp) urlUsrCert = upp;
1462  upp = (ei && ei->getEnv()) ? ei->getEnv()->Get("xrd.gsiusrkey") : 0;
1463  if (upp) urlUsrKey = upp;
1464 
1465  // Count interations
1466  (hs->Iter)++;
1467 
1468  // Update time stamp
1469  hs->TimeStamp = time(0);
1470 
1471  // Local vars
1472  int step = 0;
1473  int nextstep = 0;
1474  const char *stepstr = 0;
1475  char *bpub = 0;
1476  int lpub = 0;
1477  String CryptoMod = "";
1478  String Host = "";
1479  String RemID = "";
1480  String Emsg;
1481  String specID = "";
1482  String issuerHash = "";
1483  // Buffer / Bucket related
1484  XrdSutBuffer *bpar = 0; // Global buffer
1485  XrdSutBuffer *bmai = 0; // Main buffer
1486  XrdSutBucket *bck = 0; // Generic bucket
1487 
1488  //
1489  // Decode received buffer
1490  bpar = hs->Parms;
1491  if (!bpar && !(bpar = new XrdSutBuffer((const char *)parm->buffer,parm->size)))
1492  return ErrC(ei,0,0,0,kGSErrDecodeBuffer,"global",stepstr);
1493  // Ownership has been transferred
1494  hs->Parms = 0;
1495  //
1496  // Check protocol ID name
1497  if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
1498  return ErrC(ei,bpar,bmai,0,kGSErrBadProtocol,stepstr);
1499  //
1500  // The step indicates what we are supposed to do
1501  if (!(step = bpar->GetStep())) {
1502  // The first, fake, step
1503  step = kXGS_init;
1504  bpar->SetStep(step);
1505  }
1506  stepstr = ServerStepStr(step);
1507  // Dump, if requested
1508  XrdOucString bmsg;
1509  if (QTRACE(Dump)) {
1510  bmsg.form("IN: bpar: %s", stepstr);
1511  bpar->Dump(bmsg.c_str());
1512  }
1513  //
1514  // Parse input buffer
1515  if (ParseClientInput(bpar, &bmai, Emsg) == -1) {
1516  DEBUG(Emsg<<" CF: "<<sessionCF);
1517  return ErrC(ei,bpar,bmai,0,kGSErrParseBuffer,Emsg.c_str(),stepstr);
1518  }
1519  // Dump, if requested
1520  if (QTRACE(Dump)) {
1521  if (bmai) {
1522  bmsg.form("IN: bmai: %s", stepstr);
1523  bmai->Dump(bmsg.c_str());
1524  }
1525  }
1526  //
1527  // Version
1528  DEBUG("version run by server: "<< hs->RemVers);
1529  //
1530  // Check random challenge
1531  if (!CheckRtag(bmai, Emsg))
1532  return ErrC(ei,bpar,bmai,0,kGSErrBadRndmTag,Emsg.c_str(),stepstr);
1533  //
1534  // Login name if any
1535  String user(Entity.name);
1536  if (user.length() <= 0) user = getenv("XrdSecUSER");
1537  //
1538  // Now action depens on the step
1539  nextstep = kXGC_none;
1540 
1541  XrdCryptoX509 *c = 0;
1542 
1543  switch (step) {
1544 
1545  case kXGS_init:
1546  //
1547  // Add bucket with cryptomod to the global list
1548  // (This must be always visible from now on)
1549  CryptoMod = hs->CryptoMod;
1550  if (hs->RemVers >= XrdSecgsiVersDHsigned && !(hs->HasPad)) CryptoMod += gNoPadTag;
1551  if (bpar->AddBucket(CryptoMod,kXRS_cryptomod) != 0)
1552  return ErrC(ei,bpar,bmai,0,
1554  //
1555  // Add bucket with our version to the main list
1556  if (bpar->MarshalBucket(kXRS_version,(kXR_int32)(Version)) != 0)
1557  return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
1558  XrdSutBuckStr(kXRS_version),"global",stepstr);
1559  //
1560  // Add our issuer hash
1561  c = hs->PxyChain->Begin();
1562  if (c->type == XrdCryptoX509::kCA) {
1563  issuerHash = c->SubjectHash();
1564  if (HashCompatibility && c->SubjectHash(1)) {
1565  issuerHash += "|"; issuerHash += c->SubjectHash(1); }
1566  } else {
1567  issuerHash = c->IssuerHash();
1568  if (HashCompatibility && c->IssuerHash(1)
1569  && strcmp(c->IssuerHash(1),c->IssuerHash())) {
1570  issuerHash += "|"; issuerHash += c->IssuerHash(1); }
1571  }
1572  while ((c = hs->PxyChain->Next()) != 0) {
1573  if (c->type != XrdCryptoX509::kCA)
1574  break;
1575  issuerHash = c->SubjectHash();
1576  if (HashCompatibility && c->SubjectHash(1)
1577  && strcmp(c->IssuerHash(1),c->IssuerHash())) {
1578  issuerHash += "|"; issuerHash += c->SubjectHash(1); }
1579  }
1580 
1581  DEBUG("Client issuer hash: " << issuerHash);
1582  if (bpar->AddBucket(issuerHash,kXRS_issuer_hash) != 0)
1583  return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
1584  XrdSutBuckStr(kXRS_issuer_hash),stepstr);
1585  //
1586  // Add bucket with our delegate proxy options
1587  if (hs->RemVers >= 10100) {
1588  if (bpar->MarshalBucket(kXRS_clnt_opts,(kXR_int32)(hs->Options)) != 0)
1589  return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
1590  XrdSutBuckStr(kXRS_clnt_opts),"global",stepstr);
1591  }
1592 
1593  //
1594  nextstep = kXGC_certreq;
1595  break;
1596 
1597  case kXGS_cert:
1598  //
1599  // We must have a session cipher at this point
1600  if (!(sessionKey))
1601  return ErrC(ei,bpar,bmai,0,
1602  kGSErrNoCipher,"session cipher",stepstr);
1603 
1604  //
1605  // Extract buffer with public info for the cipher agreement
1606  if (!(bpub = sessionKey->Public(lpub)))
1607  return ErrC(ei,bpar,bmai,0,
1608  kGSErrNoPublic,"session",stepstr);
1609 
1610  //
1611  // If server supports decoding of signed DH, do sign them
1612  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
1613  bck = new XrdSutBucket(bpub,lpub,kXRS_cipher);
1614  if (sessionKsig) {
1615  // Encrypt client DH public parameters with client private key
1616  if (sessionKsig->EncryptPrivate(*bck) <= 0)
1617  return ErrC(ei,bpar,bmai,0, kGSErrExportPuK,
1618  "encrypting client DH public parameters",stepstr);
1619  } else {
1620  return ErrC(ei,bpar,bmai,0, kGSErrExportPuK,
1621  "client signing key undefined!",stepstr);
1622  }
1623  //
1624  // Add it to the global list
1625  if (bpar->AddBucket(bck) != 0)
1626  return ErrC(ei,bpar,bmai,0, kGSErrAddBucket, "main",stepstr);
1627  //
1628  // Export client public key
1629  XrdOucString cpub;
1630  if (sessionKsig->ExportPublic(cpub) < 0)
1631  return ErrC(ei,bpar,bmai,0, kGSErrExportPuK,
1632  "exporting client public key",stepstr);
1633  // Add it to the global list
1634  if (bpar->UpdateBucket(cpub.c_str(),cpub.length(),kXRS_puk) != 0)
1635  return ErrC(ei,bpar,bmai,0, kGSErrAddBucket,
1636  XrdSutBuckStr(kXRS_puk),"global",stepstr);
1637  } else {
1638  //
1639  // Add it to the global list
1640  if (bpar->UpdateBucket(bpub,lpub,kXRS_puk) != 0)
1641  return ErrC(ei,bpar,bmai,0, kGSErrAddBucket,
1642  XrdSutBuckStr(kXRS_puk),"global",stepstr);
1643  delete[] bpub; // bpub is being duplicated inside of 'UpdateBucket'
1644  }
1645 
1646  //
1647  // Add the proxy certificate
1648  bmai->AddBucket(hs->Cbck);
1649  //
1650  // Add login name if any, needed while chosing where to export the proxies
1651  if (user.length() > 0) {
1652  if (bmai->AddBucket(user, kXRS_user) != 0)
1653  return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
1654  XrdSutBuckStr(kXRS_user),stepstr);
1655  }
1656  //
1657  nextstep = kXGC_cert;
1658  break;
1659 
1660  case kXGS_pxyreq:
1661  //
1662  // If something went wrong, send explanation
1663  if (Emsg.length() > 0) {
1664  if (bmai->AddBucket(Emsg,kXRS_message) != 0)
1665  return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
1666  XrdSutBuckStr(kXRS_message),stepstr);
1667  }
1668  //
1669  // Add login name if any, needed while chosing where to export the proxies
1670  if (user.length() > 0) {
1671  if (bmai->AddBucket(user, kXRS_user) != 0)
1672  return ErrC(ei,bpar,bmai,0, kGSErrCreateBucket,
1673  XrdSutBuckStr(kXRS_user),stepstr);
1674  }
1675  //
1676  // The relevant buckets should already be in the buffers
1677  nextstep = kXGC_sigpxy;
1678  break;
1679 
1680  default:
1681  return ErrC(ei,bpar,bmai,0, kGSErrBadOpt,stepstr);
1682  }
1683 
1684  //
1685  // Serialize and encrypt
1686  if (AddSerialized('c', nextstep, hs->ID,
1687  bpar, bmai, kXRS_main, sessionKey) != 0) {
1688  return ErrC(ei,bpar,bmai,0,
1689  kGSErrSerialBuffer,"main",stepstr);
1690  }
1691  //
1692  // Serialize the global buffer
1693  char *bser = 0;
1694  int nser = bpar->Serialized(&bser,'f');
1695 
1696  if (QTRACE(Authen)) {
1697  bmsg.form("OUT: bpar: %s", ClientStepStr(bpar->GetStep()));
1698  bpar->Dump(bmsg.c_str());
1699  bmsg.form("OUT: bmai: %s", ClientStepStr(bpar->GetStep()));
1700  bmai->Dump(bmsg.c_str());
1701  }
1702  //
1703  // We may release the buffers now
1704  REL2(bpar,bmai);
1705  //
1706  // Return serialized buffer
1707  if (nser > 0) {
1708  DEBUG("returned " << nser <<" bytes of credentials");
1709  return new XrdSecCredentials(bser, nser);
1710  } else {
1711  NOTIFY("problems with final serialization");
1712  return (XrdSecCredentials *)0;
1713  }
1714 }
1715 
1716 /******************************************************************************/
1717 /* S e r v e r O r i e n t e d M e t h o d s */
1718 /******************************************************************************/
1719 
1720 //_____________________________________________________________________________
1721 static bool AuthzFunCheck(XrdSutCacheEntry *e, void *a) {
1722 
1723  int st_ref = (*((XrdSutCacheArg_t *)a)).arg1;
1724  time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg2;
1725  long to_ref = (*((XrdSutCacheArg_t *)a)).arg3;
1726  int st_exp = (*((XrdSutCacheArg_t *)a)).arg4;
1727 
1728  if (e && (e->status == st_ref)) {
1729  // Check expiration, if required
1730  bool expired = 0;
1731  if (to_ref > 0 && (ts_ref - e->mtime) > to_ref) expired = 1;
1732  int notafter = *((int *) e->buf2.buf);
1733  if (to_ref > notafter) expired = 1;
1734 
1735  if (expired) {
1736  // Invalidate the entry, if the case
1737  e->status = st_exp;
1738  } else {
1739  return true;
1740  }
1741  }
1742  return false;
1743 }
1744 
1745 /******************************************************************************/
1746 /* A u t h e n t i c a t e */
1747 /******************************************************************************/
1748 
1750  XrdSecParameters **parms,
1751  XrdOucErrInfo *ei)
1752 {
1753  //
1754  // Check if we have any credentials or if no credentials really needed.
1755  // In either case, use host name as client name
1756  EPNAME("Authenticate");
1757 
1758  //
1759  // If cred buffer is two small or empty assume host protocol
1760  if (cred->size <= (int)XrdSecPROTOIDLEN || !cred->buffer) {
1761  strncpy(Entity.prot, "host", sizeof(Entity.prot));
1762  return 0;
1763  }
1764 
1765  // Handshake vars conatiner must be initialized at this point
1766  if (!hs)
1767  return ErrS(Entity.tident,ei,0,0,0,kGSErrError,
1768  "handshake var container missing",
1769  "protocol initialization problems");
1770 
1771  // Update time stamp
1772  hs->TimeStamp = time(0);
1773 
1774  //
1775  // ID of this handshaking
1776  if (hs->ID.length() <= 0)
1777  hs->ID = Entity.tident;
1778  DEBUG("handshaking ID: " << hs->ID);
1779 
1780  // Local vars
1781  int kS_rc = kgST_more;
1782  int step = 0;
1783  int nextstep = 0;
1784  char *bpub = 0;
1785  int lpub = 0;
1786  bool vomsFailed = false;
1787  const char *stepstr = 0;
1788  String Message;
1789  String CryptList;
1790  String Ciphers;
1791  String Host;
1792  String SrvPuKExp;
1793  String Salt;
1794  String RndmTag;
1795  String ClntMsg(256);
1796  // Buffer related
1797  XrdSutBuffer *bpar = 0; // Global buffer
1798  XrdSutBuffer *bmai = 0; // Main buffer
1799  XrdSutBucket *bck = 0; // Generic bucket
1800  // Proxy export related
1801  XrdOucString spxy;
1802  XrdSutBucket *bpxy = 0;
1803 
1804  //
1805  // Decode received buffer
1806  if (!(bpar = new XrdSutBuffer((const char *)cred->buffer,cred->size)))
1807  return ErrS(hs->ID,ei,0,0,0,kGSErrDecodeBuffer,"global",stepstr);
1808  //
1809  // Check protocol ID name
1810  if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
1811  return ErrS(hs->ID,ei,bpar,bmai,0,kGSErrBadProtocol,stepstr);
1812  //
1813  // The step indicates what we are supposed to do
1814  step = bpar->GetStep();
1815  stepstr = ClientStepStr(step);
1816  // Dump, if requested
1817  XrdOucString bmsg;
1818  if (QTRACE(Dump)) {
1819  bmsg.form("IN: bpar: %s", stepstr);
1820  bpar->Dump(bmsg.c_str());
1821  }
1822  //
1823  // Parse input buffer
1824  if (ParseServerInput(bpar, &bmai, ClntMsg) == -1) {
1825  DEBUG(ClntMsg);
1826  return ErrS(hs->ID,ei,bpar,bmai,0,kGSErrParseBuffer,ClntMsg.c_str(),stepstr);
1827  }
1828  //
1829  // Version
1830  DEBUG("version run by client: "<< hs->RemVers);
1831  DEBUG("options req by client: "<< hs->Options);
1832  //
1833  // Dump, if requested
1834  if (QTRACE(Dump)) {
1835  if (bmai) {
1836  bmsg.form("IN: bmai: %s", stepstr);
1837  bmai->Dump(bmsg.c_str());
1838  }
1839  }
1840  //
1841  // Check random challenge
1842  if (!CheckRtag(bmai, ClntMsg))
1843  return ErrS(hs->ID,ei,bpar,bmai,0,kGSErrBadRndmTag,stepstr,ClntMsg.c_str());
1844 
1845  // Extract the VOMS attrbutes, if required
1846  XrdCryptoX509ExportChain_t X509ExportChain = (sessionCF) ? sessionCF->X509ExportChain() : 0;
1847  if (!X509ExportChain) {
1848  // Error
1849  return ErrS(hs->ID,ei,0,0,0,kGSErrError,
1850  "crypto factory function for chain export not found");
1851  }
1852 
1853  //
1854  // Now action depens on the step
1855  switch (step) {
1856 
1857  case kXGC_certreq:
1858  //
1859  // Client required us to send our certificate and cipher DH public parameters:
1860  // add first this last one.
1861  // Extract buffer with public info for the cipher agreement
1862  if (!(bpub = hs->Rcip->Public(lpub)))
1863  return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrNoPublic,
1864  "session",stepstr);
1865 
1866  // If client supports decoding of signed DH, do sign them
1867  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
1868  bck = new XrdSutBucket(bpub,lpub,kXRS_cipher);
1869  if (sessionKsig) {
1870  //
1871  // Encrypt server DH public parameters with server key
1872  if (sessionKsig->EncryptPrivate(*bck) <= 0)
1873  return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrExportPuK,
1874  "encrypting server DH public parameters",stepstr);
1875  } else {
1876  return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrExportPuK,
1877  "server signing key undefined!",stepstr);
1878  }
1879  } else {
1880  // Previous naming
1881  bck = new XrdSutBucket(bpub,lpub,kXRS_puk);
1882  }
1883 
1884  //
1885  // Add it to the global list
1886  if (bpar->AddBucket(bck) != 0)
1887  return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrAddBucket,
1888  "main",stepstr);
1889 
1890  //
1891  // Add bucket with list of supported ciphers
1892  if (bpar->AddBucket(DefCipher,kXRS_cipher_alg) != 0)
1893  return ErrS(hs->ID,ei,bpar,bmai,0,
1895  //
1896  // Add bucket with list of supported MDs
1897  if (bpar->AddBucket(DefMD,kXRS_md_alg) != 0)
1898  return ErrS(hs->ID,ei,bpar,bmai,0,
1900  //
1901  // Add the server certificate
1902  bpar->AddBucket(hs->Cbck);
1903 
1904  // We are done for the moment
1905  nextstep = kXGS_cert;
1906  break;
1907 
1908  case kXGC_cert:
1909  //
1910  // Client sent its own credentials: their are checked in
1911  // ParseServerInput, so if we are here they are OK
1912  kS_rc = kgST_ok;
1913  nextstep = kXGS_none;
1914 
1915  if (GMAPOpt > 0) {
1916  // Get name from gridmap
1917  String name;
1918  QueryGMAP(hs->Chain, hs->TimeStamp, name);
1919  DEBUG("username(s) associated with this DN: "<<name);
1920  if (name.length() <= 0) {
1921  // Grid map lookup failure
1922  if (GMAPOpt == 2) {
1923  // It was required, so we fail
1924  kS_rc = kgST_error;
1925  PRINT("ERROR: user mapping required, but lookup failed - failure");
1926  break;
1927  } else {
1928  NOTIFY("WARNING: user mapping lookup failed - use DN or DN-hash as name");
1929  }
1930  } else {
1931  //
1932  // Extract user login name, if any
1933  XrdSutBucket *bck = 0;
1934  String user;
1935  if ((bck = bmai->GetBucket(kXRS_user))) {
1936  bck->ToString(user);
1937  bmai->Deactivate(kXRS_user);
1938  }
1939  DEBUG("target user: "<<user);
1940  if (user.length() > 0) {
1941  // Check if the wanted username is authorized
1942  String u;
1943  int from = 0;
1944  bool ok = 0;
1945  while ((from = name.tokenize(u, from, ',')) != -1) {
1946  if (user == u) { ok = 1; break; }
1947  }
1948  if (ok) {
1949  name = u;
1950  DEBUG("DN mapping: requested user is authorized: name is '"<<name<<"'");
1951  } else {
1952  // The requested username is not in the list; we warn and default to the first
1953  // found (to be Globus compliant)
1954  if (name.find(',') != STR_NPOS) name.erase(name.find(','));
1955  PRINT("WARNING: user mapping lookup ok, but the requested user is not"
1956  " authorized ("<<user<<"). Instead, mapped as " << name << ".");
1957  }
1958  } else {
1959  // No username requested: we default to the first found (to be Globus compliant)
1960  if (name.find(',') != STR_NPOS) name.erase(name.find(','));
1961  DEBUG("user mapping lookup successful: name is '"<<name<<"'");
1962  }
1963  Entity.name = strdup(name.c_str());
1964  Entity.eaAPI->Add("gridmap.name", "1", true);
1965  }
1966  }
1967  // If not set, use DN
1968  if (!Entity.name || (strlen(Entity.name) <= 0)) {
1969  // No grid map: set the hash of the client DN as name
1970  if (!GMAPuseDNname && hs->Chain->EEChash()) {
1971  Entity.name = strdup(hs->Chain->EEChash());
1972  } else if (GMAPuseDNname && hs->Chain->EECname()) {
1973  Entity.name = strdup(hs->Chain->EECname());
1974  } else {
1975  PRINT("WARNING: DN missing: corruption? ");
1976  }
1977  }
1978 
1979  // Add the DN as default moninfo if requested (the authz plugin may change this)
1980  if (MonInfoOpt > 0 || ShowDN) {
1981  const char *theDN = hs->Chain->EECname();
1982  if (theDN) {
1983  if (ShowDN && !GMAPuseDNname) {
1984  PRINT(Entity.name<<" Subject DN='"<<theDN<<"'");
1985  }
1986  if (MonInfoOpt > 0) Entity.moninfo = strdup(theDN);
1987  }
1988  }
1989 
1990  if (VOMSAttrOpt > vatIgnore && VOMSFun) {
1991  // Fill the information needed by the external function
1992  if (VOMSCertFmt == 1) {
1993  // PEM base64
1994  bpxy = (*X509ExportChain)(hs->Chain, true);
1995  bpxy->ToString(spxy);
1996  delete bpxy;
1997  Entity.creds = strdup(spxy.c_str());
1998  Entity.credslen = spxy.length();
1999  } else {
2000  // Raw (opaque) format, to be used with XrdCrypto
2001  Entity.creds = (char *) hs->Chain;
2002  Entity.credslen = 0;
2003  }
2004  if ((*VOMSFun)(Entity) != 0) {
2005  vomsFailed = true;
2006  if (VOMSAttrOpt == vatRequire) {
2007  // Error
2008  kS_rc = kgST_error;
2009  PRINT("ERROR: the VOMS extraction plug-in reported "
2010  "authentication failure");
2011  break;
2012  }
2013  }
2014  NOTIFY("VOMS: Entity.vorg: "<< (Entity.vorg ? Entity.vorg : "<none>"));
2015  NOTIFY("VOMS: Entity.grps: "<< (Entity.grps ? Entity.grps : "<none>"));
2016  NOTIFY("VOMS: Entity.role: "<< (Entity.role ? Entity.role : "<none>"));
2017  NOTIFY("VOMS: Entity.endorsements: "<< (Entity.endorsements ? Entity.endorsements : "<none>"));
2018  }
2019 
2020  // Here prepare/extract the information for authorization
2021  spxy = "";
2022  bpxy = 0;
2023  if (AuthzFun && AuthzKey && (AuthzAlways || vomsFailed)) {
2024  // Fill the information needed by the external function
2025  if (AuthzCertFmt == 1) {
2026  // May have been already done
2027  if (!Entity.creds || (Entity.creds && Entity.credslen == 0)) {
2028  // PEM base64
2029  bpxy = (*X509ExportChain)(hs->Chain, true);
2030  bpxy->ToString(spxy);
2031  Entity.creds = strdup(spxy.c_str());
2032  Entity.credslen = spxy.length();
2033  // If not empty Entity.creds is a pointer to hs->Chain and
2034  // we need not to free it
2035  }
2036  } else {
2037  // May have been already done
2038  if (Entity.creds && Entity.credslen > 0) {
2039  // Entity.creds is in PEM form, we need to free it
2040  free(Entity.creds);
2041  // Raw (opaque) format, to be used with XrdCrypto
2042  Entity.creds = (char *) hs->Chain;
2043  Entity.credslen = 0;
2044  }
2045  }
2046  // Get the key
2047  char *key = 0;
2048  int lkey = 0;
2049  if ((lkey = (*AuthzKey)(Entity, &key)) < 0) {
2050  // Fatal error
2051  kS_rc = kgST_error;
2052  PRINT("ERROR: unable to get the key associated to this user");
2053  break;
2054  }
2055  const char *dn = (const char *)key;
2056  time_t now = hs->TimeStamp;
2057  // We may have it in the cache
2058  XrdSutCERef ceref;
2059  bool rdlock = false;
2060  XrdSutCacheArg_t arg = {kCE_ok, now, AuthzCacheTimeOut, kCE_disabled};
2061  XrdSutCacheEntry *cent = cacheAuthzFun.Get(dn, rdlock, AuthzFunCheck, (void *) &arg);
2062  if (!cent) {
2063  // Fatal error
2064  kS_rc = kgST_error;
2065  PRINT("ERROR: unable to get cache entry for dn: "<<dn);
2066  break;
2067  }
2068  ceref.Set(&(cent->rwmtx));
2069  if (!rdlock) {
2070  if (cent->buf1.buf)
2071  FreeEntity((XrdSecEntity *) cent->buf1.buf);
2072  SafeDelete(cent->buf1.buf);
2073  SafeDelete(cent->buf2.buf);
2074  }
2075  if (cent->status != kCE_ok) {
2076  int authzrc = 0;
2077  if ((authzrc = (*AuthzFun)(Entity)) != 0) {
2078  // Error
2079  kS_rc = kgST_error;
2080  PRINT("ERROR: the authz plug-in reported failure");
2081  SafeDelete(key);
2082  ceref.UnLock();
2083  break;
2084  } else {
2085  cent->status = kCE_ok;
2086  // Save a copy of the relevant Entity fields
2087  XrdSecEntity *se = new XrdSecEntity();
2088  int slen = 0;
2089  CopyEntity(&Entity, se, &slen);
2090  FreeEntity((XrdSecEntity *) cent->buf1.buf);
2091  SafeDelete(cent->buf1.buf);
2092  cent->buf1.buf = (char *) se;
2093  cent->buf1.len = slen;
2094  // Proxy expiration time
2095  int notafter = hs->Chain->End() ? hs->Chain->End()->NotAfter() : -1;
2096  cent->buf2.buf = (char *) new int(notafter);
2097  cent->buf2.len = sizeof(int);
2098  // Fill up the rest
2099  cent->cnt = 0;
2100  cent->mtime = now; // creation time
2101  // Notify
2102  DEBUG("Saved Entity to cacheAuthzFun ("<<slen<<" bytes)");
2103  }
2104  } else {
2105  // Fetch a copy of the saved entity
2106  int slen = 0;
2107  FreeEntity(&Entity);
2108  CopyEntity((XrdSecEntity *) cent->buf1.buf, &Entity, &slen);
2109  // Notify
2110  DEBUG("Got Entity from cacheAuthzFun ("<<slen<<" bytes)");
2111  }
2112  // Release lock
2113  ceref.UnLock();
2114  // Cleanup
2115  SafeDelArray(key);
2116  }
2117 
2118  // Export proxy for authorization, if required
2119  if (AuthzPxyWhat >= azFull) {
2120  if (bpxy && AuthzPxyWhat == azLast) {
2121  SafeDelete(bpxy); spxy = "";
2123  Entity.credslen = 0;
2124  }
2125  if (!bpxy) {
2126  if (AuthzPxyWhat == 1 && hs->Chain->End()) {
2127  bpxy = hs->Chain->End()->Export();
2128  } else {
2129  bpxy = (*X509ExportChain)(hs->Chain, true);
2130  }
2131  bpxy->ToString(spxy);
2132  }
2133  if (AuthzPxyWhere == azCred) {
2134  Entity.creds = strdup(spxy.c_str());
2135  Entity.credslen = spxy.length();
2136  } else {
2137  // This should be deprecated
2138  Entity.endorsements = strdup(spxy.c_str());
2139  }
2140  delete bpxy;
2141  NOTIFY("Entity.endorsements: "<<(void *)Entity.endorsements);
2142  NOTIFY("Entity.creds: "<<(void *)Entity.creds);
2143  NOTIFY("Entity.credslen: "<<Entity.credslen);
2144 
2145  } else if (bpxy) {
2146  // Cleanup
2147  SafeDelete(bpxy); spxy = "";
2148  }
2149 
2150  if (hs->RemVers >= 10100) {
2151  if (hs->PxyChain) {
2152  // The client is going to send over info for delegation
2153  kS_rc = kgST_more;
2154  nextstep = kXGS_pxyreq;
2155  }
2156  }
2157 
2158  break;
2159 
2160  case kXGC_sigpxy:
2161  //
2162  // Nothing to do after this
2163  kS_rc = kgST_ok;
2164  nextstep = kXGS_none;
2165  //
2166  // If something went wrong, print explanation
2167  if (ClntMsg.length() > 0) {
2168  PRINT(ClntMsg);
2169  }
2170  break;
2171 
2172  default:
2173  return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrBadOpt, stepstr);
2174  }
2175 
2176  if (kS_rc == kgST_more) {
2177  //
2178  // Add message to client
2179  if (ClntMsg.length() > 0)
2180  if (bmai->AddBucket(ClntMsg,kXRS_message) != 0) {
2181  NOTIFY("problems adding bucket with message for client");
2182  }
2183  //
2184  // Serialize, encrypt and add to the global list
2185  if (AddSerialized('s', nextstep, hs->ID,
2186  bpar, bmai, kXRS_main, sessionKey) != 0) {
2187  return ErrS(hs->ID,ei,bpar,bmai,0, kGSErrSerialBuffer,
2188  "main / session cipher",stepstr);
2189  }
2190  //
2191  // Serialize the global buffer
2192  char *bser = 0;
2193  int nser = bpar->Serialized(&bser,'f');
2194  //
2195  // Dump, if requested
2196  if (QTRACE(Authen)) {
2197  bmsg.form("OUT: bpar: %s", ServerStepStr(bpar->GetStep()));
2198  bpar->Dump(bmsg.c_str());
2199  bmsg.form("OUT: bmai: %s", ServerStepStr(bpar->GetStep()));
2200  bmai->Dump(bmsg.c_str());
2201  }
2202  //
2203  // Create buffer for client
2204  *parms = new XrdSecParameters(bser,nser);
2205 
2206  } else {
2207  //
2208  // Cleanup handshake vars
2209  SafeDelete(hs);
2210  }
2211  //
2212  // We may release the buffers now
2213  REL2(bpar,bmai);
2214  //
2215  // All done
2216  return kS_rc;
2217 }
2218 
2219 /******************************************************************************/
2220 /* C o p y E n t i ty */
2221 /******************************************************************************/
2222 
2223 void XrdSecProtocolgsi::CopyEntity(XrdSecEntity *in, XrdSecEntity *out, int *lout)
2224 {
2225  // Copy relevant fields of 'in' into 'out'; return length of 'out'
2226 
2227  if (!in || !out) return;
2228 
2229  int slen = sizeof(XrdSecEntity);
2230  if (in->name) { out->name = strdup(in->name); slen += strlen(in->name); }
2231  if (in->host) { out->host = strdup(in->host); slen += strlen(in->host); }
2232  if (in->vorg) { out->vorg = strdup(in->vorg); slen += strlen(in->vorg); }
2233  if (in->role) { out->role = strdup(in->role); slen += strlen(in->role); }
2234  if (in->grps) { out->grps = strdup(in->grps); slen += strlen(in->grps); }
2235  if (in->creds && in->credslen > 0) {
2236  out->creds = strdup(in->creds); slen += in->credslen;
2237  out->credslen = in->credslen; }
2238  if (in->endorsements) { out->endorsements = strdup(in->endorsements);
2239  slen += strlen(in->endorsements); }
2240  if (in->moninfo) { out->moninfo = strdup(in->moninfo);
2241  slen += strlen(in->moninfo); }
2242 
2243  // Save length, if required
2244  if (lout) *lout = slen;
2245 
2246  // Done
2247  return;
2248 }
2249 
2250 /******************************************************************************/
2251 /* F r e e E n t i ty */
2252 /******************************************************************************/
2253 
2254 void XrdSecProtocolgsi::FreeEntity(XrdSecEntity *in)
2255 {
2256  // Free relevant fields of 'in';
2257 
2258  if (!in) return;
2259 
2260  if (in->name) SafeFree(in->name);
2261  if (in->host) SafeFree(in->host);
2262  if (in->vorg) SafeFree(in->vorg);
2263  if (in->role) SafeFree(in->role);
2264  if (in->grps) SafeFree(in->grps);
2265  if (in->creds && in->credslen > 0) { SafeFree(in->creds); in->credslen = 0; }
2266  if (in->endorsements) SafeFree(in->endorsements);
2267  if (in->moninfo) SafeFree(in->moninfo);
2268 
2269  // Done
2270  return;
2271 }
2272 
2273 /******************************************************************************/
2274 /* E n a b l e T r a c i n g */
2275 /******************************************************************************/
2276 
2278 {
2279  // Initiate error logging and tracing
2280 
2281  eDest.logger(&Logger);
2282  GSITrace = new XrdOucTrace(&eDest);
2283  return GSITrace;
2284 }
2285 
2286 /******************************************************************************/
2287 /* g s i O p t i o n s :: P r i n t */
2288 /******************************************************************************/
2289 
2291 {
2292  // Dump summary of GSI init options
2293 // EPNAME("InitOpts");
2294 
2295  // For clients print only if really required (for servers we notified it
2296  // always once for all)
2297  if ((mode == 'c') && debug <= 0) return;
2298 
2299  POPTS(t, " -------------------------------------------------------------------");
2300  POPTS(t, " Mode: "<< ((mode == 'c') ? "client" : "server"));
2301  POPTS(t, " Debug: "<< debug);
2302  POPTS(t, " CA dir: " << (certdir ? certdir : XrdSecProtocolgsi::CAdir));
2303  POPTS(t, " CA verification level: "<< getOptName(caVerOpts, ca));
2304  POPTS(t, " CRL dir: " << (crldir ? crldir : XrdSecProtocolgsi::CRLdir ));
2305  POPTS(t, " CRL extension: " << (crlext ? crlext : XrdSecProtocolgsi::DefCRLext));
2306  POPTS(t, " CRL check level: "<< getOptName(crlOpts,crl));
2307  if (crl > 0) POPTS(t, " CRL refresh time: "<< crlrefresh);
2308  if (mode == 'c') {
2309  POPTS(t, " Certificate: " << (cert ? cert : XrdSecProtocolgsi::UsrCert));
2310  POPTS(t, " Key: " << (key ? key : XrdSecProtocolgsi::UsrKey));
2311  POPTS(t, " Proxy file: " << XrdSecProtocolgsi::UsrProxy);
2312  POPTS(t, " Proxy validity: " << (valid ? valid : XrdSecProtocolgsi::PxyValid));
2313  POPTS(t, " Proxy dep length: " << deplen);
2314  POPTS(t, " Proxy bits: " << bits);
2315  POPTS(t, " Proxy sign option: "<< sigpxy);
2316  POPTS(t, " Proxy delegation option: "<< dlgpxy);
2317  if (createpxy) POPTS(t, " Pure Cert/Key authentication allowed");
2318  POPTS(t, " Allowed server names: "<< (srvnames ? srvnames : "[*/]<target host name>[/*]"));
2319  } else {
2320  POPTS(t, " Certificate: " << (cert ? cert : XrdSecProtocolgsi::SrvCert));
2321  POPTS(t, " Key: " << (key ? key : XrdSecProtocolgsi::SrvKey));
2322  POPTS(t, " Proxy delegation option: "<< getOptName(sDlgOpts,dlgpxy));
2323  if (exppxy)
2324  POPTS(t, " Template for exported proxy: "<< (exppxy ? exppxy : gUsrPxyDef));
2325  POPTS(t, " GRIDmap file: " << (gridmap ? gridmap : XrdSecProtocolgsi::GMAPFile));
2326  POPTS(t, " GRIDmap option: "<< getOptName(gmoOpts,ogmap));
2327  POPTS(t, " GRIDmap cache entries expiration (secs): "<< gmapto);
2328  if (gmapfun) {
2329  POPTS(t, " DN mapping function: " << gmapfun);
2330  if (gmapfunparms) POPTS(t, " DN mapping function parms: " << gmapfunparms);
2331  } else {
2332  if (gmapfunparms) POPTS(t, " DN mapping function parms: ignored (no mapping function defined)");
2333  }
2334  if (authzfun) {
2335  POPTS(t, " Authz function: " << authzfun);
2336  if (authzfunparms) POPTS(t, " Authz function parms: " << authzfunparms);
2337  POPTS(t, " Authz call: " <<getOptName(azCallOpts,authzcall));
2338  POPTS(t, " Authz cache entries expiration (secs): " << authzto);
2339  } else {
2340  if (authzfunparms) POPTS(t, " Authz function parms: ignored (no authz function defined)");
2341  }
2342  if (authzpxy)
2343  POPTS(t, " Client proxy availability in XrdSecEntity.endorsement: "<< getOptName(azPxyOpts,authzpxy));
2344  POPTS(t, " VOMS option: "<< getOptName(vomsatOpts,vomsat));
2345  if (vomsfun) {
2346  POPTS(t, " VOMS extraction function: " << vomsfun);
2347  if (vomsfunparms) POPTS(t, " VOMS extraction function parms: " << vomsfunparms);
2348  } else {
2349  if (vomsfunparms) POPTS(t, " VOMS extraction function parms: ignored (no VOMS extraction function defined)");
2350  }
2351  POPTS(t, " MonInfo option: "<< moninfo);
2352  if (!hashcomp)
2353  POPTS(t, " Name hashing algorithm compatibility OFF");
2354  POPTS(t, " Show DN option: "<<showDN);
2355  }
2356  // Crypto options
2357  POPTS(t, " Crypto modules: "<< (clist ? clist : XrdSecProtocolgsi::DefCrypto));
2358  POPTS(t, " Ciphers: "<< (cipher ? cipher : XrdSecProtocolgsi::DefCipher));
2359  POPTS(t, " MDigests: "<< (md ? md : XrdSecProtocolgsi::DefMD));
2360  if (trustdns) {
2361  POPTS(t, " Trusting DNS for hostname checking");
2362  } else {
2363  POPTS(t, " Untrusting DNS for hostname checking");
2364  }
2365  POPTS(t, " -------------------------------------------------------------------");
2366 }
2367 
2368 /******************************************************************************/
2369 /* X r d S e c P r o t o c o l g s i I n i t */
2370 /******************************************************************************/
2371 
2372 extern "C"
2373 {
2374 char *XrdSecProtocolgsiInit(const char mode,
2375  const char *parms, XrdOucErrInfo *erp)
2376 {
2377  // One-time protocol initialization, filling the static flags and options
2378  // of the protocol.
2379  // For clients (mode == 'c') we use values in envs.
2380  // For servers (mode == 's') the command line options are passed through
2381  // parms.
2382  EPNAME("ProtocolgsiInit");
2383 
2384  gsiOptions opts;
2385  char *rc = (char *)"";
2386  char *cenv = 0;
2387 
2388  // Initiate error logging and tracing
2390 
2391  //
2392  // Clients first
2393  if (mode == 'c') {
2394  //
2395  // Decode envs:
2396  // "XrdSecDEBUG" debug flag ("0","1","2","3")
2397  // "XrdSecGSICADIR" full path to an alternative path
2398  // containing the CA info
2399  // [/etc/grid-security/certificates]
2400  // "XrdSecGSICRLDIR" full path to an alternative path
2401  // containing the CRL info
2402  // [/etc/grid-security/certificates]
2403  // "XrdSecGSICRLEXT" default extension of CRL files [.r0]
2404  // "XrdSecGSIUSERCERT" full path to an alternative file
2405  // containing the user certificate
2406  // [$HOME/.globus/usercert.pem]
2407  // "XrdSecGSIUSERKEY" full path to an alternative file
2408  // containing the user key
2409  // [$HOME/.globus/userkey.pem]
2410  // "XrdSecGSIUSERPROXY" full path to an alternative file
2411  // containing the user proxy
2412  // [/tmp/x509up_u<uid>]
2413  // "XrdSecGSIPROXYVALID" validity of proxies in the
2414  // grid-proxy-init format
2415  // ["12:00", i.e. 12 hours]
2416  // "XrdSecGSIPROXYDEPLEN" depth of signature path for proxies;
2417  // use -1 for unlimited [0]
2418  // "XrdSecGSIPROXYKEYBITS" bits in PKI for proxies [default: XrdCryptoDefRSABits]
2419  // "XrdSecGSICACHECK" CA check level [1]:
2420  // 0 do not verify;
2421  // 1 verify if self-signed, warn if not;
2422  // 2 verify in all cases, fail if not possible
2423  // "XrdSecGSICRLCHECK" CRL check level [2]:
2424  // 0 don't care;
2425  // 1 use if available;
2426  // 2 require,
2427  // 3 require non-expired CRL
2428  // "XrdSecGSIDELEGPROXY" Forwarding of credentials option:
2429  // 0 deny; 1 sign request created
2430  // by server; 2 forward local proxy
2431  // (include private key) [1]
2432  // "XrdSecGSICREATEPROXY" Controls use of proxy [1]:
2433  // 1 auto-generate proxy from the cert/key pair if no one is not found
2434  // 0 a proxy is used if present; else, the cert/key pair is used if present.
2435  // "XrdSecGSISRVNAMES" Server names allowed: if the server CN
2436  // does not match any of these, or it is
2437  // explicitely denied by these, or it is
2438  // not in the form "*/<hostname>", the
2439  // handshake fails.
2440  // "XrdSecGSIUSEDEFAULTHASH" If this variable is set only the default
2441  // name hashing algorithm is used
2442 
2443  //
2444  opts.mode = mode;
2445  // debug
2446  cenv = getenv("XrdSecDEBUG");
2447  if (cenv)
2448  {if (cenv[0] >= 49 && cenv[0] <= 51) opts.debug = atoi(cenv);
2449  else {PRINT("unsupported debug value from env XrdSecDEBUG: "<<cenv<<" - setting to 1");
2450  opts.debug = 1;
2451  }
2452  }
2453 
2454  // directory with CA certificates
2455  cenv = (getenv("XrdSecGSICADIR") ? getenv("XrdSecGSICADIR")
2456  : getenv("X509_CERT_DIR"));
2457  if (cenv)
2458  opts.certdir = strdup(cenv);
2459 
2460  // directory with CRL info
2461  cenv = (getenv("XrdSecGSICRLDIR") ? getenv("XrdSecGSICRLDIR")
2462  : getenv("X509_CERT_DIR"));
2463  if (cenv)
2464  opts.crldir = strdup(cenv);
2465 
2466  // Default extension CRL files
2467  cenv = getenv("XrdSecGSICRLEXT");
2468  if (cenv)
2469  opts.crlext = strdup(cenv);
2470 
2471  // CRL refresh or expiration time
2472  cenv = getenv("XrdSecGSICRLRefresh");
2473  if (cenv)
2474  opts.crlrefresh = atoi(cenv);
2475 
2476  // file with user cert
2477  cenv = (getenv("XrdSecGSIUSERCERT") ? getenv("XrdSecGSIUSERCERT")
2478  : getenv("X509_USER_CERT"));
2479  if (cenv)
2480  opts.cert = strdup(cenv);
2481 
2482  // file with user key
2483  cenv = (getenv("XrdSecGSIUSERKEY") ? getenv("XrdSecGSIUSERKEY")
2484  : getenv("X509_USER_KEY"));
2485  if (cenv)
2486  opts.key = strdup(cenv);
2487 
2488  // file with user proxy
2489  cenv = (getenv("XrdSecGSIUSERPROXY") ? getenv("XrdSecGSIUSERPROXY")
2490  : getenv("X509_USER_PROXY"));
2491  if (cenv)
2492  opts.proxy = strdup(cenv);
2493 
2494  // file with user proxy
2495  cenv = getenv("XrdSecGSIPROXYVALID");
2496  if (cenv)
2497  opts.valid = strdup(cenv);
2498 
2499  // Depth of signature path for proxies
2500  cenv = getenv("XrdSecGSIPROXYDEPLEN");
2501  if (cenv)
2502  opts.deplen = atoi(cenv);
2503 
2504  // Key Bit length
2505  cenv = getenv("XrdSecGSIPROXYKEYBITS");
2506  if (cenv)
2507  opts.bits = atoi(cenv);
2508 
2509  // CA verification level
2510  cenv = getenv("XrdSecGSICACHECK");
2511  if (cenv)
2512  opts.ca = atoi(cenv);
2513 
2514  // CRL check level
2515  cenv = getenv("XrdSecGSICRLCHECK");
2516  if (cenv)
2517  opts.crl = atoi(cenv);
2518 
2519  // Delegate proxy
2520  cenv = getenv("XrdSecGSIDELEGPROXY");
2521  if (cenv)
2522  opts.dlgpxy = atoi(cenv);
2523 
2524  // No proxy
2525  cenv = getenv("XrdSecGSICREATEPROXY");
2526  if (cenv)
2527  opts.createpxy = atoi(cenv);
2528 
2529  // Allowed server name formats
2530  cenv = getenv("XrdSecGSISRVNAMES");
2531  if (cenv)
2532  opts.srvnames = strdup(cenv);
2533 
2534  // Name hashing algorithm
2535  cenv = getenv("XrdSecGSIUSEDEFAULTHASH");
2536  if (cenv)
2537  opts.hashcomp = 0;
2538 
2539  // DNS trusting control
2540  if ((cenv = getenv("XrdSecGSITRUSTDNS")))
2541  opts.trustdns = (!strcmp(cenv, "0")) ? false : true;
2542 
2543  //
2544  // Setup the object with the chosen options
2545  rc = XrdSecProtocolgsi::Init(opts,erp);
2546 
2547  // Notify init options, if required or in case of init errors
2548  if (!rc) opts.debug = 1;
2549  opts.Print(gsiTrace);
2550 
2551  // Some cleanup
2552  SafeFree(opts.certdir);
2553  SafeFree(opts.crldir);
2554  SafeFree(opts.crlext);
2555  SafeFree(opts.cert);
2556  SafeFree(opts.key);
2557  SafeFree(opts.proxy);
2558  SafeFree(opts.valid);
2559  SafeFree(opts.srvnames);
2560 
2561  // We are done
2562  return rc;
2563  }
2564 
2565  // Take into account xrootd debug flag
2566  cenv = getenv("XRDDEBUG");
2567  if (cenv && !strcmp(cenv,"1")) opts.debug = 1;
2568 
2569  //
2570  // Server initialization
2571  if (parms) {
2572  //
2573  // Duplicate the parms
2574  char parmbuff[1024];
2575  strlcpy(parmbuff, parms, sizeof(parmbuff));
2576  //
2577  // The tokenizer
2578  XrdOucTokenizer inParms(parmbuff);
2579  //
2580  // Decode parms:
2581  // for servers:
2582  // [-d:<debug_level>]
2583  // [-c:[-]ssl[:[-]<CryptoModuleName]]
2584  // [-certdir:<dir_with_CA_info>]
2585  // [-crldir:<dir_with_CRL_info>]
2586  // [-crlext:<default_extension_CRL_files>]
2587  // [-cert:<path_to_server_certificate>]
2588  // [-key:<path_to_server_key>]
2589  // [-cipher:<list_of_supported_ciphers>]
2590  // [-md:<list_of_supported_digests>]
2591  // [-ca:<crl_verification_level>]
2592  // [-crl:<crl_check_level>]
2593  // [-crlrefresh:<crl_refresh_time>]
2594  // [-gridmap:<grid_map_file>]
2595  // [-gmapfun:<grid_map_function>]
2596  // [-gmapfunparms:<grid_map_function_init_parameters>]
2597  // [-authzcall:<authz_callopt>]
2598  // [-authzfun:<authz_function>]
2599  // [-authzfunparms:<authz_function_init_parameters>]
2600  // [-authzto:<authz_cache_entry_validity_in_secs>]
2601  // [-gmapto:<grid_map_cache_entry_validity_in_secs>]
2602  // [-gmapopt:<grid_map_check_option>]
2603  // [-dlgpxy:<proxy_req_option>]
2604  // [-exppxy:<filetemplate>]
2605  // [-authzpxy]
2606  // [-vomsat:<voms_option>]
2607  // [-vomsfun:<voms_function>]
2608  // [-vomsfunparms:<voms_function_init_parameters>]
2609  // [-defaulthash]
2610  // [-trustdns:<0|1>]
2611  //
2612  int debug = -1;
2613  String clist = "";
2614  String certdir = "";
2615  String crldir = "";
2616  String crlext = "";
2617  String cert = "";
2618  String key = "";
2619  String cipher = "";
2620  String md = "";
2621  String gridmap = "";
2622  String gmapfun = "";
2623  String gmapfunparms = "";
2624  String authzfun = "";
2625  String authzfunparms = "";
2626  String vomsfun = "";
2627  String vomsfunparms = "";
2628  String exppxy = "";
2629  int ca = 1;
2630  int crl = 1;
2631  int crlrefresh = 86400;
2632  int ogmap = 1;
2633  int gmapto = 600;
2634  int authzto = -1;
2635  int authzcall = 1;
2636  int dlgpxy = dlgIgnore;
2637  int authzpxy = 0;
2638  int vomsat = vatIgnore; // Was 1 or extract
2639  int moninfo = 0;
2640  int hashcomp = 1;
2641  int trustdns = false;
2642  int showDN = false;
2643  char *op = 0;
2644  while (inParms.GetLine()) {
2645  while ((op = inParms.GetToken())) {
2646  if (!strncmp(op, "-d:",3)) {
2647  debug = atoi(op+3);
2648  } else if (!strncmp(op, "-c:",3)) {
2649  clist = (const char *)(op+3);
2650  } else if (!strncmp(op, "-certdir:",9)) {
2651  certdir = (const char *)(op+9);
2652  } else if (!strncmp(op, "-crldir:",8)) {
2653  crldir = (const char *)(op+8);
2654  } else if (!strncmp(op, "-crlext:",8)) {
2655  crlext = (const char *)(op+8);
2656  } else if (!strncmp(op, "-cert:",6)) {
2657  cert = (const char *)(op+6);
2658  } else if (!strncmp(op, "-key:",5)) {
2659  key = (const char *)(op+5);
2660  } else if (!strncmp(op, "-cipher:",8)) {
2661  cipher = (const char *)(op+8);
2662  } else if (!strncmp(op, "-md:",4)) {
2663  md = (const char *)(op+4);
2664  } else if (!strncmp(op, "-ca:",4)) {
2665  ca = getOptVal(caVerOpts, op+4);
2666  ca = atoi(op+4);
2667  } else if (!strncmp(op, "-crl:",5)) {
2668  crl = getOptVal(crlOpts, op+5);
2669  } else if (!strncmp(op, "-crlrefresh:",12)) {
2670  crlrefresh = atoi(op+12);
2671  } else if (!strncmp(op, "-gmapopt:",9)) {
2672  ogmap = getOptVal(gmoOpts, op+9);
2673  } else if (!strncmp(op, "-gridmap:",9)) {
2674  gridmap = (const char *)(op+9);
2675  } else if (!strncmp(op, "-gmapfun:",9)) {
2676  gmapfun = (const char *)(op+9);
2677  } else if (!strncmp(op, "-gmapfunparms:",14)) {
2678  gmapfunparms = (const char *)(op+14);
2679  } else if (!strncmp(op, "-authzcall:",11)) {
2680  authzcall = getOptVal(azCallOpts, op+11);
2681  } else if (!strncmp(op, "-authzfun:",10)) {
2682  authzfun = (const char *)(op+10);
2683  } else if (!strncmp(op, "-authzfunparms:",15)) {
2684  authzfunparms = (const char *)(op+15);
2685  } else if (!strncmp(op, "-authzto:",9)) {
2686  authzto = atoi(op+9);
2687  } else if (!strncmp(op, "-gmapto:",8)) {
2688  gmapto = atoi(op+8);
2689  } else if (!strncmp(op, "-dlgpxy:",8)) {
2690  opts.dlgpxy = getOptVal(sDlgOpts, op+8);
2691  } else if (!strncmp(op, "-exppxy:",8)) {
2692  exppxy = (const char *)(op+8);
2693  } else if (!strncmp(op, "-authzpxy:",10)) {
2694  opts.authzpxy = getOptVal(azPxyOpts, op+10);
2695  } else if (!strncmp(op, "-authzpxy",9)) {
2696  authzpxy = 11;
2697  } else if (!strncmp(op, "-vomsat:",8)) {
2698  vomsat = getOptVal(vomsatOpts, op+8);
2699  if (vomsat != vatIgnore && vomsfun.length() == 0)
2700  vomsfun = "default";
2701  } else if (!strncmp(op, "-vomsfun:",9)) {
2702  vomsfun = (const char *)(op+9);
2703  } else if (!strncmp(op, "-vomsfunparms:",14)) {
2704  vomsfunparms = (const char *)(op+14);
2705  } else if (!strcmp(op, "-moninfo")) {
2706  moninfo = 1;
2707  } else if (!strncmp(op, "-moninfo:",9)) {
2708  moninfo = atoi(op+9);
2709  } else if (!strcmp(op, "-defaulthash")) {
2710  hashcomp = 0;
2711  } else if (!strncmp(op, "-trustdns:",10)) {
2712  trustdns = getOptVal(tdnsOpts, op+10);
2713  } else if (!strncmp(op, "-showdn:",8)) {
2714  showDN = getOptVal(tdnsOpts, op+8);
2715  } else {
2716  PRINT("ignoring unknown switch: "<<op);
2717  }
2718  }
2719  }
2720 
2721  // If vomsfun is 'default' substitute the default plugin. The go on to
2722  // resolve conflicts between vomsfun and vomsat options. So, if vomsfun
2723  // was specified but vomsat is set to 'ignore' then we set vomsat to be
2724  // 'required'.
2725  //
2726  if (vomsfun.length() > 0)
2727  {if (vomsat == vatIgnore) vomsat = vatExtract;
2728  if (vomsfun == "default") vomsfun = LIB_XRDVOMS;
2729  } else authzcall = azAlways;
2730 
2731  //
2732  // Build the option object
2733  opts.debug = (debug > -1) ? debug : opts.debug;
2734  opts.mode = 's';
2735  opts.ca = ca;
2736  opts.crl = crl;
2737  opts.crlrefresh = crlrefresh;
2738  opts.ogmap = ogmap;
2739  opts.gmapto = gmapto;
2740  opts.authzcall = authzcall;
2741  opts.authzto = authzto;
2742  opts.dlgpxy = (dlgpxy >= dlgIgnore && dlgpxy <= dlgReqSign) ? dlgpxy : 0;
2743  opts.authzpxy = authzpxy;
2744  opts.vomsat = vomsat;
2745  opts.moninfo = moninfo;
2746  opts.hashcomp = hashcomp;
2747  opts.trustdns = (trustdns <= 0) ? false : true;
2748  opts.showDN = (showDN > 0) ? true : false;
2749  if (clist.length() > 0)
2750  opts.clist = (char *)clist.c_str();
2751  if (certdir.length() > 0)
2752  opts.certdir = (char *)certdir.c_str();
2753  if (crldir.length() > 0)
2754  opts.crldir = (char *)crldir.c_str();
2755  if (crlext.length() > 0)
2756  opts.crlext = (char *)crlext.c_str();
2757  if (cert.length() > 0)
2758  opts.cert = (char *)cert.c_str();
2759  if (key.length() > 0)
2760  opts.key = (char *)key.c_str();
2761  if (cipher.length() > 0)
2762  opts.cipher = (char *)cipher.c_str();
2763  if (md.length() > 0)
2764  opts.md = (char *)md.c_str();
2765  if (gridmap.length() > 0)
2766  opts.gridmap = (char *)gridmap.c_str();
2767  if (gmapfun.length() > 0)
2768  opts.gmapfun = (char *)gmapfun.c_str();
2769  if (gmapfunparms.length() > 0)
2770  opts.gmapfunparms = (char *)gmapfunparms.c_str();
2771  if (authzfun.length() > 0)
2772  opts.authzfun = (char *)authzfun.c_str();
2773  if (authzfunparms.length() > 0)
2774  opts.authzfunparms = (char *)authzfunparms.c_str();
2775  if (exppxy.length() > 0)
2776  opts.exppxy = (char *)exppxy.c_str();
2777  if (vomsfun.length() > 0)
2778  opts.vomsfun = (char *)vomsfun.c_str();
2779  if (vomsfunparms.length() > 0)
2780  opts.vomsfunparms = (char *)vomsfunparms.c_str();
2781 
2782  // Notify init options, if required
2783  opts.Print(gsiTrace);
2784 
2785  //
2786  // Setup the plug-in with the chosen options
2787  return XrdSecProtocolgsi::Init(opts,erp);
2788  }
2789 
2790  // Notify init options, if required
2791  opts.Print(gsiTrace);
2792  //
2793  // Setup the plug-in with the defaults
2794  return XrdSecProtocolgsi::Init(opts,erp);
2795 }}
2796 
2797 
2798 /******************************************************************************/
2799 /* X r d S e c P r o t o c o l g s i O b j e c t */
2800 /******************************************************************************/
2801 
2803 
2804 namespace
2805 {XrdVersionInfo *gsiVersion = &XrdVERSIONINFOVAR(XrdSecProtocolgsiObject);}
2806 
2807 extern "C"
2808 {
2810  const char *hostname,
2811  XrdNetAddrInfo &endPoint,
2812  const char *parms,
2813  XrdOucErrInfo *erp)
2814 {
2815  XrdSecProtocolgsi *prot;
2816  int options = XrdSecNOIPCHK;
2817 
2818  //
2819  // Get a new protocol object
2820  if (!(prot = new XrdSecProtocolgsi(options, hostname, endPoint, parms))) {
2821  const char *msg = "Secgsi: Insufficient memory for protocol.";
2822  if (erp)
2823  erp->setErrInfo(ENOMEM, msg);
2824  else
2825  std::cerr <<msg <<std::endl;
2826  return (XrdSecProtocol *)0;
2827  }
2828  //
2829  // We are done
2830  if (!erp)
2831  std::cerr << "protocol object instantiated" << std::endl;
2832  return prot;
2833 }}
2834 
2835 
2836 /******************************************************************************/
2837 /* P r i v a t e M e t h o d s */
2838 /******************************************************************************/
2839 
2840 //_________________________________________________________________________
2841 int XrdSecProtocolgsi::AddSerialized(char opt, kXR_int32 step, String ID,
2842  XrdSutBuffer *bls, XrdSutBuffer *buf,
2843  kXR_int32 type,
2844  XrdCryptoCipher *cip)
2845 {
2846  // Serialize buf, and add it encrypted to bls as bucket type
2847  // Cipher cip is used if defined; else PuK rsa .
2848  // If both are undefined the buffer is just serialized and added.
2849  EPNAME("AddSerialized");
2850 
2851  if (!bls || !buf || (opt != 0 && opt != 'c' && opt != 's')) {
2852  PRINT("invalid inputs ("
2853  <<bls<<","<<buf<<","<<opt<<")"
2854  <<" - type: "<<XrdSutBuckStr(type));
2855  return -1;
2856  }
2857 
2858  //
2859  // Add step to indicate the counterpart what we send
2860  if (step > 0) {
2861  bls->SetStep(step);
2862  buf->SetStep(step);
2863  hs->LastStep = step;
2864  }
2865 
2866  //
2867  // If a random tag has been sent and we have a session cipher,
2868  // we sign it
2869  XrdSutBucket *brt = buf->GetBucket(kXRS_rtag);
2870  if (brt && sessionKsig) {
2871  //
2872  // The signature has no digest and no padding of its own, so we must
2873  // never sign a value that the counter part chose. Accept only a well
2874  // formed random tag, whatever version the counter part claims to run
2875  if (!XrdSecgsiRtagIsValid(brt->buffer, brt->size)) {
2876  PRINT("malformed random tag ("<<brt->size<<" bytes): refuse to sign");
2877  return -1;
2878  }
2879  //
2880  // From XrdSecgsiVersRtagHash on we sign the context bound digest of
2881  // the tag. The digest is not a DigestInfo, so the signature cannot be
2882  // replayed against a PKCS#1 v1.5 verifier
2883  if (hs->RemVers >= XrdSecgsiVersRtagHash) {
2884  char rtd[kXRSrtagMDMax] = {0};
2885  int lrtd = XrdSecgsiRtagDigest(sessionCF, brt->buffer, brt->size,
2886  rtd, kXRSrtagMDMax);
2887  if (lrtd <= 0 || brt->SetBuf(rtd, lrtd) != 0) {
2888  PRINT("error hashing random tag");
2889  return -1;
2890  }
2891  }
2892  //
2893  // Encrypt random tag with session cipher
2894  if (sessionKsig->EncryptPrivate(*brt) <= 0) {
2895  PRINT("error encrypting random tag");
2896  return -1;
2897  }
2898  //
2899  // Update type
2900  brt->type = kXRS_signed_rtag;
2901  }
2902  //
2903  // Add an random challenge: if a next exchange is required this will
2904  // allow to prove authenticity of counter part
2905  //
2906  // Generate new random tag and create a bucket
2907  if (!(opt == 'c' && step == kXGC_sigpxy)) {
2908  String RndmTag;
2909  XrdSutRndm::GetRndmTag(RndmTag);
2910  //
2911  // Get bucket
2912  brt = 0;
2913  if (!(brt = new XrdSutBucket(RndmTag,kXRS_rtag))) {
2914  PRINT("error creating random tag bucket");
2915  return -1;
2916  }
2917  buf->AddBucket(brt);
2918  }
2919  //
2920  // Get cache entry
2921  if (!hs->Cref) {
2922  PRINT("cache entry not found: protocol error");
2923  return -1;
2924  }
2925  //
2926  // Add random tag to the cache and update timestamp
2927  hs->Cref->buf1.SetBuf(brt->buffer,brt->size);
2928  hs->Cref->mtime = (kXR_int32)hs->TimeStamp;
2929  //
2930  // Now serialize the buffer ...
2931  char *bser = 0;
2932  int nser = buf->Serialized(&bser);
2933  //
2934  // Update bucket with this content
2935  XrdSutBucket *bck = 0;;
2936  if (!(bck = bls->GetBucket(type))) {
2937  // or create new bucket, if not existing
2938  if (!(bck = new XrdSutBucket(bser,nser,type))) {
2939  PRINT("error creating bucket "
2940  <<" - type: "<<XrdSutBuckStr(type));
2941  return -1;
2942  }
2943  //
2944  // Add the bucket to the list
2945  bls->AddBucket(bck);
2946  } else {
2947  bck->Update(bser,nser);
2948  }
2949  //
2950  // Encrypted the bucket
2951  if (cip) {
2952  if (cip->Encrypt(*bck, useIV) == 0) {
2953  PRINT("error encrypting bucket - cipher "
2954  <<" - type: "<<XrdSutBuckStr(type));
2955  return -1;
2956  }
2957  }
2958  // We are done
2959  return 0;
2960 }
2961 
2962 //_________________________________________________________________________
2963 int XrdSecProtocolgsi::ParseClientInput(XrdSutBuffer *br, XrdSutBuffer **bm,
2964  String &cmsg)
2965 {
2966  // Parse received buffer b,
2967  // Result used to fill the handshake local variables
2968  EPNAME("ParseClientInput");
2969 
2970  // Space for pointer to main buffer must be already allocated
2971  if (!br || !bm) {
2972  PRINT("invalid inputs ("<<br<<","<<bm<<")");
2973  cmsg = "invalid inputs";
2974  return -1;
2975  }
2976 
2977  //
2978  // Get the step
2979  int step = br->GetStep();
2980 
2981  // Do the right action
2982  switch (step) {
2983  case kXGS_init:
2984  // Process message
2985  if (ClientDoInit(br, bm, cmsg) != 0)
2986  return -1;
2987  break;
2988  case kXGS_cert:
2989  // Process message
2990  if (ClientDoCert(br, bm, cmsg) != 0)
2991  return -1;
2992  break;
2993  case kXGS_pxyreq:
2994  // Process message
2995  if (ClientDoPxyreq(br, bm, cmsg) != 0)
2996  return -1;
2997  break;
2998  default:
2999  cmsg = "protocol error: unknown action: "; cmsg += step;
3000  return -1;
3001  break;
3002  }
3003 
3004  // We are done
3005  return 0;
3006 }
3007 
3008 //_________________________________________________________________________
3009 int XrdSecProtocolgsi::ClientDoInit(XrdSutBuffer *br, XrdSutBuffer **bm,
3010  String &emsg)
3011 {
3012  // Client side: process a kXGS_init message.
3013  // Return 0 on success, -1 on error. If the case, a message is returned
3014  // in cmsg.
3015  EPNAME("ClientDoInit");
3016 
3017  //
3018  // Create the main buffer as a copy of the buffer received
3019  if (!((*bm) = new XrdSutBuffer(br->GetProtocol(),br->GetOptions()))) {
3020  emsg = "error instantiating main buffer";
3021  return -1;
3022  }
3023  //
3024  // Extract server version from options
3025  String opts = br->GetOptions();
3026  int ii = opts.find("v:");
3027  if (ii >= 0) {
3028  String sver(opts,ii+2);
3029  sver.erase(sver.find(','));
3030  hs->RemVers = atoi(sver.c_str());
3031  } else {
3032  hs->RemVers = Version;
3033  emsg = "server version information not found in options:"
3034  " assume same as local";
3035  }
3036  // Set use IV depending on the remote version
3037  useIV = false;
3038  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
3039  // Supports setting a unique IV in enc/dec operations
3040  useIV = true;
3041  }
3042  //
3043  // Create cache
3044  if (!(hs->Cref = new XrdSutPFEntry("c"))) {
3045  emsg = "error creating cache";
3046  return -1;
3047  }
3048  //
3049  // Save server version in cache
3050  hs->Cref->status = hs->RemVers;
3051  //
3052  // Set options
3053  hs->Options = PxyReqOpts;
3054  //
3055  // Extract list of crypto modules
3056  String clist;
3057  ii = opts.find("c:");
3058  if (ii >= 0) {
3059  clist.assign(opts, ii+2);
3060  clist.erase(clist.find(','));
3061  } else {
3062  NOTIFY("Crypto list missing: protocol error? (use defaults)");
3063  clist = DefCrypto;
3064  }
3065  // Parse the list loading the first we can
3066  if (ParseCrypto(clist) != 0) {
3067  emsg = "cannot find / load crypto requested modules :";
3068  emsg += clist;
3069  return -1;
3070  }
3071  //
3072  // Extract server certificate CA hashes
3073  String srvca;
3074  ii = opts.find("ca:");
3075  if (ii >= 0) {
3076  srvca.assign(opts, ii+3);
3077  srvca.erase(srvca.find(','));
3078  }
3079  // Parse the list loading the first we can
3080  if (ParseCAlist(srvca) != 0) {
3081  emsg = "unknown CA: cannot verify server certificate";
3082  hs->Chain = 0;
3083  return -1;
3084  }
3085 
3086  //
3087  // Extract no proxy option, if any
3088  bool createpxy = (PxyReqOpts & kOptsCreatePxy) ? 1 : 0;
3089  if (hs->RemVers < XrdSecgsiVersCertKey && !createpxy) {
3090  // Server does not accept pure cert files
3091  createpxy = 1;
3092  DEBUG("Server does not accept pure cert/key authentication: version < "<< (int)XrdSecgsiVersCertKey);
3093  }
3094 
3095  String clientcert = UsrCert, clientkey = UsrKey, clientproxy = UsrProxy;
3096  if (urlUsrCert.length()>0) clientcert = urlUsrCert;
3097  if (urlUsrKey.length()>0) clientkey = urlUsrKey;
3098  if (urlUsrProxy.length()>0) clientproxy = urlUsrProxy;
3099 
3100  //
3101  // Resolve place-holders in cert, key and proxy file paths, if any
3102  if (XrdSutResolve(clientcert, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
3103  PRINT("Problems resolving templates in "<<clientcert);
3104  return -1;
3105  }
3106  if (XrdSutResolve(clientkey, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
3107  PRINT("Problems resolving templates in "<<clientkey);
3108  return -1;
3109  }
3110  //
3111  // In the standard case we need to resolve also the proxy file path
3112  // Get the proxy path
3113  if (XrdSutResolve(clientproxy, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
3114  PRINT("Problems resolving templates in "<<clientproxy);
3115  return -1;
3116  }
3117  //
3118  // Load / Attach-to user proxies
3119  ProxyIn_t pi = {clientcert.c_str(), clientkey.c_str(), CAdir.c_str(),
3120  clientproxy.c_str(), PxyValid.c_str(),
3121  DepLength, DefBits, createpxy};
3122  ProxyOut_t po = {hs->PxyChain, sessionKsig, hs->Cbck };
3123  if (QueryProxy(1, &cachePxy, clientproxy.c_str(),
3124  sessionCF, hs->TimeStamp, &pi, &po) != 0) {
3125  emsg = "error getting user proxies";
3126  hs->Chain = 0;
3127  return -1;
3128  }
3129 
3130  if (!po.cbck) {
3131  emsg = "failed to initialize user proxies";
3132  hs->Chain = 0;
3133  return -1;
3134  }
3135 
3136  // Save the result
3137  hs->PxyChain = po.chain;
3138  hs->Cbck = new XrdSutBucket(*((XrdSutBucket *)(po.cbck)));
3139  if (!po.ksig || !(sessionKsig = sessionCF->RSA(*(po.ksig)))) {
3140  emsg = "could not get a copy of the signing key:";
3141  hs->Chain = 0;
3142  return -1;
3143  }
3144  //
3145  // And we are done;
3146  return 0;
3147 }
3148 
3149 //_________________________________________________________________________
3150 int XrdSecProtocolgsi::ClientDoCert(XrdSutBuffer *br, XrdSutBuffer **bm,
3151  String &emsg)
3152 {
3153  // Client side: process a kXGS_cert message.
3154  // Return 0 on success, -1 on error. If the case, a message is returned
3155  // in cmsg.
3156  EPNAME("ClientDoCert");
3157  XrdSutBucket *bck = 0;
3158 
3159  //
3160  // make sure the cache is still there
3161  if (!hs->Cref) {
3162  emsg = "cache entry not found";
3163  hs->Chain = 0;
3164  return -1;
3165  }
3166  //
3167  // make sure is not too old
3168  int reftime = hs->TimeStamp - TimeSkew;
3169  if (hs->Cref->mtime < reftime) {
3170  emsg = "cache entry expired";
3171  // Remove: should not be checked a second time
3172  SafeDelete(hs->Cref);
3173  hs->Chain = 0;
3174  return -1;
3175  }
3176  //
3177  // Get from cache version run by server
3178  hs->RemVers = hs->Cref->status;
3179 
3180  //
3181  // Extract list of cipher algorithms supported by the server
3182  String cip = "";
3183  if ((bck = br->GetBucket(kXRS_cipher_alg))) {
3184  String ciplist;
3185  bck->ToString(ciplist);
3186  // Parse the list
3187  int from = 0;
3188  while ((from = ciplist.tokenize(cip, from, ':')) != -1) {
3189  if (cip.length() > 0)
3190  if (sessionCF->SupportedCipher(cip.c_str()))
3191  break;
3192  cip = "";
3193  }
3194  // Must have a common cipher algorithm
3195  if (cip.length() <= 0) {
3196  emsg = "no common cipher algorithm";
3197  hs->Chain = 0;
3198  return -1;
3199  }
3200  } else {
3201  NOTIFY("WARNING: list of ciphers supported by server missing"
3202  " - using default");
3203  }
3204 
3205  //
3206  // Extract server certificate
3207  if (!(bck = br->GetBucket(kXRS_x509))) {
3208  emsg = "server certificate missing";
3209  hs->Chain = 0;
3210  return -1;
3211  }
3212 
3213  //
3214  // Finalize chain: get a copy of it (we do not touch the reference)
3215  hs->Chain = new X509Chain(hs->Chain);
3216  if (!(hs->Chain)) {
3217  emsg = "cannot duplicate reference chain";
3218  return -1;
3219  }
3220  // The new chain must be deleted at destruction
3221  hs->Options |= kOptsDelChn;
3222 
3223  // Get hook to parsing function
3224  XrdCryptoX509ParseBucket_t ParseBucket = sessionCF->X509ParseBucket();
3225  if (!ParseBucket) {
3226  emsg = "cannot attach to ParseBucket function!";
3227  return -1;
3228  }
3229  // Parse bucket
3230  int nci = (*ParseBucket)(bck, hs->Chain);
3231  if (nci != 1) {
3232  emsg += nci;
3233  emsg += " vs 1 expected)";
3234  return -1;
3235  }
3236  //
3237  // Verify the chain
3238  x509ChainVerifyOpt_t vopt = {0,static_cast<int>(hs->TimeStamp),-1,hs->Crl};
3240  if (!(hs->Chain->Verify(ecode, &vopt))) {
3241  emsg = "certificate chain verification failed: ";
3242  emsg += hs->Chain->LastError();
3243  return -1;
3244  }
3245  //
3246  // Verify server identity using RFC2818 method
3247  //
3248 
3249  // First we check the SAN. If the check succeeds then we are all done.
3250  // Otherwise, if there is no SAN extension or if trustDNS is in effect,
3251  // we check if the common name matches.
3252  //
3253  DEBUG("Checking cert is for host " <<Entity.host);
3254 
3255  bool hasSAN, usedDNS = false;
3256  const char *wantHost = (Entity.host ? Entity.host : "");
3257 
3258  if (!hs->Chain->End()->MatchesSAN(Entity.host, hasSAN))
3259  {if (hasSAN && !TrustDNS)
3260  {emsg = "Unable to verify server hostname '"; emsg += wantHost;
3261  emsg+= "' using SAN extension; common name fallback disallowed.";
3262  return -1;
3263  }
3264  // If the common name check fails, TrustDNS allows fallback
3265  if (!ServerCertNameOK(hs->Chain->End()->Subject(),Entity.host,emsg))
3266  {if (!TrustDNS || Entity.addrInfo == 0 || expectedHost)
3267  {emsg = "Unable to verify server hostname '"; emsg += wantHost;
3268  emsg+= "' using common name; DNS fallback prohibited.";
3269  return -1;
3270  }
3271  // Use DNS to resolve possible alias name
3272  const char *name = Entity.addrInfo->Name();
3273  if (name == NULL)
3274  {emsg = "Unable to verify server hostname '"; emsg += wantHost;
3275  emsg+= "'; DNS fallback translation failed.";
3276  return -1;
3277  }
3278  DEBUG("TrustDNS: checking if cert is for host " <<name);
3279  usedDNS = true;
3280  bool hostOK = ServerCertNameOK(hs->Chain->End()->Subject(),name,emsg)
3281  || (hasSAN && hs->Chain->End()->MatchesSAN(name,hasSAN));
3282  if (!hostOK) return -1;
3283  }
3284  }
3285 
3286  // If we used the DNS then we must prohibit proxy delegation of any kind
3287  //
3288  // In the case of delegation, give client a chance to use XrdSecGSISRVNAMES
3289  // to limit where it is being redirected to. If the new destination does not
3290  // match XrdSecGSISRVNAMES, refuse to delegate.
3291  //
3292  if (usedDNS ||
3293  (SrvAllowedNames.length() > 0 &&
3294  !ServerCertNameOK(hs->Chain->End()->Subject(), NULL, emsg)))
3295  {if (hs->Options & (kOptsFwdPxy | kOptsSigReq))
3296  {hs->Options &= ~(kOptsFwdPxy | kOptsSigReq);
3297  std::cerr <<"secgsi: proxy delegation forbidden when trusting DNS "
3298  "to resolve '" <<wantHost <<"'!\n" <<std::flush;
3299  }
3300  }
3301 
3302  //
3303  // Extract the server key
3304  sessionKver = sessionCF->RSA(*(hs->Chain->End()->PKI()));
3305  if (!sessionKver || !sessionKver->IsValid()) {
3306  emsg = "server certificate contains an invalid key";
3307  return -1;
3308  }
3309  // Move next part to here, after sessionKver set, in order to
3310  // verify the signature of DH parameters
3311 
3312  //
3313  // If client supports decoding of signed DH, do sign them
3314  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
3315 
3316  // Extract server public part for session cipher
3317  if (!(bck = br->GetBucket(kXRS_cipher))) {
3318  emsg = "server public part for session cipher missing";
3319  hs->Chain = 0;
3320  return -1;
3321  }
3322 
3323  // Encrypt server DH public parameters with server key
3324  if (sessionKver->DecryptPublic(*bck) <= 0) {
3325  emsg = "decrypting server DH public parameters";
3326  return -1;
3327  }
3328  } else {
3329 
3330  // Extract server public part for session cipher
3331  if (!(bck = br->GetBucket(kXRS_puk))) {
3332  emsg = "server public part for session cipher missing";
3333  hs->Chain = 0;
3334  return -1;
3335  }
3336 
3337  // If the server doesn't provide signed DH parameter, disable proxy delegation
3338  if (hs->Options & (kOptsFwdPxy | kOptsSigReq)) {
3339  hs->Options &= ~(kOptsFwdPxy | kOptsSigReq);
3340  PRINT("no signed DH parameters from " << Entity.host
3341  << ". Will not delegate x509 proxy to it");
3342  }
3343  }
3344 
3345  //
3346  // Initialize session cipher
3347  SafeDelete(sessionKey);
3348  if (!(sessionKey =
3349  sessionCF->Cipher(hs->HasPad, 0,bck->buffer,bck->size,cip.c_str())) || !(sessionKey->IsValid())) {
3350  PRINT("could not instantiate session cipher "
3351  "using cipher public info from server");
3352  emsg = "could not instantiate session cipher ";
3353  return -1;
3354  }
3355 
3356  //
3357  // Communicate the cipher name to server
3358  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
3359  // Including the length of the IV if supported
3360  String cipiv;
3361  String::form(cipiv, "%s#%d", cip.c_str(), sessionKey->MaxIVLength());
3362  br->UpdateBucket(cipiv, kXRS_cipher_alg);
3363  } else {
3364  br->UpdateBucket(cip, kXRS_cipher_alg);
3365  }
3366 
3367  // Deactivate what not needed any longer
3368  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
3369  br->Deactivate(kXRS_cipher);
3370  } else {
3371  br->Deactivate(kXRS_puk);
3372  }
3373  br->Deactivate(kXRS_x509);
3374 
3375  //
3376  // Extract list of MD algorithms supported by the server
3377  String md = "";
3378  if ((bck = br->GetBucket(kXRS_md_alg))) {
3379  String mdlist;
3380  bck->ToString(mdlist);
3381  // Parse the list
3382  int from = 0;
3383  while ((from = mdlist.tokenize(md, from, ':')) != -1) {
3384  if (md.length() > 0)
3385  if (sessionCF->SupportedMsgDigest(md.c_str()))
3386  break;
3387  md = "";
3388  }
3389  } else {
3390  NOTIFY("WARNING: list of digests supported by server missing"
3391  " - using default");
3392  md = "sha256";
3393  }
3394  if (!(sessionMD = sessionCF->MsgDigest(md.c_str()))) {
3395  emsg = "could not instantiate digest object";
3396  return -1;
3397  }
3398  // Communicate choice to server
3399  br->UpdateBucket(md, kXRS_md_alg);
3400 
3401  //
3402  // Extract the main buffer (it contains the random challenge
3403  // and will contain our credentials encrypted)
3404  XrdSutBucket *bckm = 0;
3405  if (!(bckm = br->GetBucket(kXRS_main))) {
3406  emsg = "main buffer missing";
3407  return -1;
3408  }
3409 
3410  //
3411  // Deserialize main buffer
3412  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
3413  emsg = "error deserializing main buffer";
3414  return -1;
3415  }
3416 
3417  //
3418  // And we are done;
3419  return 0;
3420 }
3421 
3422 //_________________________________________________________________________
3423 int XrdSecProtocolgsi::ClientDoPxyreq(XrdSutBuffer *br, XrdSutBuffer **bm,
3424  String &emsg)
3425 {
3426  // Client side: process a kXGS_pxyreq message.
3427  // Return 0 on success, -1 on error. If the case, a message is returned
3428  // in cmsg.
3429  XrdSutBucket *bck = 0;
3430 
3431  //
3432  // Extract the main buffer (it contains the random challenge
3433  // and will contain our credentials encrypted)
3434  XrdSutBucket *bckm = 0;
3435  if (!(bckm = br->GetBucket(kXRS_main))) {
3436  emsg = "main buffer missing";
3437  return -1;
3438  }
3439  //
3440  // Decrypt the main buffer with the session cipher, if available
3441  if (sessionKey) {
3442  if (!(sessionKey->Decrypt(*bckm, useIV))) {
3443  emsg = "error with session cipher";
3444  return -1;
3445  }
3446  }
3447 
3448  //
3449  // Deserialize main buffer
3450  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
3451  emsg = "error deserializing main buffer";
3452  return -1;
3453  }
3454 
3455  //
3456  // Check if we are ready to proces this
3457  if ((hs->Options & kOptsFwdPxy)) {
3458  // We have to send the private key of our proxy
3459  XrdCryptoX509 *pxy = 0;
3460  XrdCryptoRSA *kpxy = 0;
3461  if (!(hs->PxyChain) ||
3462  !(pxy = hs->PxyChain->End()) || !(kpxy = pxy->PKI())) {
3463  emsg = "local proxy info missing or corrupted";
3464  return 0;
3465  }
3466  // Send back the signed request as bucket
3467  String pri;
3468  if (kpxy->ExportPrivate(pri) != 0) {
3469  emsg = "problems exporting private key";
3470  return 0;
3471  }
3472  // Add it to the main list
3473  if ((*bm)->AddBucket(pri, kXRS_x509) != 0) {
3474  emsg = "problem adding bucket with private key to main buffer";
3475  return 0;
3476  }
3477  } else {
3478  // Proxy request: check if we are allowed to sign it
3479  if (!(hs->Options & kOptsSigReq)) {
3480  emsg = "Not allowed to sign proxy requests";
3481  return 0;
3482  }
3483  // Get the request
3484  if (!(bck = (*bm)->GetBucket(kXRS_x509_req))) {
3485  emsg = "bucket with proxy request missing";
3486  return 0;
3487  }
3488  XrdCryptoX509Req *req = sessionCF->X509Req(bck);
3489  if (!req) {
3490  emsg = "could not resolve proxy request";
3491  return 0;
3492  }
3493  req->SetVersion(hs->RemVers);
3494  // Get our proxy and its private key
3495  XrdCryptoX509 *pxy = 0;
3496  XrdCryptoRSA *kpxy = 0;
3497  if (!(hs->PxyChain) ||
3498  !(pxy = hs->PxyChain->End()) || !(kpxy = pxy->PKI())) {
3499  emsg = "local proxy info missing or corrupted";
3500  return 0;
3501  }
3502  // Sign the request
3503  XrdCryptoX509SignProxyReq_t X509SignProxyReq = (sessionCF) ? sessionCF->X509SignProxyReq() : 0;
3504  if (!X509SignProxyReq) {
3505  emsg = "problems getting method to sign request";
3506  return 0;
3507  }
3508  XrdCryptoX509 *npxy = 0;
3509  if ((*X509SignProxyReq)(pxy, kpxy, req, &npxy) != 0) {
3510  emsg = "problems signing the request";
3511  return 0;
3512  }
3513  delete req;
3514  (*bm)->Deactivate(kXRS_x509_req);
3515 
3516  // Send back the signed request as bucket
3517  if ((bck = npxy->Export())) {
3518  // Add it to the main list
3519  if ((*bm)->AddBucket(bck) != 0) {
3520  emsg = "problem adding signed request to main buffer";
3521  return 0;
3522  }
3523  }
3524  delete npxy; // has been allocated in *X509SignProxyReq
3525  }
3526 
3527  //
3528  // And we are done;
3529  return 0;
3530 
3531 }
3532 
3533 //_________________________________________________________________________
3534 int XrdSecProtocolgsi::ParseServerInput(XrdSutBuffer *br, XrdSutBuffer **bm,
3535  String &cmsg)
3536 {
3537  // Parse received buffer b, extracting and decrypting the main
3538  // buffer *bm and extracting the session
3539  // cipher, random tag buckets and user name, if any.
3540  // Results used to fill the local handshake variables
3541  EPNAME("ParseServerInput");
3542 
3543  // Space for pointer to main buffer must be already allocated
3544  if (!br || !bm) {
3545  PRINT("invalid inputs ("<<br<<","<<bm<<")");
3546  cmsg = "invalid inputs";
3547  return -1;
3548  }
3549 
3550  //
3551  // Get the step
3552  int step = br->GetStep();
3553 
3554  // Do the right action
3555  switch (step) {
3556  case kXGC_certreq:
3557  // Process message
3558  if (ServerDoCertreq(br, bm, cmsg) != 0)
3559  return -1;
3560  break;
3561  case kXGC_cert:
3562  // Process message
3563  if (ServerDoCert(br, bm, cmsg) != 0)
3564  return -1;
3565  break;
3566  case kXGC_sigpxy:
3567  // Process message
3568  if (ServerDoSigpxy(br, bm, cmsg) != 0)
3569  return -1;
3570  break;
3571  default:
3572  cmsg = "protocol error: unknown action: "; cmsg += step;
3573  return -1;
3574  break;
3575  }
3576 
3577  //
3578  // We are done
3579  return 0;
3580 }
3581 
3582 //_________________________________________________________________________
3583 int XrdSecProtocolgsi::ServerDoCertreq(XrdSutBuffer *br, XrdSutBuffer **bm,
3584  String &cmsg)
3585 {
3586  // Server side: process a kXGC_certreq message.
3587  // Return 0 on success, -1 on error. If the case, a message is returned
3588  // in cmsg.
3589  XrdSutCERef ceref;
3590  XrdSutBucket *bck = 0;
3591  XrdSutBucket *bckm = 0;
3592 
3593  //
3594  // Get version run by client, if there
3595  if (br->UnmarshalBucket(kXRS_version,hs->RemVers) != 0) {
3596  hs->RemVers = Version;
3597  cmsg = "client version information not found in options:"
3598  " assume same as local";
3599  } else {
3600  br->Deactivate(kXRS_version);
3601  }
3602  // Reset use IV; will be set in next round depending on the remote version
3603  useIV = false;
3604 
3605  //
3606  // Extract the main buffer
3607  if (!(bckm = br->GetBucket(kXRS_main))) {
3608  cmsg = "main buffer missing";
3609  return -1;
3610  }
3611  //
3612  // Extract bucket with crypto module
3613  if (!(bck = br->GetBucket(kXRS_cryptomod))) {
3614  cmsg = "crypto module specification missing";
3615  return -1;
3616  }
3617  String cmod;
3618  bck->ToString(cmod);
3619  // Parse the list loading the first we can
3620  if (ParseCrypto(cmod) != 0) {
3621  cmsg = "cannot find / load crypto requested module :";
3622  cmsg += cmod;
3623  return -1;
3624  }
3625  //
3626  // Extract bucket with client issuer hash
3627  if (!(bck = br->GetBucket(kXRS_issuer_hash))) {
3628  cmsg = "client issuer hash missing";
3629  return -1;
3630  }
3631  String cahash;
3632  bck->ToString(cahash);
3633  //
3634  // Check if we know it
3635  if (ParseCAlist(cahash) != 0) {
3636  cmsg = "unknown CA: cannot verify client credentials";
3637  return -1;
3638  }
3639  // Find our certificate in cache
3640  String cadum;
3641  XrdSutCacheEntry *cent = GetSrvCertEnt(ceref, sessionCF, hs->TimeStamp, cadum);
3642  if (!cent) {
3643  cmsg = "cannot find certificate: corruption?";
3644  return -1;
3645  }
3646 
3647  // Fill some relevant handshake variables
3648  sessionKsig = sessionCF->RSA(*((XrdCryptoRSA *)(cent->buf2.buf)));
3649  hs->Cbck = new XrdSutBucket(*((XrdSutBucket *)(cent->buf3.buf)));
3650  ceref.UnLock();
3651 
3652  // Create a handshake cache
3653  if (!(hs->Cref = new XrdSutPFEntry(hs->ID.c_str()))) {
3654  cmsg = "cannot create cache entry";
3655  return -1;
3656  }
3657  //
3658  // Deserialize main buffer
3659  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
3660  cmsg = "error deserializing main buffer";
3661  return -1;
3662  }
3663 
3664  // Deactivate what not need any longer
3666 
3667  //
3668  // Get options, if any
3669  if (br->UnmarshalBucket(kXRS_clnt_opts, hs->Options) == 0)
3671 
3672  // We are done
3673  return 0;
3674 }
3675 
3676 //_________________________________________________________________________
3677 int XrdSecProtocolgsi::ServerDoCert(XrdSutBuffer *br, XrdSutBuffer **bm,
3678  String &cmsg)
3679 {
3680  // Server side: process a kXGC_cert message.
3681  // Return 0 on success, -1 on error. If the case, a message is returned
3682  // in cmsg.
3683  EPNAME("ServerDoCert");
3684 
3685  XrdSutBucket *bck = 0;
3686  XrdSutBucket *bckm = 0;
3687 
3688  //
3689  // Extract the main buffer
3690  if (!(bckm = br->GetBucket(kXRS_main))) {
3691  cmsg = "main buffer missing";
3692  return -1;
3693  }
3694  //
3695  // Extract cipher algorithm chosen by the client
3696  int lenIV = 0;
3697  String cip = "";
3698  if ((bck = br->GetBucket(kXRS_cipher_alg))) {
3699  bck->ToString(cip);
3700  // Extract IV length, if any
3701  int piv = cip.find('#');
3702  if (piv >= 0) {
3703  String siv(cip, piv+1);
3704  if (siv.isdigit()) lenIV = siv.atoi();
3705  cip.erase(piv);
3706  }
3707  // Parse the list
3708  if (DefCipher.find(cip) == -1) {
3709  cmsg = "unsupported cipher chosen by the client";
3710  hs->Chain = 0;
3711  return -1;
3712  }
3713  // Deactivate the bucket
3715  } else {
3716  NOTIFY("WARNING: client choice for cipher missing"
3717  " - using default");
3718  }
3719 
3720  XrdOucString cpub;
3721  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
3722  // Supports setting a unique IV in enc/dec operations
3723  useIV = true;
3724  // First get the client public key
3725  if (!(bck = br->GetBucket(kXRS_puk))) {
3726  cmsg = "bucket with client public key missing";
3727  return -1;
3728  }
3729  bck->ToString(cpub);
3730  sessionKver = sessionCF->RSA(cpub.c_str(), cpub.length());
3731  if (!sessionKver || !sessionKver->IsValid()) {
3732  cmsg = "bucket with client public key contains an invalid key";
3733  return -1;
3734  }
3735 
3736  // Get the client DH parameters
3737  if (!(bck = br->GetBucket(kXRS_cipher))) {
3738  cmsg = "bucket with client DH parameters missing";
3739  return -1;
3740  }
3741 
3742  // Decrypt client DH public parameters with client key
3743  if (sessionKver->DecryptPublic(*bck) <= 0) {
3744  cmsg = "decrypting client DH public parameters";
3745  return -1;
3746  }
3747 
3748  } else {
3749 
3750  // Get the client DH parameters
3751  if (!(bck = br->GetBucket(kXRS_puk))) {
3752  cmsg = "bucket with client DH parameters missing";
3753  return -1;
3754  }
3755 
3756  // If the client doesn't provide signed DH parameter, disable proxy delegation
3757  if ((PxyReqOpts & kOptsSrvReq) ||
3759  PRINT("no signed DH parameters from client:" << Entity.tident <<
3760  " : will not delegate x509 proxy to it");
3761  if ((PxyReqOpts & kOptsSrvReq)) PxyReqOpts &= ~kOptsSrvReq;
3762  if (hs->Options & (kOptsDlgPxy | kOptsSigReq | kOptsFwdPxy))
3764  }
3765 
3766  // Get the session cipher
3767  if (bck) {
3768  //
3769  // Cleanup
3770  SafeDelete(sessionKey);
3771  //
3772  // Prepare cipher agreement: make sure we have the reference cipher
3773  if (!hs->Rcip) {
3774  cmsg = "reference cipher missing";
3775  hs->Chain = 0;
3776  return -1;
3777  }
3778  sessionKey = hs->Rcip;
3779  //
3780  // Instantiate the session cipher
3781  if (!(sessionKey->Finalize(hs->HasPad,bck->buffer,bck->size,cip.c_str()))) {
3782  cmsg = "cannot finalize session cipher";
3783  hs->Chain = 0;
3784  return -1;
3785  }
3786 
3787  // Set IV length, if any
3788  if (lenIV > 0) sessionKey->SetIV(lenIV, (const char *)0);
3789 
3790  } else {
3791  cmsg = "bucket with DH parameters not found or invalid: cannot finalize session cipher";
3792  return -1;
3793  }
3794  //
3795  // We need it only once
3797  br->Deactivate(kXRS_puk);
3798 
3799  //
3800  // Decrypt the main buffer with the session cipher, if available
3801  if (sessionKey) {
3802  if (!(sessionKey->Decrypt(*bckm, useIV))) {
3803  cmsg = "error decrypting main buffer with session cipher";
3804  hs->Chain = 0;
3805  return -1;
3806  }
3807  }
3808  //
3809  // Deserialize main buffer
3810  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
3811  cmsg = "error deserializing main buffer";
3812  hs->Chain = 0;
3813  return -1;
3814  }
3815  //
3816  // Get version run by client, if there
3817  if (hs->RemVers == -1) {
3818  if ((*bm)->UnmarshalBucket(kXRS_version,hs->RemVers) != 0) {
3819  hs->RemVers = Version;
3820  cmsg = "client version information not found in options:"
3821  " assume same as local";
3822  } else {
3823  (*bm)->Deactivate(kXRS_version);
3824  }
3825  }
3826 
3827  //
3828  // Get cache entry
3829  if (!hs->Cref) {
3830  cmsg = "session cache has gone";
3831  hs->Chain = 0;
3832  return -1;
3833  }
3834  //
3835  // make sure cache is not too old
3836  int reftime = hs->TimeStamp - TimeSkew;
3837  if (hs->Cref->mtime < reftime) {
3838  cmsg = "cache entry expired";
3839  SafeDelete(hs->Cref);
3840  hs->Chain = 0;
3841  return -1;
3842  }
3843 
3844  //
3845  // Extract the client certificate
3846  if (!(bck = (*bm)->GetBucket(kXRS_x509))) {
3847  cmsg = "client certificate missing";
3848  SafeDelete(hs->Cref);
3849  hs->Chain = 0;
3850  return -1;
3851  }
3852 
3853  //
3854  // Finalize chain: get a copy of it (we do not touch the reference)
3855  hs->Chain = new X509Chain(hs->Chain);
3856  if (!(hs->Chain)) {
3857  cmsg = "cannot duplicate reference chain";
3858  return -1;
3859  }
3860  // The new chain must be deleted at destruction
3861  hs->Options |= kOptsDelChn;
3862 
3863  // Get hook to parsing function
3864  XrdCryptoX509ParseBucket_t ParseBucket = sessionCF->X509ParseBucket();
3865  if (!ParseBucket) {
3866  cmsg = "cannot attach to ParseBucket function!";
3867  return -1;
3868  }
3869  // Parse bucket
3870  int ncimin = (hs->Options & kOptsCreatePxy) ? 2 : 1;
3871  int nci = (*ParseBucket)(bck, hs->Chain);
3872  if (nci < ncimin) {
3873  cmsg = "wrong number of certificates in received bucket (received: ";
3874  cmsg += nci;
3875  cmsg += ", expected: >= ";
3876  cmsg += ncimin;
3877  cmsg += ")";
3878  return -1;
3879  }
3880  //
3881  // Verify the chain
3882  x509ChainVerifyOpt_t vopt = {0,static_cast<int>(hs->TimeStamp),-1,hs->Crl};
3884  if (!(hs->Chain->Verify(ecode, &vopt))) {
3885  cmsg = "certificate chain verification failed: ";
3886  cmsg += hs->Chain->LastError();
3887  return -1;
3888  }
3889 
3890  //
3891  // Extract the client public key from the certificate
3892  XrdCryptoRSA *ckey = sessionCF->RSA(*(hs->Chain->End()->PKI()));
3893  if (!ckey || !ckey->IsValid()) {
3894  cmsg = "client certificate contains an invalid key";
3895  return -1;
3896  }
3897  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
3898  // For new clients, make sure it is the same we got from the bucket
3899  XrdOucString cpubcert;
3900  if ((ckey->ExportPublic(cpubcert) < 0)) {
3901  cmsg = "exporting client public key";
3902  return -1;
3903  }
3904  if (cpubcert != cpub) {
3905  cmsg = "client public key does not match the one from the bucket!";
3906  return -1;
3907  }
3908  delete ckey;
3909  } else {
3910  // For old clients, set the client public key from the certificate
3911  sessionKver = ckey;
3912  }
3913 
3914  // Deactivate certificate buffer
3915  (*bm)->Deactivate(kXRS_x509);
3916 
3917  //
3918  // Check if there will be delegated proxies; these can be through
3919  // normal request+signature, or just forwarded by the client.
3920  // In both cases we need to save the proxy chain. If we need a
3921  // request, we have to prepare it and send it back to the client.
3922  // Get hook to parsing function
3923  XrdCryptoX509CreateProxyReq_t X509CreateProxyReq = sessionCF->X509CreateProxyReq();
3924  if (!X509CreateProxyReq) {
3925  cmsg = "cannot attach to X509CreateProxyReq function!";
3926  return -1;
3927  }
3928  bool needReq =
3929  ((PxyReqOpts & kOptsSrvReq) && (hs->Options & kOptsSigReq)) ||
3930  (hs->Options & kOptsDlgPxy);
3931  if (needReq || (hs->Options & kOptsFwdPxy)) {
3932  // Create a new proxy chain
3933  hs->PxyChain = new X509Chain();
3934  // The new chain must be deleted if still in the handshake info
3935  // when the info is destroyed
3936  hs->Options |= kOptsDelPxy;
3937  // Add the current proxy
3938  if ((*ParseBucket)(bck, hs->PxyChain) > 1) {
3939  // Reorder it
3940  hs->PxyChain->Reorder();
3941  if (needReq) {
3942  // Create the request
3943  XrdCryptoX509Req *rPXp = (XrdCryptoX509Req *) &(hs->RemVers);
3944  XrdCryptoRSA *krPXp = 0;
3945  if ((*X509CreateProxyReq)(hs->PxyChain->End(), &rPXp, &krPXp) == 0) {
3946  // Save key in the cache
3947  hs->Cref->buf4.len = krPXp->GetPrilen() + 1;
3948  hs->Cref->buf4.buf = new char[hs->Cref->buf4.len];
3949  if (krPXp->ExportPrivate(hs->Cref->buf4.buf, hs->Cref->buf4.len) != 0) {
3950  delete krPXp;
3951  delete rPXp;
3952  if (hs->PxyChain) hs->PxyChain->Cleanup();
3953  SafeDelete(hs->PxyChain);
3954  cmsg = "cannot export private key of the proxy request!";
3955  return -1;
3956  }
3957  // Prepare export bucket for request
3958  XrdSutBucket *bckr = rPXp->Export();
3959  // Add it to the main list
3960  if ((*bm)->AddBucket(bckr) != 0) {
3961  if (hs->PxyChain) hs->PxyChain->Cleanup();
3962  SafeDelete(hs->PxyChain);
3963  NOTIFY("WARNING: proxy req: problem adding bucket to main buffer");
3964  }
3965  delete krPXp;
3966  delete rPXp;
3967  } else {
3968  if (hs->PxyChain) hs->PxyChain->Cleanup();
3969  SafeDelete(hs->PxyChain);
3970  NOTIFY("WARNING: proxy req: problem creating request");
3971  }
3972  }
3973  } else {
3974  if (hs->PxyChain) hs->PxyChain->Cleanup();
3975  SafeDelete(hs->PxyChain);
3976  NOTIFY("WARNING: proxy req: wrong number of certificates");
3977  }
3978  }
3979 
3980  //
3981  // Extract the MD algorithm chosen by the client
3982  String md = "";
3983  if ((bck = br->GetBucket(kXRS_md_alg))) {
3984  String mdlist;
3985  bck->ToString(md);
3986  // Parse the list
3987  if (DefMD.find(md) == -1) {
3988  cmsg = "unsupported MD chosen by the client";
3989  return -1;
3990  }
3991  // Deactivate
3992  br->Deactivate(kXRS_md_alg);
3993  } else {
3994  NOTIFY("WARNING: client choice for digests missing"
3995  " - using default");
3996  md = "md5";
3997  }
3998  if (!(sessionMD = sessionCF->MsgDigest(md.c_str()))) {
3999  cmsg = "could not instantiate digest object";
4000  return -1;
4001  }
4002 
4003  // We are done
4004  return 0;
4005 }
4006 
4007 //_________________________________________________________________________
4008 int XrdSecProtocolgsi::ServerDoSigpxy(XrdSutBuffer *br, XrdSutBuffer **bm,
4009  String &cmsg)
4010 {
4011  // Server side: process a kXGC_sigpxy message.
4012  // Return 0 on success, -1 on error. If the case, a message is returned
4013  // in cmsg.
4014  EPNAME("ServerDoSigpxy");
4015 
4016  XrdSutBucket *bck = 0;
4017  XrdSutBucket *bckm = 0;
4018 
4019  //
4020  // Extract the main buffer
4021  if (!(bckm = br->GetBucket(kXRS_main))) {
4022  cmsg = "main buffer missing";
4023  return 0;
4024  }
4025  //
4026  // Decrypt the main buffer with the session cipher, if available
4027  if (sessionKey) {
4028  if (!(sessionKey->Decrypt(*bckm, useIV))) {
4029  cmsg = "error decrypting main buffer with session cipher";
4030  return 0;
4031  }
4032  }
4033  //
4034  // Deserialize main buffer
4035  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
4036  cmsg = "error deserializing main buffer";
4037  return 0;
4038  }
4039 
4040  // Get the bucket
4041  if (!(bck = (*bm)->GetBucket(kXRS_x509))) {
4042  cmsg = "buffer with requested info missing";
4043  // Is there a message from the client?
4044  if ((bck = (*bm)->GetBucket(kXRS_message))) {
4045  // Yes: decode it and print it
4046  String m;
4047  bck->ToString(m);
4048  DEBUG("msg from client: "<<m);
4049  // Add it to the main message
4050  cmsg += " :"; cmsg += m;
4051  }
4052  return 0;
4053  }
4054 
4055  // Make sure we still have the chain
4056  X509Chain *pxyc = hs->PxyChain;
4057  if (!pxyc) {
4058  cmsg = "the proxy chain is gone";
4059  return 0;
4060  }
4061 
4062  // Action depend on the type of message
4063  if ((hs->Options & kOptsFwdPxy)) {
4064  // The bucket contains a private key to be added to the proxy
4065  // public key
4066  XrdCryptoRSA *kpx = pxyc->End()->PKI();
4067  if (kpx->ImportPrivate(bck->buffer, bck->size) != 0) {
4068  cmsg = "problems importing private key";
4069  return 0;
4070  }
4071  } else {
4072  // The bucket contains our request signed by the client
4073  // The full key is in the cache
4074  if (!hs->Cref) {
4075  cmsg = "session cache has gone";
4076  return 0;
4077  }
4078  // Get the signed certificate
4079  XrdCryptoX509 *npx = sessionCF->X509(bck);
4080  if (!npx) {
4081  cmsg = "could not resolve signed request";
4082  return 0;
4083  }
4084  // Set full PKI
4085  XrdCryptoRSA *const knpx = npx->PKI();
4086  if (!knpx || knpx->ImportPrivate(hs->Cref->buf4.buf, hs->Cref->buf4.len) != 0) {
4087  delete npx;
4088  cmsg = "could not import private key into signed request";
4089  return 0;
4090  }
4091  // Add the new proxy ecert to the chain
4092  pxyc->PushBack(npx);
4093  }
4094  // Save the chain in the instance
4095  proxyChain = pxyc;
4096  hs->PxyChain = 0;
4097  // Notify
4098  if (QTRACE(Authen)) { proxyChain->Dump(); }
4099 
4100  // Check if the proxy chain is to become the actual credentials
4101  //
4102  if ((PxyReqOpts & kOptsPxCred)) {
4104  (sessionCF) ? sessionCF->X509ExportChain() : 0;
4105  if (!c2mem) {
4106  cmsg = "chain exporter not found; proxy chain not exported";
4107  return 0;
4108  }
4109  XrdOucString spxy;
4110  XrdSutBucket *bpxy = (*c2mem)(proxyChain, true);
4111  bpxy->ToString(spxy);
4112  if (Entity.credslen > 0) SafeFree(Entity.creds);
4113  Entity.creds = strdup(spxy.c_str());
4114  Entity.credslen = spxy.length();
4115  DEBUG("proxy chain exported in Entity.creds (" << Entity.credslen << " bytes)");
4116  DEBUG("\n\n" << spxy.c_str() << "\n\n");
4117  delete bpxy;
4118  return 0;
4119  }
4120 
4121  //
4122  // Extract user login name, if any
4123  String user;
4124  if ((bck = (*bm)->GetBucket(kXRS_user))) {
4125  bck->ToString(user);
4126  (*bm)->Deactivate(kXRS_user);
4127  }
4128  if (user.length() <= 0) user = Entity.name;
4129 
4130  // Dump to file if required
4131  if ((PxyReqOpts & kOptsPxFile)) {
4132  if (user.length() > 0) {
4133  String pxfile = UsrProxy, name;
4134  struct passwd *pw = getpwnam(user.c_str());
4135  if (pw) {
4136  name = pw->pw_name;
4137  } else {
4138  // Get Hash of the subject
4139  XrdCryptoX509 *c = proxyChain->SearchBySubject(proxyChain->EECname());
4140  if (c) {
4141  name = c->SubjectHash();
4142  } else {
4143  cmsg = "proxy chain not dumped to file: could not find subject hash";
4144  return 0;
4145  }
4146  }
4147  if (XrdSutResolve(pxfile, Entity.host,
4148  Entity.vorg, Entity.grps, name.c_str()) != 0) {
4149  PRINT("Problems resolving templates in "<<pxfile);
4150  return 0;
4151  }
4152  // Replace <uid> placeholder
4153  if (pw && pxfile.find("<uid>") != STR_NPOS) {
4154  String suid; suid += (int) pw->pw_uid;
4155  pxfile.replace("<uid>", suid.c_str());
4156  }
4157 
4158  // Get the function
4159  XrdCryptoX509ChainToFile_t ctofile = sessionCF->X509ChainToFile();
4160  if ((*ctofile)(proxyChain,pxfile.c_str()) != 0) {
4161  cmsg = "problems dumping proxy chain to file ";
4162  cmsg += pxfile;
4163  return 0;
4164  }
4165  PRINT("proxy chain dumped to "<< pxfile);
4166  } else {
4167  cmsg = "proxy chain not dumped to file: entity name undefined";
4168  return 0;
4169  }
4170  }
4171 
4172  // We are done
4173  return 0;
4174 }
4175 
4176 //__________________________________________________________________
4177 void XrdSecProtocolgsi::ErrF(XrdOucErrInfo *einfo, kXR_int32 ecode,
4178  const char *msg1, const char *msg2,
4179  const char *msg3)
4180 {
4181  // Filling the error structure
4182  EPNAME("ErrF");
4183 
4184  char *msgv[12];
4185  int k, i = 0, sz = strlen("Secgsi");
4186 
4187  //
4188  // Code message, if any
4189  int cm = (ecode >= kGSErrParseBuffer &&
4190  ecode <= kGSErrError) ? (ecode-kGSErrParseBuffer) : -1;
4191  const char *cmsg = (cm > -1) ? gGSErrStr[cm] : 0;
4192 
4193  //
4194  // Build error message array
4195  msgv[i++] = (char *)"Secgsi"; //0
4196  if (cmsg) {msgv[i++] = (char *)": "; //1
4197  msgv[i++] = (char *)cmsg; //2
4198  sz += strlen(msgv[i-1]) + 2;
4199  }
4200  if (msg1) {msgv[i++] = (char *)": "; //3
4201  msgv[i++] = (char *)msg1; //4
4202  sz += strlen(msgv[i-1]) + 2;
4203  }
4204  if (msg2) {msgv[i++] = (char *)": "; //5
4205  msgv[i++] = (char *)msg2; //6
4206  sz += strlen(msgv[i-1]) + 2;
4207  }
4208  if (msg3) {msgv[i++] = (char *)": "; //7
4209  msgv[i++] = (char *)msg3; //8
4210  sz += strlen(msgv[i-1]) + 2;
4211  }
4212 
4213  // save it (or print it)
4214  if (einfo) {
4215  einfo->setErrInfo(ecode, (const char **)msgv, i);
4216  }
4217  if (QTRACE(Debug)) {
4218  char *bout = new char[sz+10];
4219  if (bout) {
4220  bout[0] = 0;
4221  for (k = 0; k < i; k++)
4222  strcat(bout, msgv[k]);
4223  DEBUG(bout);
4224  } else {
4225  for (k = 0; k < i; k++)
4226  DEBUG(msgv[k]);
4227  }
4228  }
4229 }
4230 
4231 //__________________________________________________________________
4232 XrdSecCredentials *XrdSecProtocolgsi::ErrC(XrdOucErrInfo *einfo,
4233  XrdSutBuffer *b1,
4234  XrdSutBuffer *b2,
4235  XrdSutBuffer *b3,
4236  kXR_int32 ecode,
4237  const char *msg1,
4238  const char *msg2,
4239  const char *msg3)
4240 {
4241  // Error logging client method
4242 
4243  // Fill the error structure
4244  ErrF(einfo, ecode, msg1, msg2, msg3);
4245 
4246  // Release buffers
4247  REL3(b1,b2,b3);
4248 
4249  // We are done
4250  return (XrdSecCredentials *)0;
4251 }
4252 
4253 //__________________________________________________________________
4254 int XrdSecProtocolgsi::ErrS(String ID, XrdOucErrInfo *einfo,
4255  XrdSutBuffer *b1, XrdSutBuffer *b2,
4256  XrdSutBuffer *b3, kXR_int32 ecode,
4257  const char *msg1, const char *msg2,
4258  const char *msg3)
4259 {
4260  // Error logging server method
4261 
4262  // Fill the error structure
4263  ErrF(einfo, ecode, msg1, msg2, msg3);
4264 
4265  // Release buffers
4266  REL3(b1,b2,b3);
4267 
4268  // We are done
4269  return kgST_error;
4270 }
4271 
4272 //______________________________________________________________________________
4273 bool XrdSecProtocolgsi::CheckRtag(XrdSutBuffer *bm, String &emsg)
4274 {
4275  // Check random tag signature if it was sent with previous packet
4276  EPNAME("CheckRtag");
4277 
4278  // Make sure we got a buffer
4279  if (!bm) {
4280  emsg = "Buffer not defined";
4281  return 0;
4282  }
4283  //
4284  // If we sent out a random tag check its signature
4285  if (hs->Cref && hs->Cref->buf1.len > 0) {
4286  XrdSutBucket *brt = 0;
4287  if ((brt = bm->GetBucket(kXRS_signed_rtag))) {
4288  // Make sure we got the right key to decrypt
4289  if (!(sessionKver)) {
4290  emsg = "Session cipher undefined";
4291  return 0;
4292  }
4293  // Decrypt it with the counter part public key
4294  if (sessionKver->DecryptPublic(*brt) <= 0) {
4295  emsg = "error decrypting random tag with public key";
4296  return 0;
4297  }
4298  } else {
4299  emsg = "random tag missing - protocol error";
4300  return 0;
4301  }
4302  //
4303  // Work out what the counter part must have signed: from
4304  // XrdSecgsiVersRtagHash on this is the context bound digest of the
4305  // tag we sent, and the tag itself before that
4306  const char *ref = hs->Cref->buf1.buf;
4307  int lref = hs->Cref->buf1.len;
4308  char rtd[kXRSrtagMDMax] = {0};
4309  if (hs->RemVers >= XrdSecgsiVersRtagHash) {
4310  lref = XrdSecgsiRtagDigest(sessionCF, hs->Cref->buf1.buf,
4311  hs->Cref->buf1.len, rtd, kXRSrtagMDMax);
4312  if (lref <= 0) {
4313  emsg = "error hashing random tag";
4314  return 0;
4315  }
4316  ref = rtd;
4317  }
4318  //
4319  // Random tag cross-check: size and content
4320  if (brt->size != lref || memcmp(brt->buffer, ref, lref)) {
4321  emsg = "random tag content mismatch";
4322  SafeDelete(hs->Cref);
4323  // Remove: should not be checked a second time
4324  return 0;
4325  }
4326  //
4327  // Reset the cache entry but we will not use the info a second time
4328  memset(hs->Cref->buf1.buf,0,hs->Cref->buf1.len);
4329  hs->Cref->buf1.SetBuf();
4330  //
4331  // Flag successful check
4332  hs->RtagOK = 1;
4334  DEBUG("Random tag successfully checked");
4335  } else {
4336  DEBUG("Nothing to check");
4337  }
4338 
4339  // We are done
4340  return 1;
4341 }
4342 
4343 //______________________________________________________________________________
4344 XrdCryptoX509Crl *XrdSecProtocolgsi::LoadCRL(XrdCryptoX509 *xca, const char *subjhash,
4345  XrdCryptoFactory *CF, int dwld, int &errcrl)
4346 {
4347  // Scan crldir for a valid CRL certificate associated to CA whose
4348  // certificate is xca. If 'dwld' is true try to download the CRL from
4349  // the relevant URI, if any.
4350  // If the CRL is found and is valid according
4351  // to the chosen option, return its content in a X509Crl object.
4352  // Return 0 in any other case
4353  EPNAME("LoadCRL");
4354  XrdCryptoX509Crl *crl = 0;
4355  errcrl = 0;
4356 
4357  // make sure we got what we need
4358  if (!xca || !CF) {
4359  PRINT("Invalid inputs");
4360  errcrl = -1;
4361  return crl;
4362  }
4363 
4364  // Get the CA hash
4365  String cahash(subjhash);
4366  int hashalg = 0;
4367  if (strcmp(subjhash, xca->SubjectHash())) hashalg = 1;
4368  // Drop the extension (".0")
4369  String caroot(cahash, 0, cahash.find(".0")-1);
4370 
4371  // The dir
4372  String crlext = XrdSecProtocolgsi::DefCRLext;
4373 
4374  String crldir;
4375  int from = 0;
4376  while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
4377  if (crldir.length() <= 0) continue;
4378  // Add the default CRL extension and the dir
4379  String crlfile = crldir + caroot;
4380  crlfile += crlext;
4381  DEBUG("target file: "<<crlfile);
4382  // Try to init a crl
4383  if ((crl = CF->X509Crl(crlfile.c_str()))) {
4384  if ((errcrl = VerifyCRL(crl, xca, crldir, CF, hashalg)) == 0) return crl;
4385  }
4386  SafeDelete(crl);
4387  }
4388 
4389  // If not required, we are done
4390  if (CRLCheck < 2 || (dwld == 0)) {
4391  // Done
4392  return crl;
4393  }
4394 
4395  // If in 'required' mode, we will also try to load the CRL from the
4396  // information found in the CA certificate or in the certificate directory.
4397  // To avoid this overload, the CRL information should be installed offline, e.g. with
4398  // utils/getCRLcert
4399 
4400  errcrl = 0;
4401  // Try to retrieve it from the URI in the CA certificate, if any
4402  if ((crl = CF->X509Crl(xca))) {
4403  if ((errcrl = VerifyCRL(crl, xca, crldir, CF, hashalg)) == 0) return crl;
4404  SafeDelete(crl);
4405  }
4406 
4407  // Finally try the ".crl_url" file
4408  from = 0;
4409  while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
4410  if (crldir.length() <= 0) continue;
4411  SafeDelete(crl);
4412  String crlurl = crldir + caroot;
4413  crlurl += ".crl_url";
4414  DEBUG("target file: "<<crlurl);
4415  FILE *furl = fopen(crlurl.c_str(), "r");
4416  if (!furl) {
4417  PRINT("could not open file: "<<crlurl);
4418  continue;
4419  }
4420  char line[2048];
4421  while ((fgets(line, sizeof(line), furl))) {
4422  if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = 0;
4423  if ((crl = CF->X509Crl(line, 1))) {
4424  if ((errcrl = VerifyCRL(crl, xca, crldir, CF, hashalg)) == 0) return crl;
4425  SafeDelete(crl);
4426  }
4427  }
4428  }
4429 
4430  // We need to parse the full dirs: make some cleanup first
4431  from = 0;
4432  while ((from = CRLdir.tokenize(crldir, from, ',')) != -1) {
4433  if (crldir.length() <= 0) continue;
4434  SafeDelete(crl);
4435  // Open directory
4436  DIR *dd = opendir(crldir.c_str());
4437  if (!dd) {
4438  PRINT("could not open directory: "<<crldir<<" (errno: "<<errno<<")");
4439  continue;
4440  }
4441  // Read the content
4442  struct dirent *dent = 0;
4443  while ((dent = readdir(dd))) {
4444  // Do not analyse the CA certificate
4445  if (!strcmp(cahash.c_str(),dent->d_name)) continue;
4446  // File name contain the root CA hash
4447  if (!strstr(dent->d_name,caroot.c_str())) continue;
4448  // candidate name
4449  String crlfile = crldir + dent->d_name;
4450  DEBUG("analysing entry "<<crlfile);
4451  // Try to init a crl
4452  if ((crl = CF->X509Crl(crlfile.c_str()))) {
4453  if ((errcrl = VerifyCRL(crl, xca, crldir, CF, hashalg)) == 0) break;
4454  SafeDelete(crl);
4455  }
4456  }
4457  // Close dir
4458  closedir(dd);
4459  // Are we done?
4460  if (crl) break;
4461  }
4462 
4463  // We are done
4464  return crl;
4465 }
4466 
4467 //______________________________________________________________________________
4468 int XrdSecProtocolgsi::VerifyCRL(XrdCryptoX509Crl *crl, XrdCryptoX509 *xca, String crldir,
4469  XrdCryptoFactory *CF, int hashalg)
4470 {
4471  EPNAME("VerifyCRL");
4472  int rc = 0;
4473  // Make sure they have the same issuer
4474  if (!strcmp(xca->SubjectHash(hashalg), crl->IssuerHash(hashalg))) {
4475  // Signing certificate file
4476  String casigfile = crldir + crl->IssuerHash(hashalg);
4477  DEBUG("CA signing certificate file = "<<casigfile);
4478  // Try to get signing certificate
4479  XrdCryptoX509 *xcasig = 0;
4480  if (!(xcasig = CF->X509(casigfile.c_str()))) {
4481  if (CRLCheck >= 2) {
4482  PRINT("CA certificate to verify the signature ("<<crl->IssuerHash(hashalg)<<
4483  ") could not be loaded - exit");
4484  } else {
4485  DEBUG("CA certificate to verify the signature could not be loaded - verification skipped");
4486  }
4487  rc = -3;
4488  } else {
4489  // Verify signature
4490  if (crl->Verify(xcasig)) {
4491  // Ok, we are done
4492  if (CRLCheck >= 3 && crl && crl->IsExpired()) {
4493  rc = -5;
4494  NOTIFY("CRL is expired (CRLCheck: "<<CRLCheck<<")");
4495  }
4496  } else {
4497  rc = -4;
4498  PRINT("CA signature or CRL verification failed!");
4499  }
4500  SafeDelete(xcasig);
4501  }
4502  } else {
4503  rc = -2;
4504  PRINT("Loaded CRL does not match CA (subject CA "<<xca->SubjectHash(hashalg)<<
4505  " does not match CRL issuer "<<crl->IssuerHash(hashalg)<<"! ");
4506  }
4507  return rc;
4508 }
4509 
4510 //______________________________________________________________________________
4511 String XrdSecProtocolgsi::GetCApath(const char *cahash)
4512 {
4513  // Look in the paths defined by CAdir for the certificate file related to
4514  // 'cahash', in the form <CAdir_entry>/<cahash>.0
4515 
4516  String path;
4517  String ent;
4518  int from = 0;
4519  while ((from = CAdir.tokenize(ent, from, ',')) != -1) {
4520  if (ent.length() > 0) {
4521  path = ent;
4522  if (!path.endswith('/'))
4523  path += "/";
4524  path += cahash;
4525  if (!path.endswith(".0"))
4526  path += ".0";
4527  if (!access(path.c_str(), R_OK))
4528  break;
4529  }
4530  path = "";
4531  }
4532 
4533  // Done
4534  return path;
4535 }
4536 //______________________________________________________________________________
4537 bool XrdSecProtocolgsi::VerifyCA(int opt, X509Chain *cca, XrdCryptoFactory *CF)
4538 {
4539  // Verify the CA in 'cca' according to 'opt':
4540  // opt = 2 full check
4541  // 1 only if self-signed
4542  // 0 no check
4543  EPNAME("VerifyCA");
4544 
4545  bool verified = 0;
4547  cca->SetStatusCA(st);
4548 
4549  // We nust have got a chain
4550  if (!cca) {
4551  PRINT("Invalid input ");
4552  return 0;
4553  }
4554 
4555  // Get the parse function
4557  if (!ParseFile) {
4558  PRINT("Cannot attach to the ParseFile function");
4559  return 0;
4560  }
4561 
4562  // Point to the certificate
4563  XrdCryptoX509 *xc = cca->Begin();
4564  if (!xc) {
4565  PRINT("Cannot attach to first certificate in chain");
4566  return 0;
4567  }
4568  // Make sure it is valid
4569  if (!(xc->IsValid())) {
4570  PRINT("CA certificate is expired ("<<xc->SubjectHash()<<", not_before: "<<xc->NotBefore()<<" secs UTC )");
4571  return 0;
4572  }
4573  // Is it self-signed ?
4574  bool self = (!strcmp(xc->IssuerHash(), xc->SubjectHash())) ? 1 : 0;
4575  if (!self) {
4576  String inam;
4577  if (opt == 2) {
4578  // We are requested to verify it
4579  bool notdone = 1;
4580  // We need to load the issuer(s) CA(s)
4581  XrdCryptoX509 *xd = xc;
4582  while (notdone) {
4583  X509Chain *ch = 0;
4584  int ncis = -1;
4585  for (int ha = 0; ha < 2; ha++) {
4586  inam = GetCApath(xd->IssuerHash(ha));
4587  if (inam.length() <= 0) continue;
4588  ch = new X509Chain();
4589  ncis = (*ParseFile)(inam.c_str(), ch, 0);
4590  if (ncis >= 1) break;
4591  SafeDelete(ch);
4592  }
4593  if (ncis < 1) break;
4594  XrdCryptoX509 *xi = ch->Begin();
4595  while (xi) {
4596  if (!strcmp(xd->IssuerHash(), xi->SubjectHash()))
4597  break;
4598  xi = ch->Next();
4599  }
4600  if (xi) {
4601  // Add the certificate to the requested CA chain
4602  ch->Remove(xi);
4603  cca->PutInFront(xi);
4604  SafeDelete(ch);
4605  // We may be over
4606  if (!strcmp(xi->IssuerHash(), xi->SubjectHash())) {
4607  notdone = 0;
4608  break;
4609  } else {
4610  // This becomes the daughter
4611  xd = xi;
4612  }
4613  } else {
4614  break;
4615  }
4616  }
4617  if (!notdone) {
4618  // Verify the chain
4620  x509ChainVerifyOpt_t vopt = {kOptsCheckSubCA, 0, -1, 0};
4621  if (!(verified = cca->Verify(e, &vopt)))
4622  PRINT("CA certificate not self-signed: verification failed for '"<<xc->SubjectHash()<<"': error: "<< cca->X509ChainError(e));
4623  } else {
4624  PRINT("CA certificate not self-signed: cannot verify integrity ("<<xc->SubjectHash()<<")");
4625  }
4626  } else {
4627  // Fill CA information
4628  cca->CheckCA(0);
4629  // Set OK in any case
4630  verified = 1;
4631  // Notify if some sort of check was required
4632  if (opt == 1) {
4633  NOTIFY("Warning: CA certificate not self-signed and"
4634  " integrity not checked: assuming OK ("<<xc->SubjectHash()<<")");
4635  }
4636  }
4637  } else {
4638  if (CACheck > caNoVerify) {
4639  // Check self-signature and fail if needed
4640  bool checkselfsigned = (CACheck > caVerifyss) ? true : false;
4641  if (!(verified = cca->CheckCA(checkselfsigned)))
4642  PRINT("CA certificate self-signed: integrity check failed ("<<xc->SubjectHash()<<")");
4643  } else {
4644  // Set OK in any case
4645  verified = 1;
4646  // Notify if some sort of check was required
4647  NOTIFY("Warning: CA certificate self-signed but"
4648  " integrity not checked: assuming OK ("<<xc->SubjectHash()<<")");
4649  }
4650  }
4651 
4652  // Set the status in the chain
4653  st = (verified) ? XrdCryptoX509Chain::kValid : st;
4654  cca->SetStatusCA(st);
4655 
4656  // Done
4657  return verified;
4658 }
4659 
4660 //_____________________________________________________________________________
4661 static bool GetCACheck(XrdSutCacheEntry *e, void *a) {
4662 
4663  EPNAME("GetCACheck");
4664 
4665  int crl_check = (*((XrdSutCacheArg_t *)a)).arg1;
4666  int crl_refresh = (*((XrdSutCacheArg_t *)a)).arg2;
4667  time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg3;
4668 
4669  if (!e) return false;
4670 
4671  X509Chain *chain = 0;
4672  // If we had already something, check it, as we may be done
4673  bool goodca = 0;
4674  if ((chain = (X509Chain *)(e->buf1.buf))) {
4675  // Check the validity of the certificates in the chain; if a certificate became invalid,
4676  // we need to reload a valid one for the same CA.
4677  if (chain->CheckValidity() == 0) {
4678  goodca = 1;
4679  } else {
4680  PRINT("CA entry for '"<<e->name<<"' needs refreshing: clean the related entry cache first");
4681  return false;
4682  }
4683  }
4684  if (goodca) {
4685  XrdCryptoX509Crl *crl = (XrdCryptoX509Crl *)(e->buf2.buf);
4686  bool goodcrl = 1;
4687  if ((crl_check == 2 && !crl) || (crl_check == 3 && crl->IsExpired())) goodcrl = 0;
4688  if (crl_refresh > 0 && ((ts_ref - e->mtime) > crl_refresh)) goodcrl = 0;
4689  if (goodcrl) {
4690  return true;
4691  } else if (crl) {
4692  PRINT("CRL entry for '"<<e->name<<"' needs refreshing: clean the related entry cache first ("<<e<<")");
4693  }
4694  }
4695  return false;
4696 }
4697 
4698 //______________________________________________________________________________
4699 int XrdSecProtocolgsi::GetCA(const char *cahash,
4700  XrdCryptoFactory *cf, gsiHSVars *hs)
4701 {
4702  // Gets entry for CA with hash cahash for crypt factory cf.
4703  // If not found in cache, try loading from <CAdir>/<cahash>.0 .
4704  // If 'hs' is defined, store pointers to chain and crl into 'hs'.
4705  // Return 0 if ok, -1 if not available, -2 if CRL not ok
4706  EPNAME("GetCA");
4707  XrdSutCERef ceref;
4708  int rc = 0;
4709 
4710  // We nust have got a CA hash
4711  if (!cahash || !cf) {
4712  PRINT("Invalid input ");
4713  return -1;
4714  }
4715 
4716  // Timestamp
4717  time_t timestamp = (hs) ? hs->TimeStamp : time(0);
4718 
4719  // The tag
4720  String tag(cahash,20);
4721  tag += ':';
4722  tag += cf->ID();
4723  DEBUG("Querying cache for tag: "<<tag<<" (timestamp:"<<timestamp<<
4724  ", refresh fq:"<< CRLRefresh <<")");
4725 
4726  bool rdlock = false;
4727  XrdSutCacheArg_t arg = {CRLCheck, CRLRefresh, timestamp, -1};
4728  XrdSutCacheEntry *cent = cacheCA.Get(tag.c_str(), rdlock, GetCACheck, (void *) &arg);
4729  if (!cent) {
4730  PRINT("unable to get a valid entry from cache for " << tag);
4731  return -1;
4732  }
4733  ceref.Set(&(cent->rwmtx));
4734 
4735  // Point to the content
4736  X509Chain *chain = (X509Chain *)(cent->buf1.buf);
4737  XrdCryptoX509Crl *crl = (XrdCryptoX509Crl *)(cent->buf2.buf);
4738 
4739  // If invalid we fail
4740  if (cent->status == kCE_inactive) {
4741  // Cleanup and remove existing invalid entries
4742  if (chain) stackCA.Del(chain);
4743  if (crl) stackCRL->Del(crl);
4744  PRINT("unable to get a valid entry from cache for " << tag);
4745  return -1;
4746  }
4747 
4748  // Check if we are done
4749  if (rdlock) {
4750  // Save chain
4751  if (hs) hs->Chain = chain;
4752  stackCA.Add(chain);
4753  // Save crl
4754  if (crl) {
4755  if (hs) hs->Crl = crl;
4756  // Add to the stack for proper cleaning of invalidated CRLs
4757  stackCRL->Add(crl);
4758  }
4759  return 0;
4760  }
4761 
4762  // Cleanup and remove existing invalid entries
4763  if (chain) stackCA.Del(chain);
4764  if (crl) stackCRL->Del(crl);
4765 
4766  chain = 0;
4767  crl = 0;
4768  cent->buf1.buf = 0;
4769  cent->buf2.buf = 0;
4770 
4771  // If not, prepare the file name
4772  String fnam = GetCApath(cahash);
4773  DEBUG("trying to load CA certificate from "<<fnam);
4774 
4775  // Create chain ?
4776  bool createchain = (hs && hs->Chain) ? 0 : 1;
4777  chain = (createchain) ? new X509Chain() : hs->Chain;
4778  if (!chain) {
4779  PRINT("could not attach-to or create new GSI chain");
4780  rc = -1;
4781  }
4782 
4783  // Get the parse function
4785  if (rc == 0 && ParseFile) {
4786  int nci = (createchain) ? (*ParseFile)(fnam.c_str(), chain, 0) : 1;
4787  bool ok = 0, verified = 0;
4788  if (nci == 1) {
4789  // Verify the CA
4790  verified = VerifyCA(CACheck, chain, cf);
4791  XrdCryptoX509Crl *crl = 0;
4792  if (verified) {
4793  // Get CRL, if required
4794  ok = 1;
4795  if (CRLCheck > 0) {
4796  int errcrl = 0;
4797  if ((crl = LoadCRL(chain->EffCA(), cahash, cf, CRLDownload, errcrl))) {
4798  // Good CA
4799  DEBUG("CRL successfully loaded");
4800  } else {
4801  String em = "missing or expired: ignoring";
4802  if ((CRLCheck == 1 && errcrl != 0 && errcrl != -5) || (CRLCheck >= 2 && errcrl != 0)) {
4803  ok = 0;
4804  em = "invalid: failing";
4805  } else if (CRLCheck >= 2) {
4806  ok = 0;
4807  em = "missing or expired: failing";
4808  }
4809  NOTIFY("CRL is "<<em<<" (CRLCheck: "<<CRLCheck<<")");
4810  }
4811  }
4812  }
4813  //
4814  if (ok) {
4815  // Add to the cache
4816  cent->buf1.buf = (char *)(chain);
4817  cent->buf1.len = 0; // Just a flag
4818  stackCA.Add(chain);
4819  if (crl) {
4820  cent->buf2.buf = (char *)(crl);
4821  cent->buf2.len = 0; // Just a flag
4822  stackCRL->Add(crl);
4823  }
4824  cent->mtime = timestamp;
4825  cent->status = kCE_ok;
4826  cent->cnt = 0;
4827  // Fill output, if required
4828  if (hs) {
4829  hs->Chain = chain;
4830  hs->Crl = crl;
4831  if (strcmp(cahash, chain->Begin()->SubjectHash())) hs->HashAlg = 1;
4832  }
4833  } else {
4834  SafeDelete(crl);
4835  SafeDelete(chain);
4836  rc = -2;
4837  }
4838  } else {
4839  SafeDelete(chain);
4840  NOTIFY("certificate not found or invalid (nci: "<<nci<<", CA: "<<
4841  (int)(verified)<<")");
4842  rc = -1;
4843  }
4844  }
4845 
4846  // We are done: release the lock
4847  ceref.UnLock();
4848 
4849  // We are done
4850  return (rc != 0) ? rc : 0;
4851 }
4852 
4853 //______________________________________________________________________________
4854 int XrdSecProtocolgsi::InitProxy(ProxyIn_t *pi, XrdCryptoFactory *cf, X509Chain *ch, XrdCryptoRSA **kp)
4855 {
4856  // Invoke 'grid-proxy-init' via the shell to create a valid the proxy file
4857  // If the variable GLOBUS_LOCATION is defined it prepares the external shell
4858  // by sourcing $GLOBUS_LOCATION/etc/globus-user-env.sh .
4859  // Return 0 in cse of success, != 0 in any other case .
4860  EPNAME("InitProxy");
4861  int rc = 0;
4862 
4863  // We must be able to get an answer
4864  if (isatty(0) == 0 || isatty(1) == 0) {
4865  NOTIFY("Not a tty: cannot prompt for proxies - do nothing ");
4866  return -1;
4867  }
4868 
4869  //
4870  // Use internal function for proxy initialization
4871  //
4872  // Make sure we got a chain and a key to fill
4873  if (!ch || !kp) {
4874  PRINT("chain or key container undefined");
4875  return -1;
4876  }
4877  // Check existence and permission of the key file
4878  struct stat st;
4879  if (stat(pi->key, &st) != 0) {
4880  DEBUG("cannot access private key file: "<<pi->key);
4881  return 1;
4882  }
4883  if (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
4884  (st.st_mode & (S_IWGRP | S_IWOTH)) != 0 ||
4885  (st.st_mode & (S_IRGRP | S_IROTH)) != 0) {
4886  DEBUG("wrong permissions for file: "<<pi->key<< " (should be 0600)");
4887  return 1;
4888  }
4889  //
4890  // Validity
4891  int valid = (pi->valid) ? XrdSutParseTime(pi->valid, 1) : -1;
4892  //
4893  // Options
4894  XrdProxyOpt_t pxopt = {pi->bits, // bits in key
4895  valid, // duration validity in secs
4896  pi->deplen}; // signature path depth
4897  //
4898  // Init now
4899  XrdCryptoX509CreateProxy_t X509CreateProxy = cf->X509CreateProxy();
4900  if (!X509CreateProxy) {
4901  PRINT("cannot attach to X509CreateProxy function!");
4902  return 1;
4903  }
4904  rc = (*X509CreateProxy)(pi->cert, pi->key, &pxopt, ch, kp, pi->out);
4905 
4906  // We are done
4907  return rc;
4908 }
4909 
4910 //__________________________________________________________________________
4911 int XrdSecProtocolgsi::ParseCAlist(String calist)
4912 {
4913  // Parse received ca list, find the first available CA in the list
4914  // and return a chain initialized with such a CA.
4915  // If nothing found return 0.
4916  EPNAME("ParseCAlist");
4917 
4918  // Check inputs
4919  if (calist.length() <= 0) {
4920  PRINT("nothing to parse");
4921  return -1;
4922  }
4923  DEBUG("parsing list: "<<calist);
4924 
4925  // Load module and define relevant pointers
4926  hs->Chain = 0;
4927  String cahash = "";
4928  // Parse list
4929  if (calist.length()) {
4930  int from = 0;
4931  while ((from = calist.tokenize(cahash, from, '|')) != -1) {
4932  // Check this hash
4933  if (cahash.length()) {
4934  // Make sure the extension ".0" if there, as external implementations may not
4935  // include it
4936  if (!cahash.endswith(".0")) cahash += ".0";
4937  // Get the CA chain
4938  if (GetCA(cahash.c_str(), sessionCF, hs) == 0)
4939  return 0;
4940  }
4941  }
4942  }
4943 
4944  // We did not find it
4945  return -1;
4946 }
4947 
4948 //__________________________________________________________________________
4949 int XrdSecProtocolgsi::ParseCrypto(String clist)
4950 {
4951  // Parse crypto list clist, extracting the first available module
4952  // and getting a related local cipher and a related reference
4953  // cipher to be used to agree the session cipher; the local lists
4954  // crypto info is updated, if needed
4955  // The results are used to fill the handshake part of the protocol
4956  // instance.
4957  EPNAME("ParseCrypto");
4958 
4959  // Check inputs
4960  if (clist.length() <= 0) {
4961  NOTIFY("empty list: nothing to parse");
4962  return -1;
4963  }
4964  DEBUG("parsing list: "<<clist);
4965 
4966  // Load module and define relevant pointers
4967  hs->CryptoMod = "";
4968 
4969  // Parse list
4970  int from = 0;
4971  while ((from = clist.tokenize(hs->CryptoMod, from, '|')) != -1) {
4972  // Check this module
4973  if (hs->CryptoMod.length() > 0) {
4974  DEBUG("found module: "<<hs->CryptoMod);
4975  // Padding support?
4976  bool otherHasPad = true;
4977  if (hs->RemVers >= XrdSecgsiVersDHsigned) {
4978  if (hs->CryptoMod.endswith(gNoPadTag)) {
4979  otherHasPad = false;
4980  hs->CryptoMod.replace(gNoPadTag, "");
4981  }
4982  } else {
4983  otherHasPad = false;
4984  }
4985  // Load the crypto factory
4986  if ((sessionCF =
4988  sessionCF->SetTrace(GSITrace->What);
4989  if (QTRACE(Debug)) sessionCF->Notify();
4990  if (otherHasPad && sessionCF->HasPaddingSupport()) hs->HasPad = 1;
4991  int fid = sessionCF->ID();
4992  int i = 0;
4993  // Retrieve the index in local table
4994  while (i < ncrypt) {
4995  if (cryptID[i] == fid) break;
4996  i++;
4997  }
4998  if (i >= ncrypt) {
4999  if (ncrypt == XrdCryptoMax) {
5000  DEBUG("max number of crypto slots reached - do nothing");
5001  return 0;
5002  } else {
5003  // Add new entry
5004  cryptF[i] = sessionCF;
5005  cryptID[i] = fid;
5006  ncrypt++;
5007  }
5008  }
5009  // On servers the ref cipher should be defined at this point
5010  hs->Rcip = sessionCF->Cipher(hs->HasPad, 0,0,0);
5011  // we are done
5012  return 0;
5013  }
5014  }
5015  }
5016 
5017  // Nothing found
5018  return -1;
5019 }
5020 
5021 //_____________________________________________________________________________
5022 static bool QueryProxyCheck(XrdSutCacheEntry *e, void *a) {
5023 
5024  time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg1;
5025 
5026  if (e && e->buf1.buf) {
5027  X509Chain *chain = (X509Chain *)(e->buf1.buf);
5028  if (chain->CheckValidity(1, ts_ref) == 0) return true;
5029  }
5030  return false;
5031 }
5032 
5033 
5034 //__________________________________________________________________________
5035 int XrdSecProtocolgsi::QueryProxy(bool checkcache, XrdSutCache *cache,
5036  const char *tag, XrdCryptoFactory *cf,
5037  time_t timestamp, ProxyIn_t *pi, ProxyOut_t *po)
5038 {
5039  // Query users proxies, initializing if needed
5040  EPNAME("QueryProxy");
5041  XrdSutCERef ceref;
5042 
5043  bool hasproxy = 0;
5044  // We may already loaded valid proxies
5045  bool rdlock = false;
5046  XrdSutCacheArg_t arg = {timestamp, -1, -1, -1};
5047  XrdSutCacheEntry *cent = cache->Get(tag, rdlock, QueryProxyCheck, (void *) &arg);
5048  if (!cent) {
5049  PRINT("cannot get cache entry for: "<<tag);
5050  return -1;
5051  }
5052  ceref.Set(&(cent->rwmtx));
5053 
5054  if (checkcache && rdlock) {
5055  po->chain = (X509Chain *)(cent->buf1.buf);
5056  po->ksig = (XrdCryptoRSA *)(cent->buf2.buf);
5057  po->cbck = (XrdSutBucket *)(cent->buf3.buf);
5058  // We are done
5059  ceref.UnLock();
5060  return 0;
5061  }
5062 
5063  // Cleanup the chain
5064  po->chain = (X509Chain *)(cent->buf1.buf);
5065  if (po->chain) po->chain->Cleanup();
5066  SafeDelete(po->chain);
5067 
5068  // Cleanup cache entry
5069  cent->buf1.buf = 0;
5070  cent->buf1.len = 0;
5071  // The key is deleted by the certificate destructor
5072  // Just reset the buffer
5073  cent->buf2.buf = 0;
5074  cent->buf2.len = 0;
5075  // and the related bucket
5076  if (cent->buf3.buf)
5077  delete (XrdSutBucket *)(cent->buf3.buf);
5078  cent->buf3.buf = 0;
5079  cent->buf3.len = 0;
5080 
5081  //
5082  // We do not have good proxies, try load (user may have initialized
5083  // them in the meanwhile)
5084  // Create a new chain first, if needed
5085  if (!(po->chain))
5086  po->chain = new X509Chain();
5087  if (!(po->chain)) {
5088  PRINT("cannot create new chain!");
5089  return -1;
5090  }
5091  int ntry = 3;
5092  bool parsefile = 1;
5093  bool exportbucket = 0;
5095  XrdCryptoX509ParseBucket_t ParseBucket = 0;
5096  while (!hasproxy && ntry > 0) {
5097 
5098  // Try init as last option if not in pure cert/key mode
5099  if (ntry == 1 && pi->createpxy) {
5100 
5101  // Cleanup the chain
5102  po->chain->Cleanup();
5103 
5104  if (InitProxy(pi, cf, po->chain, &(po->ksig)) != 0) {
5105  NOTIFY("problems initializing proxy via external shell");
5106  ntry--;
5107  continue;
5108  }
5109  // We need to explicitely export the proxy in a bucket
5110  exportbucket = 1;
5111  // Chain is already loaded if we used the internal function
5112  // to initialize the proxies
5113  parsefile = 0;
5114  timestamp = time(0);
5115  }
5116  ntry--;
5117 
5118  //
5119  // A proxy chain may have been passed via XrdSecCREDS: check that first
5120  if (ntry == 2) {
5121 
5122  char *cbuf = getenv("XrdSecCREDS");
5123  if (cbuf) {
5124  // Import into a bucket
5125  XrdSutBucket xbck(0, 0, kXRS_x509);
5126  // Fill bucket
5127  xbck.SetBuf(cbuf, strlen(cbuf));
5128  // Parse the bucket
5129  if (!(ParseBucket = cf->X509ParseBucket())) {
5130  PRINT("cannot attach to ParseBucket function!");
5131  continue;
5132  }
5133  int nci = (*ParseBucket)(&xbck, po->chain);
5134  if (nci < 2) {
5135  NOTIFY("proxy bucket must have at least two certificates"
5136  " (found: "<<nci<<")");
5137  continue;
5138  }
5139  } else {
5140  // No env: parse the file
5141  ntry--;
5142  }
5143  }
5144  if (ntry == 1) {
5145  if (parsefile) {
5146  if (!ParseFile) {
5147  if (!(ParseFile = cf->X509ParseFile())) {
5148  PRINT("cannot attach to ParseFile function!");
5149  continue;
5150  }
5151  }
5152 
5153  // Parse the proxy file
5154  int nci = (*ParseFile)(pi->out, po->chain, 0);
5155  if (nci < 2) {
5156  DEBUG("proxy files must have at least 2 certificates"
5157  " (found: "<<nci<<")");
5158  if (!pi->createpxy) {
5159  // Parse the cert file if requested
5160  int nci = (*ParseFile)(pi->cert, po->chain, pi->key);
5161  if (nci < 1) {
5162  DEBUG("cert files must have at least 1 certificates"
5163  " (found: "<<nci<<")");
5164  continue;
5165  }
5166  } else {
5167  continue;
5168  }
5169  }
5170 
5171  // Check if any CA was in the file
5172  bool checkselfsigned = (CACheck > caVerifyss) ? true : false;
5173  po->chain->CheckCA(checkselfsigned);
5174  exportbucket = 1;
5175  }
5176  }
5177 
5178  // Check validity in time
5179  if (po->chain->CheckValidity(1, timestamp) != 0) {
5180  NOTIFY("proxy files contains expired certificates");
5181  continue;
5182  }
5183 
5184  // Reorder chain
5185  if (po->chain->Reorder() != 0) {
5186  NOTIFY("proxy files contains inconsistent certificates");
5187  continue;
5188  }
5189 
5190  // Check key
5191  po->ksig = po->chain->End()->PKI();
5192  if (po->ksig->status != XrdCryptoRSA::kComplete) {
5193  NOTIFY("proxy files contain invalid key pair");
5194  continue;
5195  }
5196 
5197  XrdCryptoX509ExportChain_t ExportChain = cf->X509ExportChain();
5198  if (!ExportChain) {
5199  PRINT("cannot attach to ExportChain function!");
5200  continue;
5201  }
5202 
5203  // Create bucket for export
5204  if (exportbucket) {
5205  po->cbck = (*ExportChain)(po->chain, 0);
5206  if (!(po->cbck)) {
5207  PRINT("could not create bucket for export");
5208  continue;
5209  }
5210  }
5211 
5212  // Save info in cache
5213  cent->mtime = po->chain->End()->NotAfter(); // the expiring time
5214  cent->status = kCE_special; // distinguish from normal certs
5215  cent->cnt = 0;
5216  // The chain
5217  cent->buf1.buf = (char *)(po->chain);
5218  cent->buf1.len = 0; // Just a flag
5219  // The key
5220  cent->buf2.buf = (char *)(po->chain->End()->PKI());
5221  cent->buf2.len = 0; // Just a flag
5222  // The export bucket
5223  cent->buf3.buf = (char *)(po->cbck);
5224  cent->buf3.len = 0; // Just a flag
5225 
5226  // Set the positive flag
5227  hasproxy = 1;
5228  }
5229  // Always unlock
5230  ceref.UnLock();
5231 
5232  // We are done
5233  if (!hasproxy) {
5234  // Some cleanup
5235  po->chain->Cleanup();
5236  SafeDelete(po->chain);
5237  SafeDelete(po->cbck);
5238  return -1;
5239  }
5240  return 0;
5241 }
5242 
5243 
5244 //_____________________________________________________________________________
5245 static bool QueryGMAPCheck(XrdSutCacheEntry *e, void *a) {
5246  int st_ref = (*((XrdSutCacheArg_t *)a)).arg1;
5247  time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg2;
5248  long to_ref = (*((XrdSutCacheArg_t *)a)).arg3;
5249  if (e) {
5250  // Check expiration, if required
5251  if ((e->status != st_ref) ||
5252  ((e->status == st_ref) &&
5253  (to_ref > 0) &&
5254  ((ts_ref - e->mtime) > to_ref))) {
5255  return false;
5256  } else {
5257  return true;
5258  }
5259  }
5260  return false;
5261 }
5262 
5263 //__________________________________________________________________________
5264 void XrdSecProtocolgsi::QueryGMAP(XrdCryptoX509Chain *chain, int now, String &usrs)
5265 {
5266  // Resolve usernames associated with this proxy. The lookup is typically
5267  // based on the 'dn' (either in the grid mapfile or via the 'GMAPFun' plugin) but
5268  // it can also be based on the full proxy via the AuthzFun plugin.
5269  // For 'grid mapfile' and 'GMAPFun' the result is kept valid for a certain amount
5270  // of time, hashed on the 'dn'.
5271  // On return, an empty string in 'usrs' indicates failure.
5272  // Note that 'usrs' can be a comma-separated list of usernames.
5273  EPNAME("QueryGMAP");
5274 
5275  // List of user names attached to the entity
5276  usrs = "";
5277 
5278  // The chain must be defined
5279  if (!chain) {
5280  PRINT("input chain undefined!");
5281  return;
5282  }
5283 
5284  // Now we check the DN-mapping function and eventually the gridmap file.
5285  // The result can be cached for a while.
5286  const char *dn = chain->EECname();
5287  if (GMAPFun) {
5288  XrdSutCERef ceref;
5289  bool rdlock = false;
5290  XrdSutCacheArg_t arg = {kCE_ok, now, GMAPCacheTimeOut, -1};
5291  XrdSutCacheEntry *cent = cacheGMAPFun.Get(dn, rdlock, QueryGMAPCheck, (void *) &arg);
5292  if (!cent) {
5293  PRINT("unable to get a valid entry from cache for dn: " << dn);
5294  return;
5295  }
5296  ceref.Set(&(cent->rwmtx));
5297 
5298  // Check if we need to get/update the content
5299  if (!rdlock) {
5300  // Run the search via the external function
5301  char *name = (*GMAPFun)(dn, now);
5302  if (name) {
5303  cent->status = kCE_ok;
5304  // Add username
5305  SafeDelArray(cent->buf1.buf);
5306  cent->buf1.buf = name;
5307  cent->buf1.len = strlen(name);
5308  }
5309  // Fill up the rest
5310  cent->cnt = 0;
5311  cent->mtime = now; // creation time
5312  }
5313  // Retrieve result form cache
5314  usrs = cent->buf1.buf;
5315  // We are done with the cache
5316  ceref.UnLock();
5317  }
5318 
5319  // Check the map file, if any
5320  //
5321  if (servGMap) {
5322  char u[65];
5323  if (servGMap->dn2user(dn, u, sizeof(u), now) == 0) {
5324  if (usrs.length() > 0) usrs += ",";
5325  usrs += (const char *)u;
5326  }
5327  }
5328 
5329  // Done
5330  return;
5331 }
5332 
5333 //_____________________________________________________________________________
5334 XrdSecgsiGMAP_t XrdSecProtocolgsi::LoadGMAPFun(const char *plugin,
5335  const char *parms)
5336 {
5337  // Load the DN-Username mapping function from the specified plug-in
5338  EPNAME("LoadGMAPFun");
5339  char errBuff[2048];
5340 
5341  // Make sure the input config file is defined
5342  if (!plugin || strlen(plugin) <= 0) {
5343  PRINT("plug-in file undefined");
5344  return (XrdSecgsiGMAP_t)0;
5345  }
5346 
5347  // Create the plug-in instance
5348  XrdOucPinLoader gmapLib(errBuff,sizeof(errBuff),gsiVersion,"gmaplib",plugin);
5349 
5350  // Use global symbols?
5351  bool useglobals = 0;
5352  XrdOucString params, ps(parms), p;
5353  int from = 0;
5354  while ((from = ps.tokenize(p, from, '|')) != -1) {
5355  if (p == "useglobals") {
5356  useglobals = 1;
5357  } else {
5358  if (params.length() > 0) params += " ";
5359  params += p;
5360  }
5361  }
5362  DEBUG("params: '"<< params<<"'; useglobals: "<<useglobals);
5363 
5364  // Get the function
5365  XrdSecgsiGMAP_t ep = 0;
5366  if (useglobals) gmapLib.Global(true);
5367  ep = (XrdSecgsiGMAP_t) gmapLib.Resolve("XrdSecgsiGMAPFun");
5368 
5369  if (!ep) {
5370  PRINT(errBuff);
5371  PRINT("could not find 'XrdSecgsiGMAPFun()' in "<<plugin);
5372  return (XrdSecgsiGMAP_t)0;
5373  }
5374 
5375  // Init it
5376  if ((*ep)(params.c_str(), 0) == (char *)-1) {
5377  PRINT("could not initialize 'XrdSecgsiGMAPFun()'");
5378  return (XrdSecgsiGMAP_t)0;
5379  }
5380 
5381  // Notify
5382  PRINT("using 'XrdSecgsiGMAPFun()' from "<<plugin);
5383 
5384  // Done
5385  return ep;
5386 }
5387 
5388 //_____________________________________________________________________________
5389 XrdSecgsiAuthz_t XrdSecProtocolgsi::LoadAuthzFun(const char *plugin,
5390  const char *parms, int &certfmt)
5391 {
5392  // Load the authorization function from the specified plug-in.
5393  // The plug-in must contain three functions, to be all declared as 'extern C'.
5394  //
5395  // 1. The main function:
5396  //
5397  // int XrdSecgsiAuthzFun(XrdSecEntity &entity)
5398  //
5399  // here entity is the XrdSecEntity object associated with the handshake on the
5400  // server side. On input entity contains:
5401  // - in 'name' the username, DN, DN hash according to the GMAP option
5402  // - in 'host' the client hostname
5403  // - in 'creds'the proxy chain
5404  // The proxy chain can be either in 'raw' or 'PEM base64' format (see below).
5405  // This function returns
5406  // 0 on success
5407  // <0 on error (implies authentication failure)
5408  //
5409  // 2. The initialization function:
5410  //
5411  // int XrdSecgsiAuthzInit(const char *)
5412  //
5413  // here 'parameters' is the string of parameters, separated by ' '.
5414  // This function return <0 in case of failure or the format type of the proxy chain
5415  // expected by the main function:
5416  // 0 raw, to be used with XrdCrypto tools
5417  // 1 PEM (base64 standard string)
5418  //
5419  // 3. The key function:
5420  //
5421  // int XrdSecgsiAuthzKey(XrdSecEntity &entity, char **key)
5422  //
5423  // here entity is the XrdSecEntity object associated with the handshake on the
5424  // server side. On input entity contains in 'creds' the proxy chain, with the same
5425  // convention for the format as above. The function is expecetd to fill in '*key'
5426  // the key to be used to cache the result of the main function and to return the
5427  // length of the key. The key will be destroyed with 'delete []', so it must be
5428  // allocated internally with 'new char[]'.
5429  //
5430  EPNAME("LoadAuthzFun");
5431  char errBuff[2048];
5432 
5433  certfmt = -1;
5434  // Make sure the input config file is defined
5435  if (!plugin || strlen(plugin) <= 0) {
5436  PRINT("plug-in file undefined");
5437  return (XrdSecgsiAuthz_t)0;
5438  }
5439 
5440  // Create the plug-in instance
5441  XrdOucPinLoader authzLib(errBuff,sizeof(errBuff),gsiVersion,"authzlib",plugin);
5442 
5443  // Use global symbols?
5444  bool useglobals = 0;
5445  XrdOucString params, ps(parms), p;
5446  int from = 0;
5447  while ((from = ps.tokenize(p, from, '|')) != -1) {
5448  if (p == "useglobals") {
5449  useglobals = 1;
5450  } else {
5451  if (params.length() > 0) params += " ";
5452  params += p;
5453  }
5454  }
5455  DEBUG("params: '"<< params<<"'; useglobals: "<<useglobals);
5456 
5457  // Get the function
5458  XrdSecgsiAuthz_t ep = 0;
5459  if (useglobals) authzLib.Global(true);
5460  ep = (XrdSecgsiAuthz_t) authzLib.Resolve("XrdSecgsiAuthzFun");
5461  if (!ep) {
5462  PRINT(errBuff);
5463  PRINT("could not find 'XrdSecgsiAuthzFun()' in "<<plugin);
5464  return (XrdSecgsiAuthz_t)0;
5465  }
5466 
5467  // Get the key function
5468  AuthzKey = (XrdSecgsiAuthzKey_t) authzLib.Resolve("XrdSecgsiAuthzKey");
5469  if (!AuthzKey) {
5470  PRINT(errBuff);
5471  PRINT("could not find 'XrdSecgsiAuthzKey()' in "<<plugin);
5472  return (XrdSecgsiAuthz_t)0;
5473  }
5474 
5475  // Get the init function
5476  XrdSecgsiAuthzInit_t epinit = 0;
5477  epinit = (XrdSecgsiAuthzInit_t) authzLib.Resolve("XrdSecgsiAuthzInit");
5478  if (!epinit) {
5479  PRINT("could not find 'XrdSecgsiAuthzInit()' in "<<plugin);
5480  return (XrdSecgsiAuthz_t)0;
5481  }
5482 
5483  // Init it
5484  if ((certfmt = (*epinit)(params.c_str())) == -1) {
5485  PRINT("problems executing 'XrdSecgsiAuthzInit()' (rc: "<<certfmt<<")");
5486  return (XrdSecgsiAuthz_t)0;
5487  }
5488 
5489  // Notify
5490  PRINT("using 'XrdSecgsiAuthzFun()' from "<<plugin);
5491 
5492  // Done
5493  return ep;
5494 }
5495 
5496 //_____________________________________________________________________________
5497 XrdSecgsiVOMS_t XrdSecProtocolgsi::LoadVOMSFun(const char *plugin,
5498  const char *parms, int &certfmt)
5499 {
5500  // Load the authorization function from the specified plug-in.
5501  // The plug-in must contain two functions, to be all declared as 'extern C'.
5502  //
5503  // 1. The main function:
5504  //
5505  // int XrdSecgsiVOMSFun(XrdSecEntity &entity)
5506  //
5507  // here entity is the XrdSecEntity object associated with the handshake on the
5508  // server side. On input entity contains:
5509  // - in 'name' the username, DN, DN hash according to the GMAP option
5510  // - in 'host' the client hostname
5511  // - in 'creds'the proxy chain
5512  // The proxy chain can be either in 'raw' or 'PEM base64' format (see below).
5513  // This function returns
5514  // 0 on success
5515  // <0 on error (implies authentication failure)
5516  //
5517  // 2. The initialization function:
5518  //
5519  // int XrdSecgsiVOMSInit(const char *)
5520  //
5521  // here 'parameters' is the string of parameters, separated by ' '.
5522  // This function return <0 in case of failure or the format type of the proxy chain
5523  // expected by the main function:
5524  // 0 raw, to be used with XrdCrypto tools
5525  // 1 PEM (base64 standard string)
5526  //
5527  EPNAME("LoadVOMSFun");
5528  char errBuff[2048];
5529 
5530  certfmt = -1;
5531  // Make sure the input config file is defined
5532  if (!plugin || strlen(plugin) <= 0) {
5533  PRINT("plug-in file undefined");
5534  return (XrdSecgsiAuthz_t)0;
5535  }
5536 
5537  // Create the plug-in instance
5538  XrdOucPinLoader vomsLib(errBuff,sizeof(errBuff),gsiVersion,"vomslib",plugin);
5539 
5540  // Use global symbols?
5541  bool useglobals = 0;
5542  XrdOucString params, ps(parms), p;
5543  int from = 0;
5544  while ((from = ps.tokenize(p, from, '|')) != -1) {
5545  if (p == "useglobals") {
5546  useglobals = 1;
5547  } else {
5548  if (params.length() > 0) params += " ";
5549  params += p;
5550  }
5551  }
5552  DEBUG("params: '"<< params<<"'; useglobals: "<<useglobals);
5553 
5554  // Get the function
5555  XrdSecgsiVOMS_t ep = 0;
5556  if (useglobals) vomsLib.Global(true);
5557  ep = (XrdSecgsiVOMS_t) vomsLib.Resolve("XrdSecgsiVOMSFun");
5558  if (!ep) {
5559  PRINT(errBuff);
5560  PRINT("could not find 'XrdSecgsiVOMSFun()' in "<<plugin);
5561  return (XrdSecgsiAuthz_t)0;
5562  }
5563 
5564  // Get the init function
5565  XrdSecgsiVOMSInit_t epinit = 0;
5566  epinit = (XrdSecgsiVOMSInit_t) vomsLib.Resolve("XrdSecgsiVOMSInit");
5567  if (!epinit) {
5568  PRINT(errBuff);
5569  PRINT("could not find 'XrdSecgsiVOMSInit()' in "<<plugin);
5570  return (XrdSecgsiVOMS_t)0;
5571  }
5572 
5573  // Init it
5574  if ((certfmt = (*epinit)(params.c_str())) == -1) {
5575  PRINT("problems executing 'XrdSecgsiVOMSInit()' (rc: "<<certfmt<<")");
5576  return (XrdSecgsiVOMS_t)0;
5577  }
5578 
5579  // Notify
5580  PRINT("using 'XrdSecgsiVOMSFun()' from "<<plugin);
5581 
5582  // Done
5583  return ep;
5584 }
5585 
5586 
5587 //_____________________________________________________________________________
5588 bool XrdSecProtocolgsi::ServerCertNameOK(const char *subject, const char *hname, XrdOucString &emsg)
5589 {
5590  // Check that the server certificate subject name is consistent with the
5591  // expectations defined by the static SrvAllowedNames
5592 
5593  // The subject must be defined
5594  if (!subject || strlen(subject) <= 0) return 0;
5595 
5596  bool allowed = 0;
5597  emsg = "";
5598 
5599  // The server subject and its CN
5600  String srvsubj(subject);
5601  String srvcn;
5602  int cnidx = srvsubj.find("CN=");
5603  if (cnidx != STR_NPOS) srvcn.assign(srvsubj, cnidx + 3);
5604 
5605  // Always check if the server CN is in the standard form "[*/]<target host name>[/*]"
5606  if (hname) {
5607  size_t ih = srvcn.find("/");
5608  if (ih != std::string::npos) {
5609  srvcn.erasefromstart(ih + 1);
5610  }
5611  allowed = XrdCryptoX509::MatchHostnames(srvcn.c_str(), hname);
5612 
5613  // Update the error msg, if the case
5614  if (!allowed) {
5615  if (emsg.length() <= 0) {
5616  emsg = "server certificate CN '"; emsg += srvcn;
5617  emsg += "' does not match the expected format(s):";
5618  }
5619  String defcn("[*/]"); defcn += hname; defcn += "[/*]";
5620  emsg += " '"; emsg += defcn; emsg += "' (default)";
5621  }
5622  }
5623 
5624  // Take into account specific requests, if any
5625  if (SrvAllowedNames.length() > 0) {
5626  // The SrvAllowedNames string contains the allowed formats separated by a '|'.
5627  // The specifications can contain the <host> or <fqdn> placeholders which
5628  // are replaced by hname; they can also contain the '*' wildcard, in
5629  // which case XrdOucString::matches is used. A '-' before the specification
5630  // will deny the matching CN's; the last matching wins.
5631  String allowedfmts(SrvAllowedNames);
5632  allowedfmts.replace("<host>", hname);
5633  allowedfmts.replace("<fqdn>", hname);
5634  int from = 0;
5635  String fmt;
5636  while ((from = allowedfmts.tokenize(fmt, from, '|')) != -1) {
5637  // Check if this should be denied
5638  bool deny = 0;
5639  if (fmt.beginswith("-")) {
5640  deny = 1;
5641  fmt.erasefromstart(1);
5642  }
5643  if (srvcn.matches(fmt.c_str()) > 0) allowed = (deny) ? 0 : 1;
5644  }
5645  // Update the error msg, if the case
5646  if (!allowed) {
5647  if (emsg.length() <= 0) {
5648  emsg = "server certificate CN '"; emsg += srvcn;
5649  emsg += "' does not match the expected format:";
5650  }
5651  emsg += " '"; emsg += SrvAllowedNames; emsg += "' (exceptions)";
5652  }
5653  }
5654  // Reset error msg, if the match was successful
5655  if (allowed)
5656  emsg = "";
5657  else
5658  emsg += "; exceptions are controlled by the env XrdSecGSISRVNAMES";
5659 
5660  // Done
5661  return allowed;
5662 }
5663 
5664 //_____________________________________________________________________________
5665 static bool GetSrvCertEntCheck(XrdSutCacheEntry *e, void *a) {
5666  int st_ref = (*((XrdSutCacheArg_t *)a)).arg1;
5667  time_t ts_ref = (time_t)(*((XrdSutCacheArg_t *)a)).arg2;
5668  if (e) {
5669  if (e->status > st_ref) {
5670  if (e->mtime >= ts_ref)
5671  return true;
5672  }
5673  }
5674  return false;
5675 }
5676 
5677 //_____________________________________________________________________________
5678 XrdSutCacheEntry *XrdSecProtocolgsi::GetSrvCertEnt(XrdSutCERef &ceref,
5679  XrdCryptoFactory *cf,
5680  time_t timestamp, String &certcalist)
5681 {
5682  // Get cache entry for server certificate. This function checks the cache
5683  // and loads or re-loads the certificate form the specified files if required.
5684  // make sure we got what we need
5685  EPNAME("GetSrvCertEnt");
5686 
5687  if (!cf) {
5688  PRINT("Invalid inputs");
5689  return (XrdSutCacheEntry *)0;
5690  }
5691 
5692  bool rdlock = false;
5693  XrdSutCacheArg_t arg = {kCE_allowed, timestamp, -1, -1};
5694  XrdSutCacheEntry *cent = cacheCert.Get(cf->Name(), rdlock, GetSrvCertEntCheck, (void *) &arg);
5695  if (!cent) {
5696  PRINT("unable to get a valid entry from cache for " << cf->Name());
5697  return (XrdSutCacheEntry *)0;
5698  }
5699  ceref.Set(&(cent->rwmtx));
5700 
5701  // Are we done ?
5702  if (rdlock) return cent;
5703  if (cent->buf1.buf) PRINT("entry has expired: trying to renew ...");
5704 
5705  // Try get one or renew-it
5706  if (cent->status == kCE_special) {
5707  // Try init proxies
5708  ProxyIn_t pi = {SrvCert.c_str(), SrvKey.c_str(), CAdir.c_str(),
5709  UsrProxy.c_str(), PxyValid.c_str(), 0, 512, false};
5710  X509Chain *ch = 0;
5711  XrdCryptoRSA *k = 0;
5712  XrdSutBucket *b = 0;
5713  ProxyOut_t po = {ch, k, b };
5714  // We lock inside
5715  ceref.UnLock(false);
5716  if (QueryProxy(0, &cacheCert, cf->Name(), cf, timestamp, &pi, &po) != 0) {
5717  PRINT("proxy expired and cannot be renewed");
5718  return (XrdSutCacheEntry *)0;
5719  }
5720  // When successful we return read-locked (this flow needs checking; but it is not mainstream)
5721  ceref.ReadLock();
5722  return cent;
5723  }
5724 
5725  // Reset the entry
5726  XrdCryptoX509 *buf1 = (XrdCryptoX509*) cent->buf1.buf;
5727  XrdSutBucket *buf3 = (XrdSutBucket*) cent->buf3.buf;
5728 
5729  if (buf1)
5730  delete buf1; // Destroys also xsrv->PKI() pointed in cent->buf2.buf
5731  if (buf3)
5732  delete buf3;
5733 
5734  cent->buf1.buf = nullptr;
5735  cent->buf2.buf = nullptr;
5736  cent->buf3.buf = nullptr;
5737 
5738  //
5739  // Get the IDs of the file: we need them to acquire the right privileges when opening
5740  // the certificate
5741  uid_t gsi_uid = geteuid();
5742  gid_t gsi_gid = getegid();
5743  struct stat st;
5744  if (!stat(SrvKey.c_str(), &st)) {
5745  if (st.st_uid != gsi_uid || st.st_gid != gsi_gid) {
5746  gsi_uid = st.st_uid;
5747  gsi_gid = st.st_gid;
5748  }
5749  }
5750 
5751  // Check normal certificates
5752  XrdCryptoX509 *xsrv = cf->X509(SrvCert.c_str(), SrvKey.c_str());
5753  if (xsrv) {
5754  // Must be of EEC type
5755  if (xsrv->type != XrdCryptoX509::kEEC) {
5756  PRINT("problems loading srv cert: not EEC but: "<<xsrv->Type());
5757  SafeDelete(xsrv);
5758  ceref.UnLock();
5759  return (XrdSutCacheEntry *)0;
5760  }
5761  // Must be valid
5762  if (!(xsrv->IsValid())) {
5763  PRINT("problems loading srv cert: invalid");
5764  SafeDelete(xsrv);
5765  ceref.UnLock();
5766  return (XrdSutCacheEntry *)0;
5767  }
5768  // PKI must have been successfully initialized
5769  if (!xsrv->PKI() || xsrv->PKI()->status != XrdCryptoRSA::kComplete) {
5770  PRINT("problems loading srv cert: invalid PKI");
5771  SafeDelete(xsrv);
5772  ceref.UnLock();
5773  return (XrdSutCacheEntry *)0;
5774  }
5775  // Must be exportable
5776  XrdSutBucket *xbck = xsrv->Export();
5777  if (!xbck) {
5778  PRINT("problems loading srv cert: cannot export into bucket");
5779  SafeDelete(xsrv);
5780  ceref.UnLock();
5781  return (XrdSutCacheEntry *)0;
5782  }
5783  // We must have the issuing CA certificate
5784  int rcgetca = 0;
5785  if ((rcgetca = GetCA(xsrv->IssuerHash(), cf)) != 0) {
5786  String emsg(xsrv->IssuerHash());
5787  // Try different name hash, if it makes sense
5788  if (strcmp(xsrv->IssuerHash(1), xsrv->IssuerHash(0))) {
5789  if ((rcgetca = GetCA(xsrv->IssuerHash(1), cf)) != 0) {
5790  emsg += "|";
5791  emsg += xsrv->IssuerHash(1);
5792  }
5793  }
5794  if (rcgetca != 0) {
5795  // We do not have it, really
5796  if (rcgetca == -1) {
5797  PRINT("do not have certificate for the issuing CA '"<<emsg<<"'");
5798  } else {
5799  PRINT("failed to load certificate for the issuing CA '"<<emsg<<"'");
5800  }
5801  SafeDelete(xsrv);
5802  SafeDelete(xbck);
5803  ceref.UnLock();
5804  return (XrdSutCacheEntry *)0;
5805  }
5806  }
5807 
5808  // Ok: save it into the cache
5809  cent->status = kCE_ok;
5810  cent->cnt = 0;
5811  cent->mtime = xsrv->NotAfter(); // expiration time
5812 
5813  // Save pointer to certificate (destroys also xsrv->PKI())
5814  if (cent->buf1.buf)
5815  delete (XrdCryptoX509 *) cent->buf1.buf;
5816  cent->buf1.buf = (char *)xsrv;
5817  cent->buf1.len = 0; // just a flag
5818 
5819  // Save pointer to key
5820  cent->buf2.buf = (char *)(xsrv->PKI());
5821  cent->buf2.len = 0; // just a flag
5822 
5823  // Save pointer to bucket
5824  if (cent->buf3.buf)
5825  delete (XrdSutBucket *) cent->buf3.buf;
5826  cent->buf3.buf = (char *)(xbck);
5827  cent->buf3.len = 0; // just a flag
5828 
5829  // Save CA hash in list to communicate to clients
5830  if (certcalist.find(xsrv->IssuerHash()) == STR_NPOS) {
5831  if (certcalist.length() > 0) certcalist += "|";
5832  certcalist += xsrv->IssuerHash();
5833  }
5834  // Save also old CA hash in list to communicate to clients, if relevant
5835  if (HashCompatibility && xsrv->IssuerHash(1) &&
5836  strcmp(xsrv->IssuerHash(1),xsrv->IssuerHash())) {
5837  if (certcalist.find(xsrv->IssuerHash(1)) == STR_NPOS) {
5838  if (certcalist.length() > 0) certcalist += "|";
5839  certcalist += xsrv->IssuerHash(1);
5840  }
5841  }
5842  } else {
5843  PRINT("failed to load certificate from files ("<< SrvCert <<","<<SrvKey<<")");
5844  }
5845 
5846  // When successful we return read-locked; need to write-unlock before to avoid dead locking
5847  ceref.UnLock(false);
5848  ceref.ReadLock();
5849 
5850  // Done
5851  return cent;
5852 }
5853 
int kXR_int32
Definition: XPtypes.hh:89
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define TRACE_Debug
Definition: XrdCmsTrace.hh:37
#define QTRACE(act)
Definition: XrdCmsTrace.hh:49
void XrdCryptoSetTrace(kXR_int32 trace)
Definition: XrdCryptoAux.cc:49
static XrdSysError eDest(0,"crypto_")
#define cryptoTRACE_Notify
Definition: XrdCryptoAux.hh:49
#define cryptoTRACE_Dump
Definition: XrdCryptoAux.hh:47
#define cryptoTRACE_Debug
Definition: XrdCryptoAux.hh:48
#define XrdCryptoDefRSABits
Definition: XrdCryptoAux.hh:53
int(* XrdCryptoX509ChainToFile_t)(XrdCryptoX509Chain *, const char *)
int(* XrdCryptoX509CreateProxy_t)(const char *, const char *, XrdProxyOpt_t *, XrdCryptogsiX509Chain *, XrdCryptoRSA **, const char *)
int(* XrdCryptoX509SignProxyReq_t)(XrdCryptoX509 *, XrdCryptoRSA *, XrdCryptoX509Req *, XrdCryptoX509 **)
int(* XrdCryptoX509ParseBucket_t)(XrdSutBucket *, XrdCryptoX509Chain *)
XrdSutBucket *(* XrdCryptoX509ExportChain_t)(XrdCryptoX509Chain *, bool)
int(* XrdCryptoX509ParseFile_t)(const char *fname, XrdCryptoX509Chain *, const char *)
int(* XrdCryptoX509CreateProxyReq_t)(XrdCryptoX509 *, XrdCryptoX509Req **, XrdCryptoRSA **)
const int kOptsCheckSubCA
#define PRINT(y)
XrdOucGMap * XrdOucgetGMap(XrdOucGMapArgs)
Definition: XrdOucGMap.cc:92
#define STR_NPOS
int access(const char *path, int amode)
int closedir(DIR *dirp)
DIR * opendir(const char *path)
#define fopen(a, b)
Definition: XrdPosix.hh:54
#define stat(a, b)
Definition: XrdPosix.hh:101
#define readdir(a)
Definition: XrdPosix.hh:86
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
static bool GetCACheck(XrdSutCacheEntry *e, void *a)
static const char * gGSErrStr[]
static const char * gsiServerSteps[]
static bool QueryProxyCheck(XrdSutCacheEntry *e, void *a)
static const int kOneDay
XrdSecProtocol * XrdSecProtocolgsiObject(const char mode, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *erp)
static const char * gNoPadTag
static const char * ServerStepStr(int ksrv)
static const char * gUsrPxyDef
static const kXR_int32 Version
static String ProtoID
static bool GetSrvCertEntCheck(XrdSutCacheEntry *e, void *a)
static bool QueryGMAPCheck(XrdSutCacheEntry *e, void *a)
XrdVERSIONINFO(XrdSecProtocolgsiObject, secgsi)
#define POPTS(t, y)
static String Prefix
static const char * gsiClientSteps[]
char * XrdSecProtocolgsiInit(const char mode, const char *parms, XrdOucErrInfo *erp)
static bool AuthzFunCheck(XrdSutCacheEntry *e, void *a)
XrdOucTrace * gsiTrace
static const char * ClientStepStr(int kclt)
@ kOptsDelChn
@ kOptsDelPxy
@ kOptsSigReq
@ kOptsFwdPxy
@ kOptsPxCred
@ kOptsSrvReq
@ kOptsDlgPxy
@ kOptsCreatePxy
@ kOptsPxFile
#define SafeDelete(x)
const char * valid
int(* XrdSecgsiAuthz_t)(XrdSecEntity &)
XrdSutBucket * cbck
const char * out
XrdCryptoRSA * ksig
XrdCryptogsiX509Chain X509Chain
const char * key
#define REL2(x, y)
@ kXGS_cert
@ kXGS_none
@ kXGS_pxyreq
@ kXGS_init
@ kXGS_reserved
XrdSecgsiAuthz_t XrdSecgsiVOMS_t
int(* XrdSecgsiAuthzKey_t)(XrdSecEntity &, char **)
#define XrdSecgsiVersCertKey
#define XrdSecgsiVersDHsigned
@ kgST_ok
@ kgST_error
@ kgST_more
#define SafeFree(x)
int(* XrdSecgsiAuthzInit_t)(const char *)
char *(* XrdSecgsiGMAP_t)(const char *, int)
const char * cert
#define SafeDelArray(x)
#define XrdCryptoMax
@ kXGC_sigpxy
@ kXGC_cert
@ kXGC_reserved
@ kXGC_none
@ kXGC_certreq
#define XrdSecPROTOIDLEN
XrdSecgsiAuthzInit_t XrdSecgsiVOMSInit_t
#define REL3(x, y, z)
@ kGSErrExportPuK
@ kGSErrBadRndmTag
@ kGSErrNoCipher
@ kGSErrInit
@ kGSErrParseBuffer
@ kGSErrBadProtocol
@ kGSErrNoPublic
@ kGSErrSerialBuffer
@ kGSErrDecodeBuffer
@ kGSErrBadOpt
@ kGSErrAddBucket
@ kGSErrError
@ kGSErrCreateBucket
@ kGSErrNoBuffer
#define XrdSecPROTOIDENT
#define XrdSecgsiVERSION
X509Chain * chain
#define XrdSecNOIPCHK
#define XrdSecgsiVersRtagHash
#define TRACE_Authen
Definition: XrdSecTrace.hh:62
#define LIB_XRDVOMS
XrdCryptoX509ParseFile_t ParseFile
XrdOucString CAdir
XrdOucString CRLdir
bool Debug
XrdOucString CryptoMod
#define kXRSrtagMDMax
int XrdSecgsiRtagDigest(XrdCryptoFactory *cf, const char *rtag, int len, char *out, int outmax)
bool XrdSecgsiRtagIsValid(const char *rtag, int len)
#define NOTIFY(y)
int ncrypt
XrdOucString DefCrypto
XrdOucString CryptList
XrdCryptoFactory ** CF
void ParseCrypto()
struct myOpts opts
int emsg(int rc, char *msg)
int XrdSutParseTime(const char *tstr, int opt)
Definition: XrdSutAux.cc:534
int XrdSutExpand(XrdOucString &path)
Definition: XrdSutAux.cc:360
int XrdSutResolve(XrdOucString &path, const char *ho, const char *vo, const char *gr, const char *us)
Definition: XrdSutAux.cc:419
const char * XrdSutHome()
Definition: XrdSutAux.cc:459
const char * XrdSutBuckStr(int kbck)
Definition: XrdSutAux.cc:121
void XrdSutSetTrace(kXR_int32 trace)
Definition: XrdSutAux.cc:93
@ kXRS_issuer_hash
Definition: XrdSutAux.hh:80
@ kXRS_user
Definition: XrdSutAux.hh:65
@ kXRS_signed_rtag
Definition: XrdSutAux.hh:64
@ kXRS_cipher_alg
Definition: XrdSutAux.hh:82
@ kXRS_rtag
Definition: XrdSutAux.hh:63
@ kXRS_version
Definition: XrdSutAux.hh:71
@ kXRS_message
Definition: XrdSutAux.hh:68
@ kXRS_x509
Definition: XrdSutAux.hh:79
@ kXRS_puk
Definition: XrdSutAux.hh:61
@ kXRS_cipher
Definition: XrdSutAux.hh:62
@ kXRS_main
Definition: XrdSutAux.hh:58
@ kXRS_x509_req
Definition: XrdSutAux.hh:81
@ kXRS_md_alg
Definition: XrdSutAux.hh:83
@ kXRS_cryptomod
Definition: XrdSutAux.hh:57
@ kXRS_clnt_opts
Definition: XrdSutAux.hh:76
#define sutTRACE_Notify
Definition: XrdSutAux.hh:100
#define sutTRACE_Debug
Definition: XrdSutAux.hh:99
#define sutTRACE_Dump
Definition: XrdSutAux.hh:98
@ kCE_special
@ kCE_ok
@ kCE_allowed
@ kCE_disabled
@ kCE_inactive
if(Avsz)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE(act, x)
Definition: XrdTrace.hh:63
#define TRACE_ALL
Definition: XrdTrace.hh:35
#define ID
void Add(T *t)
void Del(T *t)
virtual int Length() const
virtual char * Buffer() const
virtual void SetIV(int l, const char *iv)
virtual int Decrypt(const char *in, int lin, char *out)
virtual int DecOutLength(int l)
virtual char * RefreshIV(int &l)
virtual int Encrypt(const char *in, int lin, char *out)
virtual int MaxIVLength() const
virtual XrdSutBucket * AsBucket()
virtual char * Public(int &lpub)
virtual bool IsValid()
virtual int EncOutLength(int l)
virtual bool Finalize(bool padded, char *pub, int lpub, const char *t)
virtual bool HasPaddingSupport()
virtual XrdCryptoX509ParseBucket_t X509ParseBucket()
virtual XrdCryptoX509CreateProxyReq_t X509CreateProxyReq()
virtual XrdCryptoX509 * X509(const char *cf, const char *kf=0)
virtual void SetTrace(kXR_int32 trace)
virtual XrdCryptoX509ParseFile_t X509ParseFile()
virtual XrdCryptoX509CreateProxy_t X509CreateProxy()
virtual XrdCryptoX509ChainToFile_t X509ChainToFile()
char * Name() const
virtual XrdCryptoCipher * Cipher(const char *t, int l=0)
virtual XrdCryptoRSA * RSA(int b=0, int e=0)
virtual bool SupportedMsgDigest(const char *dgst)
virtual XrdCryptoMsgDigest * MsgDigest(const char *dgst)
virtual XrdCryptoX509Crl * X509Crl(const char *crlfile, int opt=0)
static XrdCryptoFactory * GetCryptoFactory(const char *factoryname)
virtual bool SupportedCipher(const char *t)
virtual XrdCryptoX509Req * X509Req(XrdSutBucket *bck)
virtual XrdCryptoX509SignProxyReq_t X509SignProxyReq()
virtual XrdCryptoX509ExportChain_t X509ExportChain()
virtual void Notify()
virtual int Update(const char *b, int l)
virtual int Reset(const char *dgst)
virtual int ExportPrivate(char *out, int lout)
ERSAStatus status
Definition: XrdCryptoRSA.hh:58
virtual int EncryptPrivate(const char *in, int lin, char *out, int lout)
virtual int GetOutlen(int lin)
Definition: XrdCryptoRSA.cc:59
virtual int ImportPrivate(const char *in, int lin)
Definition: XrdCryptoRSA.cc:99
virtual int DecryptPublic(const char *in, int lin, char *out, int lout)
virtual int GetPrilen()
Definition: XrdCryptoRSA.cc:75
bool IsValid()
Definition: XrdCryptoRSA.hh:69
virtual int ExportPublic(char *out, int lout)
Definition: XrdCryptoRSA.cc:91
bool CheckCA(bool checkselfsigned=1)
XrdCryptoX509 * Next()
virtual int CheckValidity(bool outatfirst=1, int when=0)
XrdCryptoX509 * Begin()
XrdCryptoX509 * End() const
void Cleanup(bool keepCA=0)
void Remove(XrdCryptoX509 *c)
void SetStatusCA(ECAStatus st)
void PushBack(XrdCryptoX509 *c)
const char * X509ChainError(EX509ChainErr e)
XrdCryptoX509 * EffCA() const
const char * LastError() const
void PutInFront(XrdCryptoX509 *c)
virtual const char * IssuerHash(int)
virtual bool IsExpired(int when=0)
virtual bool Verify(XrdCryptoX509 *ref)
virtual XrdSutBucket * Export()
void SetVersion(int v)
virtual const char * Subject()
const char * Type(EX509Type t=kUnknown) const
virtual bool MatchesSAN(const char *fqdn, bool &hasSAN)=0
virtual XrdCryptoRSA * PKI()
virtual const char * SubjectHash(int)
virtual time_t NotBefore()
virtual const char * IssuerHash(int)
virtual XrdSutBucket * Export()
static bool MatchHostnames(const char *match_pattern, const char *fqdn)
virtual bool IsValid(int when=0)
virtual time_t NotAfter()
EX509Type type
bool Verify(EX509ChainErr &e, x509ChainVerifyOpt_t *vopt=0)
static const int noPort
Do not add port number.
static bool isHostName(const char *name)
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtName
Hostname if it is resolvable o/w use fmtAddr.
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
const char * getErrText()
int setErrInfo(int code, const char *emsg)
XrdOucEnv * getEnv()
virtual int dn2user(const char *dn, char *user, int ulen, time_t now=0)
Definition: XrdOucGMap.cc:292
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
int erasefromstart(int sz=0)
bool endswith(char c)
bool beginswith(char c)
int erase(int start=0, int size=0)
int matches(const char *s, char wch=' *')
int replace(const char *s1, const char *s2, int from=0, int to=-1)
int find(const char c, int start=0, bool forward=1)
int length() const
int form(const char *fmt,...)
int tokenize(XrdOucString &tok, int from, char del=':')
char * GetToken(char **rest=0, int lowcase=0)
bool Add(XrdSecAttr &attr)
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
int credslen
Length of the 'creds' data.
Definition: XrdSecEntity.hh:78
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
XrdSecEntityAttr * eaAPI
non-const API to attributes
Definition: XrdSecEntity.hh:92
const char * tident
Trace identifier always preset.
Definition: XrdSecEntity.hh:81
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * caps
Entity's capabilities.
Definition: XrdSecEntity.hh:74
char * creds
Raw entity credentials or cert.
Definition: XrdSecEntity.hh:77
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
char * endorsements
Protocol specific endorsements.
Definition: XrdSecEntity.hh:75
char * moninfo
Information for monitoring.
Definition: XrdSecEntity.hh:76
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70
XrdSecEntity Entity
static XrdOucTrace * EnableTracing()
int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)
int Verify(const char *inbuf, int inlen, const char *sigbuf, int siglen)
XrdSecProtocolgsi(int opts, const char *hname, XrdNetAddrInfo &endPoint, const char *parms=0)
int Decrypt(const char *inbuf, int inlen, XrdSecBuffer **outbuf)
int Encrypt(const char *inbuf, int inlen, XrdSecBuffer **outbuf)
void Delete()
Delete the protocol object. DO NOT use C++ delete() on this object.
static char * Init(gsiOptions o, XrdOucErrInfo *erp)
XrdSecCredentials * getCredentials(XrdSecParameters *parm=0, XrdOucErrInfo *einfo=0)
int getKey(char *kbuf=0, int klen=0)
int Sign(const char *inbuf, int inlen, XrdSecBuffer **outbuf)
int setKey(char *kbuf, int klen)
kXR_int32 type
Definition: XrdSutBucket.hh:46
kXR_int32 size
Definition: XrdSutBucket.hh:47
int SetBuf(const char *nb=0, int ns=0)
void ToString(XrdOucString &s)
void Update(char *nb=0, int ns=0, int ty=0)
Definition: XrdSutBucket.cc:95
int AddBucket(char *bp=0, int sz=0, int ty=0)
Definition: XrdSutBuffer.hh:59
int UpdateBucket(const char *bp, int sz, int ty)
int Serialized(char **buffer, char opt='n')
const char * GetOptions() const
Definition: XrdSutBuffer.hh:87
void SetStep(int s)
Definition: XrdSutBuffer.hh:90
void Dump(const char *stepstr=0, bool all=false)
int GetStep() const
Definition: XrdSutBuffer.hh:89
XrdSutBucket * GetBucket(kXR_int32 type, const char *tag=0)
kXR_int32 MarshalBucket(kXR_int32 type, kXR_int32 code)
const char * GetProtocol() const
Definition: XrdSutBuffer.hh:88
void Deactivate(kXR_int32 type)
kXR_int32 UnmarshalBucket(kXR_int32 type, kXR_int32 &code)
void UnLock(bool reset=true)
void ReadLock(XrdSysRWLock *lock=0)
void Set(XrdSysRWLock *lock)
XrdSysRWLock rwmtx
XrdSutCacheEntryBuf buf2
XrdSutCacheEntryBuf buf1
XrdSutCacheEntryBuf buf3
XrdSutCacheEntry * Get(const char *tag)
Definition: XrdSutCache.hh:54
void SetBuf(const char *b=0, kXR_int32 l=0)
kXR_int32 len
kXR_int32 mtime
XrdSutPFBuf buf1
XrdSutPFBuf buf4
static int GetRndmTag(XrdOucString &rtag)
Definition: XrdSutRndm.cc:235
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
XrdSutPFEntry * Cref
X509Chain * PxyChain
XrdCryptoX509Crl * Crl
XrdSutBuffer * Parms
XrdSutBucket * Cbck
void Dump(XrdSecProtocolgsi *p=0)
X509Chain * Chain
XrdSutPFEntry * Pent
XrdCryptoCipher * Rcip
void Print(XrdOucTrace *t)
XrdSysLogger Logger
Definition: XrdGlobals.cc:47
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.