XRootD
Loading...
Searching...
No Matches
XrdSecProtocolsss.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 s s s . c c */
4/* */
5/* (c) 2008 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#if !defined(__FreeBSD__)
32#include <alloca.h>
33#endif
34#include <cctype>
35#include <iostream>
36#include <cstdlib>
37#include <cstring>
38#include <strings.h>
39#include <cstdio>
40#include <sys/param.h>
41#include <unistd.h>
42
43#include "XrdVersion.hh"
44
45#include "XrdNet/XrdNetUtils.hh"
46#include "XrdOuc/XrdOucCRC.hh"
48#include "XrdOuc/XrdOucEnv.hh"
49#include "XrdOuc/XrdOucPup.hh"
51#include "XrdOuc/XrdOucUtils.hh"
55#include "XrdSys/XrdSysE2T.hh"
58
59/******************************************************************************/
60/* D e f i n e s */
61/******************************************************************************/
62
63#define XrdsssPROTOIDENT "sss"
64
65#define CLDBG(x) if (sssDEBUG) std::cerr<<"sec_sss: "<<x<<'\n'<<std::flush
66
67/******************************************************************************/
68/* L o c a l C l a s s e s */
69/******************************************************************************/
70
71namespace
72{
73class Persona
74{
75public:
77char *xAuth;
78char *xUser;
79char *xGrup;
80char *name;
81char *host;
82char *vorg;
83char *role;
84char *grps;
85char *caps;
86char *endo;
87char *creds;
88int credslen;
89char *pident;
90
91 Persona(XrdSecsssKT::ktEnt *kP)
92 : kTab(kP),
93 xAuth(nullptr),
94 xUser(nullptr),
95 xGrup(nullptr),
96 name(nullptr),
97 host(nullptr),
98 vorg(nullptr),
99 role(nullptr),
100 grps(nullptr),
101 caps(nullptr),
102 endo(nullptr),
103 creds(nullptr),
104 credslen(0),
105 pident(nullptr)
106 {}
107
108bool Clonable(const char *aTypes)
109 {char aKey[XrdSecPROTOIDSIZE+2];
110 if (!xAuth || !name || !pident
111 || !(kTab->Data.Opts & XrdSecsssKT::ktEnt::allUSR)) return false;
112 int n = strlen(xAuth);
113 if (n < 2 || n >= XrdSecPROTOIDSIZE) return false;
114 *aKey = ':';
115 strcpy(aKey+1, xAuth);
116 return strstr(aTypes, aKey) != 0;
117 }
118 };
119
120// Struct to manage dynamically allocated data buffer
121//
122struct sssRR_DataHdr
123{
125
126 sssRR_DataHdr() : P(0) {}
127 ~sssRR_DataHdr() {if (P) free(P);}
128};
129}
130
131/******************************************************************************/
132/* S t a t i c D a t a */
133/******************************************************************************/
134
135XrdCryptoLite *XrdSecProtocolsss::CryptObj = 0;
136XrdSecsssKT *XrdSecProtocolsss::ktObject = 0;
137XrdSecsssID *XrdSecProtocolsss::idMap = 0;
138char *XrdSecProtocolsss::aProts = 0;
139XrdSecsssEnt *XrdSecProtocolsss::staticID = 0;
140int XrdSecProtocolsss::deltaTime =13;
141bool XrdSecProtocolsss::isMutual = false;
142bool XrdSecProtocolsss::isMapped = false;
143bool XrdSecProtocolsss::ktFixed = false;
144
145struct XrdSecProtocolsss::Crypto XrdSecProtocolsss::CryptoTab[] = {
147 {0, '0'}
148 };
149
150namespace
151{
152XrdSysMutex initMutex;
153
154bool sssDEBUG = false;
155bool sssUseKN = false;
156}
157
158/******************************************************************************/
159/* A u t h e n t i c a t e */
160/******************************************************************************/
161
163 XrdSecParameters **parms,
164 XrdOucErrInfo *einfo)
165{
166 static const int minLen = sizeof(XrdSecsssRR_Hdr) + XrdSecsssRR_Data_HdrLen;
167 static const int maxLen = XrdSecsssRR_Data::MaxDSz + minLen;
168 static const int Special= XrdSecsssKT::ktEnt::anyUSR
170
171 XrdSecsssRR_Hdr *rrHdr = (XrdSecsssRR_Hdr *)(cred->buffer);
172 XrdSecsssRR_Data *rrData;
173 XrdSecsssKT::ktEnt decKey;
174 Persona myID(&decKey);
175
176 char *idP = 0, *dP = 0, *eodP = 0, *theIP = 0, *theHost = 0, *atKey = 0, eType = '\0';
177 int idNum = 0, idTLen, idSz, dLen;
178 bool badAttr = false;
179
180// Make sure we have atleast the header plus the data header
181//
182 if (cred->size < minLen)
183 return Fatal(einfo, "Auth", EINVAL, "Credentials too small.");
184
185// Make sure the credentials are not too big (people misuse sss)
186//
187 if (cred->size > maxLen)
188 return Fatal(einfo, "Auth", EINVAL, "Credentials too big.");
189
190// Allocate the buffer from the stack
191//
192 rrData = (XrdSecsssRR_Data *)alloca(cred->size);
193
194// Decode the credentials
195//
196 if ((dLen = Decode(einfo, decKey, cred->buffer, rrData, cred->size)) <= 0)
197 return -1;
198
199// Check if we should echo back the LID
200//
202 {XrdSecsssRR_DataResp rrResp;
203 char lidBuff[16];
204 rrResp.Options = 0;
205 getLID(lidBuff, sizeof(lidBuff));
206 dP = rrResp.Data;
208 XrdOucPup::Pack(&dP, lidBuff);
209 int n = dP-rrResp.Data + XrdSecsssRR_Data_HdrLen;
210 *parms = Encode(einfo, decKey, rrHdr, &rrResp, n);
211 return (*parms ? 1 : -1);
212 }
213
214// Extract out the entity information
215//
216 dP = rrData->Data; eodP = dP + dLen - XrdSecsssRR_Data_HdrLen;
217 CLDBG("Processing " <<dLen <<" byes");
218 while(dP < eodP)
219 {eType = *dP++;
220 CLDBG("eType=" <<static_cast<int>(eType)
221 <<" Used " <<dP-rrData->Data <<" left " <<eodP-dP);
222 if (!XrdOucPup::Unpack(&dP, eodP, &idP, idSz) || (idP && *idP == '\0'))
223 {Fatal(einfo, "Authenticate", EINVAL, "Invalid id string.");
224 return -1;
225 }
226 idNum++;
227 switch(eType)
228 {case XrdSecsssRR_Data::theName: myID.name = idP; break;
229 case XrdSecsssRR_Data::theVorg: myID.vorg = idP; break;
230 case XrdSecsssRR_Data::theRole: myID.role = idP; break;
231 case XrdSecsssRR_Data::theGrps: myID.grps = idP; break;
232 case XrdSecsssRR_Data::theEndo: myID.endo = idP; break;
233 case XrdSecsssRR_Data::theCred: myID.creds = idP;
234 myID.credslen = idSz;break;
236 if (idP && *idP == '[')
237 myID.host = theIP = idP;
238
239 else theHost = idP;
240 break;
241 case XrdSecsssRR_Data::theRand: idNum--; break;
242
243 case XrdSecsssRR_Data::theAuth: myID.xAuth = idP; break;
244
245 case XrdSecsssRR_Data::theTID: myID.pident = idP; break;
246 case XrdSecsssRR_Data::theAKey: if (atKey) badAttr = true;
247 atKey = idP; break;
249 if (!atKey) badAttr = true;
250 else {Entity.eaAPI->Add(std::string(atKey),
251 std::string(idP), true);
252 atKey = 0;
253 }
254 break;
255 case XrdSecsssRR_Data::theUser: myID.xUser = idP; break;
256 case XrdSecsssRR_Data::theGrup: myID.xGrup = idP; break;
257 case XrdSecsssRR_Data::theCaps: myID.caps = idP; break;
258 default: break;
259 }
260 }
261
262// Verify that we have some kind of identification
263//
264 if (!idNum)
265 {Fatal(einfo, "Authenticate", ENOENT, "No identification specified.");
266 return -1;
267 }
268
269// Make sure we didn't encounter any attribute errors
270//
271 if (badAttr)
272 {Fatal(einfo, "Authenticate", EINVAL, "Invalid attribute specification.");
273 return -1;
274 }
275
276// Verify the source of the information to largely prevent packet stealing. New
277// version of the protocol will send an IP address which we prefrentially use.
278// Older version used a hostname. This causes problems for multi-homed machines.
279//
280if (!(decKey.Data.Opts & XrdSecsssKT::ktEnt::noIPCK))
281 {if (!theHost && !theIP)
282 {Fatal(einfo,"Authenticate",ENOENT,"No hostname or IP address specified.");
283 return -1;
284 }
285 CLDBG(urName <<' ' <<urIP <<" or " <<urIQ << " must match "
286 <<(theHost ? theHost : "?") <<' ' <<(theIP ? theIP : "[?]"));
287 if (theIP)
288 {if (strcmp(theIP, urIP) && strcmp(theIP, urIQ))
289 {Fatal(einfo, "Authenticate", EINVAL, "IP address mismatch.");
290 return -1;
291 }
292 } else if (strcmp(theHost, urName))
293 {Fatal(einfo, "Authenticate", EINVAL, "Hostname mismatch.");
294 return -1;
295 }
296 } else {
297 CLDBG(urName <<' ' <<urIP <<" or " <<urIQ << " forwarded token from "
298 <<(theHost ? theHost : "?") <<' ' <<(theIP ? theIP : "[?]"));
299 }
300
301// At this point we need to check if this identity can be passed as a clone
302//
303 if (aProts && myID.Clonable(aProts))
304 {strlcpy(Entity.prot, myID.xAuth, sizeof(Entity.prot));
305 Entity.prot[XrdSecPROTOIDSIZE-1] = 0;
306 if (myID.xUser) XrdOucUtils::getUID(myID.xUser,Entity.uid,&Entity.gid);
307 if (myID.xGrup) XrdOucUtils::getGID(myID.xGrup,Entity.gid);
308 } else {
309 // Set correct username
310 //
311 if (decKey.Data.Opts & Special)
312 {if (!myID.name) myID.name = (char *)"nobody";}
313 else myID.name = decKey.Data.User;
314
315 // Set correct group
316 //
317 if (decKey.Data.Opts & XrdSecsssKT::ktEnt::usrGRP) myID.grps = 0;
318 else {if (decKey.Data.Opts & XrdSecsssKT::ktEnt::anyGRP)
319 {if (!myID.grps) myID.grps = (char *)"nogroup";}
320 else myID.grps = decKey.Data.Grup;
321 }
322
323 // Set corresponding uid and gid
324 //
325 if (myID.name) XrdOucUtils::getUID(myID.name, Entity.uid, &Entity.gid);
326 if (myID.grps) XrdOucUtils::getGID(myID.grps, Entity.gid);
327 }
328
329// Calculate the amount of space we will need
330//
331 idTLen = strlen(urName)
332 + (myID.name ? strlen(myID.name)+1 : 0)
333 + (myID.vorg ? strlen(myID.vorg)+1 : 0)
334 + (myID.role ? strlen(myID.role)+1 : 0)
335 + (myID.grps ? strlen(myID.grps)+1 : 0)
336 + (myID.caps ? strlen(myID.caps)+1 : 0)
337 + (myID.endo ? strlen(myID.endo)+1 : 0)
338 + (myID.creds ? myID.credslen : 0)
339 + (myID.pident ? strlen(myID.pident)+1 : 0);
340
341// Complete constructing our identification
342//
343 if (idBuff) free(idBuff);
344 idBuff = idP = (char *)malloc(idTLen);
345 Entity.host = urName;
346 Entity.name = setID(myID.name, &idP);
347 Entity.vorg = setID(myID.vorg, &idP);
348 Entity.role = setID(myID.role, &idP);
349 Entity.grps = setID(myID.grps, &idP);
350 Entity.caps = setID(myID.caps, &idP);
351 Entity.endorsements = setID(myID.endo, &idP);
352
353 if (myID.pident)
354 {strcpy(idP, myID.pident);
355 Entity.pident = idP;
356 idP += strlen(myID.pident) + 1;
357 }
358
359 if (myID.creds)
360 {memcpy(idP, myID.creds, myID.credslen);
361 Entity.creds = idP;
362 Entity.credslen = myID.credslen;
363 }
364
365// All done
366//
367 return 0;
368}
369
370/******************************************************************************/
371/* Private: D e c o d e */
372/******************************************************************************/
373
374int XrdSecProtocolsss::Decode(XrdOucErrInfo *error,
375 XrdSecsssKT::ktEnt &decKey,
376 char *iBuff,
377 XrdSecsssRR_DataHdr *rrDHdr,
378 int iSize)
379{
380 XrdSecsssRR_Hdr *rrHdr = (XrdSecsssRR_Hdr *)iBuff;
381 char *iData = iBuff+sizeof(XrdSecsssRR_Hdr);
382 int rc, genTime, dLen = iSize - sizeof(XrdSecsssRR_Hdr);
383
384// Check if this is a recognized protocol
385//
386 if (strcmp(rrHdr->ProtID, XrdsssPROTOIDENT))
387 {char emsg[256];
388 snprintf(emsg, sizeof(emsg),
389 "Authentication protocol id mismatch (%.4s != %.4s).",
390 XrdsssPROTOIDENT, rrHdr->ProtID);
391 return Fatal(error, "Decode", EINVAL, emsg);
392 }
393
394// Verify decryption method
395//
396 if (rrHdr->EncType != Crypto->Type())
397 return Fatal(error, "Decode", ENOTSUP, "Crypto type not supported.");
398
399// Check if this is a V2 client. V2 client always supply the keyname of the
400// key which we may or may not use. If specified, make sure it's correct.
401//
402 if (rrHdr->knSize)
403 {int knSize = static_cast<int>(rrHdr->knSize);
404 v2EndPnt = true;
405 if (knSize > XrdSecsssKT::ktEnt::NameSZ || knSize & 0x07
406 || knSize >= dLen || iData[knSize-1])
407 return Fatal(error, "Decode", EINVAL, "Invalid keyname specified.");
408 if (sssUseKN) strcpy(decKey.Data.Name, iData);
409 else decKey.Data.Name[0] = '\0';
410 CLDBG("V2 client using keyname '" <<iData <<"' dLen=" <<dLen
411 <<(sssUseKN ? "" : " (ignored)"));
412 iData += knSize; dLen -= knSize;
413 } else decKey.Data.Name[0] = '\0';
414
415// Get the key ID
416//
417 decKey.Data.ID = ntohll(rrHdr->KeyID);
418 if (keyTab->getKey(decKey, *decKey.Data.Name))
419 return Fatal(error, "Decode", ENOENT, "Decryption key not found.");
420
421// Decrypt
422//
423 CLDBG("Decode keyid: " <<decKey.Data.ID <<" bytes " <<dLen);
424 if ((rc = Crypto->Decrypt(decKey.Data.Val, decKey.Data.Len, iData, dLen,
425 (char *)rrDHdr, dLen)) <= 0)
426 return Fatal(error, "Decode", -rc, "Unable to decrypt credentials.");
427
428// Verify that the packet has not expired (OK to do before CRC check)
429//
430 genTime = ntohl(rrDHdr->GenTime);
431 if (genTime + deltaTime <= myClock())
432 return Fatal(error, "Decode", ESTALE,
433 "Credentials expired (check for clock skew).");
434
435// Return success (size of decrypted info)
436//
437 return rc;
438}
439
440/******************************************************************************/
441/* D e l e t e */
442/******************************************************************************/
443
445{
446// Delete things that get re-allocated every time. The staticID is allocated
447// only once so it must stick around for every instance of this object.
448//
449 if (urName) free(urName); // Same pointer as Entity.host
450 if (idBuff) free(idBuff);
451 if (Crypto && Crypto != CryptObj) delete Crypto;
452 if (keyTab && keyTab != ktObject) delete keyTab;
453
454 delete this;
455}
456
457/******************************************************************************/
458/* Private: e M s g */
459/******************************************************************************/
460
461int XrdSecProtocolsss::eMsg(const char *epname, int rc,
462 const char *txt1, const char *txt2,
463 const char *txt3, const char *txt4)
464{
465 std::cerr <<"Secsss (" << epname <<"): ";
466 std::cerr <<txt1;
467 if (rc>0) std::cerr <<"; " <<XrdSysE2T(rc);
468 if (txt2) std::cerr <<txt2;
469 if (txt3) std::cerr <<txt3;
470 if (txt4) {std::cerr <<txt4;}
471 std::cerr <<"\n" <<std::flush;
472
473 return (rc ? (rc < 0 ? rc : -rc) : -1);
474}
475
476/******************************************************************************/
477/* Private: E n c o d e */
478/******************************************************************************/
479
480XrdSecCredentials *XrdSecProtocolsss::Encode(XrdOucErrInfo *einfo,
481 XrdSecsssKT::ktEnt &encKey,
482 XrdSecsssRR_Hdr *rrHdr,
483 XrdSecsssRR_DataHdr *rrDHdr,
484 int dLen)
485{
486 char *credP;
487 int knum, cLen, hdrSZ = sizeof(XrdSecsssRR_Hdr) + rrHdr->knSize;
488
489// Make sure we don't overrun a 1 server's buffer. V2 servers are forgiving.
490//
491 if (!v2EndPnt && dLen > (int)sizeof(XrdSecsssRR_Data))
492 {Fatal(einfo,"Encode",ENOBUFS,"Insufficient buffer space for credentials.");
493 return (XrdSecCredentials *)0;
494 }
495
496// Complete the packet
497//
498 XrdSecsssKT::genKey(rrDHdr->Rand, sizeof(rrDHdr->Rand));
499 rrDHdr->GenTime = htonl(myClock());
500 memset(rrDHdr->Pad, 0, sizeof(rrDHdr->Pad));
501
502// Allocate an output buffer
503//
504 cLen = hdrSZ + dLen + Crypto->Overhead();
505 if (!(credP = (char *)malloc(cLen)))
506 {Fatal(einfo, "Encode", ENOMEM, "Insufficient memory for credentials.");
507 return (XrdSecCredentials *)0;
508 }
509
510// Copy the header and encrypt the data
511//
512 memcpy(credP, (const void *)rrHdr, hdrSZ);
513 CLDBG("Encode keyid: " <<encKey.Data.ID <<" bytes " <<cLen-hdrSZ);
514 if ((dLen = Crypto->Encrypt(encKey.Data.Val, encKey.Data.Len, (char *)rrDHdr,
515 dLen, credP+hdrSZ, cLen-hdrSZ)) <= 0)
516 {Fatal(einfo, "Encode", -dLen, "Unable to encrypt credentials.");
517 return (XrdSecCredentials *)0;
518 }
519
520// Return new credentials
521//
522 dLen += hdrSZ; knum = encKey.Data.ID&0x7fffffff;
523 CLDBG("Ret " <<dLen <<" bytes of credentials; k=" <<knum);
524 return new XrdSecCredentials(credP, dLen);
525}
526
527/******************************************************************************/
528/* Private: F a t a l */
529/******************************************************************************/
530
531int XrdSecProtocolsss::Fatal(XrdOucErrInfo *erP, const char *epn, int rc,
532 const char *etxt)
533{
534 if (erP) {erP->setErrInfo(rc, etxt);
535 CLDBG(epn <<": " <<etxt);
536 }
537 else eMsg(epn, rc, etxt);
538 return 0;
539}
540
541/******************************************************************************/
542/* Private: g e t C r e d */
543/******************************************************************************/
544
545int XrdSecProtocolsss::getCred(XrdOucErrInfo *einfo, XrdSecsssRR_DataHdr *&dP,
546 const char *myUrlID, const char *myIP)
547{
548 int dLen;
549
550// Indicate we have been here
551//
552 Sequence = 1;
553
554// For mutual authentication, the server needs to first send back a handshake.
555//
556 if (isMutual)
560 }
561
562// Otherwise we use a static ID or a mapped id. Note that we disallow sending
563// credentials unless mutual authentication occurs.
564//
565 if (myUrlID && idMap)
566 {if ((dLen = idMap->Find(myUrlID, (char *&)dP, myIP, dataOpts)) <= 0)
567 return Fatal(einfo, "getCred", ESRCH, "No loginid mapping.");
568 } else {
569 int theOpts = dataOpts & ~XrdSecsssEnt::addCreds;
570 dLen = staticID->RR_Data((char *&)dP, myIP, theOpts);
571 }
572
573// Return response length
574//
576 return dLen;
577}
578
579/******************************************************************************/
580
581int XrdSecProtocolsss::getCred(XrdOucErrInfo *einfo,
583 const char *myUrlID,
584 const char *myIP,
585 XrdSecParameters *parm)
586{
587 XrdSecsssKT::ktEnt decKey;
588 XrdSecsssRR_Data prData;
589 char *lidP = 0, *bP, *idP, *eodP, idType;
590 int idSz, dLen, theOpts;
591
592// Make sure we can decode this and not overrun our buffer
593//
594 if (parm->size > (int)sizeof(prData.Data))
595 return Fatal(einfo, "getCred", EINVAL, "Invalid server response size.");
596
597// Decode the credentials
598//
599 if ((dLen = Decode(einfo, decKey, parm->buffer, &prData, parm->size)) <= 0)
600 return Fatal(einfo, "getCred", EINVAL, "Unable to decode server response.");
601
602// Extract out the loginid. This messy code is for backwards compatibility.
603//
604 bP = prData.Data; eodP = dLen + (char *)&prData;
605 while(bP < eodP)
606 {idType = *bP++;
607 if (!XrdOucPup::Unpack(&bP, eodP, &idP, idSz) || !idP || *idP == 0)
608 return Fatal(einfo, "getCred", EINVAL, "Invalid id string.");
609 switch(idType)
610 {case XrdSecsssRR_Data::theLgid: lidP = idP; break;
611 case XrdSecsssRR_Data::theHost: break;
612 case XrdSecsssRR_Data::theRand: break;
613 default: return Fatal(einfo,"getCred",EINVAL,"Invalid id type.");
614 }
615 }
616
617// Verify that we have the loginid
618//
619 if (!lidP) return Fatal(einfo, "getCred", ENOENT, "No loginid returned.");
620
621// Try to map the id appropriately
622//
623 if (!idMap) return staticID->RR_Data((char *&)dP, myIP, dataOpts);
624
625// Map the loginid. We disallow sending credentials unless the key allows it.
626//
627 if (!myUrlID) myUrlID = lidP;
628 if (!(decKey.Data.Opts & XrdSecsssKT::ktEnt::allUSR))
629 theOpts = dataOpts & ~XrdSecsssEnt::addCreds;
630 else theOpts = dataOpts;
631 if ((dLen = idMap->Find(lidP, (char *&)dP, myIP, theOpts)) <= 0)
632 return Fatal(einfo, "getCred", ESRCH, "No loginid mapping.");
633
634// All done
635//
636 dP->Options = XrdSecsssRR_DataHdr::UseData;
637 return dLen;
638}
639
640/******************************************************************************/
641/* g e t C r e d e n t i a l s */
642/******************************************************************************/
643
645 XrdOucErrInfo *einfo)
646{
647 static const int nOpts = XrdNetUtils::oldFmt;
648 XrdSecsssRR_Hdr2 rrHdr;
649 sssRR_DataHdr rrDataHdr;
650 XrdSecsssKT::ktEnt encKey;
651 XrdOucEnv *errEnv;
652
653 const char *myIP = 0, *myUD = 0;
654 char ipBuff[64];
655 int dLen;
656
657// Make sure we can extract out required information and get it as needed
658//
659 if (einfo && (errEnv=einfo->getEnv()))
660 {if (isMapped) myUD = errEnv->Get("username");
661 if (!(myIP=errEnv->Get("sockname")))
662 {int fd = epAddr->SockFD();
663 if (fd > 0 && XrdNetUtils::IPFormat(-fd,ipBuff,sizeof(ipBuff),nOpts))
664 myIP = ipBuff;
665 else myIP = 0;
666 }
667 }
668
669// Do some debugging here
670//
671 CLDBG("getCreds: " <<static_cast<int>(Sequence)
672 << " ud: '" <<(myUD ? myUD : "")
673 <<"' ip: '" <<(myIP ? myIP : "") <<"'");
674
675// Get the actual data portion
676//
677 if (Sequence) dLen = getCred(einfo, rrDataHdr.P, myUD, myIP, parms);
678 else dLen = getCred(einfo, rrDataHdr.P, myUD, myIP);
679 if (!dLen) return (XrdSecCredentials *)0;
680
681// Get an encryption key
682//
683 if (keyTab->getKey(encKey))
684 {Fatal(einfo, "getCredentials", ENOENT, "Encryption key not found.");
685 return (XrdSecCredentials *)0;
686 }
687
688// Fill out the header
689//
690 strcpy(rrHdr.ProtID, XrdsssPROTOIDENT);
691 memset(rrHdr.Pad, 0, sizeof(rrHdr.Pad));
692 rrHdr.KeyID = htonll(encKey.Data.ID);
693 rrHdr.EncType = Crypto->Type();
694
695// Determine if we should send the keyname (v2 servers only)
696//
697 if (v2EndPnt)
698 {int k = strlen(encKey.Data.Name), n = (k + 8) & ~7;
699 if (strlcpy(rrHdr.keyName, encKey.Data.Name, sizeof(rrHdr.keyName)) >= sizeof(rrHdr.keyName))
700 { Fatal(einfo, "getCredentials", EINVAL, "Encryption key name is too long.");
701 return nullptr;
702 }
703 if (n - k > 1) memset(rrHdr.keyName + k, 0, n - k);
704 rrHdr.knSize = static_cast<uint8_t>(n);
705 } else rrHdr.knSize = 0;
706
707// Now simply encode the data and return the result
708//
709 return Encode(einfo, encKey, &rrHdr, rrDataHdr.P, dLen);
710}
711
712/******************************************************************************/
713/* Private: g e t L I D */
714/******************************************************************************/
715
716char *XrdSecProtocolsss::getLID(char *buff, int blen)
717{
718 const char *dot;
719
720// Extract out the loginid from the trace id
721//
722 if (!Entity.tident
723 || !(dot = index(Entity.tident,'.'))
724 || dot == Entity.tident
725 || dot >= (Entity.tident+blen)) strcpy(buff,"nobody");
726 else {int idsz = dot - Entity.tident;
727 strncpy(buff, Entity.tident, idsz);
728 *(buff+idsz) = '\0';
729 }
730
731// All done
732//
733 return buff;
734}
735
736/******************************************************************************/
737/* I n i t _ C l i e n t */
738/******************************************************************************/
739
741{
742 XrdSysMutexHelper initMon(&initMutex);
743 XrdSecsssKT *ktP;
744 struct stat buf;
745 char *Colon;
746 int lifeTime;
747
748// We must have <enccode>.[+]<lifetime>:<keytab>
749//
750 if (!pP || !*pP) return Fatal(erp, "Init_Client", EINVAL,
751 "Client parameters missing.");
752
753// Get encryption object
754//
755 if (!*pP || *(pP+1) != '.') return Fatal(erp, "Init_Client", EINVAL,
756 "Encryption type missing.");
757 if (!(Crypto = Load_Crypto(erp, *pP))) return 0;
758 pP += 2;
759
760// Check if this is a v2 server and if credentials are to be sent
761//
762 if (*pP == '+')
763 {v2EndPnt = true;
764 dataOpts |= XrdSecsssEnt::addExtra;
765 if (*(pP+1) == '0') dataOpts |= XrdSecsssEnt::addCreds;
766 }
767
768// The next item is the cred lifetime
769//
770 lifeTime = strtol(pP, &Colon, 10);
771 if (!lifeTime || *Colon != ':') return Fatal(erp, "Init_Client", EINVAL,
772 "Credential lifetime missing.");
773 deltaTime = lifeTime; pP = Colon+1;
774
775// Get the correct keytab
776//
777 if (ktFixed || (ktObject && ktObject->Same(pP))) keyTab = ktObject;
778 else if (*pP == '/' && !stat(pP, &buf))
779 {if (!(ktP=new XrdSecsssKT(erp,pP,XrdSecsssKT::isClient,3600)))
780 return Fatal(erp, "Init_Client", ENOMEM,
781 "Unable to create keytab object.");
782 if (erp->getErrInfo()) {delete ktP; return 0;}
783 if (!ktObject) ktObject = ktP;
784 keyTab = ktP;
785 CLDBG("Client keytab='" <<pP <<"'");
786 } else keyTab = ktObject;
787
788 if (!keyTab)
789 return Fatal(erp, "Init_Client", ENOENT,
790 "Unable to determine keytab location.");
791
792// All done
793//
794 return 1;
795}
796
797/******************************************************************************/
798/* I n i t _ S e r v e r */
799/******************************************************************************/
800
802{
803
804// This is a trivial init
805//
806 keyTab = ktObject;
807 Crypto = CryptObj;
808 return 1;
809}
810
811/******************************************************************************/
812/* L o a d _ C l i e n t */
813/******************************************************************************/
814
815char *XrdSecProtocolsss::Load_Client(XrdOucErrInfo *erp, const char *parms)
816{
817 static const char *KTPath = XrdSecsssKT::genFN();
818 static const int rfrHR = 60*60;
819 struct stat buf;
821 const char *kP = 0;
822 char *myName;
823
824// Get our full host name
825//
826 if (!(myName = XrdNetUtils::MyHostName(0)))
827 {Fatal(erp, "Load_Client", ENOENT, "Unable to obtain local hostname.");
828 return (char *)0;
829 }
830
831// Tell the entity serialization object who we are
832//
834 free(myName);
835
836// Check for the presence of a registry object
837//
838 idMap = XrdSecsssID::getObj(aType, staticID);
839 switch(aType)
840 {case XrdSecsssID::idDynamic: isMutual = true; break;
841 case XrdSecsssID::idStaticM: isMutual = true;
842 idMap = 0; break;
843 case XrdSecsssID::idStatic: idMap = 0; break;
844 case XrdSecsssID::idMapped: isMapped = true; break;
845 case XrdSecsssID::idMappedM: isMapped = true; break;
846 default: idMap = 0; break;
847 }
848
849// We want to establish the default location of the keytable. First check
850// the environment passed from the client then the envar. We support two
851// version of the envar for backward compatibility due to an early mistake.
852//
853 if( erp && erp->getEnv() && ( kP = erp->getEnv()->Get( "xrd.sss" ) ) )
854 ktFixed = true;
855 else if ( ( (kP = getenv("XrdSecSSSKT")) || (kP = getenv("XrdSecsssKT")) )
856 && *kP && !stat(kP, &buf))
857 ktFixed = true;
858 else kP = 0;
859
860 if (!kP && !stat(KTPath, &buf)) kP = KTPath;
861
862// Build the keytable if we actual have a path (if none, then the server
863// will have to supply the path)
864//
865 if (kP)
866 {if (!(ktObject=new XrdSecsssKT(erp,kP,XrdSecsssKT::isClient,rfrHR)))
867 {Fatal(erp, "Load_Client", ENOMEM, "Unable to create keytab object.");
868 return (char *)0;
869 }
870 if (erp && erp->getErrInfo())
871 {delete ktObject, ktObject = 0; return (char *)0;}
872 CLDBG("Client keytab='" <<kP <<"'");
873 }
874
875// All done
876//
877 return (char *)"";
878}
879
880/******************************************************************************/
881/* Private: L o a d _ C r y p t o */
882/******************************************************************************/
883
884XrdCryptoLite *XrdSecProtocolsss::Load_Crypto(XrdOucErrInfo *erp,
885 const char *eN)
886{
887 XrdCryptoLite *cP;
888 char buff[128];
889 int rc, i = 0;
890
891// Find correct crypto object
892//
893 while(CryptoTab[i].cName && strcmp(CryptoTab[i].cName, eN)) i++;
894
895// If we didn't find it, complain
896//
897 if (!CryptoTab[i].cName)
898 {sprintf(buff, "Secsss: %s cryptography not supported.", eN);
899 Fatal(erp, "Load_Crypto", EINVAL, buff);
900 return (XrdCryptoLite *)0;
901 }
902
903// Return load result
904//
905 if ((cP = XrdCryptoLite::Create(rc, eN, CryptoTab[i].cType))) return cP;
906 sprintf(buff,"Secsss: %s cryptography load failed; %s",eN,XrdSysE2T(rc));
907 Fatal(erp, "Load_Crypto", EINVAL, buff);
908 return (XrdCryptoLite *)0;
909}
910
911/******************************************************************************/
912
913XrdCryptoLite *XrdSecProtocolsss::Load_Crypto(XrdOucErrInfo *erp,
914 const char eT)
915{
916 XrdCryptoLite *cP;
917 char buff[128];
918 int rc, i = 0;
919
920// Check if we can use the satic object
921//
922 if (CryptObj && eT == CryptObj->Type()) return CryptObj;
923
924// Find correct crypto object
925//
926 while(CryptoTab[i].cName && CryptoTab[i].cType != eT) i++;
927
928// If we didn't find it, complain
929//
930 if (!CryptoTab[i].cName)
931 {sprintf(buff, "Secsss: 0x%hhx cryptography not supported.", eT);
932 Fatal(erp, "Load_Crypto", EINVAL, buff);
933 return (XrdCryptoLite *)0;
934 }
935
936// Return load result
937//
938 if ((cP = XrdCryptoLite::Create(rc, CryptoTab[i].cName, eT))) return cP;
939 sprintf(buff,"Secsss: 0x%hhx cryptography load failed; %s",eT,XrdSysE2T(rc));
940 Fatal(erp, "Load_Crypto", EINVAL, buff);
941 return (XrdCryptoLite *)0;
942}
943
944/******************************************************************************/
945/* L o a d _ S e r v e r */
946/******************************************************************************/
947
948char *XrdSecProtocolsss::Load_Server(XrdOucErrInfo *erp, const char *parms)
949{
950 const char *msg = 0;
951 const char *encName = "bf32", *ktClient = "", *ktServer = 0;
952 char buff[2048], parmbuff[2048], *op, *od, *eP;
953 int lifeTime = 13, rfrTime = 60*60;
954 XrdOucTokenizer inParms(parmbuff);
955 const char *ask4Creds = "";
956
957// Duplicate the parms
958//
959 if (parms) strlcpy(parmbuff, parms, sizeof(parmbuff));
960
961// Expected parameters: [{-c | --clientkt} <ckt_path>]
962// [{-e | --encrypt} <enctype>]
963// [{-g | --getcreds}]
964// [{-k | --keyname}]
965// [{-l | --lifetime} <seconds>]
966// [{-p | --proxy} <prots>]
967// [{-r | --refresh} <minutes>]
968// [{-s | --serverkt} <skt_path>]
969//
970 if (parms && inParms.GetLine())
971 while((op = inParms.GetToken()))
972 {if (!strcmp("-k", op) || !strcmp("--keyname", op))
973 {sssUseKN = true;
974 continue;
975 }
976 if (!strcmp("-g", op) || !strcmp("--getcreds", op))
977 {ask4Creds = "0";
978 continue;
979 }
980 if (!(od = inParms.GetToken()))
981 {sprintf(buff,"Secsss: Missing %s parameter argument",op);
982 msg = buff; break;
983 }
984 if (!strcmp("-c", op) || !strcmp("--clientkt", op))
985 ktClient = od;
986 else if (!strcmp("-e", op) || !strcmp("--encrypt", op))
987 encName = od;
988 else if (!strcmp("-l", op) || !strcmp("--lifetime", op))
989 {lifeTime = strtol(od, &eP, 10) * 60;
990 if (errno || *eP || lifeTime < 1)
991 {msg = "Secsss: Invalid life time"; break;}
992 }
993 else if (!strcmp("-p", op) || !strcmp("--proxy", op))
994 {int n = strlen(od) + 2;
995 aProts = (char *)malloc(n);
996 *aProts = ':';
997 strcpy(aProts+1, od);
998 }
999 else if (!strcmp("-r", op) || !strcmp("--rfresh", op))
1000 {rfrTime = strtol(od, &eP, 10) * 60;
1001 if (errno || *eP || rfrTime < 600)
1002 {msg = "Secsss: Invalid refresh time"; break;}
1003 }
1004 else if (!strcmp("-s", op) || !strcmp("-serverkt", op))
1005 ktServer = od;
1006 else {sprintf(buff,"Secsss: Invalid parameter - %s",op);
1007 msg = buff; break;
1008 }
1009 }
1010
1011// Check for errors
1012//
1013 if (msg) {Fatal(erp, "Load_Server", EINVAL, msg); return (char *)0;}
1014
1015// Load the right crypto object
1016//
1017 if (!(CryptObj = Load_Crypto(erp, encName))) return (char *)0;
1018
1019// Supply default keytab location if not specified
1020//
1021 if (!ktServer) ktServer = XrdSecsssKT::genFN();
1022
1023// Set the delta time used to expire credentials
1024//
1025 deltaTime = lifeTime;
1026
1027// Create a keytab object (only one for the server)
1028//
1029 if (!(ktObject = new XrdSecsssKT(erp, ktServer, XrdSecsssKT::isServer,
1030 rfrTime)))
1031 {Fatal(erp, "Load_Server", ENOMEM, "Unable to create keytab object.");
1032 return (char *)0;
1033 }
1034 if (erp->getErrInfo()) return (char *)0;
1035 ktFixed = true;
1036 CLDBG("Server keytab='" <<ktServer <<"'");
1037
1038// Construct client parameter <enccode>.+<lifetime>:<keytab>
1039// Note: The plus preceding the <lifetime> indicates that we are a V2 server.
1040// V1 clients will simply ignore this and treat us as a V1 server.
1041//
1042 sprintf(buff, "%c.+%s%d:%s", CryptObj->Type(),ask4Creds,lifeTime,ktClient);
1043 CLDBG("client parms='" <<buff <<"'");
1044 return strdup(buff);
1045}
1046
1047/******************************************************************************/
1048/* m y C l o c k */
1049/******************************************************************************/
1050
1051int XrdSecProtocolsss::myClock()
1052{
1053 static const time_t baseTime = 1222183880;
1054
1055 return static_cast<int>(time(0)-baseTime);
1056}
1057
1058/******************************************************************************/
1059/* s e t I D */
1060/******************************************************************************/
1061
1062char *XrdSecProtocolsss::setID(char *id, char **idP)
1063{
1064 if (id)
1065 {int n = strlen(id);
1066 strcpy(*idP, id); id = *idP; *idP = *idP + n + 1;
1067 }
1068 return id;
1069}
1070
1071/******************************************************************************/
1072/* s e t I P */
1073/******************************************************************************/
1074
1075void XrdSecProtocolsss::setIP(XrdNetAddrInfo &endPoint)
1076{
1077 if (!endPoint.Format(urIP, sizeof(urIP), XrdNetAddrInfo::fmtAdv6)) *urIP=0;
1078 if (!endPoint.Format(urIQ, sizeof(urIQ), XrdNetAddrInfo::fmtAdv6,
1079 XrdNetAddrInfo::old6Map4)) *urIQ=0;
1080 Entity.addrInfo = epAddr = &endPoint;
1081}
1082
1083/******************************************************************************/
1084/* X r d S e c P r o t o c o l s s s I n i t */
1085/******************************************************************************/
1086
1087extern "C"
1088{
1089char *XrdSecProtocolsssInit(const char mode,
1090 const char *parms,
1091 XrdOucErrInfo *erp)
1092{
1093
1094// Set debug option
1095//
1096 if (getenv("XrdSecDEBUG")) sssDEBUG = true;
1097
1098// Perform load-time initialization
1099//
1100 return (mode == 'c' ? XrdSecProtocolsss::Load_Client(erp, parms)
1101 : XrdSecProtocolsss::Load_Server(erp, parms));
1102}
1103}
1104
1105/******************************************************************************/
1106/* X r d S e c P r o t o c o l s s s O b j e c t */
1107/******************************************************************************/
1108
1110
1111extern "C"
1112{
1114 const char *hostname,
1115 XrdNetAddrInfo &endPoint,
1116 const char *parms,
1117 XrdOucErrInfo *erp)
1118{
1119 XrdSecProtocolsss *prot;
1120 int Ok;
1121
1122// Get a new protocol object
1123//
1124 if (!(prot = new XrdSecProtocolsss(endPoint.Name(hostname), endPoint)))
1125 XrdSecProtocolsss::Fatal(erp, "sss_Object", ENOMEM,
1126 "Secsss: Insufficient memory for protocol.");
1127 else {Ok = (mode == 'c' ? prot->Init_Client(erp, parms)
1128 : prot->Init_Server(erp, parms));
1129
1130 if (!Ok) {prot->Delete(); prot = 0;}
1131 }
1132
1133// All done
1134//
1135 return (XrdSecProtocol *)prot;
1136}
1137}
#define stat(a, b)
Definition XrdPosix.hh:101
#define XrdSecPROTOIDSIZE
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
#define CLDBG(x)
#define XrdsssPROTOIDENT
XrdSecProtocol * XrdSecProtocolsssObject(const char mode, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *erp)
XrdVERSIONINFO(XrdSecProtocolsssObject, secsss)
char * XrdSecProtocolsssInit(const char mode, const char *parms, XrdOucErrInfo *erp)
#define eMsg(x)
static const int XrdSecsssRR_Data_HdrLen
int emsg(int rc, char *msg)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
size_t strlcpy(char *dst, const char *src, size_t sz)
static XrdCryptoLite * Create(int &rc, const char *Name, const char Type='\0')
static const int old6Map4
Use deprecated IPV6 mapped format.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
const char * Name(const char *eName=0, const char **eText=0)
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
static int IPFormat(const struct sockaddr *sAddr, char *bP, int bL, int opts=0)
static const int oldFmt
char * Get(const char *varname)
Definition XrdOucEnv.hh:69
XrdOucEnv * getEnv()
int setErrInfo(int code, const char *emsg)
static int Unpack(char **buff, const char *bend, char **data, int &dlen)
Definition XrdOucPup.cc:250
static int Pack(struct iovec **, const char *, unsigned short &buff)
Definition XrdOucPup.cc:52
char * GetToken(char **rest=0, int lowcase=0)
static bool getGID(const char *gName, gid_t &gID)
static bool getUID(const char *uName, uid_t &uID, gid_t *gID=0)
const char * tident
Trace identifier always preset.
XrdSecEntity Entity
static int eMsg(const char *epn, int rc, const char *txt1, const char *txt2=0, const char *txt3=0, const char *txt4=0)
static char * Load_Client(XrdOucErrInfo *erp, const char *Parms)
int Init_Server(XrdOucErrInfo *erp, const char *Parms)
XrdSecCredentials * getCredentials(XrdSecParameters *parms=0, XrdOucErrInfo *einfo=0)
static char * Load_Server(XrdOucErrInfo *erp, const char *Parms)
int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)
static int Fatal(XrdOucErrInfo *erP, const char *epn, int rc, const char *etxt)
void Delete()
Delete the protocol object. DO NOT use C++ delete() on this object.
int Init_Client(XrdOucErrInfo *erp, const char *Parms)
static void setHostName(const char *hnP)
static const int addExtra
Add v2 data.
static const int addCreds
Add v2 data plus creds.
static const int anyUSR
struct XrdSecsssKT::ktEnt::ktData Data
static const int noIPCK
static const int anyGRP
static const int allUSR
static const int usrGRP
static const int NameSZ
static char * genFN()
static void genKey(char *Buff, int blen)
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.
static const char SndLID
static const char UseData
char Data[XrdSecsssRR_Data::MinDSz+16]
static const char theHost
static const char theUser
static const char theAKey
static const char theCaps
char Data[DataSz]
static const char theAuth
static const char theRole
static const char theName
static const char theLgid
static const char theGrps
static const char theRand
static const char theEndo
static const char theAVal
static const char theVorg
static const char theGrup
static const char theTID
static const int MaxDSz
static const char theCred
char keyName[XrdSecsssKT::ktEnt::NameSZ]
long long KeyID
static const char etBFish32