Logo ROOT   6.07/09
Reference Guide
XrdProofdClientMgr.cxx
Go to the documentation of this file.
1 // @(#)root/proofd:$Id$
2 // Author: G. Ganis Jan 2008
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // XrdProofdClientMgr //
15 // //
16 // Author: G. Ganis, CERN, 2008 //
17 // //
18 // Class managing clients. //
19 // //
20 //////////////////////////////////////////////////////////////////////////
21 #include "XrdProofdPlatform.h"
22 
23 #include "XrdProofdXrdVers.h"
24 #if ROOTXRDVERS < ROOT_OldXrdOuc
25 # define XPD_LOG_01 OUC_LOG_01
26 #else
27 # define XPD_LOG_01 SYS_LOG_01
28 #endif
29 
30 #include "XpdSysError.h"
31 
32 #include "Xrd/XrdBuffer.hh"
33 #ifdef ROOT_XrdFour
34 #include "XrdNet/XrdNetAddrInfo.hh"
35 #endif
36 #include "XrdOuc/XrdOucErrInfo.hh"
37 #include "XrdOuc/XrdOucStream.hh"
38 #include "XrdSec/XrdSecInterface.hh"
39 #include "XrdSys/XrdSysPlugin.hh"
40 
41 #include "XrdProofdClient.h"
42 #include "XrdProofdClientMgr.h"
43 #include "XrdProofdManager.h"
44 #include "XrdProofdProtocol.h"
45 #include "XrdProofGroup.h"
46 #include "XrdProofdProofServ.h"
47 #include "XrdProofdProofServMgr.h"
48 #include "XrdROOT.h"
49 
50 // Tracing utilities
51 #include "XrdProofdTrace.h"
52 
54 
55 // Security handle
56 typedef XrdSecService *(*XrdSecServLoader_t)(XrdSysLogger *, const char *cfn);
57 
58 //--------------------------------------------------------------------------
59 //
60 // XrdProofdClientCron
61 //
62 // Client manager thread
63 //
64 ////////////////////////////////////////////////////////////////////////////////
65 /// This is an endless loop to check the system periodically or when
66 /// triggered via a message in a dedicated pipe
67 
68 void *XrdProofdClientCron(void *p)
69 {
70  XPDLOC(CMGR, "ClientCron")
71 
73  XrdProofdClientMgr *mgr = mc->fClientMgr;
74  if (!(mgr)) {
75  TRACE(REQ, "undefined client manager: cannot start");
76  return (void *)0;
77  }
79  if (!(smgr)) {
80  TRACE(REQ, "undefined session manager: cannot start");
81  return (void *)0;
82  }
83 
84  // Time of last session check
85  int lastcheck = time(0), ckfreq = mgr->CheckFrequency(), deltat = 0;
86  while(1) {
87  // We wait for processes to communicate a session status change
88  if ((deltat = ckfreq - (time(0) - lastcheck)) <= 0)
89  deltat = ckfreq;
90  int pollRet = mgr->Pipe()->Poll(deltat);
91 
92  if (pollRet > 0) {
93  // Read message
94  XpdMsg msg;
95  int rc = 0;
96  if ((rc = mgr->Pipe()->Recv(msg)) != 0) {
97  XPDERR("problems receiving message; errno: "<<-rc);
98  continue;
99  }
100  // Parse type
101  //XrdOucString buf;
103  // obsolete
104  TRACE(XERR, "obsolete type: XrdProofdClientMgr::kClientDisconnect");
105  } else {
106  TRACE(XERR, "unknown type: "<<msg.Type());
107  continue;
108  }
109  } else {
110  // Run regular checks
111  mgr->CheckClients();
112  // Remember when ...
113  lastcheck = time(0);
114  }
115  }
116 
117  // Should never come here
118  return (void *)0;
119 }
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 /// Constructor
123 
125  XrdProtocol_Config *pi, XrdSysError *e)
126  : XrdProofdConfig(pi->ConfigFN, e), fSecPlugin(0)
127 {
128  XPDLOC(CMGR, "XrdProofdClientMgr")
129 
130  fMutex = new XrdSysRecMutex;
131  fMgr = mgr;
132  fCIA = 0;
133  fNDisconnected = 0;
134  fReconnectTimeOut = 300;
135  // Defaults can be changed via 'clientmgr'
136  fActivityTimeOut = 1200;
137  fCheckFrequency = 60;
138 
139  // Init pipe for manager thread
140  if (!fPipe.IsValid()) {
141  TRACE(XERR, "unable to generate the pipe");
142  return;
143  }
144 
145  // Configuration directives
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 /// Register directives for configuration
151 
153 {
154  Register("clientmgr", new XrdProofdDirective("clientmgr", this, &DoDirectiveClass));
155  Register("seclib", new XrdProofdDirective("seclib",
156  (void *)&fSecLib, &DoDirectiveString, 0));
157  Register("reconnto", new XrdProofdDirective("reconnto",
158  (void *)&fReconnectTimeOut, &DoDirectiveInt));
159 }
160 
161 ////////////////////////////////////////////////////////////////////////////////
162 /// Update the priorities of the active sessions.
163 
165  char *val, XrdOucStream *cfg, bool rcf)
166 {
167  XPDLOC(SMGR, "ClientMgr::DoDirective")
168 
169  if (!d)
170  // undefined inputs
171  return -1;
172 
173  if (d->fName == "clientmgr") {
174  return DoDirectiveClientMgr(val, cfg, rcf);
175  }
176  TRACE(XERR,"unknown directive: "<<d->fName);
177  return -1;
178 }
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// Process 'clientmgr' directive
182 /// eg: xpd.clientmgr checkfq:120 activityto:600
183 
184 int XrdProofdClientMgr::DoDirectiveClientMgr(char *val, XrdOucStream *cfg, bool)
185 {
186  XPDLOC(SMGR, "ClientMgr::DoDirectiveClientMgr")
187 
188  if (!val || !cfg)
189  // undefined inputs
190  return -1;
191 
192  int checkfq = -1;
193  int activityto = -1;
194 
195  while (val) {
196  XrdOucString tok(val);
197  if (tok.beginswith("checkfq:")) {
198  tok.replace("checkfq:", "");
199  checkfq = strtol(tok.c_str(), 0, 10);
200  } else if (tok.beginswith("activityto:")) {
201  tok.replace("activityto:", "");
202  activityto = strtol(tok.c_str(), 0, 10);
203  }
204  // Get next
205  val = cfg->GetWord();
206  }
207 
208  // Check deprecated 'if' directive
209  if (fMgr->Host() && cfg)
210  if (XrdProofdAux::CheckIf(cfg, fMgr->Host()) == 0)
211  return 0;
212 
213  // Set the values
214  fCheckFrequency = (XPD_LONGOK(checkfq) && checkfq > 0) ? checkfq : fCheckFrequency;
215  fActivityTimeOut = (XPD_LONGOK(activityto) && activityto > 0) ? activityto : fActivityTimeOut;
216 
217  XrdOucString msg;
218  XPDFORM(msg, "checkfq: %d s, activityto: %d s", fCheckFrequency, fActivityTimeOut);
219  TRACE(ALL, msg);
220 
221  return 0;
222 }
223 
224 ////////////////////////////////////////////////////////////////////////////////
225 /// Run configuration and parse the entered config directives.
226 /// Return 0 on success, -1 on error
227 
229 {
230  XPDLOC(CMGR, "ClientMgr::Config")
231 
232  // Run first the configurator
233  if (XrdProofdConfig::Config(rcf) != 0) {
234  XPDERR("problems parsing file ");
235  return -1;
236  }
237 
238  XrdOucString msg;
239  msg = (rcf) ? "re-configuring" : "configuring";
240  TRACE(ALL, msg.c_str());
241 
242  // Admin paths
244  fClntAdminPath += "/clients";
245 
246  // Make sure they exist
247  XrdProofUI ui;
249  if (XrdProofdAux::AssertDir(fClntAdminPath.c_str(), ui, 1) != 0) {
250  XPDERR("unable to assert the clients admin path: "<<fClntAdminPath);
251  fClntAdminPath = "";
252  return -1;
253  }
254  TRACE(ALL, "clients admin path set to: "<<fClntAdminPath);
255 
256  // Init place holders for previous active clients, if any
257  if (ParsePreviousClients(msg) != 0) {
258  XPDERR("problems parsing previous active clients: "<<msg);
259  }
260 
261  // Initialize the security system if this is wanted
262  if (!rcf) {
263  if (fSecLib.length() <= 0) {
264  TRACE(ALL, "XRD seclib not specified; strong authentication disabled");
265  } else {
266  if (!(fCIA = LoadSecurity())) {
267  XPDERR("unable to load security system.");
268  return -1;
269  }
270  TRACE(ALL, "security library loaded");
271  }
272  }
273 
274  if (rcf) {
275  // Re-assign groups
276  if (fMgr->GroupsMgr() && fMgr->GroupsMgr()->Num() > 0) {
277  std::list<XrdProofdClient *>::iterator pci;
278  for (pci = fProofdClients.begin(); pci != fProofdClients.end(); ++pci)
279  (*pci)->SetGroup(fMgr->GroupsMgr()->GetUserGroup((*pci)->User())->Name());
280  }
281  }
282 
283  if (!rcf) {
284  // Start cron thread
285  pthread_t tid;
286  // Fill manager pointers structure
287  fManagerCron.fClientMgr = this;
288  fManagerCron.fSessionMgr = fMgr->SessionMgr();
289  if (XrdSysThread::Run(&tid, XrdProofdClientCron,
290  (void *)&fManagerCron, 0, "ClientMgr cron thread") != 0) {
291  XPDERR("could not start cron thread");
292  return 0;
293  }
294  TRACE(ALL, "cron thread started");
295  }
296 
297  // Done
298  return 0;
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Process a login request
303 
305 {
306  XPDLOC(CMGR, "ClientMgr::Login")
307 
308  int rc = 0;
309  XPD_SETRESP(p, "Login");
310 
311  TRACEP(p, HDBG, "enter");
312 
313  // If this server is explicitly required to be a worker node or a
314  // submaster, check whether the requesting host is allowed to connect
315  if (p->Request()->login.role[0] != 'i' &&
317  if (!fMgr->CheckMaster(p->Link()->Host())) {
318  TRACEP(p, XERR,"master not allowed to connect - "
319  "ignoring request ("<<p->Link()->Host()<<")");
320  response->Send(kXR_InvalidRequest,
321  "master not allowed to connect - request ignored");
322  return 0;
323  }
324  }
325 
326  // Get user and group names for the entity requiring to login
327  int i, pid;
328  XrdOucString uname, gname, emsg;
329 
330  // If this is the second call (after authentication) we just need mapping
331  if (p->Status() == XPD_NEED_MAP) {
332 
333  // Finalize the login, checking the if username is allowed to use the facility.
334  // The username could have been set as part of the authentication process (for
335  // example via a user mapping funtion or a grid-map file), so these checks have
336  // to be done at this level.
337  // (The XrdProofdClient instance is created in here, if everything else goes well)
338  int rccc = 0;
339  if ((rccc = CheckClient(p, 0, emsg)) != 0) {
340  TRACEP(p, XERR, emsg);
341  XErrorCode rcode = (rccc == -2) ? (XErrorCode) kXR_NotAuthorized
342  : (XErrorCode) kXR_InvalidRequest;
343  response->Send(rcode, emsg.c_str());
344  response->Send(kXR_InvalidRequest, emsg.c_str());
345  return 0;
346  }
347 
348  // Acknowledge the client
349  response->Send();
351  return MapClient(p, 0);
352  }
353 
354  // Make sure the user is not already logged in
355  if ((p->Status() & XPD_LOGGEDIN)) {
356  response->Send(kXR_InvalidRequest, "duplicate login; already logged in");
357  return 0;
358  }
359 
360  TRACE(ALL," hostname: '"<<p->Link()->Host()<<"'");
361  //
362  // Check if in any-server mode (localhost connections always are)
363  bool anyserver = (fMgr->SrvType() == kXPD_AnyServer ||
364  !strcmp(p->Link()->Host(), "localhost") ||
365  !strcmp(p->Link()->Host(), "127.0.0.0")) ? 1 : 0;
366 
367  // Find out the connection type: 'i', internal, means this is a proofsrv calling back.
368  bool needauth = 0;
369  bool ismaster = (fMgr->SrvType() == kXPD_TopMaster || fMgr->SrvType() == kXPD_Master) ? 1 : 0;
370  switch (p->Request()->login.role[0]) {
371  case 'A':
373  response->SetTag("adm");
374  break;
375  case 'i':
377  response->SetTag("int");
378  break;
379  case 'M':
380  if (anyserver || ismaster) {
382  needauth = 1;
383  response->SetTag("m2c");
384  } else {
385  TRACEP(p, XERR,"top master mode not allowed - ignoring request");
386  response->Send(kXR_InvalidRequest,
387  "Server not allowed to be top master - ignoring request");
388  return 0;
389  }
390  break;
391  case 'm':
392  if (anyserver || ismaster) {
394  needauth = 1;
395  response->SetTag("m2m");
396  } else {
397  TRACEP(p, XERR,"submaster mode not allowed - ignoring request");
398  response->Send(kXR_InvalidRequest,
399  "Server not allowed to be submaster - ignoring request");
400  return 0;
401  }
402  break;
403  case 'L':
404  if (fMgr->SrvType() == kXPD_AnyServer || fMgr->RemotePLite()) {
406  needauth = 1;
407  response->SetTag("m2l");
408  p->Request()->login.role[0] = 'm';
409  } else {
410  TRACEP(p, XERR,"PLite submaster mode not allowed - ignoring request");
411  response->Send(kXR_InvalidRequest,
412  "Server not allowed to be PLite submaster - ignoring request");
413  return 0;
414  }
415  break;
416  case 's':
417  if (anyserver || fMgr->SrvType() == kXPD_MasterWorker) {
419  needauth = 1;
420  response->SetTag("w2m");
421  } else {
422  TRACEP(p, XERR,"worker mode not allowed - ignoring request");
423  response->Send(kXR_InvalidRequest,
424  "Server not allowed to be worker - ignoring request");
425  return 0;
426  }
427  break;
428  default:
429  TRACEP(p, XERR, "unknown mode: '" << p->Request()->login.role[0] <<"'");
430  response->Send(kXR_InvalidRequest, "Server type: invalide mode");
431  return rc;
432  }
433  response->SetTraceID();
434 
435  // Unmarshall the data: process ID
436  pid = (int)ntohl(p->Request()->login.pid);
437  p->SetPid(pid);
438 
439  // Username
440  char un[9];
441  for (i = 0; i < (int)sizeof(un)-1; i++) {
442  if (p->Request()->login.username[i] == '\0' || p->Request()->login.username[i] == ' ')
443  break;
444  un[i] = p->Request()->login.username[i];
445  }
446  un[i] = '\0';
447  uname = un;
448 
449  // Longer usernames are in the attached buffer
450  if (uname == "?>buf") {
451  // Attach to buffer
452  char *buf = p->Argp()->buff;
453  int len = p->Request()->login.dlen;
454  // Extract username
455  uname.assign(buf,0,len-1);
456  int iusr = uname.find("|usr:");
457  if (iusr == -1) {
458  TRACEP(p, XERR,"long user name not found");
459  response->Send(kXR_InvalidRequest, "long user name not found");
460  return 0;
461  }
462  uname.erase(0,iusr+5);
463  uname.erase(uname.find("|"));
464  }
465 
466  // Extract group name, if specified (syntax is uname[:gname])
467  int ig = uname.find(":");
468  if (ig != -1) {
469  gname.assign(uname, ig+1);
470  uname.erase(ig);
471  TRACEP(p, DBG, "requested group: "<<gname);
472  // Save the requested group info in the protocol instance
473  p->SetGroupIn(gname.c_str());
474  }
475 
476  // Save the incoming username setting in the protocol instance
477  p->SetUserIn(uname.c_str());
478 
479  // Establish IDs for this link
480  p->Link()->setID(uname.c_str(), pid);
481  p->SetTraceID();
482  response->SetTraceID();
483  p->SetClntCapVer(p->Request()->login.capver[0]);
484 
485  // Get the security token for this link. We will either get a token, a null
486  // string indicating host-only authentication, or a null indicating no
487  // authentication. We can then optimize of each case.
488  if (needauth && fCIA) {
489 #ifdef ROOT_XrdFour
490  const char *pp = fCIA->getParms(i, (XrdNetAddrInfo *) p->Link()->NetAddr());
491 #else
492  const char *pp = fCIA->getParms(i, p->Link()->Name());
493 #endif
494  if (pp && i ) {
495  response->SendI((kXR_int32)XPROOFD_VERSBIN, (void *)pp, i);
497  return 0;
498  } else if (pp) {
499  p->SetAuthEntity();
500  }
501  }
502  // Check the client at this point; the XrdProofdClient instance is created
503  // in here, if everything else goes well
504  int rccc = 0;
505  if ((rccc = CheckClient(p, p->UserIn(), emsg)) != 0) {
506  TRACEP(p, XERR, emsg);
507  XErrorCode rcode = (rccc == -2) ? (XErrorCode) kXR_NotAuthorized
508  : (XErrorCode) kXR_InvalidRequest;
509  response->Send(rcode, emsg.c_str());
510  return 0;
511  }
512  rc = response->SendI((kXR_int32)XPROOFD_VERSBIN);
514 
515  // Map the client
516  return MapClient(p, 1);
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 /// Perform checks on the client username. In case authentication is required
521 /// this is called afetr authentication.
522 /// Return 0 on success; on error, return -1 .
523 
525  const char *user, XrdOucString &emsg)
526 {
527  XPDLOC(CMGR, "ClientMgr::CheckClient")
528 
529  if (!p) {
530  emsg = "protocol object undefined!";
531  return -1;
532  }
533 
534  XrdOucString uname(user), gname(p->GroupIn());
535  if (!user) {
536  if (p && p->AuthProt() && strlen(p->AuthProt()->Entity.name) > 0) {
537  uname = p->AuthProt()->Entity.name;
538  } else {
539  emsg = "username not passed and not available in the protocol security entity - failing";
540  return -1;
541  }
542  }
543 
544  // Check if user belongs to a group
545  XrdProofGroup *g = 0;
546  if (fMgr->GroupsMgr() && fMgr->GroupsMgr()->Num() > 0) {
547  if (gname.length() > 0) {
548  g = fMgr->GroupsMgr()->GetGroup(gname.c_str());
549  if (!g) {
550  XPDFORM(emsg, "group unknown: %s", gname.c_str());
551  return -1;
552  } else if (strncmp(g->Name(),"default",7) &&
553  !g->HasMember(uname.c_str())) {
554  XPDFORM(emsg, "user %s is not member of group %s", uname.c_str(), gname.c_str());
555  return -1;
556  } else {
557  if (TRACING(DBG)) {
558  TRACEP(p, DBG,"group: "<<gname<<" found");
559  g->Print();
560  }
561  }
562  } else {
563  g = fMgr->GroupsMgr()->GetUserGroup(uname.c_str());
564  gname = g ? g->Name() : "default";
565  }
566  }
567 
568  // Here we check if the user is allowed to use the system
569  // If not, we fail.
570  XrdProofUI ui;
571  bool su;
572  if (fMgr->CheckUser(uname.c_str(), gname.c_str(), ui, emsg, su) != 0) {
573  if (emsg.length() <= 0)
574  XPDFORM(emsg, "Controlled access: user '%s', group '%s' not allowed to connect",
575  uname.c_str(), gname.c_str());
576  return -2;
577  }
578  if (su) {
579  // Update superuser flag
580  p->SetSuperUser(su);
581  TRACEP(p, DBG, "request from entity: "<<uname<<":"<<gname<<" (privileged)");
582  } else {
583  TRACEP(p, DBG, "request from entity: "<<uname<<":"<<gname);
584  }
585 
586  // Attach-to / Create the XrdProofdClient instance for this user: if login
587  // fails this will be removed at a later stage
588  XrdProofdClient *c = GetClient(uname.c_str(), gname.c_str());
589  if (c) {
590  if (!c->ROOT())
592  if (c->IsValid()) {
593  // Set the group, if any
594  c->SetGroup(gname.c_str());
595  }
596  } else {
597  emsg = "unable to instantiate object for client ";
598  emsg += uname;
599  return -1;
600  }
601  // Save into the protocol instance
602  p->SetClient(c);
603 
604  // Done
605  return 0;
606 }
607 
608 ////////////////////////////////////////////////////////////////////////////////
609 /// Process a login request
610 
612 {
613  XPDLOC(CMGR, "ClientMgr::MapClient")
614 
615  int rc = 0;
616  XPD_SETRESP(p, "MapClient");
617 
618  XrdOucString msg;
619 
620  TRACEP(p, HDBG, "all: "<< all);
621 
622  // Attach to the client
623  XrdProofdClient *pc = p->Client();
624 
625  // Map the existing session, if found
626  if (!pc || !pc->IsValid()) {
627  if (pc) {
628  { // Remove from the list
630  fProofdClients.remove(pc);
631  }
632  SafeDelete(pc);
633  p->SetClient(0);
634  }
635  TRACEP(p, DBG, "cannot find valid instance of XrdProofdClient");
636  response->Send(kXP_ServerError,
637  "MapClient: cannot find valid instance of XrdProofdClient");
638  return 0;
639  }
640 
641  // Flag for internal connections
642  bool proofsrv = ((p->ConnType() == kXPD_Internal) && all) ? 1 : 0;
643 
644  // If call back from proofsrv, find out the target session
645  short int psid = -1;
646  char protver = -1;
647  short int clientvers = -1;
648  if (proofsrv) {
649  memcpy(&psid, (const void *)&(p->Request()->login.reserved[0]), 2);
650  if (psid < 0) {
651  TRACEP(p, XERR, "proofsrv callback: sent invalid session id");
652  response->Send(kXR_InvalidRequest,
653  "MapClient: proofsrv callback: sent invalid session id");
654  return 0;
655  }
656  protver = p->Request()->login.capver[0];
657  TRACEP(p, DBG, "proofsrv callback for session: " <<psid);
658  } else {
659  // Get PROOF version run by client
660  memcpy(&clientvers, (const void *)&(p->Request()->login.reserved[0]), 2);
661  TRACEP(p, DBG, "PROOF version run by client: " <<clientvers);
662  }
663 
664  // If proofsrv, locate the target session
665  if (proofsrv) {
666  XrdProofdProofServ *psrv = pc->GetServer(psid);
667  if (!psrv) {
668  TRACEP(p, XERR, "proofsrv callback: wrong target session: "<<psid<<" : protocol error");
669  response->Send(kXP_nosession, "MapClient: proofsrv callback:"
670  " wrong target session: protocol error");
671  return -1;
672  } else {
673  // Set the protocol version
674  psrv->SetProtVer(protver);
675  // Assign this link to it
676  XrdProofdResponse *resp = p->Response(1);
677  psrv->SetConnection(resp);
678  psrv->SetValid(1);
679  // Set Trace ID
680  XrdOucString tid;
681  XPDFORM(tid, "xrd->%s", psrv->Ordinal());
682  resp->SetTag(tid.c_str());
683  resp->SetTraceID();
684  TRACEI(resp->TraceID(), DBG, "proofsrv callback: link assigned to target session "<<psid);
685  }
686  } else {
687 
688  // Only one instance of this client can map at a time
689  XrdSysMutexHelper mhc(pc->Mutex());
690 
691  // Make sure that the version is filled correctly (if an admin operation
692  // was run before this may still be -1 on workers)
693  p->SetProofProtocol(clientvers);
694 
695  // Check if we have already an ID for this client from a previous connection
696  XrdOucString cpath;
697  int cid = -1;
698  if ((cid = CheckAdminPath(p, cpath, msg)) >= 0) {
699  // Assign the slot
700  pc->SetClientID(cid, p);
701  // The index of the next free slot will be the unique ID
702  p->SetCID(cid);
703  // Remove the file indicating that this client was still disconnected
704  XrdOucString discpath(cpath, 0, cpath.rfind("/cid"));
705  discpath += "/disconnected";
706  if (unlink(discpath.c_str()) != 0) {
707  XPDFORM(msg, "warning: could not remove %s (errno: %d)", discpath.c_str(), errno);
708  TRACEP(p, XERR, msg.c_str());
709  }
710  // Update counters
712 
713  } else {
714  // The index of the next free slot will be the unique ID
715  p->SetCID(pc->GetClientID(p));
716  // Create the client directory in the admin path
717  if (CreateAdminPath(p, cpath, msg) != 0) {
718  TRACEP(p, XERR, msg.c_str());
719  fProofdClients.remove(pc);
720  SafeDelete(pc);
721  p->SetClient(0);
722  response->Send(kXP_ServerError, msg.c_str());
723  return 0;
724  }
725  }
726  p->SetAdminPath(cpath.c_str());
727  XPDFORM(msg, "client ID and admin paths created: %s", cpath.c_str());
728  TRACEP(p, DBG, msg.c_str());
729 
730  TRACEP(p, DBG, "CID: "<<p->CID()<<", size: "<<pc->Size());
731  }
732 
733  // Document this login
734  if (!(p->Status() & XPD_NEED_AUTH)) {
735  const char *srvtype[6] = {"ANY", "MasterWorker", "MasterMaster",
736  "ClientMaster", "Internal", "Admin"};
737  XPDFORM(msg, "user %s logged-in%s; type: %s", pc->User(),
738  p->SuperUser() ? " (privileged)" : "", srvtype[p->ConnType()+1]);
739  TRACEP(p, LOGIN, msg);
740  }
741 
742  // Done
743  return 0;
744 }
745 
746 ////////////////////////////////////////////////////////////////////////////////
747 /// Create the client directory in the admin path
748 
750  XrdOucString &cpath, XrdOucString &emsg)
751 {
752  if (!p || !p->Link()) {
753  XPDFORM(emsg, "invalid inputs (p: %p)", p);
754  return -1;
755  }
756 
757  // Create link ID
758  XrdOucString lid;
759  XPDFORM(lid, "%s.%d", p->Link()->Host(), p->Pid());
760 
761  // Create the path now
762  XPDFORM(cpath, "%s/%s", p->Client()->AdminPath(), lid.c_str());
763  XrdProofUI ui;
765  if (XrdProofdAux::AssertDir(cpath.c_str(), ui, 1) != 0) {
766  XPDFORM(emsg, "error creating client admin path: %s", cpath.c_str());
767  return -1;
768  }
769  // Save client ID for full recovery
770  cpath += "/cid";
771  FILE *fcid = fopen(cpath.c_str(), "w");
772  if (fcid) {
773  fprintf(fcid, "%d", p->CID());
774  fclose(fcid);
775  } else {
776  XPDFORM(emsg, "error creating file for client id: %s", cpath.c_str());
777  return -1;
778  }
779  // Done
780  return 0;
781 }
782 
783 ////////////////////////////////////////////////////////////////////////////////
784 /// Check the old-clients admin for an existing entry for this client and
785 /// read the client ID;
786 
788  XrdOucString &cidpath, XrdOucString &emsg)
789 {
790  emsg = "";
791  if (!p) {
792  XPDFORM(emsg, "CheckAdminPath: invalid inputs (p: %p)", p);
793  return -1;
794  }
795 
796  // Create link ID
797  XrdOucString lid;
798  XPDFORM(lid, "%s.%d", p->Link()->Host(), p->Pid());
799 
800  // Create the path now
801  XPDFORM(cidpath, "%s/%s/cid", p->Client()->AdminPath(), lid.c_str());
802 
803  // Create disconnected path
804  XrdOucString discpath;
805  XPDFORM(discpath, "%s/%s/disconnected", p->Client()->AdminPath(), lid.c_str());
806 
807  // Check last access time of disconnected if available, otherwise cid
808  bool expired = false;
809  struct stat st;
810  int rc = stat(discpath.c_str(), &st);
811  if (rc != 0) rc = stat(cidpath.c_str(), &st);
812  if (rc != 0 || (expired = ((int)(time(0) - st.st_atime) > fReconnectTimeOut))) {
813  if (expired || (rc != 0 && errno != ENOENT)) {
814  // Remove the file
815  cidpath.replace("/cid", "");
816  if (expired)
817  XPDFORM(emsg, "CheckAdminPath: reconnection timeout expired: remove %s ",
818  cidpath.c_str());
819  else
820  XPDFORM(emsg, "CheckAdminPath: problems stat'ing %s (errno: %d): remove ",
821  cidpath.c_str(), errno);
822  if (XrdProofdAux::RmDir(cidpath.c_str()) != 0)
823  emsg += ": failure!";
824  } else {
825  XPDFORM(emsg, "CheckAdminPath: no such file %s", cidpath.c_str());
826  }
827  return -1;
828  }
829 
830  // Get the client ID for full recovery
831  return XrdProofdAux::GetIDFromPath(cidpath.c_str(), emsg);
832 }
833 
834 ////////////////////////////////////////////////////////////////////////////////
835 /// Client entries for the clients still connected when the daemon terminated
836 
838 {
839  XPDLOC(CMGR, "ClientMgr::ParsePreviousClients")
840 
841  emsg = "";
842 
843  // Open dir
844  DIR *dir = opendir(fClntAdminPath.c_str());
845  if (!dir) {
846  TRACE(XERR, "cannot open dir "<<fClntAdminPath<<" ; error: "<<errno);
847  return -1;
848  }
849  TRACE(DBG, "creating holders for active clients ...");
850 
851  // Scan the active sessions admin path
852  XrdOucString usrpath, cidpath, discpath, usr, grp;
853  struct dirent *ent = 0;
854  while ((ent = (struct dirent *)readdir(dir))) {
855  // Skip the basic entries
856  if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
857  XPDFORM(usrpath, "%s/%s", fClntAdminPath.c_str(), ent->d_name);
858  bool rm = 0;
859  struct stat st;
860  if (stat(usrpath.c_str(), &st) == 0) {
861  usr = ent->d_name;
862  grp = usr;
863  usr.erase(usr.find('.'));
864  grp.erase(0, grp.find('.')+1);
865  TRACE(DBG, "found usr: "<<usr<<", grp: "<<grp);
866  // Get client instance
867  XrdProofdClient *c = GetClient(usr.c_str(), grp.c_str());
868  if (!c) {
869  XPDFORM(emsg, "ParsePreviousClients: could not get client instance"
870  " for {%s, %s}", usr.c_str(), grp.c_str());
871  rm = 1;
872  }
873  // Open user sub-dir
874  DIR *subdir = 0;
875  if (!rm && !(subdir = opendir(usrpath.c_str()))) {
876  TRACE(XERR, "cannot open dir "<<usrpath<<" ; error: "<<errno);
877  rm = 1;
878  }
879  if (!rm) {
880  bool xrm = 0;
881  struct dirent *sent = 0;
882  while ((sent = (struct dirent *)readdir(subdir))) {
883  // Skip the basic entries
884  if (!strcmp(sent->d_name, ".") || !strcmp(sent->d_name, "..")) continue;
885  if (!strcmp(sent->d_name, "xpdsock")) continue;
886  XPDFORM(cidpath, "%s/%s/cid", usrpath.c_str(), sent->d_name);
887  // Check last access time
888  if (stat(cidpath.c_str(), &st) != 0 ||
889  (int)(time(0) - st.st_atime) > fReconnectTimeOut) {
890  xrm = 1;
891  }
892  // Read the client ID and and reserve an entry in the related vector
893  int cid = (!xrm) ? XrdProofdAux::GetIDFromPath(cidpath.c_str(), emsg) : -1;
894  if (cid < 0)
895  xrm = 1;
896  // Reserve an entry in the related vector
897  if (!xrm && c->ReserveClientID(cid) != 0)
898  xrm = 1;
899  // Flag this as disconnected
900  if (!xrm) {
901  XPDFORM(discpath, "%s/%s/disconnected", usrpath.c_str(), sent->d_name);
902  FILE *fd = fopen(discpath.c_str(), "w");
903  if (!fd) {
904  TRACE(XERR, "unable to create path: " <<discpath);
905  xrm = 1;
906  } else {
907  fclose(fd);
908  }
909  if (!xrm)
910  fNDisconnected++;
911  }
912  // If it did not work remove the entry
913  if (xrm) {
914  TRACE(DBG, "removing path: " <<cidpath);
915  cidpath.replace("/cid", "");
916  XPDFORM(emsg, "ParsePreviousClients: failure: remove %s ", cidpath.c_str());
917  if (XrdProofdAux::RmDir(cidpath.c_str()) != 0)
918  emsg += ": failure!";
919  }
920  }
921  }
922  if (subdir)
923  closedir(subdir);
924  } else {
925  rm = 1;
926  }
927  // If it did not work remove the entry
928  if (rm) {
929  TRACE(DBG, "removing path: " <<usrpath);
930  XPDFORM(emsg, "ParsePreviousClients: failure: remove %s ", usrpath.c_str());
931  if (XrdProofdAux::RmDir(usrpath.c_str()) != 0)
932  emsg += ": failure!";
933  }
934  }
935  // Close the directory
936  closedir(dir);
937 
938  // Notify the number of previously active clients now offline
939  TRACE(DBG, "found "<<fNDisconnected<<" active clients");
940 
941  // Done
942  return 0;
943 }
944 
945 ////////////////////////////////////////////////////////////////////////////////
946 /// Regular checks of the client admin path; run by the cron job
947 
949 {
950  XPDLOC(CMGR, "ClientMgr::CheckClients")
951 
952  // Open dir
953  DIR *dir = opendir(fClntAdminPath.c_str());
954  if (!dir) {
955  TRACE(XERR, "cannot open dir "<<fClntAdminPath<<" ; error: "<<errno);
956  return -1;
957  }
958  TRACE(REQ, "checking active clients ...");
959 
960  // Scan the active sessions admin path
961  int rc = 0;
962  XrdOucString usrpath, cidpath, discpath;
963  struct dirent *ent = 0;
964  while ((ent = (struct dirent *)readdir(dir))) {
965  // Skip the basic entries
966  if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
967  XPDFORM(usrpath, "%s/%s", fClntAdminPath.c_str(), ent->d_name);
968  bool rm = 0;
969  XrdProofdClient *c = 0;
970  struct stat st, xst;
971  if (stat(usrpath.c_str(), &xst) == 0) {
972  // Find client instance
973  XrdOucString usr, grp;
974  XrdProofdAux::ParseUsrGrp(ent->d_name, usr, grp);
975  if (!(c = GetClient(usr.c_str(), grp.c_str(), 0))) {
976  TRACE(XERR, "instance for client "<<ent->d_name<<" not found!");
977  rm = 1;
978  }
979  // Open user sub-dir
980  DIR *subdir = 0;
981  if (!rm && !(subdir = opendir(usrpath.c_str()))) {
982  TRACE(XERR, "cannot open dir "<<usrpath<<" ; error: "<<errno);
983  rm = 1;
984  }
985  if (!rm) {
986  bool xrm = 0, xclose = 0;
987  struct dirent *sent = 0;
988  while ((sent = (struct dirent *)readdir(subdir))) {
989  // Skip the basic entries
990  if (!strcmp(sent->d_name, ".") || !strcmp(sent->d_name, "..")) continue;
991  if (!strcmp(sent->d_name, "xpdsock")) continue;
992  XPDFORM(discpath, "%s/%s/disconnected", usrpath.c_str(), sent->d_name);
993  // Client admin path
994  XPDFORM(cidpath, "%s/%s/cid", usrpath.c_str(), sent->d_name);
995  // Check last access time
996  if (stat(cidpath.c_str(), &st) == 0) {
997  // If in disconnected state, check if it needs to be cleaned
998  if (stat(discpath.c_str(), &xst) == 0) {
999  if ((int)(time(0) - st.st_atime) > fReconnectTimeOut) {
1000  xrm = 1;
1001  }
1002  } else {
1003  // If required, check the recent activity; if inactive since too long
1004  // we ask the client to proof its vitality; but only once: next time
1005  // we close the link
1006  if (fActivityTimeOut > 0 &&
1007  (int)(time(0) - st.st_atime) > fActivityTimeOut) {
1008  if (c->Touch() == 1) {
1009  // The client was already asked to proof its vitality
1010  // during last cycle and it did not do it, so we close
1011  // the link
1012  xclose = 1;
1013  }
1014  }
1015  }
1016  } else {
1017  // No id info, clean
1018  xrm = 1;
1019  }
1020  // If inactive since too long, close the associated link
1021  if (xclose) {
1022  // Get the client id
1023  XrdOucString emsg;
1024  int cid = XrdProofdAux::GetIDFromPath(cidpath.c_str(), emsg);
1025  if (cid >= 0) {
1026  // Get the XrdProofdProtocol instance
1027  XrdProofdProtocol *p = c->GetProtocol(cid);
1028  if (p && p->Link()) {
1029  // This client will try to reconnect, if alive, so give it
1030  // some time by skipping the next sessions check
1031  c->SkipSessionsCheck(0, emsg);
1032  // Close the associated link; Recycle is called from there
1033  p->Link()->Close();
1034  } else {
1035  TRACE(XERR, "protocol or link associated with ID "<<cid<<" are invalid");
1036  xrm = 1;
1037  }
1038  } else {
1039  TRACE(XERR, "could not resolve client id from "<<cidpath);
1040  xrm = 1;
1041  }
1042  }
1043  // If too old remove the entry
1044  if (xrm) {
1045  discpath.replace("/disconnected", "");
1046  TRACE(DBG, "removing path "<<discpath);
1047  if ((rc = XrdProofdAux::RmDir(discpath.c_str())) != 0) {
1048  TRACE(XERR, "problems removing "<<discpath<<"; error: "<<-rc);
1049  }
1050  }
1051  }
1052  }
1053  if (subdir)
1054  closedir(subdir);
1055  } else {
1056  rm = 1;
1057  }
1058  // If it did not work remove the entry
1059  if (rm) {
1060  TRACE(DBG, "removing path: " <<usrpath);
1061  if ((rc = XrdProofdAux::RmDir(usrpath.c_str())) != 0) {
1062  TRACE(XERR, "problems removing "<<usrpath<<"; error: "<<-rc);
1063  }
1064  }
1065  }
1066  // Close the directory
1067  closedir(dir);
1068 
1069  // Done
1070  return 0;
1071 }
1072 
1073 ////////////////////////////////////////////////////////////////////////////////
1074 /// Analyse client authentication info
1075 
1077 {
1078  XPDLOC(CMGR, "ClientMgr::Auth")
1079 
1080  XrdSecCredentials cred;
1081  XrdSecParameters *parm = 0;
1082  XrdOucErrInfo eMsg;
1083  const char *eText;
1084  int rc = 1;
1085  XPD_SETRESP(p, "Auth");
1086 
1087  TRACEP(p, REQ, "enter");
1088 
1089  // Ignore authenticate requests if security turned off
1090  if (!fCIA)
1091  return response->Send();
1092  cred.size = p->Request()->header.dlen;
1093  cred.buffer = p->Argp()->buff;
1094 
1095  // If we have no auth protocol, try to get it
1096  if (!p->AuthProt()) {
1097  XrdSecProtocol *ap = 0;
1098 #ifdef ROOT_XrdFour
1099  XrdNetAddr netaddr(p->Link()->NetAddr());
1100 #else
1101  struct sockaddr netaddr;
1102  p->Link()->Name(&netaddr);
1103 #endif
1104  if (!(ap = fCIA->getProtocol(p->Link()->Host(), netaddr, &cred, &eMsg))) {
1105  eText = eMsg.getErrText(rc);
1106  TRACEP(p, XERR, "user authentication failed; "<<eText);
1107  response->Send(kXR_NotAuthorized, eText);
1108  return -EACCES;
1109  }
1110  p->SetAuthProt(ap);
1111  p->AuthProt()->Entity.tident = p->Link()->ID;
1112  }
1113  // Set the wanted login name
1114  size_t len = strlen("XrdSecLOGINUSER=")+strlen(p->UserIn())+2;
1115  char *u = new char[len];
1116  snprintf(u, len, "XrdSecLOGINUSER=%s", p->UserIn());
1117  putenv(u);
1118 
1119  // Now try to authenticate the client using the current protocol
1120  XrdOucString namsg;
1121  if (!(rc = p->AuthProt()->Authenticate(&cred, &parm, &eMsg))) {
1122 
1123  // Make sure that the user name that we want is allowed
1124  if (p->AuthProt()->Entity.name && strlen(p->AuthProt()->Entity.name) > 0) {
1125  if (p->UserIn() && strlen(p->UserIn()) > 0) {
1126  XrdOucString usrs(p->AuthProt()->Entity.name);
1127  SafeFree(p->AuthProt()->Entity.name);
1128  XrdOucString usr;
1129  int from = 0, rcmtc = -1;
1130  while ((from = usrs.tokenize(usr, from, ',')) != STR_NPOS) {
1131  // The first one by default, if no match is found
1132  if (!(p->AuthProt()->Entity.name))
1133  p->AuthProt()->Entity.name = strdup(usr.c_str());
1134  if ((usr == p->UserIn())) {
1135  free(p->AuthProt()->Entity.name);
1136  p->AuthProt()->Entity.name = strdup(usr.c_str());
1137  rcmtc = 0;
1138  break;
1139  }
1140  }
1141  if (rcmtc != 0) {
1142  namsg = "logging as '";
1143  namsg += p->AuthProt()->Entity.name;
1144  namsg += "' instead of '";
1145  namsg += p->UserIn();
1146  namsg += "' following admin settings";
1147  TRACEP(p, LOGIN, namsg.c_str());
1148  namsg.insert("Warning: ", 0);
1149  response->Send(kXR_attn, kXPD_srvmsg, 2, (char *) namsg.c_str(), namsg.length());
1150  }
1151  } else {
1152  TRACEP(p, XERR, "user name is empty: protocol error?");
1153  }
1154  } else {
1155  TRACEP(p, XERR, "name of the authenticated entity is empty: protocol error?");
1156  rc = -1;
1157  }
1158 
1159  if (rc == 0) {
1160  const char *msg = (p->Status() & XPD_ADMINUSER) ? " admin login as " : " login as ";
1161  rc = response->Send();
1162  char status = p->Status();
1163  status &= ~XPD_NEED_AUTH;
1164  p->SetStatus(status);
1165  p->SetAuthEntity(&(p->AuthProt()->Entity));
1166  if (p->AuthProt()->Entity.name) {
1167  TRACEP(p, LOGIN, p->Link()->ID << msg << p->AuthProt()->Entity.name);
1168  } else {
1169  TRACEP(p, LOGIN, p->Link()->ID << msg << " nobody");
1170  }
1171  return rc;
1172  }
1173  }
1174 
1175  // If we need to continue authentication, tell the client as much
1176  if (rc > 0) {
1177  TRACEP(p, DBG, "more auth requested; sz: " <<(parm ? parm->size : 0));
1178  if (parm) {
1179  rc = response->Send(kXR_authmore, parm->buffer, parm->size);
1180  delete parm;
1181  return rc;
1182  }
1183  if (p->AuthProt()) {
1184  p->AuthProt()->Delete();
1185  p->SetAuthProt(0);
1186  }
1187  TRACEP(p, XERR, "security requested additional auth w/o parms!");
1188  response->Send(kXP_ServerError, "invalid authentication exchange");
1189  return -EACCES;
1190  }
1191 
1192  // We got an error, bail out
1193  if (p->AuthProt()) {
1194  p->AuthProt()->Delete();
1195  p->SetAuthProt(0);
1196  }
1197  eText = (namsg.length() > 0) ? namsg.c_str() : eMsg.getErrText(rc);
1198  TRACEP(p, XERR, "user authentication failed; "<<eText);
1199  response->Send(kXR_NotAuthorized, eText);
1200  return -EACCES;
1201 }
1202 
1203 ////////////////////////////////////////////////////////////////////////////////
1204 /// Load security framework and plugins, if not already done
1205 
1207 {
1208  XPDLOC(CMGR, "ClientMgr::LoadSecurity")
1209 
1210  TRACE(REQ, "LoadSecurity");
1211 
1212  const char *cfn = CfgFile();
1213  const char *seclib = fSecLib.c_str();
1214 
1215  // Make sure the input config file is defined
1216  if (!cfn) {
1217  TRACE(XERR, "config file not specified");
1218  return 0;
1219  }
1220 
1221  // Create the plug-in instance
1222  if (!(fSecPlugin = new XrdSysPlugin((fEDest ? fEDest : (XrdSysError *)0), seclib))) {
1223  TRACE(XERR, "could not create plugin instance for "<<seclib);
1224  return (XrdSecService *)0;
1225  }
1226 
1227  // Get the function
1228  XrdSecServLoader_t ep = (XrdSecServLoader_t) fSecPlugin->getPlugin("XrdSecgetService");
1229  if (!ep) {
1230  TRACE(XERR, "could not find 'XrdSecgetService()' in "<<seclib);
1231  return (XrdSecService *)0;
1232  }
1233 
1234  // Extract in a temporary file the directives prefixed "xpd.sec..." (filtering
1235  // out the prefix), "sec.protocol" and "sec.protparm"
1236  int nd = 0;
1237  char *rcfn = FilterSecConfig(nd);
1238  if (!rcfn) {
1240  if (nd == 0) {
1241  // No directives to be processed
1242  TRACE(XERR, "no security directives: strong authentication disabled");
1243  return 0;
1244  }
1245  // Failure
1246  TRACE(XERR, "creating temporary config file");
1247  return 0;
1248  }
1249 
1250  // Get the server object
1251  XrdSecService *cia = 0;
1252  if (!(cia = (*ep)((fEDest ? fEDest->logger() : (XrdSysLogger *)0), rcfn))) {
1253  TRACE(XERR, "Unable to create security service object via " << seclib);
1255  unlink(rcfn);
1256  delete[] rcfn;
1257  return 0;
1258  }
1259  // Notify
1260  TRACE(ALL, "strong authentication enabled");
1261 
1262  // Unlink the temporary file and cleanup its path
1263  unlink(rcfn);
1264  delete[] rcfn;
1265 
1266  // All done
1267  return cia;
1268 }
1269 
1270 ////////////////////////////////////////////////////////////////////////////////
1271 /// Grep directives of the form "xpd.sec...", "sec.protparm" and
1272 /// "sec.protocol" from file 'cfn' and save them in a temporary file,
1273 /// stripping off the prefix "xpd." when needed.
1274 /// If any such directory is found, the full path of the temporary file
1275 /// is returned, with the number of directives found in 'nd'.
1276 /// Otherwise 0 is returned and '-errno' specified in nd.
1277 /// The caller has the responsability to unlink the temporary file and
1278 /// to release the memory allocated for the path.
1279 
1281 {
1282  XPDLOC(CMGR, "ClientMgr::FilterSecConfig")
1283 
1284  static const char *pfx[] = { "xpd.sec.", "sec.protparm", "sec.protocol", "set" };
1285  char *rcfn = 0;
1286 
1287  TRACE(REQ, "enter");
1288 
1289  const char *cfn = CfgFile();
1290 
1291  // Make sure that we got an input file path and that we can open the
1292  // associated path.
1293  FILE *fin = 0;
1294  if (!cfn || !(fin = fopen(cfn,"r"))) {
1295  nd = (errno > 0) ? -errno : -1;
1296  return rcfn;
1297  }
1298 
1299  // Read the directives: if an interesting one is found, we create
1300  // the output temporary file
1301  int fd = -1;
1302  char lin[2048];
1303  while (fgets(lin,sizeof(lin),fin)) {
1304  if (!strncmp(lin, pfx[0], strlen(pfx[0])) ||
1305  !strncmp(lin, pfx[1], strlen(pfx[1])) ||
1306  !strncmp(lin, pfx[2], strlen(pfx[2])) ||
1307  !strncmp(lin, pfx[3], strlen(pfx[3]))) {
1308  // Target directive found
1309  nd++;
1310  // Create the output file, if not yet done
1311  if (!rcfn) {
1312  size_t len = strlen(fMgr->TMPdir()) + strlen("/xpdcfn_XXXXXX") + 2;
1313  rcfn = new char[len];
1314  snprintf(rcfn, len, "%s/xpdcfn_XXXXXX", fMgr->TMPdir());
1315  mode_t oldum = umask(022);
1316  if ((fd = mkstemp(rcfn)) < 0) {
1317  delete[] rcfn;
1318  nd = (errno > 0) ? -errno : -1;
1319  fclose(fin);
1320  rcfn = 0;
1321  oldum = umask(oldum);
1322  return rcfn;
1323  }
1324  oldum = umask(oldum);
1325  }
1326  XrdOucString slin = lin;
1327  // Strip the prefix "xpd."
1328  if (slin.beginswith("xpd.")) slin.replace("xpd.","");
1329  // Make keyword substitution
1330  fMgr->ResolveKeywords(slin, 0);
1331  // Write the line to the output file
1332  XrdProofdAux::Write(fd, slin.c_str(), slin.length());
1333  }
1334  }
1335 
1336  // Close files
1337  fclose(fin);
1338  if (fd >= 0) close(fd);
1339 
1340  return rcfn;
1341 }
1342 
1343 ////////////////////////////////////////////////////////////////////////////////
1344 /// Handle request for localizing a client instance for {usr, grp} from the list.
1345 /// Create a new instance, if required; for new instances, use the path at 'sock'
1346 /// for the unix socket, or generate a new one, if sock = 0.
1347 
1348 XrdProofdClient *XrdProofdClientMgr::GetClient(const char *usr, const char *grp,
1349  bool create)
1350 {
1351  XPDLOC(CMGR, "ClientMgr::GetClient")
1352 
1353  TRACE(DBG, "usr: "<< (usr ? usr : "undef")<<", grp:"<<(grp ? grp : "undef"));
1354 
1355  XrdOucString dmsg, emsg;
1356  XrdProofdClient *c = 0;
1357  bool newclient = 0;
1358  std::list<XrdProofdClient *>::iterator i;
1359 
1360  { XrdSysMutexHelper mh(fMutex);
1361  for (i = fProofdClients.begin(); i != fProofdClients.end(); ++i) {
1362  if ((c = *i) && c->Match(usr,grp)) break;
1363  c = 0;
1364  }
1365  }
1366 
1367  if (!c && create) {
1368  // Is this a potential user?
1369  XrdProofUI ui;
1370  bool su;
1371  if (fMgr->CheckUser(usr, grp, ui, emsg, su) == 0) {
1372  // Yes: create an (invalid) instance of XrdProofdClient:
1373  // It would be validated on the first valid login
1374  ui.fUser = usr;
1375  ui.fGroup = grp;
1376  bool full = (fMgr->SrvType() != kXPD_Worker) ? 1 : 0;
1377  c = new XrdProofdClient(ui, full, fMgr->ChangeOwn(), fEDest, fClntAdminPath.c_str(), fReconnectTimeOut);
1378  newclient = 1;
1379  bool freeclient = 1;
1380  if (c && c->IsValid()) {
1381  // Locate and set the group, if any
1382  if (fMgr->GroupsMgr() && fMgr->GroupsMgr()->Num() > 0) {
1383  XrdProofGroup *g = fMgr->GroupsMgr()->GetUserGroup(usr, grp);
1384  if (g) {
1385  c->SetGroup(g->Name());
1386  } else if (TRACING(XERR)) {
1387  emsg = "group = "; emsg += grp; emsg += " nor found";
1388  }
1389  }
1390  { XrdSysMutexHelper mh(fMutex);
1391  XrdProofdClient *nc = 0;
1392  for (i = fProofdClients.begin(); i != fProofdClients.end(); ++i) {
1393  if ((nc = *i) && nc->Match(usr,grp)) break;
1394  nc = 0;
1395  newclient = 0;
1396  }
1397  if (!nc) {
1398  // Add to the list
1399  fProofdClients.push_back(c);
1400  freeclient = 0;
1401  }
1402  }
1403  if (freeclient) {
1404  SafeDelete(c);
1405  } else if (TRACING(DBG)) {
1406  XPDFORM(dmsg, "instance for {client, group} = {%s, %s} created"
1407  " and added to the list (%p)", usr, grp, c);
1408  }
1409  } else {
1410  if (TRACING(XERR)) {
1411  XPDFORM(dmsg, "instance for {client, group} = {%s, %s} is invalid", usr, grp);
1412  }
1413  SafeDelete(c);
1414  }
1415  } else {
1416  if (TRACING(XERR)) {
1417  XPDFORM(dmsg, "client '%s' unknown or unauthorized: %s", usr, emsg.c_str());
1418  }
1419  }
1420  }
1421 
1422  // Trim the sandbox, if needed
1423  if (c && !newclient) {
1424  if (c->TrimSessionDirs() != 0) {
1425  if (TRACING(XERR)) {
1426  XPDFORM(dmsg, "problems trimming client '%s' sandbox", usr);
1427  }
1428  }
1429  }
1430 
1431  if (dmsg.length() > 0) {
1432  if (TRACING(DBG)) {
1433  TRACE(DBG, dmsg);
1434  } else {
1435  if (emsg.length() > 0) TRACE(XERR, emsg);
1436  TRACE(XERR, dmsg);
1437  }
1438  }
1439 
1440  // Over
1441  return c;
1442 }
1443 
1444 ////////////////////////////////////////////////////////////////////////////////
1445 /// Broadcast message 'msg' to the connected instances of client 'clnt' or to all
1446 /// connected instances if clnt == 0.
1447 
1449 {
1450  // The clients to notified
1451  std::list<XrdProofdClient *> *clnts;
1452  if (!clnt) {
1453  // The full list
1454  clnts = &fProofdClients;
1455  } else {
1456  clnts = new std::list<XrdProofdClient *>;
1457  clnts->push_back(clnt);
1458  }
1459 
1460  // Loop over them
1461  XrdProofdClient *c = 0;
1462  std::list<XrdProofdClient *>::iterator i;
1464  for (i = clnts->begin(); i != clnts->end(); ++i) {
1465  if ((c = *i))
1466  c->Broadcast(msg);
1467  }
1468 
1469  // Cleanup, if needed
1470  if (clnt) delete clnts;
1471 }
1472 
1473 ////////////////////////////////////////////////////////////////////////////////
1474 /// Terminate sessions of client 'clnt' or to of all clients if clnt == 0.
1475 /// The list of process IDs having been signalled is returned.
1476 
1478  int srvtype)
1479 {
1480  XPDLOC(CMGR, "ClientMgr::TerminateSessions")
1481 
1482  // The clients to notified
1483  bool all = 0;
1484  std::list<XrdProofdClient *> *clnts;
1485  if (!clnt) {
1486  // The full list
1487  clnts = &fProofdClients;
1488  all = 1;
1489  } else {
1490  clnts = new std::list<XrdProofdClient *>;
1491  clnts->push_back(clnt);
1492  }
1493 
1494  // If cleaning all, we send a unique meassge to scan the dirs in one go;
1495  // We first broadcast the message to connected clients.
1496  XrdProofdClient *c = 0;
1497  std::list<XrdProofdClient *>::iterator i;
1499  for (i = clnts->begin(); i != clnts->end(); ++i) {
1500  if ((c = *i)) {
1501  // Notify the attached clients that we are going to cleanup
1502  c->Broadcast(msg);
1503  }
1504  }
1505 
1506  TRACE(DBG, "cleaning "<<all);
1507 
1508  if (fMgr && fMgr->SessionMgr()) {
1509  int rc = 0;
1510  XrdOucString buf;
1511  XPDFORM(buf, "%s %d", (all ? "all" : clnt->User()), srvtype);
1512  TRACE(DBG, "posting: "<<buf);
1514  buf.c_str())) != 0) {
1515  TRACE(XERR, "problem posting the pipe; errno: "<<-rc);
1516  }
1517  }
1518 
1519  // Reset the client instances
1520  for (i = clnts->begin(); i != clnts->end(); ++i) {
1521  if ((c = *i))
1522  c->ResetSessions();
1523  }
1524 
1525  // Cleanup, if needed
1526  if (clnt) delete clnts;
1527 }
int Auth(XrdProofdProtocol *xp)
Analyse client authentication info.
bool ChangeOwn() const
#define XrdSysLogger
Definition: XpdSysLogger.h:8
int GetClientID(XrdProofdProtocol *p)
Get next free client ID.
static int Write(int fd, const void *buf, size_t nb)
Write nb bytes at buf to descriptor &#39;fd&#39; ignoring interrupts Return the number of bytes written or -1...
#define XPD_LOGGEDIN
XrdSecService * fCIA
XrdProofdManager * fMgr
int Poll(int to=-1)
Poll over the read pipe for to secs; return whatever poll returns.
#define kXPD_TopMaster
int ReserveClientID(int cid)
Reserve a client ID.
#define XPD_NEED_MAP
#define TRACING(x)
#define XPROOFD_VERSBIN
const double pi
static int GetUserInfo(const char *usr, XrdProofUI &ui)
Get information about user &#39;usr&#39; in a thread safe way.
return c
#define XPD_NEED_AUTH
int DoDirectiveClass(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Generic class directive processor.
static int RmDir(const char *path)
Remove directory at path and its content.
void RegisterDirectives()
Register directives for configuration.
#define XrdSysRecMutex
Definition: XrdSysToOuc.h:18
void SetGroup(const char *g)
static XpdManagerCron_t fManagerCron
#define TRACE(Flag, Args)
Definition: TGHtml.h:124
int SrvType() const
XrdProofGroupMgr * GroupsMgr() const
void * XrdProofdClientCron(void *p)
This is an endless loop to check the system periodically or when triggered via a message in a dedicat...
int CheckAdminPath(XrdProofdProtocol *p, XrdOucString &cidpath, XrdOucString &emsg)
Check the old-clients admin for an existing entry for this client and read the client ID;...
kXR_int32 CID() const
void SetAuthProt(XrdSecProtocol *p)
void Broadcast(XrdProofdClient *c, const char *msg)
Broadcast message &#39;msg&#39; to the connected instances of client &#39;clnt&#39; or to all connected instances if ...
int DoDirectiveInt(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Process directive for an integer.
XrdProofdProofServMgr * SessionMgr() const
void SkipSessionsCheck(std::list< XrdProofdProofServ * > *active, XrdOucString &emsg, XrdProofdResponse *r=0)
Skip the next sessions status check.
#define kXPD_MasterMaster
#define XPD_LONGOK(x)
void SetAdminPath(const char *p)
#define kXPD_ClientMaster
const char * Name
Definition: TXMLSetup.cxx:67
const char * UserIn() const
XrdProofGroup * GetGroup(const char *grp)
Returns the instance of for group &#39;grp.
char Status() const
int Type() const
Definition: XrdProofdAux.h:194
XrdSysRecMutex * Mutex() const
struct ClientRequestHdr header
int Recv(XpdMsg &msg)
Recv message from the pipe.
#define SafeDelete(p)
Definition: RConfig.h:499
XrdROOT * DefaultVersion() const
Definition: XrdROOT.h:118
void SetConnType(int ct)
void SetCID(kXR_int32 cid)
void Print()
Dump group content.
void SetUserIn(const char *uin)
#define TRACEI(id, act, x)
int MapClient(XrdProofdProtocol *xp, bool all=1)
Process a login request.
bool SuperUser() const
XrdSysPlugin * fSecPlugin
XrdProofdClientMgr * fClientMgr
void SetPid(int pid)
char * FilterSecConfig(int &nd)
Grep directives of the form "xpd.sec...", "sec.protparm" and "sec.protocol" from file &#39;cfn&#39; and save ...
bool HasMember(const char *usr)
Check if &#39;usr&#39; is member of this group.
XrdOucString fUser
Definition: XrdProofdAux.h:40
XrdSysError * fEDest
const char * GroupIn() const
#define XPDLOC(d, x)
bool IsValid() const
int Login(XrdProofdProtocol *xp)
Process a login request.
const char * TraceID() const
void TerminateSessions(XrdProofdClient *c, const char *msg, int srvtype)
Terminate sessions of client &#39;clnt&#39; or to of all clients if clnt == 0.
XrdProofdPipe * Pipe()
XrdSecService * LoadSecurity()
Load security framework and plugins, if not already done.
bool Match(const char *usr, const char *grp=0)
return TRUE if this instance matches &#39;id&#39; (and &#39;grp&#39;, if defined)
void Broadcast(const char *msg)
Broadcast message &#39;msg&#39; to the connected clients.
int ConnType() const
bool CheckMaster(const char *m)
Check if master &#39;m&#39; is allowed to connect to this host.
#define XPDERR(x)
const char * Ordinal() const
int DoDirectiveClientMgr(char *, XrdOucStream *, bool)
Process &#39;clientmgr&#39; directive eg: xpd.clientmgr checkfq:120 activityto:600.
XPClientRequest * Request() const
int ParsePreviousClients(XrdOucString &emsg)
Client entries for the clients still connected when the daemon terminated.
#define kXPD_MasterWorker
XrdProofdResponse * Response(kXR_unt16 rid)
Get response instance corresponding to stream ID &#39;sid&#39;.
XrdSysRecMutex * fMutex
static int GetIDFromPath(const char *path, XrdOucString &emsg)
Extract an integer from a file.
#define kXPD_Admin
XrdOucString fGroup
Definition: XrdProofdAux.h:41
#define XrdSysMutexHelper
Definition: XrdSysToOuc.h:17
int CheckUser(const char *usr, const char *grp, XrdProofUI &ui, XrdOucString &e, bool &su)
Check if the user is allowed to use the system Return 0 if OK, -1 if not.
#define XrdSysError
Definition: XpdSysError.h:8
#define XPD_ADMINUSER
#define XrdSysPlugin
Definition: XpdSysPlugin.h:8
#define TRACEP(p, act, x)
void SetProofProtocol(short int pp)
int Config(bool rcf=0)
Run configuration and parse the entered config directives.
XrdSecProtocol * AuthProt() const
void SetTraceID()
Auxilliary set method.
void SetClntCapVer(unsigned char c)
void SetAuthEntity(XrdSecEntity *se=0)
int CheckClient(XrdProofdProtocol *p, const char *user, XrdOucString &emsg)
Perform checks on the client username.
XrdProofGroup * GetUserGroup(const char *usr, const char *grp=0)
Returns the instance of the first group to which this user belongs; if grp != 0, return the instance ...
std::list< XrdProofdClient * > fProofdClients
XrdSecService *(* XrdSecServLoader_t)(XrdSysLogger *, const char *cfn)
const char * AdminPath() const
#define kXPD_AnyServer
#define kXPD_Internal
void SetConnection(XrdProofdResponse *r)
int Touch(bool reset=0)
Send a touch the connected clients: this will remotely touch the associated TSocket instance and sche...
int Size() const
static int AssertDir(const char *path, XrdProofUI ui, bool changeown)
Make sure that &#39;path&#39; exists and is owned by the entity described by &#39;ui&#39;.
#define XPDFORM
Definition: XrdProofdAux.h:381
#define kXPD_Worker
const char * AdminPath() const
XrdROOT * ROOT() const
XrdProofdProofServMgr * fSessionMgr
static int CheckIf(XrdOucStream *s, const char *h)
Check existence and match condition of an &#39;if&#39; directive If none (valid) is found, return -1.
int ResolveKeywords(XrdOucString &s, XrdProofdClient *pcl)
Resolve special keywords in &#39;s&#39; for client &#39;pcl&#39;.
void SetClient(XrdProofdClient *c)
int DoDirective(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
Update the priorities of the active sessions.
int DoDirectiveString(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Process directive for a string.
XrdBuffer * Argp() const
#define SafeFree(x)
Definition: XrdProofdAux.h:341
static int ParseUsrGrp(const char *path, XrdOucString &usr, XrdOucString &grp)
Parse a path in the form of "<usr>[.<grp>][.<pid>]", filling &#39;usr&#39; and &#39;grp&#39;.
void SetROOT(XrdROOT *r)
void SetSuperUser(bool su=1)
#define free
Definition: civetweb.c:821
int CheckFrequency() const
const char * Host() const
void SetValid(bool valid=1)
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
bool IsValid() const
Definition: XrdProofdAux.h:209
#define XPD_SETRESP(p, x)
struct XPClientLoginRequest login
XrdProofdProtocol * GetProtocol(int ic)
Return protocol attached to client slot at &#39;ic&#39;.
XrdOucString fName
Definition: XrdProofdAux.h:111
int CreateAdminPath(XrdProofdProtocol *p, XrdOucString &path, XrdOucString &e)
Create the client directory in the admin path.
const char * EffectiveUser() const
const char * User() const
XrdROOTMgr * ROOTMgr() const
XrdProofdClientMgr(XrdProofdManager *mgr, XrdProtocol_Config *pi, XrdSysError *e)
Constructor.
#define snprintf
Definition: civetweb.c:822
const char * Name() const
Definition: XrdProofGroup.h:75
#define kXPD_Master
XrdProofdClient * GetClient(const char *usr, const char *grp=0, bool create=1)
Handle request for localizing a client instance for {usr, grp} from the list.
int Post(int type, const char *msg)
Post message on the pipe.
const char * CfgFile() const
XrdProofdProofServ * GetServer(int psid)
Get from the vector server instance with ID psid.
XrdLink * Link() const
virtual int Config(bool rcf=0)
void SetStatus(char s)
void SetTag(const char *tag)
XrdOucString fClntAdminPath
const char * TMPdir() const
bool RemotePLite() const
void Register(const char *dname, XrdProofdDirective *d)
XrdProofdClient * Client() const
int CheckClients()
Regular checks of the client admin path; run by the cron job.
void ResetSessions()
Reset this instance.
void SetGroupIn(const char *gin)
int SetClientID(int cid, XrdProofdProtocol *p)
Set slot cid to instance &#39;p&#39;.