Logo ROOT   6.14/05
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  if (!resp) {
678  TRACEP(p, XERR, "proofsrv callback: could not get XrdProofdResponse object");
679  response->Send(kXP_nosession, "MapClient: proofsrv callback: memory issue?");
680  return -1;
681  }
682  psrv->SetConnection(resp);
683  psrv->SetValid(1);
684  // Set Trace ID
685  XrdOucString tid;
686  XPDFORM(tid, "xrd->%s", psrv->Ordinal());
687  resp->SetTag(tid.c_str());
688  resp->SetTraceID();
689  TRACEI(resp->TraceID(), DBG, "proofsrv callback: link assigned to target session "<<psid);
690  }
691  } else {
692 
693  // Only one instance of this client can map at a time
694  XrdSysMutexHelper mhc(pc->Mutex());
695 
696  // Make sure that the version is filled correctly (if an admin operation
697  // was run before this may still be -1 on workers)
698  p->SetProofProtocol(clientvers);
699 
700  // Check if we have already an ID for this client from a previous connection
701  XrdOucString cpath;
702  int cid = -1;
703  if ((cid = CheckAdminPath(p, cpath, msg)) >= 0) {
704  // Assign the slot
705  pc->SetClientID(cid, p);
706  // The index of the next free slot will be the unique ID
707  p->SetCID(cid);
708  // Remove the file indicating that this client was still disconnected
709  XrdOucString discpath(cpath, 0, cpath.rfind("/cid"));
710  discpath += "/disconnected";
711  if (unlink(discpath.c_str()) != 0) {
712  XPDFORM(msg, "warning: could not remove %s (errno: %d)", discpath.c_str(), errno);
713  TRACEP(p, XERR, msg.c_str());
714  }
715  // Update counters
717 
718  } else {
719  // The index of the next free slot will be the unique ID
720  p->SetCID(pc->GetClientID(p));
721  // Create the client directory in the admin path
722  if (CreateAdminPath(p, cpath, msg) != 0) {
723  TRACEP(p, XERR, msg.c_str());
724  fProofdClients.remove(pc);
725  SafeDelete(pc);
726  p->SetClient(0);
727  response->Send(kXP_ServerError, msg.c_str());
728  return 0;
729  }
730  }
731  p->SetAdminPath(cpath.c_str());
732  XPDFORM(msg, "client ID and admin paths created: %s", cpath.c_str());
733  TRACEP(p, DBG, msg.c_str());
734 
735  TRACEP(p, DBG, "CID: "<<p->CID()<<", size: "<<pc->Size());
736  }
737 
738  // Document this login
739  if (!(p->Status() & XPD_NEED_AUTH)) {
740  const char *srvtype[6] = {"ANY", "MasterWorker", "MasterMaster",
741  "ClientMaster", "Internal", "Admin"};
742  XPDFORM(msg, "user %s logged-in%s; type: %s", pc->User(),
743  p->SuperUser() ? " (privileged)" : "", srvtype[p->ConnType()+1]);
744  TRACEP(p, LOGIN, msg);
745  }
746 
747  // Done
748  return 0;
749 }
750 
751 ////////////////////////////////////////////////////////////////////////////////
752 /// Create the client directory in the admin path
753 
755  XrdOucString &cpath, XrdOucString &emsg)
756 {
757  if (!p || !p->Link()) {
758  XPDFORM(emsg, "invalid inputs (p: %p)", p);
759  return -1;
760  }
761 
762  // Create link ID
763  XrdOucString lid;
764  XPDFORM(lid, "%s.%d", p->Link()->Host(), p->Pid());
765 
766  // Create the path now
767  XPDFORM(cpath, "%s/%s", p->Client()->AdminPath(), lid.c_str());
768  XrdProofUI ui;
770  if (XrdProofdAux::AssertDir(cpath.c_str(), ui, 1) != 0) {
771  XPDFORM(emsg, "error creating client admin path: %s", cpath.c_str());
772  return -1;
773  }
774  // Save client ID for full recovery
775  cpath += "/cid";
776  FILE *fcid = fopen(cpath.c_str(), "w");
777  if (fcid) {
778  fprintf(fcid, "%d", p->CID());
779  fclose(fcid);
780  } else {
781  XPDFORM(emsg, "error creating file for client id: %s", cpath.c_str());
782  return -1;
783  }
784  // Done
785  return 0;
786 }
787 
788 ////////////////////////////////////////////////////////////////////////////////
789 /// Check the old-clients admin for an existing entry for this client and
790 /// read the client ID;
791 
793  XrdOucString &cidpath, XrdOucString &emsg)
794 {
795  emsg = "";
796  if (!p) {
797  XPDFORM(emsg, "CheckAdminPath: invalid inputs (p: %p)", p);
798  return -1;
799  }
800 
801  // Create link ID
802  XrdOucString lid;
803  XPDFORM(lid, "%s.%d", p->Link()->Host(), p->Pid());
804 
805  // Create the path now
806  XPDFORM(cidpath, "%s/%s/cid", p->Client()->AdminPath(), lid.c_str());
807 
808  // Create disconnected path
809  XrdOucString discpath;
810  XPDFORM(discpath, "%s/%s/disconnected", p->Client()->AdminPath(), lid.c_str());
811 
812  // Check last access time of disconnected if available, otherwise cid
813  bool expired = false;
814  struct stat st;
815  int rc = stat(discpath.c_str(), &st);
816  if (rc != 0) rc = stat(cidpath.c_str(), &st);
817  if (rc != 0 || (expired = ((int)(time(0) - st.st_atime) > fReconnectTimeOut))) {
818  if (expired || (rc != 0 && errno != ENOENT)) {
819  // Remove the file
820  cidpath.replace("/cid", "");
821  if (expired)
822  XPDFORM(emsg, "CheckAdminPath: reconnection timeout expired: remove %s ",
823  cidpath.c_str());
824  else
825  XPDFORM(emsg, "CheckAdminPath: problems stat'ing %s (errno: %d): remove ",
826  cidpath.c_str(), errno);
827  if (XrdProofdAux::RmDir(cidpath.c_str()) != 0)
828  emsg += ": failure!";
829  } else {
830  XPDFORM(emsg, "CheckAdminPath: no such file %s", cidpath.c_str());
831  }
832  return -1;
833  }
834 
835  // Get the client ID for full recovery
836  return XrdProofdAux::GetIDFromPath(cidpath.c_str(), emsg);
837 }
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 /// Client entries for the clients still connected when the daemon terminated
841 
843 {
844  XPDLOC(CMGR, "ClientMgr::ParsePreviousClients")
845 
846  emsg = "";
847 
848  // Open dir
849  DIR *dir = opendir(fClntAdminPath.c_str());
850  if (!dir) {
851  TRACE(XERR, "cannot open dir "<<fClntAdminPath<<" ; error: "<<errno);
852  return -1;
853  }
854  TRACE(DBG, "creating holders for active clients ...");
855 
856  // Scan the active sessions admin path
857  XrdOucString usrpath, cidpath, discpath, usr, grp;
858  struct dirent *ent = 0;
859  while ((ent = (struct dirent *)readdir(dir))) {
860  // Skip the basic entries
861  if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
862  XPDFORM(usrpath, "%s/%s", fClntAdminPath.c_str(), ent->d_name);
863  bool rm = 0;
864  struct stat st;
865  if (stat(usrpath.c_str(), &st) == 0) {
866  usr = ent->d_name;
867  grp = usr;
868  usr.erase(usr.find('.'));
869  grp.erase(0, grp.find('.')+1);
870  TRACE(DBG, "found usr: "<<usr<<", grp: "<<grp);
871  // Get client instance
872  XrdProofdClient *c = GetClient(usr.c_str(), grp.c_str());
873  if (!c) {
874  XPDFORM(emsg, "ParsePreviousClients: could not get client instance"
875  " for {%s, %s}", usr.c_str(), grp.c_str());
876  rm = 1;
877  }
878  // Open user sub-dir
879  DIR *subdir = 0;
880  if (!rm && !(subdir = opendir(usrpath.c_str()))) {
881  TRACE(XERR, "cannot open dir "<<usrpath<<" ; error: "<<errno);
882  rm = 1;
883  }
884  if (!rm) {
885  bool xrm = 0;
886  struct dirent *sent = 0;
887  while ((sent = (struct dirent *)readdir(subdir))) {
888  // Skip the basic entries
889  if (!strcmp(sent->d_name, ".") || !strcmp(sent->d_name, "..")) continue;
890  if (!strcmp(sent->d_name, "xpdsock")) continue;
891  XPDFORM(cidpath, "%s/%s/cid", usrpath.c_str(), sent->d_name);
892  // Check last access time
893  if (stat(cidpath.c_str(), &st) != 0 ||
894  (int)(time(0) - st.st_atime) > fReconnectTimeOut) {
895  xrm = 1;
896  }
897  // Read the client ID and and reserve an entry in the related vector
898  int cid = (!xrm) ? XrdProofdAux::GetIDFromPath(cidpath.c_str(), emsg) : -1;
899  if (cid < 0)
900  xrm = 1;
901  // Reserve an entry in the related vector
902  if (!xrm && c->ReserveClientID(cid) != 0)
903  xrm = 1;
904  // Flag this as disconnected
905  if (!xrm) {
906  XPDFORM(discpath, "%s/%s/disconnected", usrpath.c_str(), sent->d_name);
907  FILE *fd = fopen(discpath.c_str(), "w");
908  if (!fd) {
909  TRACE(XERR, "unable to create path: " <<discpath);
910  xrm = 1;
911  } else {
912  fclose(fd);
913  }
914  if (!xrm)
915  fNDisconnected++;
916  }
917  // If it did not work remove the entry
918  if (xrm) {
919  TRACE(DBG, "removing path: " <<cidpath);
920  cidpath.replace("/cid", "");
921  XPDFORM(emsg, "ParsePreviousClients: failure: remove %s ", cidpath.c_str());
922  if (XrdProofdAux::RmDir(cidpath.c_str()) != 0)
923  emsg += ": failure!";
924  }
925  }
926  }
927  if (subdir)
928  closedir(subdir);
929  } else {
930  rm = 1;
931  }
932  // If it did not work remove the entry
933  if (rm) {
934  TRACE(DBG, "removing path: " <<usrpath);
935  XPDFORM(emsg, "ParsePreviousClients: failure: remove %s ", usrpath.c_str());
936  if (XrdProofdAux::RmDir(usrpath.c_str()) != 0)
937  emsg += ": failure!";
938  }
939  }
940  // Close the directory
941  closedir(dir);
942 
943  // Notify the number of previously active clients now offline
944  TRACE(DBG, "found "<<fNDisconnected<<" active clients");
945 
946  // Done
947  return 0;
948 }
949 
950 ////////////////////////////////////////////////////////////////////////////////
951 /// Regular checks of the client admin path; run by the cron job
952 
954 {
955  XPDLOC(CMGR, "ClientMgr::CheckClients")
956 
957  // Open dir
958  DIR *dir = opendir(fClntAdminPath.c_str());
959  if (!dir) {
960  TRACE(XERR, "cannot open dir "<<fClntAdminPath<<" ; error: "<<errno);
961  return -1;
962  }
963  TRACE(REQ, "checking active clients ...");
964 
965  // Scan the active sessions admin path
966  int rc = 0;
967  XrdOucString usrpath, cidpath, discpath;
968  struct dirent *ent = 0;
969  while ((ent = (struct dirent *)readdir(dir))) {
970  // Skip the basic entries
971  if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
972  XPDFORM(usrpath, "%s/%s", fClntAdminPath.c_str(), ent->d_name);
973  bool rm = 0;
974  XrdProofdClient *c = 0;
975  struct stat st, xst;
976  if (stat(usrpath.c_str(), &xst) == 0) {
977  // Find client instance
978  XrdOucString usr, grp;
979  XrdProofdAux::ParseUsrGrp(ent->d_name, usr, grp);
980  if (!(c = GetClient(usr.c_str(), grp.c_str(), 0))) {
981  TRACE(XERR, "instance for client "<<ent->d_name<<" not found!");
982  rm = 1;
983  }
984  // Open user sub-dir
985  DIR *subdir = 0;
986  if (!rm && !(subdir = opendir(usrpath.c_str()))) {
987  TRACE(XERR, "cannot open dir "<<usrpath<<" ; error: "<<errno);
988  rm = 1;
989  }
990  if (!rm) {
991  bool xrm = 0, xclose = 0;
992  struct dirent *sent = 0;
993  while ((sent = (struct dirent *)readdir(subdir))) {
994  // Skip the basic entries
995  if (!strcmp(sent->d_name, ".") || !strcmp(sent->d_name, "..")) continue;
996  if (!strcmp(sent->d_name, "xpdsock")) continue;
997  XPDFORM(discpath, "%s/%s/disconnected", usrpath.c_str(), sent->d_name);
998  // Client admin path
999  XPDFORM(cidpath, "%s/%s/cid", usrpath.c_str(), sent->d_name);
1000  // Check last access time
1001  if (stat(cidpath.c_str(), &st) == 0) {
1002  // If in disconnected state, check if it needs to be cleaned
1003  if (stat(discpath.c_str(), &xst) == 0) {
1004  if ((int)(time(0) - st.st_atime) > fReconnectTimeOut) {
1005  xrm = 1;
1006  }
1007  } else {
1008  // If required, check the recent activity; if inactive since too long
1009  // we ask the client to proof its vitality; but only once: next time
1010  // we close the link
1011  if (fActivityTimeOut > 0 &&
1012  (int)(time(0) - st.st_atime) > fActivityTimeOut) {
1013  if (c->Touch() == 1) {
1014  // The client was already asked to proof its vitality
1015  // during last cycle and it did not do it, so we close
1016  // the link
1017  xclose = 1;
1018  }
1019  }
1020  }
1021  } else {
1022  // No id info, clean
1023  xrm = 1;
1024  }
1025  // If inactive since too long, close the associated link
1026  if (xclose) {
1027  // Get the client id
1028  XrdOucString emsg;
1029  int cid = XrdProofdAux::GetIDFromPath(cidpath.c_str(), emsg);
1030  if (cid >= 0) {
1031  // Get the XrdProofdProtocol instance
1032  XrdProofdProtocol *p = c->GetProtocol(cid);
1033  if (p && p->Link()) {
1034  // This client will try to reconnect, if alive, so give it
1035  // some time by skipping the next sessions check
1036  c->SkipSessionsCheck(0, emsg);
1037  // Close the associated link; Recycle is called from there
1038  p->Link()->Close();
1039  } else {
1040  TRACE(XERR, "protocol or link associated with ID "<<cid<<" are invalid");
1041  xrm = 1;
1042  }
1043  } else {
1044  TRACE(XERR, "could not resolve client id from "<<cidpath);
1045  xrm = 1;
1046  }
1047  }
1048  // If too old remove the entry
1049  if (xrm) {
1050  discpath.replace("/disconnected", "");
1051  TRACE(DBG, "removing path "<<discpath);
1052  if ((rc = XrdProofdAux::RmDir(discpath.c_str())) != 0) {
1053  TRACE(XERR, "problems removing "<<discpath<<"; error: "<<-rc);
1054  }
1055  }
1056  }
1057  }
1058  if (subdir)
1059  closedir(subdir);
1060  } else {
1061  rm = 1;
1062  }
1063  // If it did not work remove the entry
1064  if (rm) {
1065  TRACE(DBG, "removing path: " <<usrpath);
1066  if ((rc = XrdProofdAux::RmDir(usrpath.c_str())) != 0) {
1067  TRACE(XERR, "problems removing "<<usrpath<<"; error: "<<-rc);
1068  }
1069  }
1070  }
1071  // Close the directory
1072  closedir(dir);
1073 
1074  // Done
1075  return 0;
1076 }
1077 
1078 ////////////////////////////////////////////////////////////////////////////////
1079 /// Analyse client authentication info
1080 
1082 {
1083  XPDLOC(CMGR, "ClientMgr::Auth")
1084 
1085  XrdSecCredentials cred;
1086  XrdSecParameters *parm = 0;
1087  XrdOucErrInfo eMsg;
1088  const char *eText;
1089  int rc = 1;
1090  XPD_SETRESP(p, "Auth");
1091 
1092  TRACEP(p, REQ, "enter");
1093 
1094  // Ignore authenticate requests if security turned off
1095  if (!fCIA)
1096  return response->Send();
1097  cred.size = p->Request()->header.dlen;
1098  cred.buffer = p->Argp()->buff;
1099 
1100  // If we have no auth protocol, try to get it
1101  if (!p->AuthProt()) {
1102  XrdSecProtocol *ap = 0;
1103 #ifdef ROOT_XrdFour
1104  XrdNetAddr netaddr(p->Link()->NetAddr());
1105 #else
1106  struct sockaddr netaddr;
1107  p->Link()->Name(&netaddr);
1108 #endif
1109  if (!(ap = fCIA->getProtocol(p->Link()->Host(), netaddr, &cred, &eMsg))) {
1110  eText = eMsg.getErrText(rc);
1111  TRACEP(p, XERR, "user authentication failed; "<<eText);
1112  response->Send(kXR_NotAuthorized, eText);
1113  return -EACCES;
1114  }
1115  p->SetAuthProt(ap);
1116  p->AuthProt()->Entity.tident = p->Link()->ID;
1117  }
1118  // Set the wanted login name
1119  size_t len = strlen("XrdSecLOGINUSER=")+strlen(p->UserIn())+2;
1120  char *u = new char[len];
1121  snprintf(u, len, "XrdSecLOGINUSER=%s", p->UserIn());
1122  putenv(u);
1123 
1124  // Now try to authenticate the client using the current protocol
1125  XrdOucString namsg;
1126  if (!(rc = p->AuthProt()->Authenticate(&cred, &parm, &eMsg))) {
1127 
1128  // Make sure that the user name that we want is allowed
1129  if (p->AuthProt()->Entity.name && strlen(p->AuthProt()->Entity.name) > 0) {
1130  if (p->UserIn() && strlen(p->UserIn()) > 0) {
1131  XrdOucString usrs(p->AuthProt()->Entity.name);
1132  SafeFree(p->AuthProt()->Entity.name);
1133  XrdOucString usr;
1134  int from = 0, rcmtc = -1;
1135  while ((from = usrs.tokenize(usr, from, ',')) != STR_NPOS) {
1136  // The first one by default, if no match is found
1137  if (!(p->AuthProt()->Entity.name))
1138  p->AuthProt()->Entity.name = strdup(usr.c_str());
1139  if ((usr == p->UserIn())) {
1140  free(p->AuthProt()->Entity.name);
1141  p->AuthProt()->Entity.name = strdup(usr.c_str());
1142  rcmtc = 0;
1143  break;
1144  }
1145  }
1146  if (rcmtc != 0) {
1147  namsg = "logging as '";
1148  namsg += p->AuthProt()->Entity.name;
1149  namsg += "' instead of '";
1150  namsg += p->UserIn();
1151  namsg += "' following admin settings";
1152  TRACEP(p, LOGIN, namsg.c_str());
1153  namsg.insert("Warning: ", 0);
1154  response->Send(kXR_attn, kXPD_srvmsg, 2, (char *) namsg.c_str(), namsg.length());
1155  }
1156  } else {
1157  TRACEP(p, XERR, "user name is empty: protocol error?");
1158  }
1159  } else {
1160  TRACEP(p, XERR, "name of the authenticated entity is empty: protocol error?");
1161  rc = -1;
1162  }
1163 
1164  if (rc == 0) {
1165  const char *msg = (p->Status() & XPD_ADMINUSER) ? " admin login as " : " login as ";
1166  rc = response->Send();
1167  char status = p->Status();
1168  status &= ~XPD_NEED_AUTH;
1169  p->SetStatus(status);
1170  p->SetAuthEntity(&(p->AuthProt()->Entity));
1171  if (p->AuthProt()->Entity.name) {
1172  TRACEP(p, LOGIN, p->Link()->ID << msg << p->AuthProt()->Entity.name);
1173  } else {
1174  TRACEP(p, LOGIN, p->Link()->ID << msg << " nobody");
1175  }
1176  return rc;
1177  }
1178  }
1179 
1180  // If we need to continue authentication, tell the client as much
1181  if (rc > 0) {
1182  TRACEP(p, DBG, "more auth requested; sz: " <<(parm ? parm->size : 0));
1183  if (parm) {
1184  rc = response->Send(kXR_authmore, parm->buffer, parm->size);
1185  delete parm;
1186  return rc;
1187  }
1188  if (p->AuthProt()) {
1189  p->AuthProt()->Delete();
1190  p->SetAuthProt(0);
1191  }
1192  TRACEP(p, XERR, "security requested additional auth w/o parms!");
1193  response->Send(kXP_ServerError, "invalid authentication exchange");
1194  return -EACCES;
1195  }
1196 
1197  // We got an error, bail out
1198  if (p->AuthProt()) {
1199  p->AuthProt()->Delete();
1200  p->SetAuthProt(0);
1201  }
1202  eText = (namsg.length() > 0) ? namsg.c_str() : eMsg.getErrText(rc);
1203  TRACEP(p, XERR, "user authentication failed; "<<eText);
1204  response->Send(kXR_NotAuthorized, eText);
1205  return -EACCES;
1206 }
1207 
1208 ////////////////////////////////////////////////////////////////////////////////
1209 /// Load security framework and plugins, if not already done
1210 
1212 {
1213  XPDLOC(CMGR, "ClientMgr::LoadSecurity")
1214 
1215  TRACE(REQ, "LoadSecurity");
1216 
1217  const char *cfn = CfgFile();
1218  const char *seclib = fSecLib.c_str();
1219 
1220  // Make sure the input config file is defined
1221  if (!cfn) {
1222  TRACE(XERR, "config file not specified");
1223  return 0;
1224  }
1225 
1226  // Create the plug-in instance
1227  if (!(fSecPlugin = new XrdSysPlugin((fEDest ? fEDest : (XrdSysError *)0), seclib))) {
1228  TRACE(XERR, "could not create plugin instance for "<<seclib);
1229  return (XrdSecService *)0;
1230  }
1231 
1232  // Get the function
1233  XrdSecServLoader_t ep = (XrdSecServLoader_t) fSecPlugin->getPlugin("XrdSecgetService");
1234  if (!ep) {
1235  TRACE(XERR, "could not find 'XrdSecgetService()' in "<<seclib);
1236  return (XrdSecService *)0;
1237  }
1238 
1239  // Extract in a temporary file the directives prefixed "xpd.sec..." (filtering
1240  // out the prefix), "sec.protocol" and "sec.protparm"
1241  int nd = 0;
1242  char *rcfn = FilterSecConfig(nd);
1243  if (!rcfn) {
1245  if (nd == 0) {
1246  // No directives to be processed
1247  TRACE(XERR, "no security directives: strong authentication disabled");
1248  return 0;
1249  }
1250  // Failure
1251  TRACE(XERR, "creating temporary config file");
1252  return 0;
1253  }
1254 
1255  // Get the server object
1256  XrdSecService *cia = 0;
1257  if (!(cia = (*ep)((fEDest ? fEDest->logger() : (XrdSysLogger *)0), rcfn))) {
1258  TRACE(XERR, "Unable to create security service object via " << seclib);
1260  unlink(rcfn);
1261  delete[] rcfn;
1262  return 0;
1263  }
1264  // Notify
1265  TRACE(ALL, "strong authentication enabled");
1266 
1267  // Unlink the temporary file and cleanup its path
1268  unlink(rcfn);
1269  delete[] rcfn;
1270 
1271  // All done
1272  return cia;
1273 }
1274 
1275 ////////////////////////////////////////////////////////////////////////////////
1276 /// Grep directives of the form "xpd.sec...", "sec.protparm" and
1277 /// "sec.protocol" from file 'cfn' and save them in a temporary file,
1278 /// stripping off the prefix "xpd." when needed.
1279 /// If any such directory is found, the full path of the temporary file
1280 /// is returned, with the number of directives found in 'nd'.
1281 /// Otherwise 0 is returned and '-errno' specified in nd.
1282 /// The caller has the responsability to unlink the temporary file and
1283 /// to release the memory allocated for the path.
1284 
1286 {
1287  XPDLOC(CMGR, "ClientMgr::FilterSecConfig")
1288 
1289  static const char *pfx[] = { "xpd.sec.", "sec.protparm", "sec.protocol", "set" };
1290  char *rcfn = 0;
1291 
1292  TRACE(REQ, "enter");
1293 
1294  const char *cfn = CfgFile();
1295 
1296  // Make sure that we got an input file path and that we can open the
1297  // associated path.
1298  FILE *fin = 0;
1299  if (!cfn || !(fin = fopen(cfn,"r"))) {
1300  nd = (errno > 0) ? -errno : -1;
1301  return rcfn;
1302  }
1303 
1304  // Read the directives: if an interesting one is found, we create
1305  // the output temporary file
1306  int fd = -1;
1307  char lin[2048];
1308  while (fgets(lin,sizeof(lin),fin)) {
1309  if (!strncmp(lin, pfx[0], strlen(pfx[0])) ||
1310  !strncmp(lin, pfx[1], strlen(pfx[1])) ||
1311  !strncmp(lin, pfx[2], strlen(pfx[2])) ||
1312  !strncmp(lin, pfx[3], strlen(pfx[3]))) {
1313  // Target directive found
1314  nd++;
1315  // Create the output file, if not yet done
1316  if (!rcfn) {
1317  size_t len = strlen(fMgr->TMPdir()) + strlen("/xpdcfn_XXXXXX") + 2;
1318  rcfn = new char[len];
1319  snprintf(rcfn, len, "%s/xpdcfn_XXXXXX", fMgr->TMPdir());
1320  mode_t oldum = umask(022);
1321  if ((fd = mkstemp(rcfn)) < 0) {
1322  delete[] rcfn;
1323  nd = (errno > 0) ? -errno : -1;
1324  fclose(fin);
1325  rcfn = 0;
1326  oldum = umask(oldum);
1327  return rcfn;
1328  }
1329  oldum = umask(oldum);
1330  }
1331  XrdOucString slin = lin;
1332  // Strip the prefix "xpd."
1333  if (slin.beginswith("xpd.")) slin.replace("xpd.","");
1334  // Make keyword substitution
1335  fMgr->ResolveKeywords(slin, 0);
1336  // Write the line to the output file
1337  XrdProofdAux::Write(fd, slin.c_str(), slin.length());
1338  }
1339  }
1340 
1341  // Close files
1342  fclose(fin);
1343  if (fd >= 0) close(fd);
1344 
1345  return rcfn;
1346 }
1347 
1348 ////////////////////////////////////////////////////////////////////////////////
1349 /// Handle request for localizing a client instance for {usr, grp} from the list.
1350 /// Create a new instance, if required; for new instances, use the path at 'sock'
1351 /// for the unix socket, or generate a new one, if sock = 0.
1352 
1353 XrdProofdClient *XrdProofdClientMgr::GetClient(const char *usr, const char *grp,
1354  bool create)
1355 {
1356  XPDLOC(CMGR, "ClientMgr::GetClient")
1357 
1358  TRACE(DBG, "usr: "<< (usr ? usr : "undef")<<", grp:"<<(grp ? grp : "undef"));
1359 
1360  XrdOucString dmsg, emsg;
1361  XrdProofdClient *c = 0;
1362  bool newclient = 0;
1363  std::list<XrdProofdClient *>::iterator i;
1364 
1365  { XrdSysMutexHelper mh(fMutex);
1366  for (i = fProofdClients.begin(); i != fProofdClients.end(); ++i) {
1367  if ((c = *i) && c->Match(usr,grp)) break;
1368  c = 0;
1369  }
1370  }
1371 
1372  if (!c && create) {
1373  // Is this a potential user?
1374  XrdProofUI ui;
1375  bool su;
1376  if (fMgr->CheckUser(usr, grp, ui, emsg, su) == 0) {
1377  // Yes: create an (invalid) instance of XrdProofdClient:
1378  // It would be validated on the first valid login
1379  ui.fUser = usr;
1380  ui.fGroup = grp;
1381  bool full = (fMgr->SrvType() != kXPD_Worker) ? 1 : 0;
1382  c = new XrdProofdClient(ui, full, fMgr->ChangeOwn(), fEDest, fClntAdminPath.c_str(), fReconnectTimeOut);
1383  newclient = 1;
1384  bool freeclient = 1;
1385  if (c && c->IsValid()) {
1386  // Locate and set the group, if any
1387  if (fMgr->GroupsMgr() && fMgr->GroupsMgr()->Num() > 0) {
1388  XrdProofGroup *g = fMgr->GroupsMgr()->GetUserGroup(usr, grp);
1389  if (g) {
1390  c->SetGroup(g->Name());
1391  } else if (TRACING(XERR)) {
1392  emsg = "group = "; emsg += grp; emsg += " nor found";
1393  }
1394  }
1395  { XrdSysMutexHelper mh(fMutex);
1396  XrdProofdClient *nc = 0;
1397  for (i = fProofdClients.begin(); i != fProofdClients.end(); ++i) {
1398  if ((nc = *i) && nc->Match(usr,grp)) break;
1399  nc = 0;
1400  newclient = 0;
1401  }
1402  if (!nc) {
1403  // Add to the list
1404  fProofdClients.push_back(c);
1405  freeclient = 0;
1406  }
1407  }
1408  if (freeclient) {
1409  SafeDelete(c);
1410  } else if (TRACING(DBG)) {
1411  XPDFORM(dmsg, "instance for {client, group} = {%s, %s} created"
1412  " and added to the list (%p)", usr, grp, c);
1413  }
1414  } else {
1415  if (TRACING(XERR)) {
1416  XPDFORM(dmsg, "instance for {client, group} = {%s, %s} is invalid", usr, grp);
1417  }
1418  SafeDelete(c);
1419  }
1420  } else {
1421  if (TRACING(XERR)) {
1422  XPDFORM(dmsg, "client '%s' unknown or unauthorized: %s", usr, emsg.c_str());
1423  }
1424  }
1425  }
1426 
1427  // Trim the sandbox, if needed
1428  if (c && !newclient) {
1429  if (c->TrimSessionDirs() != 0) {
1430  if (TRACING(XERR)) {
1431  XPDFORM(dmsg, "problems trimming client '%s' sandbox", usr);
1432  }
1433  }
1434  }
1435 
1436  if (dmsg.length() > 0) {
1437  if (TRACING(DBG)) {
1438  TRACE(DBG, dmsg);
1439  } else {
1440  if (emsg.length() > 0) TRACE(XERR, emsg);
1441  TRACE(XERR, dmsg);
1442  }
1443  }
1444 
1445  // Over
1446  return c;
1447 }
1448 
1449 ////////////////////////////////////////////////////////////////////////////////
1450 /// Broadcast message 'msg' to the connected instances of client 'clnt' or to all
1451 /// connected instances if clnt == 0.
1452 
1454 {
1455  // The clients to notified
1456  std::list<XrdProofdClient *> *clnts;
1457  if (!clnt) {
1458  // The full list
1459  clnts = &fProofdClients;
1460  } else {
1461  clnts = new std::list<XrdProofdClient *>;
1462  clnts->push_back(clnt);
1463  }
1464 
1465  // Loop over them
1466  XrdProofdClient *c = 0;
1467  std::list<XrdProofdClient *>::iterator i;
1469  for (i = clnts->begin(); i != clnts->end(); ++i) {
1470  if ((c = *i))
1471  c->Broadcast(msg);
1472  }
1473 
1474  // Cleanup, if needed
1475  if (clnt) delete clnts;
1476 }
1477 
1478 ////////////////////////////////////////////////////////////////////////////////
1479 /// Terminate sessions of client 'clnt' or to of all clients if clnt == 0.
1480 /// The list of process IDs having been signalled is returned.
1481 
1483  int srvtype)
1484 {
1485  XPDLOC(CMGR, "ClientMgr::TerminateSessions")
1486 
1487  // The clients to notified
1488  bool all = 0;
1489  std::list<XrdProofdClient *> *clnts;
1490  if (!clnt) {
1491  // The full list
1492  clnts = &fProofdClients;
1493  all = 1;
1494  } else {
1495  clnts = new std::list<XrdProofdClient *>;
1496  clnts->push_back(clnt);
1497  }
1498 
1499  // If cleaning all, we send a unique meassge to scan the dirs in one go;
1500  // We first broadcast the message to connected clients.
1501  XrdProofdClient *c = 0;
1502  std::list<XrdProofdClient *>::iterator i;
1504  for (i = clnts->begin(); i != clnts->end(); ++i) {
1505  if ((c = *i)) {
1506  // Notify the attached clients that we are going to cleanup
1507  c->Broadcast(msg);
1508  }
1509  }
1510 
1511  TRACE(DBG, "cleaning "<<all);
1512 
1513  if (fMgr && fMgr->SessionMgr()) {
1514  int rc = 0;
1515  XrdOucString buf;
1516  XPDFORM(buf, "%s %d", (all ? "all" : clnt->User()), srvtype);
1517  TRACE(DBG, "posting: "<<buf);
1519  buf.c_str())) != 0) {
1520  TRACE(XERR, "problem posting the pipe; errno: "<<-rc);
1521  }
1522  }
1523 
1524  // Reset the client instances
1525  for (i = clnts->begin(); i != clnts->end(); ++i) {
1526  if ((c = *i))
1527  c->ResetSessions();
1528  }
1529 
1530  // Cleanup, if needed
1531  if (clnt) delete clnts;
1532 }
int Auth(XrdProofdProtocol *xp)
Analyse client authentication info.
const char * Name() const
Definition: XrdProofGroup.h:75
XrdSysRecMutex * Mutex() 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.
static constexpr double pi
bool IsValid() const
Definition: XrdProofdAux.h:209
#define kXPD_TopMaster
int ReserveClientID(int cid)
Reserve a client ID.
#define XPD_NEED_MAP
#define TRACING(x)
XrdProofdProofServMgr * SessionMgr() const
#define XPROOFD_VERSBIN
static int GetUserInfo(const char *usr, XrdProofUI &ui)
Get information about user &#39;usr&#39; in a thread safe way.
XrdLink * Link() const
XrdROOT * DefaultVersion() const
Definition: XrdROOT.h:118
#define XPD_NEED_AUTH
#define g(i)
Definition: RSha256.hxx:105
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
bool SuperUser() const
void SetGroup(const char *g)
static XpdManagerCron_t fManagerCron
#define TRACE(Flag, Args)
Definition: TGHtml.h:120
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
int Type() const
Definition: XrdProofdAux.h:194
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.
int Size() const
#define kXPD_MasterMaster
#define XPD_LONGOK(x)
void SetAdminPath(const char *p)
bool ChangeOwn() const
#define kXPD_ClientMaster
const char * Name
Definition: TXMLSetup.cxx:66
XrdProofGroup * GetGroup(const char *grp)
Returns the instance of for group &#39;grp.
XrdSecProtocol * AuthProt() const
const char * AdminPath() const
struct ClientRequestHdr header
int Recv(XpdMsg &msg)
Recv message from the pipe.
void SetConnType(int ct)
void SetCID(kXR_int32 cid)
void Print()
Dump group content.
XrdProofGroupMgr * GroupsMgr() const
const char * User() const
void SetUserIn(const char *uin)
XrdBuffer * Argp() const
#define TRACEI(id, act, x)
int SrvType() const
int MapClient(XrdProofdProtocol *xp, bool all=1)
Process a login request.
XrdSysPlugin * fSecPlugin
XrdProofdClientMgr * fClientMgr
const char * Ordinal() const
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
#define XPDLOC(d, x)
int Login(XrdProofdProtocol *xp)
Process a login request.
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.
bool CheckMaster(const char *m)
Check if master &#39;m&#39; is allowed to connect to this host.
#define XPDERR(x)
int DoDirectiveClientMgr(char *, XrdOucStream *, bool)
Process &#39;clientmgr&#39; directive eg: xpd.clientmgr checkfq:120 activityto:600.
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
const char * Host() const
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.
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 * TraceID() const
#define kXPD_AnyServer
const char * TMPdir() const
#define kXPD_Internal
const char * UserIn() const
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...
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 SafeDelete(p)
Definition: RConfig.h:529
#define d(i)
Definition: RSha256.hxx:102
XrdROOTMgr * ROOTMgr() const
#define XPDFORM
Definition: XrdProofdAux.h:381
#define kXPD_Worker
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.
#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:1350
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
const char * AdminPath() const
const char * EffectiveUser() const
#define XPD_SETRESP(p, x)
struct XPClientLoginRequest login
XrdProofdProtocol * GetProtocol(int ic)
Return protocol attached to client slot at &#39;ic&#39;.
XrdROOT * ROOT() const
XrdOucString fName
Definition: XrdProofdAux.h:111
const char * GroupIn() const
int CreateAdminPath(XrdProofdProtocol *p, XrdOucString &path, XrdOucString &e)
Create the client directory in the admin path.
const char * CfgFile() const
XrdProofdClientMgr(XrdProofdManager *mgr, XrdProtocol_Config *pi, XrdSysError *e)
Constructor.
#define snprintf
Definition: civetweb.c:1351
#define c(i)
Definition: RSha256.hxx:101
void SkipSessionsCheck(std::list< XrdProofdProofServ *> *active, XrdOucString &emsg, XrdProofdResponse *r=0)
Skip the next sessions status check.
static constexpr double pc
#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.
XrdProofdClient * Client() const
int Post(int type, const char *msg)
Post message on the pipe.
bool IsValid() const
XrdProofdProofServ * GetServer(int psid)
Get from the vector server instance with ID psid.
virtual int Config(bool rcf=0)
void SetStatus(char s)
void SetTag(const char *tag)
bool RemotePLite() const
XrdOucString fClntAdminPath
void Register(const char *dname, XrdProofdDirective *d)
XPClientRequest * Request() 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;.