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