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