XRootD
XrdCmsLogin.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d C m s L o g i n . c c */
4 /* */
5 /* (c) 2007 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 #include <netinet/in.h>
32 #include <unistd.h>
33 
34 #include "XProtocol/YProtocol.hh"
35 
36 #include "Xrd/XrdLink.hh"
37 
39 #include "XrdCms/XrdCmsLogin.hh"
40 #include "XrdCms/XrdCmsParser.hh"
41 #include "XrdCms/XrdCmsTalk.hh"
42 #include "XrdCms/XrdCmsSecurity.hh"
43 #include "XrdCms/XrdCmsTrace.hh"
44 
45 #include "XrdOuc/XrdOucPup.hh"
46 
47 #include "XrdSys/XrdSysError.hh"
48 #include "XrdSys/XrdSysPthread.hh"
49 
50 using namespace XrdCms;
51 
52 /******************************************************************************/
53 /* Public: A d m i t */
54 /******************************************************************************/
55 
57  const char *sid, const char *envP)
58 {
59  CmsRRHdr myHdr;
60  CmsLoginData myData;
61  const char *eText, *Token;
62  int myDlen, Toksz;
63 
64 // Get complete request
65 //
66  if ((eText = XrdCmsTalk::Attend(Link, myHdr, myBuff, myBlen, myDlen)))
67  return Emsg(Link, eText, 0);
68 
69 // If we need to do authentication, do so now
70 //
71  if ((Token = XrdCmsSecurity::getToken(Toksz, Link->AddrInfo()))
72  && !XrdCmsSecurity::Authenticate(Link, Token, Toksz)) return 0;
73 
74 // Fiddle with the login data structures
75 //
76  Data.SID = Data.Paths = Data.ifList = Data.envCGI = 0;
77  memset(&myData, 0, sizeof(myData));
78  myData.Mode = Data.Mode;
79  myData.HoldTime = Data.HoldTime;
80  myData.Version = Data.Version = kYR_Version;
81 
82 // Decode the data pointers ans grab the login data
83 //
84  if (!Parser.Parse(&Data, myBuff, myBuff+myDlen))
85  return Emsg(Link, "invalid login data", 0);
86 
87 // Check if this node is blacklisted
88 //
89  if (!(Data.Mode & CmsLoginData::kYR_director))
90  {static const int rbsz = 1024;
91  char *rbP, rbuff[rbsz];
92  int rc;
93  rbP = (myData.Version <= Data.Version ? rbuff : 0);
94  rc = XrdCmsBlackList::Present(Link->Host(), 0, rbP, rbsz);
95  if (rc > 0) return SendErrorBL(Link, rbuff, rc);
96  else if (rc < 0) return SendErrorBL(Link);
97  }
98 
99 // Fill out additional information if the client can accept it
100 //
101  if (myData.Version <= Data.Version)
102  {myData.SID = (kXR_char *)sid;
103  myData.envCGI = (kXR_char *)envP;
104  }
105 
106 // Send off login reply
107 //
108  return (sendData(Link, myData) ? 0 : 1);
109 }
110 
111 /******************************************************************************/
112 /* Private: E m s g */
113 /******************************************************************************/
114 
115 int XrdCmsLogin::Emsg(XrdLink *Link, const char *msg, int ecode)
116 {
117  Say.Emsg("Login", Link->Name(), "login failed;", msg);
118  return ecode;
119 }
120 
121 /******************************************************************************/
122 /* Public: L o g i n */
123 /******************************************************************************/
124 
125 int XrdCmsLogin::Login(XrdLink *Link, CmsLoginData &Data, int timeout)
126 {
127  CmsRRHdr LIHdr;
128  char WorkBuff[4096], *hList, *wP = WorkBuff;
129  int n, dataLen;
130 
131 // We can accept permanent redirects so indicate this
132 //
134 
135 // Send the data and immediately clear the data structure of pointers
136 //
137  n = sendData(Link, Data);
138  Data.Paths = Data.SID = Data.envCGI = 0;
139  if (n) return kYR_EINVAL;
140 
141 // Get the response.
142 //
143  if ((n = Link->RecvAll((char *)&LIHdr, sizeof(LIHdr), timeout)) < 0)
144  return Emsg(Link, (n == -ETIMEDOUT ? "timed out" : "rejected"));
145 
146 // Receive and decode the response. We apparently have protocol version 2.
147 //
148  if ((dataLen = static_cast<int>(ntohs(LIHdr.datalen))))
149  {if (dataLen > (int)sizeof(WorkBuff))
150  return Emsg(Link, "login reply too long");
151  if (Link->RecvAll(WorkBuff, dataLen, timeout) < 0)
152  return Emsg(Link, "login receive error");
153  }
154 
155 // Check if we are being asked to identify ourselves
156 //
157  if (LIHdr.rrCode == kYR_xauth)
158  {if (!XrdCmsSecurity::Identify(Link, LIHdr, WorkBuff, sizeof(WorkBuff)))
159  return kYR_EINVAL;
160  dataLen = static_cast<int>(ntohs(LIHdr.datalen));
161  if (dataLen > (int)sizeof(WorkBuff))
162  return Emsg(Link, "login reply too long");
163  }
164 
165 // The response can also be a login redirect (i.e., a try request).
166 //
167  if (!(Data.Mode & CmsLoginData::kYR_director)
168  && LIHdr.rrCode == kYR_try)
169  {if (!XrdOucPup::Unpack(&wP, wP+dataLen, &hList, n))
170  return Emsg(Link, "malformed try host data");
171  Data.Paths = (kXR_char *)strdup(n ? hList : "");
172  if (!(LIHdr.modifier & CmsTryRequest::kYR_permtop))
174  return kYR_redirect;
175  }
176 
177 // Process error reply
178 //
179  if (LIHdr.rrCode == kYR_error)
180  {unsigned int eRC;
181  if (dataLen < (int)sizeof(kXR_unt32)+8)
182  return Emsg(Link, "invalid error reply");
183  Emsg(Link, WorkBuff+sizeof(kXR_unt32));
184  memcpy(&eRC, WorkBuff, sizeof(eRC));
185  eRC = ntohl(eRC);
186  return (eRC == kYR_EPERM ? -1 : kYR_EINVAL);
187  }
188 
189 // Process normal reply
190 //
191  if (LIHdr.rrCode != kYR_login
192  || !Parser.Parse(&Data, WorkBuff, WorkBuff+dataLen))
193  return Emsg(Link, "invalid login response");
194 
195 // Copy any strings that we are exporting
196 //
197  if (Data.SID) Data.SID = (kXR_char *)strdup((const char *)Data.SID);
198  if (Data.envCGI) Data.envCGI = (kXR_char *)strdup((const char *)Data.envCGI);
199  return 0;
200 }
201 
202 /******************************************************************************/
203 /* Private: s e n d D a t a */
204 /******************************************************************************/
205 
206 int XrdCmsLogin::sendData(XrdLink *Link, CmsLoginData &Data)
207 {
208  static const int xNum = 20;
209 
210  int n, iovcnt, iovnum;
211  char Work[xNum*12];
212  struct iovec Liov[xNum];
213  CmsRRHdr Resp={0, kYR_login, 0, 0};
214  static const int iovmax = XrdSys::getIovMax();
215 
216 // Pack the response (ignore the auth token for now)
217 //
218  if (!(iovcnt=Parser.Pack(kYR_login,&Liov[1],&Liov[xNum],(char *)&Data,Work)))
219  return Emsg(Link, "too much login data");
220 
221 // Complete I/O vector
222 //
223  Resp.datalen = Data.Size;
224  Liov[0].iov_base = (char *)&Resp;
225  Liov[0].iov_len = sizeof(Resp);
226 
227 // Send off the data *break it up to IOV_MAX chunks, mostly for Solaris)
228 //
229  n = 0; iovcnt++;
230  if (iovcnt <= iovmax) Link->Send(Liov, iovcnt);
231  else while(iovcnt > 0)
232  {iovnum = (iovcnt > iovmax ? iovmax : iovcnt);
233  Link->Send(&Liov[n], iovnum);
234  n += iovmax; iovcnt -= iovmax;
235  }
236 
237 // Return success
238 //
239  return 0;
240 }
241 
242 /******************************************************************************/
243 /* Private: S e n d E r r o r B L */
244 /******************************************************************************/
245 
246 int XrdCmsLogin::SendErrorBL(XrdLink *Link)
247 {
248  struct {CmsResponse rInfo;
249  char rText[512];
250  } rData;
251  const char *hName = Link->AddrInfo()->Name("???");
252  int n;
253 
254 // Format the message
255 //
256  n = snprintf(rData.rText, sizeof(rData.rText), "%s is blacklisted.", hName)
257  + sizeof(rData.rInfo.Val) + 1;
258 
259 // Construct response
260 //
261  rData.rInfo.Hdr.streamid = 0;
262  rData.rInfo.Hdr.rrCode = kYR_error;
263  rData.rInfo.Hdr.modifier = 0;
264  rData.rInfo.Hdr.datalen = htons(n);
265  rData.rInfo.Val = htonl(static_cast<unsigned int>(kYR_EPERM));
266 
267 // Send off the data
268 //
269  Link->Send((const char *)&rData, n + sizeof(CmsRRHdr));
270  return Emsg(Link, "blacklisted", 0);
271 }
272 
273 /******************************************************************************/
274 
275 int XrdCmsLogin::SendErrorBL(XrdLink *Link, char *rbuff, int rblen)
276 {
277  CmsRRHdr Rsp = {0, kYR_try, CmsTryRequest::kYR_permtop, htons((unsigned short int)rblen)};
278  struct iovec iov[2] = {{(char *)&Rsp, sizeof(Rsp)},
279  {rbuff, static_cast<size_t>(rblen)}};
280  char msgbuff[2048];
281 
282 // Send off the data
283 //
284  Link->Send(iov, 2, sizeof(Rsp) + rblen);
285 
286 // Compose the right message
287 //
288  snprintf(msgbuff, sizeof(msgbuff), "blacklisted; redirected to %s",
289  rbuff+sizeof(short));
290  return Emsg(Link, msgbuff, 0);
291 }
unsigned int kXR_unt32
Definition: XPtypes.hh:90
unsigned char kXR_char
Definition: XPtypes.hh:65
static int Present(const char *hName, XrdOucTList *bList=0, char *rbuff=0, int rblen=0)
int Admit(XrdLink *Link, XrdCms::CmsLoginData &Data, const char *sid, const char *envP)
Definition: XrdCmsLogin.cc:56
static int Login(XrdLink *Link, XrdCms::CmsLoginData &Data, int timeout=-1)
Definition: XrdCmsLogin.cc:125
static int Pack(int rnum, struct iovec *iovP, struct iovec *iovE, char *Base, char *Work)
int Parse(XrdCms::CmsLoginData *Data, const char *Aps, const char *Apt)
Definition: XrdCmsParser.hh:59
static const char * getToken(int &size, XrdNetAddrInfo *endPoint)
static int Authenticate(XrdLink *Link, const char *Token, int tlen)
static int Identify(XrdLink *Link, XrdCms::CmsRRHdr &inHdr, char *authBuff, int abLen)
static const char * Attend(XrdLink *Link, XrdCms::CmsRRHdr &Hdr, char *buff, int blen, int &rlen, int tmo=5000)
Definition: XrdCmsTalk.cc:46
const char * Name(const char *eName=0, const char **eText=0)
static int Unpack(char **buff, const char *bend, char **data, int &dlen)
Definition: XrdOucPup.cc:250
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
static const unsigned char kYR_Version
Definition: YProtocol.hh:80
kXR_unt16 datalen
Definition: YProtocol.hh:86
@ kYR_EINVAL
Definition: YProtocol.hh:153
@ kYR_EPERM
Definition: YProtocol.hh:151
kXR_char modifier
Definition: YProtocol.hh:85
XrdCmsParser Parser
@ kYR_redirect
Definition: YProtocol.hh:143
@ kYR_error
Definition: YProtocol.hh:142
XrdSysError Say
kXR_char rrCode
Definition: YProtocol.hh:84
@ kYR_xauth
Definition: YProtocol.hh:117
@ kYR_login
Definition: YProtocol.hh:90
@ kYR_try
Definition: YProtocol.hh:114
XrdOucEnv * envP
Definition: XrdPss.cc:109
int getIovMax()