Logo ROOT   6.10/09
Reference Guide
DaemonUtils.cxx
Go to the documentation of this file.
1 // @(#)root/auth:$Id$
2 // Author: Gerri Ganis 19/1/2004
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2003, 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 // DaemonUtils //
15 // //
16 // This file defines wrappers to client utils calls used by server //
17 // authentication daemons //
18 // //
19 //////////////////////////////////////////////////////////////////////////
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <signal.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <arpa/inet.h>
30 #include <netdb.h>
31 #include <errno.h>
32 
33 #if defined(linux)
34 # include <features.h>
35 # if __GNU_LIBRARY__ == 6
36 # ifndef R__GLIBC
37 # define R__GLIBC
38 # endif
39 # endif
40 #endif
41 #if defined(__MACH__) && !defined(__APPLE__)
42 # define R__GLIBC
43 #endif
44 
45 #ifdef __sun
46 # ifndef _REENTRANT
47 # if __SUNPRO_CC > 0x420
48 # define GLOBAL_ERRNO
49 # endif
50 # endif
51 #endif
52 
53 #include "Rtypes.h"
54 #include "Varargs.h"
55 #include "DaemonUtils.h"
56 #include "TAuthenticate.h"
57 #include "TSecContext.h"
58 #include "TEnv.h"
59 #include "TROOT.h"
60 
61 //________________________________________________________________________
62 
63 // --- Globals --------------------------------------------------------
64 static TSocket *gSocket;
65 
66 // This is to be changed whenever something is changed
67 // in non-backward compatible way
68 // 0 -> 1: support for SSH authentication via SSH tunnel
69 static Int_t gSrvProtocol = 1;
70 static EService gService = kSOCKD;
71 static Int_t gReuseAllow = 0x1F;
72 
73 using namespace std;
74 using namespace ROOT;
75 
76 extern "C" {
78  const char *confdir, const char *tmpdir,
79  string &user, Int_t &meth, Int_t &type, string &ctkn,
80  TSeqCollection *secctxlist) {
81  return SrvAuthImpl(socket, confdir, tmpdir, user, meth, type, ctkn, secctxlist);
82  }
83 }
84 
85 extern "C" {
87  return SrvClupImpl(sls);
88  }
89 }
90 
91 ////////////////////////////////////////////////////////////////////////////////
92 /// Set relevant environment variables
93 
94 static Int_t SrvSetVars(string /*confdir*/)
95 {
96  // Executables and conf dirs
97 
98  // Make rootbindir available to all the session via env
99  string execdir = TROOT::GetBinDir().Data();
100  if (execdir.length()) {
101  int len = 15 + execdir.length();
102  char *tmp = new char[len+1];
103  if (tmp) {
104  snprintf(tmp,len+1, "ROOTBINDIR=%.*s", len, execdir.c_str());
105  putenv(tmp);
106  } else
107  return -1;
108  }
109 
110  // Make rootetcdir available to all the session via env
111  string etcdir = TROOT::GetEtcDir().Data();
112  if (etcdir.length()) {
113  int len = 15 + etcdir.length();
114  char *tmp = new char[len+1];
115  if (tmp) {
116  snprintf(tmp, len+1, "ROOTETCDIR=%.*s", len, etcdir.c_str());
117  putenv(tmp);
118  } else
119  return -1;
120  }
121 
122  // If specified, set the special daemonrc file to be used
123  string daemonrc = string(gEnv->GetValue("SrvAuth.DaemonRc",""));
124  if (daemonrc.length()) {
125  int len = 15 + daemonrc.length();
126  char *tmp = new char[len+1];
127  if (tmp) {
128  snprintf(tmp, len+1, "ROOTDAEMONRC=%.*s", len, daemonrc.c_str());
129  putenv(tmp);
130  } else
131  return -1;
132  }
133 
134  // If specified, set the special gridmap file to be used
135  string gridmap = string(gEnv->GetValue("SrvAuth.GridMap",""));
136  if (gridmap.length()) {
137  int len = 15 + gridmap.length();
138  char *tmp = new char[len+1];
139  if (tmp) {
140  snprintf(tmp, len+1, "GRIDMAP=%.*s", len, gridmap.c_str());
141  putenv(tmp);
142  } else
143  return -1;
144  }
145 
146  // If specified, set the special hostcert.conf file to be used
147  string hcconf = string(gEnv->GetValue("SrvAuth.HostCert",""));
148  if (hcconf.length()) {
149  int len = 15 + hcconf.length();
150  char *tmp = new char[len+1];
151  if (tmp) {
152  snprintf(tmp, len+1, "ROOTHOSTCERT=%.*s", len, hcconf.c_str());
153  putenv(tmp);
154  } else
155  return -1;
156  }
157 
158  return 0;
159 }
160 
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 
164 void Err(int level, const char *msg, int size)
165 {
166  Perror((char *)msg, size);
167  if (level > -1) NetSend(level, kROOTD_ERR);
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 
172 void ErrFatal(int level, const char *msg, int size)
173 {
174  Perror((char *)msg, size);
175  if (level > -1) NetSend(msg, kMESS_STRING);
176 }
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 
180 void ErrSys(int level, const char *msg, int size)
181 {
182  Perror((char *)msg, size);
183  ErrFatal(level, msg, size);
184 }
185 
186 ////////////////////////////////////////////////////////////////////////////////
187 /// Wrapper to cleanup code
188 
190 {
191  TIter next(secls);
192  TSecContext *nsc ;
193  while ((nsc = (TSecContext *)next())) {
194  if (!strncmp(nsc->GetID(),"server",6)) {
195  int rc = RpdCleanupAuthTab(nsc->GetToken());
196  if (gDebug > 0 && rc < 0)
197  ErrorInfo("SrvClupImpl: operation unsuccessful (rc: %d, ctkn: %s)",
198  rc, nsc->GetToken());
199  }
200  }
201  return 0;
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// Server authentication code.
206 /// Returns 0 in case authentication failed
207 /// 1 in case of success
208 /// On success, returns authenticated username in user
209 
210 Int_t SrvAuthImpl(TSocket *socket, const char *confdir, const char *tmpdir,
211  string &user, Int_t &meth, Int_t &type, string &ctoken,
212  TSeqCollection *secctxlist)
213 {
214  Int_t rc = 0;
215 
216  // Check if hosts equivalence is required
217  Bool_t hequiv = gEnv->GetValue("SrvAuth.CheckHostsEquivalence",0);
218 
219  // Pass file for SRP
220  string altSRPpass = string(gEnv->GetValue("SrvAuth.SRPpassfile",""));
221 
222  // Port for the SSH daemon
223  Int_t sshdport = gEnv->GetValue("SrvAuth.SshdPort",22);
224 
225  // Set envs
226  if (SrvSetVars(string(confdir)) == -1)
227  // Problems setting environment
228  return rc;
229 
230  // Parent ID
231  int parentid = getpid(); // Process identifier
232 
233  // default job options
234  unsigned int options = kDMN_RQAUTH | kDMN_HOSTEQ;
235  if (!hequiv)
236  options &= ~kDMN_HOSTEQ;
237 
238  // Init error handlers
239  RpdSetErrorHandler(Err, ErrSys, ErrFatal);
240 
241  // Init daemon code
242  RpdInit(gService, parentid, gSrvProtocol, options,
243  gReuseAllow, sshdport,
244  tmpdir, altSRPpass.c_str());
245 
246  // Generate Local RSA keys for the session
247  if (RpdGenRSAKeys(0))
248  // Problems generating keys
249  return rc;
250 
251  // Reset check of the available method list
252  RpdSetMethInitFlag(0);
253 
254  // Trasmit relevant socket details
255  SrvSetSocket(socket);
256 
257  // Init Session (get protocol, run authentication, ...)
258  // type of authentication:
259  // 0 (new), 1 (existing), 2 (updated offset)
260  int clientprotocol = 0;
261  rc = RpdInitSession(gService, user, clientprotocol, meth, type, ctoken);
262 
263  TSecContext *seccontext = 0;
264  if (rc > 0) {
265  string openhost(socket->GetInetAddress().GetHostName());
266 
267  if (type == 1) {
268  // An existing authentication has been re-used: retrieve
269  // the related security context
270  TIter next(gROOT->GetListOfSecContexts());
271  while ((seccontext = (TSecContext *)next())) {
272  if (!(strncmp(seccontext->GetID(),"server",6))) {
273  if (seccontext->GetMethod() == meth) {
274  if (!strcmp(openhost.c_str(),seccontext->GetHost())) {
275  if (!strcmp(user.c_str(),seccontext->GetUser()))
276  break;
277  }
278  }
279  }
280  }
281  }
282 
283  if (!seccontext) {
284  // New authentication: Fill a SecContext for cleanup
285  // in case of interrupt
286  seccontext = new TSecContext(user.c_str(), openhost.c_str(), meth, -1,
287  "server", ctoken.c_str());
288  if (seccontext) {
289  // Add to the list
290  secctxlist->Add(seccontext);
291  // Store SecContext
292  socket->SetSecContext(seccontext);
293  } else {
294  if (gDebug > 0)
295  ErrorInfo("SrvAuthImpl: could not create sec context object"
296  ": potential problems in cleaning");
297  }
298  }
299  }
300 
301 
302  // Done
303  return rc;
304 }
305 
306 
307 namespace ROOT {
308 
309  static int gSockFd = -1;
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 /// Fill socket parameters
313 
314  void SrvSetSocket(TSocket *Socket)
315  {
316  gSocket = Socket;
317  gSockFd = Socket->GetDescriptor();
318  }
319 
320 ////////////////////////////////////////////////////////////////////////////////
321 /// Receive exactly length bytes into buffer. Returns number of bytes
322 /// received. Returns -1 in case of error.
323 
324  static int Recvn(int sock, void *buffer, int length)
325  {
326  if (sock < 0) return -1;
327 
328  int n, nrecv = 0;
329  char *buf = (char *)buffer;
330 
331  for (n = 0; n < length; n += nrecv) {
332  while ((nrecv = recv(sock, buf+n, length-n, 0)) == -1
333  && GetErrno() == EINTR)
334  ResetErrno(); // probably a SIGCLD that was caught
335  if (nrecv < 0) {
336  Error(gErrFatal,-1,
337  "Recvn: error (sock: %d): errno: %d",sock,GetErrno());
338  return nrecv;
339  } else if (nrecv == 0)
340  break; // EOF
341  }
342 
343  return n;
344  }
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Empty call, for consistency
348 
349  void NetClose()
350  {
351  return;
352  }
353 
354 ////////////////////////////////////////////////////////////////////////////////
355 /// return open socket descriptor
356 
358  {
359  return gSockFd;
360  }
361 
362 ////////////////////////////////////////////////////////////////////////////////
363 /// Empty call, for consistency
364 
365  int NetParOpen(int port, int size)
366  {
367  if (port+size)
368  return (port+size);
369  else
370  return 1;
371  }
372 
373 ////////////////////////////////////////////////////////////////////////////////
374 /// Receive a string of maximum length max.
375 
376  int NetRecv(char *msg, int max)
377  {
378  return gSocket->Recv(msg, max);
379  }
380 
381 ////////////////////////////////////////////////////////////////////////////////
382 /// Receive a string of maximum len length. Returns message type in kind.
383 /// Return value is msg length.
384 
385  int NetRecv(char *msg, int len, EMessageTypes &kind)
386  {
387  Int_t tmpkind;
388  Int_t rc = gSocket->Recv(msg, len, tmpkind);
389  kind = (EMessageTypes)tmpkind;
390  return rc;
391  }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 /// Receive a buffer. Returns the newly allocated buffer, the length
395 /// of the buffer and message type in kind.
396 
397  int NetRecv(void *&buf, int &len, EMessageTypes &kind)
398  {
399  int hdr[2];
400 
401  if (NetRecvRaw(hdr, sizeof(hdr)) < 0)
402  return -1;
403 
404  len = ntohl(hdr[0]) - sizeof(int);
405  kind = (EMessageTypes) ntohl(hdr[1]);
406  if (len) {
407  buf = new char* [len];
408  return NetRecvRaw(buf, len);
409  }
410  buf = 0;
411  return 0;
412 
413  }
414 
415 ////////////////////////////////////////////////////////////////////////////////
416 /// Receive a buffer of maximum len bytes.
417 
418  int NetRecvRaw(void *buf, int len)
419  {
420  return gSocket->RecvRaw(buf,len);
421  }
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// Receive a buffer of maximum len bytes from generic socket sock.
425 
426  int NetRecvRaw(int sock, void *buf, int len)
427  {
428  if (sock == -1) return -1;
429 
430  if (Recvn(sock, buf, len) < 0) {
431  Error(gErrFatal,-1,
432  "NetRecvRaw: Recvn error (sock: %d, errno: %d)",sock,GetErrno());
433  }
434 
435  return len;
436  }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 /// Send integer. Message will be of type "kind".
440 
441  int NetSend(int code, EMessageTypes kind)
442  {
443  int hdr[3];
444  int hlen = sizeof(int) + sizeof(int);
445  hdr[0] = htonl(hlen);
446  hdr[1] = htonl(kind);
447  hdr[2] = htonl(code);
448 
449  return gSocket->SendRaw(hdr, sizeof(hdr));
450  }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Send a string. Message will be of type "kind".
454 
455  int NetSend(const char *msg, EMessageTypes kind)
456  {
457  return gSocket->Send(msg, kind);
458  }
459 
460 ////////////////////////////////////////////////////////////////////////////////
461 /// Send buffer of len bytes. Message will be of type "kind".
462 
463  int NetSend(const void *buf, int len, EMessageTypes kind)
464  {
465  int hdr[2];
466  int hlen = sizeof(int) + len;
467  hdr[0] = htonl(hlen);
468  hdr[1] = htonl(kind);
469  if (gSocket->SendRaw(hdr, sizeof(hdr)) < 0)
470  return -1;
471 
472  return gSocket->SendRaw(buf, len);
473  }
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// Send acknowledge code
477 
479  {
480  return NetSend(0, kROOTD_ACK);
481  }
482 
483 ////////////////////////////////////////////////////////////////////////////////
484 /// Send error code
485 
487  {
488  return NetSend(err, kROOTD_ERR);
489  }
490 
491 ////////////////////////////////////////////////////////////////////////////////
492 /// Send buffer of len bytes.
493 
494  int NetSendRaw(const void *buf, int len)
495  {
496  return gSocket->SendRaw(buf, len);
497  }
498 
499 ////////////////////////////////////////////////////////////////////////////////
500 /// Return name of connected host
501 
502  void NetGetRemoteHost(std::string &openhost)
503  {
504  // Get Host name
505  openhost = string(gSocket->GetInetAddress().GetHostName());
506  }
507 
508 ////////////////////////////////////////////////////////////////////////////////
509 /// return errno
510 
511  int GetErrno()
512  {
513 #ifdef GLOBAL_ERRNO
514  return ::errno;
515 #else
516  return errno;
517 #endif
518  }
519 ////////////////////////////////////////////////////////////////////////////////
520 /// reset errno
521 
522  void ResetErrno()
523  {
524 #ifdef GLOBAL_ERRNO
525  ::errno = 0;
526 #else
527  errno = 0;
528 #endif
529  }
530 
531 ////////////////////////////////////////////////////////////////////////////////
532 /// Return in buf the message belonging to errno.
533 
534  void Perror(char *buf, int size)
535  {
536  int len = strlen(buf);
537 #if (defined(__sun) && defined (__SVR4)) || defined (__linux) || \
538  defined(_AIX) || defined(__MACH__)
539  snprintf(buf+len, size, " (%s)", strerror(GetErrno()));
540 #else
541  if (GetErrno() >= 0 && GetErrno() < sys_nerr)
542  snprintf(buf+len, size, " (%s)", sys_errlist[GetErrno()]);
543 #endif
544  }
545 
546 ////////////////////////////////////////////////////////////////////////////////
547 /// Formats a string in a circular formatting buffer and prints the string.
548 /// Appends a newline.
549 /// Cut & Paste from Printf in base/src/TString.cxx
550 
551  void ErrorInfo(const char *va_(fmt), ...)
552  {
553  char buf[1024];
554  va_list ap;
555  va_start(ap,va_(fmt));
556  vsprintf(buf, fmt, ap);
557  va_end(ap);
558  printf("%s\n", buf);
559  fflush(stdout);
560  }
561 
562 ////////////////////////////////////////////////////////////////////////////////
563 /// Write error message and call a handler, if required
564 
565  void Error(ErrorHandler_t func,int code,const char *va_(fmt), ...)
566  {
567  char buf[1024];
568  va_list ap;
569  va_start(ap,va_(fmt));
570  vsprintf(buf, fmt, ap);
571  va_end(ap);
572  printf("%s\n", buf);
573  fflush(stdout);
574 
575  // Actions are defined by the specific error handler (
576  // see rootd.cxx and proofd.cxx)
577  if (func) (*func)(code,(const char *)buf, sizeof(buf));
578  }
579 
580 } // namespace ROOT
virtual void Add(TObject *obj)
int NetSendError(ERootdErrors err)
Send error code.
int GetErrno()
return errno
const char * GetToken() const
Definition: TSecContext.h:81
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
const char * GetHostName() const
Definition: TInetAddress.h:71
static int Recvn(int sock, void *buffer, int length)
Receive exactly length bytes into buffer.
int NetSend(const void *buf, int len, EMessageTypes kind)
Send buffer of len bytes. Message will be of type "kind".
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition: TSocket.cxx:520
int NetGetSockFd()
return open socket descriptor
static TSocket * gSocket
Definition: DaemonUtils.cxx:64
virtual Int_t Recv(TMessage *&mess)
Receive a TMessage object.
Definition: TSocket.cxx:818
ErrorHandler_t gErrFatal
#define gROOT
Definition: TROOT.h:375
static EService gService
Definition: DaemonUtils.cxx:70
void ErrorInfo(const char *va_(fmt),...)
Formats a string in a circular formatting buffer and prints the string.
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
void SetSecContext(TSecContext *ctx)
Definition: TSocket.h:166
STL namespace.
int NetSendRaw(const void *buf, int len)
Send buffer of len bytes.
const char * GetHost() const
Definition: TSecContext.h:75
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition: TSocket.cxx:620
Sequenceable collection abstract base class.
void SrvSetSocket(TSocket *Socket)
Fill socket parameters.
Int_t SrvClupImpl(TSeqCollection *secls)
Wrapper to cleanup code.
Int_t SrvAuthCleanup(TSeqCollection *sls)
Definition: DaemonUtils.cxx:86
#define va_(arg)
Definition: Varargs.h:41
void ErrFatal(int level, const char *msg, int size)
const char * GetUser() const
Definition: TSecContext.h:82
void(* ErrorHandler_t)(int level, const char *msg, int size)
Definition: DaemonUtils.h:40
void ResetErrno()
reset errno
Int_t SrvAuthImpl(TSocket *socket, const char *confdir, const char *tmpdir, string &user, Int_t &meth, Int_t &type, string &ctoken, TSeqCollection *secctxlist)
Server authentication code.
virtual Int_t GetValue(const char *name, Int_t dflt)
Returns the integer value for a resource.
Definition: TEnv.cxx:482
EMessageTypes
Definition: MessageTypes.h:27
Int_t SrvAuthenticate(TSocket *socket, const char *confdir, const char *tmpdir, string &user, Int_t &meth, Int_t &type, string &ctkn, TSeqCollection *secctxlist)
Definition: DaemonUtils.cxx:77
int NetParOpen(int port, int size)
Empty call, for consistency.
static Int_t gSrvProtocol
Definition: DaemonUtils.cxx:69
const char * GetID() const
Definition: TSecContext.h:76
static Int_t gReuseAllow
Definition: DaemonUtils.cxx:71
void NetGetRemoteHost(std::string &openhost)
Return name of connected host.
void ErrSys(int level, const char *msg, int size)
static Int_t SrvSetVars(string)
Set relevant environment variables.
Definition: DaemonUtils.cxx:94
int type
Definition: TGX11.cxx:120
R__EXTERN TEnv * gEnv
Definition: TEnv.h:170
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
Definition: TROOT.cxx:2791
int NetSendAck()
Send acknowledge code.
double func(double *x, double *p)
Definition: stressTF1.cxx:213
int NetRecvRaw(int sock, void *buf, int len)
Receive a buffer of maximum len bytes from generic socket sock.
void NetClose()
Empty call, for consistency.
void Err(int level, const char *msg, int size)
virtual Int_t GetDescriptor() const
Definition: TSocket.h:126
#define snprintf
Definition: civetweb.c:822
void Perror(char *buf, int size)
Return in buf the message belonging to errno.
R__EXTERN Int_t gDebug
Definition: Rtypes.h:83
int NetRecv(void *&buf, int &len, EMessageTypes &kind)
Receive a buffer.
TInetAddress GetInetAddress() const
Definition: TSocket.h:127
static const TString & GetBinDir()
Get the binary directory in the installation. Static utility function.
Definition: TROOT.cxx:2728
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition: TSocket.cxx:901
static int gSockFd
const Int_t n
Definition: legend1.C:16
ERootdErrors
Definition: NetErrors.h:26
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.
Int_t GetMethod() const
Definition: TSecContext.h:77