XRootD
Loading...
Searching...
No Matches
XrdSecTLayer.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d S e c T L a y e r . c c */
4/* */
5/* */
6/* (c) 2008 by the Board of Trustees of the Leland Stanford, Jr., University */
7/* All Rights Reserved */
8/* Produced by Andrew Hanushevsky for Stanford University under contract */
9/* DE-AC02-76-SFO0515 with the Department of Energy */
10/* */
11/* This file is part of the XRootD software suite. */
12/* */
13/* XRootD is free software: you can redistribute it and/or modify it under */
14/* the terms of the GNU Lesser General Public License as published by the */
15/* Free Software Foundation, either version 3 of the License, or (at your */
16/* option) any later version. */
17/* */
18/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
19/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
20/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
21/* License for more details. */
22/* */
23/* You should have received a copy of the GNU Lesser General Public License */
24/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
25/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
26/* */
27/* The copyright holder's institutional names and contributor's names may not */
28/* be used to endorse or promote products derived from this software without */
29/* specific prior written permission of the institution or contributor. */
30/******************************************************************************/
31
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <fcntl.h>
35#include <poll.h>
36#include <cstdio>
37#include <unistd.h>
38
41#include "XrdSys/XrdSysE2T.hh"
42#include "XrdSys/XrdSysFD.hh"
44
45/******************************************************************************/
46/* S t a t i c V a l u e s */
47/******************************************************************************/
48
49// Some compilers are incapable of optimizing away inline static const char's.
50//
51const char XrdSecTLayer::TLayerRR::endData;
52const char XrdSecTLayer::TLayerRR::xfrData;
53
54/******************************************************************************/
55/* C o n s t r u c t o r */
56/******************************************************************************/
57
58XrdSecTLayer::XrdSecTLayer(const char *pName, Initiator who1st)
59 : XrdSecProtocol(pName),
60 secTid(0), mySem(0), Starter(who1st), myFD(-1), urFD(-1),
61 Tmax(275), Tcur(0), eCode(0), eText(0)
62{
63
64// Do the standard stuff
65//
66 memset((void *)&Hdr, 0, sizeof(Hdr));
67 strncpy(Hdr.protName,pName,sizeof(Hdr.protName)-1);
68}
69
70/******************************************************************************/
71/* C l i e n t O r i e n t e d M e t h o d s */
72/******************************************************************************/
73/******************************************************************************/
74/* g e t C r e d e n t i a l s */
75/******************************************************************************/
76
78 XrdOucErrInfo *einfo)
79{
80 char Buff[dataSz];
81 int Blen = 0, wrLen = 0;
82 char *bP, Req = TLayerRR::xfrData;
83
84// If this is the first time call, perform boot-up sequence and start the flow
85//
86 eDest = einfo;
87 if (!parm)
88 {if (!bootUp(isClient)) return 0;
89 if (Starter == isServer)
90 {Hdr.protCode = TLayerRR::xfrData;
91 bP = (char *)malloc(hdrSz);
92 memcpy(bP, (char *)&Hdr, hdrSz);
93 return new XrdSecCredentials(bP, hdrSz);
94 }
95 } else {
96 if (parm->size < hdrSz)
97 {secError("Invalid parms length", EPROTO);
98 return 0;
99 }
100 Req = ((TLayerRR *)parm->buffer)->protCode;
101 wrLen= parm->size - hdrSz;
102 }
103
104// Perform required action
105// xfrData -> xfrData | endData if socket gets closed
106// endData -> endData if socket still open else protocol error
107//
108 switch(Req)
109 {case TLayerRR::xfrData:
110 if (wrLen > 0 && write(myFD, parm->buffer+hdrSz, wrLen) < 0)
111 {secError("Socket write failed", errno); return 0;}
112 Blen = Read(myFD, Buff, dataSz);
113 if (Blen < 0 && (Blen != -EPIPE) && (Blen != -ECONNRESET))
114 {secError("Socket read failed", -Blen); return 0;}
115 break;
116 case TLayerRR::endData:
117 if (myFD < 0) {secError("Protocol violation", EPROTO); return 0;}
118 Blen = -1;
119 break;
120 default: secError("Unknown parms request", EINVAL); return 0;
121 }
122
123// Set correct protocol code based on value in Blen. On the client side we
124// check for proper completion upon socket close or when we get endData.
125// Note that we apply self-pacing here as well since either side can pace,
126//
127 if (Blen < 0) {if (!secDone()) return 0;
128 Blen = 0; Hdr.protCode = TLayerRR::endData;}
129 else if (Blen || wrLen) {Tcur = 0; Hdr.protCode = TLayerRR::xfrData;}
130 else if (++Tcur <= Tmax) Hdr.protCode = TLayerRR::xfrData;
131 else {Tcur = 0; Hdr.protCode = TLayerRR::endData;}
132
133// Return the credentials
134//
135 bP = (char *)malloc(hdrSz+Blen);
136 memcpy(bP, (char *)&Hdr, hdrSz);
137 if (Blen) memcpy(bP+hdrSz, Buff, Blen);
138 return new XrdSecCredentials(bP, hdrSz+Blen);
139}
140
141/******************************************************************************/
142/* S e r v e r O r i e n t e d M e t h o d s */
143/******************************************************************************/
144
146 XrdSecParameters **parms,
147 XrdOucErrInfo *einfo)
148{
149 char Buff[dataSz];
150 int Blen = 0, wrLen;
151 char *bP, Req;
152
153// If this is the first time call, perform boot-up sequence and start the flow
154//
155 eDest = einfo;
156 if (myFD < 0 && !bootUp(isServer)) return -1;
157
158// Get the request code
159//
160 if (cred->size < hdrSz) {secError("Invalid credentials",EBADMSG); return -1;}
161 Req = ((TLayerRR *)cred->buffer)->protCode;
162 wrLen= cred->size - hdrSz;
163
164// Perform required action
165// xfrData -> xfrData | endData if socket gets closed
166// endData -> noresponse
167//
168 switch(Req)
169 {case TLayerRR::xfrData:
170 if (wrLen > 0 && write(myFD, cred->buffer+hdrSz, wrLen) < 0)
171 {secError("Socket write failed", errno); return -1;}
172 Blen = Read(myFD, Buff, dataSz);
173 if (Blen < 0 && (Blen != -EPIPE) && (Blen != -ECONNRESET))
174 {secError("Socket read failed", -Blen); return 0;}
175 break;
176 case TLayerRR::endData: return (secDone() ? 0 : -1);
177 default: secError("Unknown parms request", EINVAL); return -1;
178 }
179
180// Set correct protocol code based on value in Blen and wrLen. Note that if
181// both are zero then we decrease the pace count and bail if it reaches zero.
182// Otherwise, we reset the pace count to it initial value. On the server side,
183// we defer the socket drain until we receive a endData notification.
184//
185 if (Blen < 0) {Blen = 0; Hdr.protCode = TLayerRR::endData;}
186 else if (Blen || wrLen) {Tcur = 0; Hdr.protCode = TLayerRR::xfrData;}
187 else if (++Tcur <= Tmax) Hdr.protCode = TLayerRR::xfrData;
188 else {Tcur = 0; Hdr.protCode = TLayerRR::endData;}
189
190// Return the credentials
191//
192 bP = (char *)malloc(hdrSz+Blen);
193 memcpy(bP, (char *)&Hdr, hdrSz);
194 if (Blen) memcpy(bP+hdrSz, Buff, Blen);
195 *parms = new XrdSecParameters(bP, hdrSz+Blen);
196
197 return 1;
198}
199
200
201/******************************************************************************/
202/* P r i v a t e M e t h o d s */
203/******************************************************************************/
204/******************************************************************************/
205/* b o o t U p */
206/******************************************************************************/
207
208void *XrdSecTLayerBootUp(void *carg)
209 {XrdSecTLayer *tP = (XrdSecTLayer *)carg;
210 tP->secXeq();
211 return (void *)0;
212 }
213
214/******************************************************************************/
215
216int XrdSecTLayer::bootUp(Initiator whoami)
217{
218 int sv[2];
219
220// Create a socket pair
221//
222 if (XrdSysFD_Socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
223 {secError("Unable to create socket pair", errno); return 0;}
224 myFD = sv[0]; urFD = sv[1];
225 Responder = whoami;
226
227// Start a thread to handle the socket interaction
228//
230 {int rc = errno;
231 close(myFD); myFD = -1;
232 close(urFD); urFD = -1;
233 secError("Unable to create thread", rc);
234 return 0;
235 }
236
237// All done
238//
239 return 1;
240}
241
242/******************************************************************************/
243/* R e a d */
244/******************************************************************************/
245
246int XrdSecTLayer::Read(int FD, char *Buff, int rdLen)
247{
248 struct pollfd polltab = {FD, POLLIN|POLLRDNORM|POLLHUP, 0};
249 int retc, xWt, Tlen = 0;
250
251// Read the data. We will employ a self-pacing read schedule where the
252// assumptioon is that should a read produce zero bytes after a small amount
253// of time then the data supplier needs additional data (i.e., writes) before
254// it can supply data to be read. This occurs because certain transport layer
255// protocols issue several writes in a row to complete the client/server
256// interaction. We cannot use a fixed schedule for this because streams may
257// coalesce adjacent writes, sigh.
258
259// Compute the actual poll wait time
260//
261 if (Tcur) xWt = (Tcur+10)/10;
262 else xWt = 1;
263
264// Now do the interaction
265//
266 do {do {retc = poll(&polltab, 1, xWt);} while(retc < 0 && errno == EINTR);
267 if (retc <= 0) return (retc ? -errno : Tlen);
268 do {retc = read(FD, Buff, rdLen);} while(retc < 0 && errno == EINTR);
269 if (retc <= 0) return (retc ? -errno : (Tlen ? Tlen : -EPIPE));
270 Tlen += retc; Buff += retc; rdLen -= retc; xWt = 1;
271 } while(rdLen > 0);
272
273 return Tlen;
274}
275
276/******************************************************************************/
277/* s e c D o n e */
278/******************************************************************************/
279
280int XrdSecTLayer::secDone()
281{
282
283// First close the socket and wait for thread completion
284//
285 secDrain();
286
287// Next, check if everything went well
288//
289 if (!eCode) return 1;
290
291// Diagnose the problem and return failure
292//
293 secError((eText ? eText : "?"), eCode, 0);
294 return 0;
295}
296
297/******************************************************************************/
298/* s e c D r a i n */
299/******************************************************************************/
300
301void XrdSecTLayer::secDrain()
302{
303 if (myFD >= 0)
304 {close(myFD); myFD = -1;
305 mySem.Wait();
306 }
307}
308
309/******************************************************************************/
310/* s e c E r r n o */
311/******************************************************************************/
312
313const char *XrdSecTLayer::secErrno(int rc, char *buff)
314{
315 sprintf(buff, "err %d", rc);
316 return buff;
317}
318
319/******************************************************************************/
320/* s e c E r r o r */
321/******************************************************************************/
322
323void XrdSecTLayer::secError(const char *Msg, int rc, int iserrno)
324{
325 char buff[32];
326 const char *tlist[] = {"XrdSecProtocol", Hdr.protName, ": ", Msg, "; ",
327 (iserrno ? XrdSysE2T(rc) : secErrno(rc,buff))
328 };
329 int i, n = sizeof(tlist)/sizeof(const char *);
330
331 if (eDest) eDest->setErrInfo(rc, tlist, n);
332 else {for (i = 0; i < n; i++) std::cerr <<tlist[i]; std::cerr <<std::endl;}
333
334 secDrain();
335}
336
337/******************************************************************************/
338/* s e c X e q */
339/******************************************************************************/
340
342{
343 XrdOucErrInfo einfo;
344 const char *Msg;
345
346// Initiate the protocol
347//
348 if (Responder == XrdSecTLayer::isClient) secClient(urFD, &einfo);
349 else secServer(urFD, &einfo);
350// Extract out the completion code
351//
352 Msg = einfo.getErrText(eCode);
353 if (eText) {free(eText); eText = 0;}
354 if (eCode) eText = strdup(Msg ? Msg : "Authentication failed");
355
356// Indicate we are done
357//
358 if (urFD>0) close(urFD);
359 urFD = -1;
360 mySem.Post();
361}
static XrdSysError eDest(0,"crypto_")
#define close(a)
Definition XrdPosix.hh:43
#define write(a, b, c)
Definition XrdPosix.hh:110
#define read(a, b, c)
Definition XrdPosix.hh:77
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
void * XrdSecTLayerBootUp(void *carg)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:99
#define XRDSYSTHREAD_HOLD
const char * getErrText()
virtual void secClient(int theFD, XrdOucErrInfo *einfo)=0
virtual int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)
pthread_t secTid
virtual XrdSecCredentials * getCredentials(XrdSecParameters *parm=0, XrdOucErrInfo *einfo=0)
virtual void secServer(int theFD, XrdOucErrInfo *einfo)=0
XrdSecTLayer(const char *pName, Initiator who1st=isClient)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
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.