Logo ROOT   6.08/07
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  string execdir, etcdir;
99 #ifdef ROOTBINDIR
100  execdir = string(ROOTBINDIR);
101 #endif
102 #ifdef ROOTETCDIR
103  etcdir = string(ROOTETCDIR);
104 #endif
105 
106  // Define rootbindir if not done already
107  if (!execdir.length())
108  execdir = string(confdir).append("/bin");
109  // Make it available to all the session via env
110  if (execdir.length()) {
111  int len = 15 + execdir.length();
112  char *tmp = new char[len+1];
113  if (tmp) {
114  snprintf(tmp,len+1, "ROOTBINDIR=%.*s", len, execdir.c_str());
115  putenv(tmp);
116  } else
117  return -1;
118  }
119 
120  // Define rootetcdir if not done already
121  if (!etcdir.length())
122  etcdir = string(confdir).append("/etc");
123  // Make it available to all the session via env
124  if (etcdir.length()) {
125  int len = 15 + etcdir.length();
126  char *tmp = new char[len+1];
127  if (tmp) {
128  snprintf(tmp, len+1, "ROOTETCDIR=%.*s", len, etcdir.c_str());
129  putenv(tmp);
130  } else
131  return -1;
132  }
133 
134  // If specified, set the special daemonrc file to be used
135  string daemonrc = string(gEnv->GetValue("SrvAuth.DaemonRc",""));
136  if (daemonrc.length()) {
137  int len = 15 + daemonrc.length();
138  char *tmp = new char[len+1];
139  if (tmp) {
140  snprintf(tmp, len+1, "ROOTDAEMONRC=%.*s", len, daemonrc.c_str());
141  putenv(tmp);
142  } else
143  return -1;
144  }
145 
146  // If specified, set the special gridmap file to be used
147  string gridmap = string(gEnv->GetValue("SrvAuth.GridMap",""));
148  if (gridmap.length()) {
149  int len = 15 + gridmap.length();
150  char *tmp = new char[len+1];
151  if (tmp) {
152  snprintf(tmp, len+1, "GRIDMAP=%.*s", len, gridmap.c_str());
153  putenv(tmp);
154  } else
155  return -1;
156  }
157 
158  // If specified, set the special hostcert.conf file to be used
159  string hcconf = string(gEnv->GetValue("SrvAuth.HostCert",""));
160  if (hcconf.length()) {
161  int len = 15 + hcconf.length();
162  char *tmp = new char[len+1];
163  if (tmp) {
164  snprintf(tmp, len+1, "ROOTHOSTCERT=%.*s", len, hcconf.c_str());
165  putenv(tmp);
166  } else
167  return -1;
168  }
169 
170  return 0;
171 }
172 
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 
176 void Err(int level, const char *msg, int size)
177 {
178  Perror((char *)msg, size);
179  if (level > -1) NetSend(level, kROOTD_ERR);
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 
184 void ErrFatal(int level, const char *msg, int size)
185 {
186  Perror((char *)msg, size);
187  if (level > -1) NetSend(msg, kMESS_STRING);
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 
192 void ErrSys(int level, const char *msg, int size)
193 {
194  Perror((char *)msg, size);
195  ErrFatal(level, msg, size);
196 }
197 
198 ////////////////////////////////////////////////////////////////////////////////
199 /// Wrapper to cleanup code
200 
202 {
203  TIter next(secls);
204  TSecContext *nsc ;
205  while ((nsc = (TSecContext *)next())) {
206  if (!strncmp(nsc->GetID(),"server",6)) {
207  int rc = RpdCleanupAuthTab(nsc->GetToken());
208  if (gDebug > 0 && rc < 0)
209  ErrorInfo("SrvClupImpl: operation unsuccessful (rc: %d, ctkn: %s)",
210  rc, nsc->GetToken());
211  }
212  }
213  return 0;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Server authentication code.
218 /// Returns 0 in case authentication failed
219 /// 1 in case of success
220 /// On success, returns authenticated username in user
221 
222 Int_t SrvAuthImpl(TSocket *socket, const char *confdir, const char *tmpdir,
223  string &user, Int_t &meth, Int_t &type, string &ctoken,
224  TSeqCollection *secctxlist)
225 {
226  Int_t rc = 0;
227 
228  // Check if hosts equivalence is required
229  Bool_t hequiv = gEnv->GetValue("SrvAuth.CheckHostsEquivalence",0);
230 
231  // Pass file for SRP
232  string altSRPpass = string(gEnv->GetValue("SrvAuth.SRPpassfile",""));
233 
234  // Port for the SSH daemon
235  Int_t sshdport = gEnv->GetValue("SrvAuth.SshdPort",22);
236 
237  // Set envs
238  if (SrvSetVars(string(confdir)) == -1)
239  // Problems setting environment
240  return rc;
241 
242  // Parent ID
243  int parentid = getpid(); // Process identifier
244 
245  // default job options
246  unsigned int options = kDMN_RQAUTH | kDMN_HOSTEQ;
247  if (!hequiv)
248  options &= ~kDMN_HOSTEQ;
249 
250  // Init error handlers
252 
253  // Init daemon code
254  RpdInit(gService, parentid, gSrvProtocol, options,
255  gReuseAllow, sshdport,
256  tmpdir, altSRPpass.c_str());
257 
258  // Generate Local RSA keys for the session
259  if (RpdGenRSAKeys(0))
260  // Problems generating keys
261  return rc;
262 
263  // Reset check of the available method list
265 
266  // Trasmit relevant socket details
267  SrvSetSocket(socket);
268 
269  // Init Session (get protocol, run authentication, ...)
270  // type of authentication:
271  // 0 (new), 1 (existing), 2 (updated offset)
272  int clientprotocol = 0;
273  rc = RpdInitSession(gService, user, clientprotocol, meth, type, ctoken);
274 
275  TSecContext *seccontext = 0;
276  if (rc > 0) {
277  string openhost(socket->GetInetAddress().GetHostName());
278 
279  if (type == 1) {
280  // An existing authentication has been re-used: retrieve
281  // the related security context
282  TIter next(gROOT->GetListOfSecContexts());
283  while ((seccontext = (TSecContext *)next())) {
284  if (!(strncmp(seccontext->GetID(),"server",6))) {
285  if (seccontext->GetMethod() == meth) {
286  if (!strcmp(openhost.c_str(),seccontext->GetHost())) {
287  if (!strcmp(user.c_str(),seccontext->GetUser()))
288  break;
289  }
290  }
291  }
292  }
293  }
294 
295  if (!seccontext) {
296  // New authentication: Fill a SecContext for cleanup
297  // in case of interrupt
298  seccontext = new TSecContext(user.c_str(), openhost.c_str(), meth, -1,
299  "server", ctoken.c_str());
300  if (seccontext) {
301  // Add to the list
302  secctxlist->Add(seccontext);
303  // Store SecContext
304  socket->SetSecContext(seccontext);
305  } else {
306  if (gDebug > 0)
307  ErrorInfo("SrvAuthImpl: could not create sec context object"
308  ": potential problems in cleaning");
309  }
310  }
311  }
312 
313 
314  // Done
315  return rc;
316 }
317 
318 
319 namespace ROOT {
320 
321  static int gSockFd = -1;
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// Fill socket parameters
325 
326  void SrvSetSocket(TSocket *Socket)
327  {
328  gSocket = Socket;
329  gSockFd = Socket->GetDescriptor();
330  }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// Receive exactly length bytes into buffer. Returns number of bytes
334 /// received. Returns -1 in case of error.
335 
336  static int Recvn(int sock, void *buffer, int length)
337  {
338  if (sock < 0) return -1;
339 
340  int n, nrecv = 0;
341  char *buf = (char *)buffer;
342 
343  for (n = 0; n < length; n += nrecv) {
344  while ((nrecv = recv(sock, buf+n, length-n, 0)) == -1
345  && GetErrno() == EINTR)
346  ResetErrno(); // probably a SIGCLD that was caught
347  if (nrecv < 0) {
348  Error(gErrFatal,-1,
349  "Recvn: error (sock: %d): errno: %d",sock,GetErrno());
350  return nrecv;
351  } else if (nrecv == 0)
352  break; // EOF
353  }
354 
355  return n;
356  }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Empty call, for consistency
360 
361  void NetClose()
362  {
363  return;
364  }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// return open socket descriptor
368 
370  {
371  return gSockFd;
372  }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 /// Empty call, for consistency
376 
377  int NetParOpen(int port, int size)
378  {
379  if (port+size)
380  return (port+size);
381  else
382  return 1;
383  }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Receive a string of maximum length max.
387 
388  int NetRecv(char *msg, int max)
389  {
390  return gSocket->Recv(msg, max);
391  }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 /// Receive a string of maximum len length. Returns message type in kind.
395 /// Return value is msg length.
396 
397  int NetRecv(char *msg, int len, EMessageTypes &kind)
398  {
399  Int_t tmpkind;
400  Int_t rc = gSocket->Recv(msg, len, tmpkind);
401  kind = (EMessageTypes)tmpkind;
402  return rc;
403  }
404 
405 ////////////////////////////////////////////////////////////////////////////////
406 /// Receive a buffer. Returns the newly allocated buffer, the length
407 /// of the buffer and message type in kind.
408 
409  int NetRecv(void *&buf, int &len, EMessageTypes &kind)
410  {
411  int hdr[2];
412 
413  if (NetRecvRaw(hdr, sizeof(hdr)) < 0)
414  return -1;
415 
416  len = ntohl(hdr[0]) - sizeof(int);
417  kind = (EMessageTypes) ntohl(hdr[1]);
418  if (len) {
419  buf = new char* [len];
420  return NetRecvRaw(buf, len);
421  }
422  buf = 0;
423  return 0;
424 
425  }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// Receive a buffer of maximum len bytes.
429 
430  int NetRecvRaw(void *buf, int len)
431  {
432  return gSocket->RecvRaw(buf,len);
433  }
434 
435 ////////////////////////////////////////////////////////////////////////////////
436 /// Receive a buffer of maximum len bytes from generic socket sock.
437 
438  int NetRecvRaw(int sock, void *buf, int len)
439  {
440  if (sock == -1) return -1;
441 
442  if (Recvn(sock, buf, len) < 0) {
443  Error(gErrFatal,-1,
444  "NetRecvRaw: Recvn error (sock: %d, errno: %d)",sock,GetErrno());
445  }
446 
447  return len;
448  }
449 
450 ////////////////////////////////////////////////////////////////////////////////
451 /// Send integer. Message will be of type "kind".
452 
453  int NetSend(int code, EMessageTypes kind)
454  {
455  int hdr[3];
456  int hlen = sizeof(int) + sizeof(int);
457  hdr[0] = htonl(hlen);
458  hdr[1] = htonl(kind);
459  hdr[2] = htonl(code);
460 
461  return gSocket->SendRaw(hdr, sizeof(hdr));
462  }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// Send a string. Message will be of type "kind".
466 
467  int NetSend(const char *msg, EMessageTypes kind)
468  {
469  return gSocket->Send(msg, kind);
470  }
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Send buffer of len bytes. Message will be of type "kind".
474 
475  int NetSend(const void *buf, int len, EMessageTypes kind)
476  {
477  int hdr[2];
478  int hlen = sizeof(int) + len;
479  hdr[0] = htonl(hlen);
480  hdr[1] = htonl(kind);
481  if (gSocket->SendRaw(hdr, sizeof(hdr)) < 0)
482  return -1;
483 
484  return gSocket->SendRaw(buf, len);
485  }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Send acknowledge code
489 
491  {
492  return NetSend(0, kROOTD_ACK);
493  }
494 
495 ////////////////////////////////////////////////////////////////////////////////
496 /// Send error code
497 
499  {
500  return NetSend(err, kROOTD_ERR);
501  }
502 
503 ////////////////////////////////////////////////////////////////////////////////
504 /// Send buffer of len bytes.
505 
506  int NetSendRaw(const void *buf, int len)
507  {
508  return gSocket->SendRaw(buf, len);
509  }
510 
511 ////////////////////////////////////////////////////////////////////////////////
512 /// Return name of connected host
513 
514  void NetGetRemoteHost(std::string &openhost)
515  {
516  // Get Host name
517  openhost = string(gSocket->GetInetAddress().GetHostName());
518  }
519 
520 ////////////////////////////////////////////////////////////////////////////////
521 /// return errno
522 
523  int GetErrno()
524  {
525 #ifdef GLOBAL_ERRNO
526  return ::errno;
527 #else
528  return errno;
529 #endif
530  }
531 ////////////////////////////////////////////////////////////////////////////////
532 /// reset errno
533 
534  void ResetErrno()
535  {
536 #ifdef GLOBAL_ERRNO
537  ::errno = 0;
538 #else
539  errno = 0;
540 #endif
541  }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 /// Return in buf the message belonging to errno.
545 
546  void Perror(char *buf, int size)
547  {
548  int len = strlen(buf);
549 #if (defined(__sun) && defined (__SVR4)) || defined (__linux) || \
550  defined(_AIX) || defined(__MACH__)
551  snprintf(buf+len, size, " (%s)", strerror(GetErrno()));
552 #else
553  if (GetErrno() >= 0 && GetErrno() < sys_nerr)
554  snprintf(buf+len, size, " (%s)", sys_errlist[GetErrno()]);
555 #endif
556  }
557 
558 ////////////////////////////////////////////////////////////////////////////////
559 /// Formats a string in a circular formatting buffer and prints the string.
560 /// Appends a newline.
561 /// Cut & Paste from Printf in base/src/TString.cxx
562 
563  void ErrorInfo(const char *va_(fmt), ...)
564  {
565  char buf[1024];
566  va_list ap;
567  va_start(ap,va_(fmt));
568  vsprintf(buf, fmt, ap);
569  va_end(ap);
570  printf("%s\n", buf);
571  fflush(stdout);
572  }
573 
574 ////////////////////////////////////////////////////////////////////////////////
575 /// Write error message and call a handler, if required
576 
577  void Error(ErrorHandler_t func,int code,const char *va_(fmt), ...)
578  {
579  char buf[1024];
580  va_list ap;
581  va_start(ap,va_(fmt));
582  vsprintf(buf, fmt, ap);
583  va_end(ap);
584  printf("%s\n", buf);
585  fflush(stdout);
586 
587  // Actions are defined by the specific error handler (
588  // see rootd.cxx and proofd.cxx)
589  if (func) (*func)(code,(const char *)buf, sizeof(buf));
590  }
591 
592 } // 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:87
void RpdSetMethInitFlag(int methinit)
This namespace contains pre-defined functions to be used in conjuction with TExecutor::Map and TExecu...
Definition: StringConv.hxx:21
const char * GetHostName() const
Definition: TInetAddress.h:75
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:364
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:182
STL namespace.
void RpdInit(EService serv, int pid, int sproto, unsigned int opts, int rumsk, int sshp, const char *tmpd, const char *asrpp, int login=0)
int NetSendRaw(const void *buf, int len)
Send buffer of len bytes.
const char * GetHost() const
Definition: TSecContext.h:81
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.
int RpdCleanupAuthTab(const char *crypttoken)
void SrvSetSocket(TSocket *Socket)
Fill socket parameters.
void RpdSetErrorHandler(ErrorHandler_t Err, ErrorHandler_t Sys, ErrorHandler_t Fatal)
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:88
void(* ErrorHandler_t)(int level, const char *msg, int size)
Definition: DaemonUtils.h:46
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:496
static Int_t SrvSetVars(string confdir)
Set relevant environment variables.
Definition: DaemonUtils.cxx:94
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:82
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)
int RpdGenRSAKeys(int)
int type
Definition: TGX11.cxx:120
R__EXTERN TEnv * gEnv
Definition: TEnv.h:174
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:142
#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:128
int NetRecv(void *&buf, int &len, EMessageTypes &kind)
Receive a buffer.
TInetAddress GetInetAddress() const
Definition: TSocket.h:143
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition: TSocket.cxx:901
int RpdInitSession(int, std::string &, int &, int &, int &, std::string &)
static int gSockFd
const Int_t n
Definition: legend1.C:16
ERootdErrors
Definition: NetErrors.h:28
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:83