ROOT  6.06/09
Reference Guide
proofd.cxx
Go to the documentation of this file.
1 // @(#)root/proofd:$Id$
2 // Author: Fons Rademakers 02/02/97
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 // Proofd //
15 // //
16 // PROOF, Parallel ROOT Facility, front-end daemon. //
17 // This small server is started either by inetd when a client requests //
18 // a connection to a PROOF server or by hand (i.e. from the command //
19 // line). By default proofd uses port 1093 (allocated by IANA, //
20 // www.iana.org, to proofd). If we don't want the PROOF server //
21 // to run on this specific node, e.g. because the system is being //
22 // shutdown or there are already too many servers running, we send //
23 // the client a re-route message and close the connection. Otherwise //
24 // we authenticate the user and exec the proofserv program. //
25 // To run proofd via inetd add the following line to /etc/services: //
26 // //
27 // proofd 1093/tcp //
28 // //
29 // and to /etc/inetd.conf: //
30 // //
31 // proofd stream tcp nowait root /usr/local/root/bin/proofd -i \ //
32 // /usr/local/root //
33 // //
34 // Force inetd to reread its conf file with "kill -HUP <pid inetd>". //
35 // //
36 // If xinetd is used instead, a file named 'proofd' should be created //
37 // under /etc/xinetd.d with content //
38 // //
39 // # default: off //
40 // # description: The proof daemon //
41 // # //
42 // service proofd //
43 // { //
44 // disable = no //
45 // flags = REUSE //
46 // socket_type = stream //
47 // wait = no //
48 // user = root //
49 // server = /usr/local/root/bin/proofd //
50 // server_args = -i -d 0 /usr/local/root //
51 // } //
52 // //
53 // and xinetd restarted (/sbin/service xinetd restart). //
54 // //
55 // You can also start proofd by hand running directly under your //
56 // private account (no root system priviliges needed). For example to //
57 // start proofd listening on port 5252 just type: //
58 // //
59 // prootd -p 5252 $ROOTSYS //
60 // //
61 // Notice: no & is needed. Proofd will go in background by itself. //
62 // //
63 // Proofd arguments: //
64 // -A [<rootauthrc>] Tells proofserv to read user's $HOME/.rootauthrc,//
65 // if any; by default such private file is ignored //
66 // to allow complete control on the authentication //
67 // directives to the cluster administrator, via the //
68 // system.rootauthrc file; if the optional argument //
69 // <rootauthrc> is given and points to a valid file,//
70 // this file takes the highest priority (private //
71 // user's file being still read with next-to-highest//
72 // priority) providing a mean to use non-standard //
73 // file names for authentication directives. //
74 // -b tcpwindowsize specifies the tcp window size in bytes (e.g. see //
75 // http://www.psc.edu/networking/perf_tune.html) //
76 // Default is 65535. Only change default for pipes //
77 // with a high bandwidth*delay product. //
78 // -C hostcertfile defines a file where to find information for the //
79 // local host Globus information (see GLOBUS.README //
80 // for details) //
81 // -d level level of debug info written to syslog //
82 // 0 = no debug (default) //
83 // 1 = minimum //
84 // 2 = medium //
85 // 3 = maximum //
86 // -D rootdaemonrc read access rules from file <rootdaemonrc>. //
87 // By default <root_etc_dir>/system.rootdaemonrc is //
88 // used for access rules; for privately started //
89 // daemons $HOME/.rootdaemonrc (if present) takes //
90 // highest priority. //
91 // -E obsolete; up to v4.00.08 this option was used to //
92 // force exclusivity of the authentication tokens; //
93 // with the new approach for authentication tab //
94 // files this option is dummy. //
95 // -f do not run as daemon, run in the foreground //
96 // -G gridmapfile defines the gridmap file to be used for globus //
97 // authentication if different from globus default //
98 // (/etc/grid-security/gridmap); (re)defines the //
99 // GRIDMAP environment variable. //
100 // -h print usage message //
101 // -i says we were started by inetd //
102 // -noauth do not require client authentication //
103 // -p port# specifies a different port to listen on //
104 // -s <sshd_port> specifies the port number for the sshd daemon //
105 // (default is 22) //
106 // -S keytabfile use this keytab file, instead of the default //
107 // (option only supported when compiled with //
108 // Kerberos5 support) //
109 // -T <tmpdir> specifies the directory path to be used to place //
110 // temporary files; default is /usr/tmp. //
111 // Useful if not running as root. //
112 // -w do not check /etc/hosts.equiv, $HOME/.rhosts //
113 // for UsrPwd authentications; by default these //
114 // files are checked first by calling ruserok(...); //
115 // if this option is specified a password is always //
116 // required.
117 // rootsys_dir directory which must contain bin/proofserv and //
118 // proof/etc/proof.conf. If not specified ROOTSYS //
119 // or built-in (as specified to ./configure) is //
120 // tried. (*MUST* be the last argument). //
121 // //
122 // When your system uses shadow passwords you have to compile proofd //
123 // with -DR__SHADOWPW. Since shadow passwords can only be accessed //
124 // while being superuser (root) this works only when the server is //
125 // started via inetd. Another solution is to create a file //
126 // ~/.rootdpass containing an encrypted password. If this file exists //
127 // its password is used for authentication. This method overrides //
128 // all other authentication methods. To create an encrypted password //
129 // do something like: //
130 // perl -e '$pw = crypt("<secretpasswd>","salt"); print "$pw\n"' //
131 // and store this string in ~/.rootdpass. //
132 // //
133 // To use AFS for authentication compile proofd with the -DR__AFS //
134 // flag. In that case you also need to link with the AFS libraries. //
135 // See the Makefiles for more details. //
136 // //
137 // To use Secure Remote Passwords (SRP) for authentication compile //
138 // proofd with the -DR__SRP flag. In that case you also need to link //
139 // with the SRP and gmp libraries. See the Makefile for more details. //
140 // SRP is described at: http://srp.stanford.edu/. //
141 // //
142 // See README.AUTH for more details on the authentication features. //
143 // //
144 //////////////////////////////////////////////////////////////////////////
145 
146 // Protocol changes (see gProtocol):
147 // 6: added support for kerberos5 authentication
148 // 7: added support for Globus, SSH and uid/gid authentication and negotiation
149 // 8: change in Kerberos authentication protocol
150 // 9: change authentication cleaning protocol
151 // 10: modified SSH protocol + support for server 'no authentication' mode
152 // 11: added support for openSSL keys for encryption
153 // 12: major authentication re-organization
154 // 13: support for SSH authentication via SSH tunnel
155 // 14: add env setup message
156 
157 #include "RConfigure.h"
158 #include "RConfig.h"
159 
160 #include <ctype.h>
161 #include <fcntl.h>
162 #include <pwd.h>
163 #include <stdio.h>
164 #include <string.h>
165 #include <strings.h>
166 #include <string>
167 #include <stdlib.h>
168 #include <unistd.h>
169 #include <sys/types.h>
170 #include <time.h>
171 #include <sys/stat.h>
172 #include <sys/socket.h>
173 #include <sys/param.h>
174 #include <netinet/in.h>
175 #include <arpa/inet.h>
176 #include <netdb.h>
177 #include <errno.h>
178 #include <sys/un.h>
179 #include "snprintf.h"
180 
181 #if defined(__CYGWIN__) && defined(__GNUC__)
182 # define cygwingcc
183 #endif
184 #ifdef __linux__
185 #define linux
186 #endif
187 #if defined(linux) || defined(__sun) || defined(__sgi) || \
188  defined(_AIX) || defined(__FreeBSD__) || defined(__APPLE__) || \
189  defined(__MACH__) || defined(cygwingcc) || defined(__OpenBSD__)
190 #include <grp.h>
191 #include <sys/types.h>
192 #include <signal.h>
193 #define ROOT_SIGNAL_INCLUDED
194 #endif
195 
196 #if defined(__sgi) && !defined(__GNUG__) && (SGI_REL<62)
197 extern "C" {
198  int seteuid(int euid);
199  int setegid(int egid);
200 }
201 #endif
202 
203 #if defined(_AIX)
204 extern "C" {
205  //int initgroups(const char *name, int basegid);
206  int seteuid(uid_t euid);
207  int setegid(gid_t egid);
208 }
209 #endif
210 
211 #if defined(__sun)
212 #if defined(R__SUNGCC3)
213 extern "C" int gethostname(char *, unsigned int);
214 #endif
215 #endif
216 
217 #include "proofdp.h"
218 extern "C" {
219 #include "rsadef.h"
220 #include "rsalib.h"
221 }
222 
223 // General globals
224 int gDebug = 0;
225 
226 //--- Local Globals ---------------------------------------------------------
227 
228 const int kMaxSlaves = 32;
229 
230 static std::string gAuthrc;
231 static std::string gConfDir;
232 static std::string gOpenHost;
233 static std::string gRootBinDir;
234 static std::string gRpdAuthTab; // keeps track of authentication info
235 static std::string gTmpDir;
236 static std::string gUser;
237 static EService gService = kPROOFD;
238 static int gProtocol = 14; // increase when protocol changes
239 static int gRemPid = -1; // remote process ID
240 static std::string gReadHomeAuthrc = "0";
241 static int gInetdFlag = 0;
242 static int gMaster =-1;
243 static int gRequireAuth = 1;
244 
245 using namespace ROOT;
246 
247 //--- Error handlers -----------------------------------------------------------
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 
251 void Err(int level, const char *msg, int size)
252 {
253  Perror((char *)msg, size);
254  if (level > -1) NetSend(level, kROOTD_ERR);
255 }
256 ////////////////////////////////////////////////////////////////////////////////
257 
258 void ErrFatal(int level, const char *msg, int size)
259 {
260  Perror((char *)msg, size);
261  if (level > -1) NetSend(msg, kMESS_STRING);
262  exit(1);
263 }
264 ////////////////////////////////////////////////////////////////////////////////
265 
266 void ErrSys(int level, const char *msg, int size)
267 {
268  Perror((char *)msg, size);
269  ErrFatal(level, msg, size);
270 }
271 
272 //--- Proofd routines ----------------------------------------------------------
273 
274 #if defined(__sun)
275 //______________________________________________________________________________
276 extern "C" { void ProofdTerm(int)
277 {
278  // Termination upon receipt of a SIGTERM or SIGINT.
279 
280  ErrorInfo("ProofdTerm: rootd.cxx: got a SIGTERM/SIGINT");
281  // Terminate properly
282  RpdAuthCleanup(0,0);
283  // Close network connection
284  NetClose();
285  // exit
286  exit(0);
287 }}
288 #else
289 ////////////////////////////////////////////////////////////////////////////////
290 /// Termination upon receipt of a SIGTERM or SIGINT.
291 
292 static void ProofdTerm(int)
293 {
294  ErrorInfo("ProofdTerm: rootd.cxx: got a SIGTERM/SIGINT");
295  // Terminate properly
296  RpdAuthCleanup(0,0);
297  // Close network connection
298  NetClose();
299  // exit
300  exit(0);
301 }
302 #endif
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 /// Look if user should be rerouted to another server node.
306 
307 const char *RerouteUser()
308 {
309  std::string conffile = "proof.conf";
310  FILE *proofconf;
311 
312  if (getenv("HOME")) {
313  conffile.insert(0,"/.");
314  conffile.insert(0,getenv("HOME"));
315  // string::insert is buggy on some compilers (eg gcc 2.96):
316  // new length correct but data not always null terminated
317  conffile[conffile.length()] = 0;
318  }
319  if (!(proofconf = fopen(conffile.c_str(), "r"))) {
320  conffile = "/etc/";
321  conffile.insert(0,gConfDir);
322  // string::insert is buggy on some compilers (eg gcc 2.96):
323  // new length correct but data not always null terminated
324  conffile[conffile.length()] = 0;
325  }
326  if (proofconf || (proofconf = fopen(conffile.c_str(), "r")) != 0) {
327 
328  // read configuration file
329  static char user_on_node[32];
330  struct stat statbuf;
331  char line[256];
332  char node_name[kMaxSlaves][32];
333  int nnodes = 0;
334  int i;
335 
336  strncpy(user_on_node, "any", 32);
337  user_on_node[31] = 0;
338 
339  while (fgets(line, sizeof(line), proofconf) != 0) {
340  char word[4][64];
341  if (line[0] == '#') continue; // skip comment lines
342  // coverity[secure_coding]
343  int nword = sscanf(line, "%63s %63s %63s %63s",
344  word[0], word[1], word[2], word[3]);
345 
346  //
347  // all available nodes must be configured by a line
348  // node <name>
349  //
350  if (nword >= 2 && strcmp(word[0], "node") == 0) {
351  if (gethostbyname(word[1]) != 0) {
352  if (nnodes < kMaxSlaves) {
353  if (strlen(word[1]) < 32) {
354  strncpy(node_name[nnodes], word[1], 32);
355  node_name[nnodes][31] = 0;
356  }
357  nnodes++;
358  }
359  }
360  continue;
361  }
362 
363  //
364  // users can be preferrably rerouted to a specific node
365  // user <name> on <node>
366  //
367  if (nword >= 4 && strcmp(word[0], "user") == 0 &&
368  strcmp(word[1], gUser.c_str()) == 0 &&
369  strcmp(word[2], "on") == 0) {
370  // user <name> on <node>
371  if (strlen(word[3]) < 32) {
372  strncpy(user_on_node, word[3], 32);
373  user_on_node[31] = 0;
374  }
375  continue;
376  }
377  }
378  fclose(proofconf);
379 
380  // make sure the node is running
381  for (i = 0; i < nnodes; i++) {
382  if (strcmp(node_name[i], user_on_node) == 0) {
383  return user_on_node;
384  }
385  }
386 
387  //
388  // get the node name from next.node update by a daemon monitoring
389  // the system load; make sure the file is not completely out of date
390  //
391  conffile = gConfDir + "/etc/next.node";
392  proofconf = fopen(conffile.c_str(), "r");
393  if (proofconf) {
394  if (fstat(fileno(proofconf), &statbuf) == 0 &&
395  difftime(time(0), statbuf.st_mtime) < 600) {
396  if (fgets(line, sizeof(line), proofconf) != 0) {
397  strncpy(user_on_node, line, 32);
398  user_on_node[31] = 0;
399  for (i = 0; i < nnodes; i++) {
400  if (strcmp(node_name[i], user_on_node) == 0) {
401  fclose(proofconf);
402  return user_on_node;
403  }
404  }
405  }
406  }
407  fclose(proofconf);
408  }
409  }
410  return 0;
411 }
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 /// Receive buffer for final setup of authentication related stuff
415 /// This is base 64 string to decoded by proofserv, if needed
416 
417 int RpdProofGetAuthSetup(char **abuf)
418 {
419  int nrec = -1;
420 
421  if (RpdGetOffSet() > -1) {
422  if ((nrec = RpdSecureRecv(abuf)) < 0) {
423  ErrorInfo("RpdProofGetAuthSetup: sec: problems receiving buf");
424  return -1;
425  }
426  } else {
427  // No key: receive plainly
428  EMessageTypes kind;
429  char buflen[20];
430  if (NetRecv(buflen, 20, kind) < 0) {
431  ErrorInfo("RpdProofGetAuthSetup: plain: problems receiving buf length");
432  return -1;
433  }
434  int len = atoi(buflen);
435 
436  // receive the buffer
437  *abuf = new char[len + 1];
438  if ((nrec = NetRecvRaw(*abuf, len)) < 0) {
439  ErrorInfo("RpdProofGetAuthSetup: plain: problems receiving buf");
440  delete[] *abuf;
441  return -1;
442  }
443  (*abuf)[len] = 0;
444  }
445 
446  if (gDebug > 1)
447  ErrorInfo("RpdProofGetAuthSetup: proto: %d len: %d",
448  RpdGetAuthProtocol(), nrec);
449 
450  return nrec;
451 }
452 
453 ////////////////////////////////////////////////////////////////////////////////
454 /// Authenticate the user and exec the proofserv program.
455 /// gConfdir is the location where the PROOF config files and binaries live.
456 
458 {
459  char *argvv[3];
460  std::string arg0;
461  std::string msg;
462 
463 #ifdef R__DEBUG
464  int debug = 1;
465  while (debug)
466  ;
467 #endif
468 
469  // Remote Host
471 
472  // Socket descriptor
473  int sockFd = NetGetSockFd();
474 
475  if (gDebug > 0)
476  ErrorInfo("ProofdExec: gOpenHost = %s", gOpenHost.c_str());
477 
478  if (gDebug > 0)
479  ErrorInfo("ProofdExec: gConfDir = %s", gConfDir.c_str());
480 
481  // only reroute in case of master server
482  const char *node_name;
483  if (gMaster && (node_name = RerouteUser()) != 0) {
484  // send a reroute request to the client passing the IP address
485 
486  char host_name[32];
487  gethostname(host_name, sizeof(host_name));
488 
489  // make sure that we are not already on the target node
490  if (strcmp(host_name, node_name) != 0) {
491  struct hostent *host = gethostbyname(host_name);
492  struct hostent *node; // gethostbyname(node_name) would overwrite
493 
494  if (host != 0) {
495  struct in_addr *host_addr = (struct in_addr*)(host->h_addr);
496  char host_numb[32];
497  if (strlen(inet_ntoa(*host_addr)) < 32) {
498  strncpy(host_numb, inet_ntoa(*host_addr), 32);
499  host_numb[31] = 0;
500  }
501 
502  if ((node = gethostbyname(node_name)) != 0) {
503  struct in_addr *node_addr = (struct in_addr*)(node->h_addr);
504  char node_numb[32];
505  strncpy(node_numb, inet_ntoa(*node_addr), 32);
506  node_numb[31] = 0;
507  //
508  // compare the string representation of the IP addresses
509  // to avoid possible problems with host name aliases
510  //
511  if (strcmp(host_numb, node_numb) != 0) {
512  msg = std::string("Reroute:").append(node_numb);
513  NetSend(msg.c_str());
514  exit(0);
515  }
516  }
517  }
518  }
519  }
520 
521  // Receive buffer for final setup of authentication related stuff
522  // This is base 64 string to decoded by proofserv, if needed
523  if (RpdGetClientProtocol() > 12 && gRequireAuth == 1) {
524  char *authbuff = 0;
525  int lab = 0;
526  if ((lab = RpdProofGetAuthSetup(&authbuff)) > 0) {
527  // Save it in an environment variable
528  char *rootproofauthsetup = new char[20 + strlen(authbuff)];
529  memset(rootproofauthsetup, 0, 20 + strlen(authbuff));
530  snprintf(rootproofauthsetup, 20 + strlen(authbuff), "ROOTPROOFAUTHSETUP=%s", authbuff);
531  putenv(rootproofauthsetup);
532  } else if (lab < 0) {
533  ErrorInfo("ProofdExec: problems receiving auth buffer");
534  }
535  if (authbuff) delete[] authbuff;
536  }
537 
538  if(RpdGetClientProtocol() >= 16) {
539  void *vb = 0;
540  Int_t len = 0;
541  EMessageTypes kind = kMESS_ANY;
542 
543  int rc = NetRecvAllocate(vb, len, kind);
544 
545  if (rc < 0) {
546  ErrorInfo("ProofdExec: error receiving kPROOF_SETENV message");
547  return;
548  }
549 
550  if (kind != kPROOF_SETENV) {
551  ErrorInfo("ProofdExec: expecting kPROOF_SETENV, got %d", kind);
552  return;
553 
554  }
555 
556  char *buf = (char *) vb;
557  char *end = buf + len;
558  const char name[] = "PROOF_ALLVARS=";
559  int alen = strlen(name)+len;
560  char *all = new char[alen]; // strlen("PROOF_ALLVARS=") = 14
561  strlcpy(all, name, alen);
562  while (buf < end) {
563  if (gDebug > 0) ErrorInfo("ProofdExec: setting: %s", buf);
564  char *p = index(buf, '=');
565  if (p) {
566  if (buf != (char *) vb) strlcat(all, ",", alen); // skip the first one
567  strlcat(all, buf, alen);
568  putenv(buf);
569  }
570  buf += strlen(buf) + 1;
571  }
572  if (gDebug > 0) ErrorInfo("ProofdExec: setting: %s", all);
573  putenv(all);
574  }
575 
576  if (gDebug > 0)
577  ErrorInfo("ProofdExec: send Okay (SockFd: %d)", sockFd);
578  NetSend("Okay");
579 
580  // Find a free filedescriptor outside the standard I/O range
581  if (sockFd == 0 || sockFd == 1 || sockFd == 2) {
582  Int_t fd;
583  struct stat stbuf;
584  for (fd = 3; fd < NOFILE; fd++) {
585  ResetErrno();
586  if (fstat(fd, &stbuf) == -1 && GetErrno() == EBADF) {
587  if (dup2(sockFd, fd) < 0)
588  ErrorInfo("ProofdExec: problems executing 'dup2' (errno: %d)", errno);
589  close(sockFd);
590  sockFd = fd;
591  close(2);
592  close(1);
593  close(0);
594  RpdSetSysLogFlag(1); //syslog only from here
595  break;
596  }
597  }
598 
599  if (fd == NOFILE) {
600  NetSend("Cannot start proofserver -- no free filedescriptor");
601  return;
602  }
603  }
604 
605  //
606  // Set environments vars for proofserv
607  // Config dir
608  char *rootconf = new char[13+gConfDir.length()];
609  memset(rootconf, 0, 13 + gConfDir.length());
610  snprintf(rootconf, 13 + gConfDir.length(), "ROOTCONFDIR=%s", gConfDir.c_str());
611  putenv(rootconf);
612  if (gDebug > 0)
613  ErrorInfo("ProofdExec: setting: %s", rootconf);
614  // Temp dir
615  char *roottmp = new char[12+gTmpDir.length()];
616  memset(roottmp, 0, 12 + gTmpDir.length());
617  snprintf(roottmp, 12+gTmpDir.length(), "ROOTTMPDIR=%s", gTmpDir.c_str());
618  putenv(roottmp);
619  if (gDebug > 0)
620  ErrorInfo("ProofdExec: setting: %s", roottmp);
621  // User, host, rpid
622  char *rootentity = new char[gUser.length()+gOpenHost.length()+33];
623  memset(rootentity, 0, gUser.length()+gOpenHost.length()+33);
624  snprintf(rootentity, gUser.length()+gOpenHost.length()+33,
625  "ROOTENTITY=%s:%d@%s", gUser.c_str(), gRemPid, gOpenHost.c_str());
626  putenv(rootentity);
627  if (gDebug > 2)
628  ErrorInfo("ProofdExec: setting: %s", rootentity);
629  // Open socket
630  char *rootopensock = new char[33];
631  memset(rootopensock, 0, 33);
632  snprintf(rootopensock, 33, "ROOTOPENSOCK=%d", sockFd);
633  putenv(rootopensock);
634  if (gDebug > 0)
635  ErrorInfo("ProofdExec: setting: %s", rootopensock);
636  // ReadHomeAuthrc option
637  char *roothomeauthrc = new char[20];
638  memset(roothomeauthrc, 0, 20);
639  snprintf(roothomeauthrc, 20, "ROOTHOMEAUTHRC=%s", gReadHomeAuthrc.c_str());
640  putenv(roothomeauthrc);
641  if (gDebug > 0)
642  ErrorInfo("ProofdExec: setting: %s", roothomeauthrc);
643 
644 #ifdef R__GLBS
645  // ID of shm with exported credentials
646  char *shmidcred = new char[25];
647  memset(shmidcred, 0, 25);
648  snprintf(shmidcred, 25, "ROOTSHMIDCRED=%d", RpdGetShmIdCred());
649  putenv(shmidcred);
650  if (gDebug > 0)
651  ErrorInfo("ProofdExec: setting: %s", shmidcred);
652 #endif
653 
654  // start server version
655  arg0 = gRootBinDir + "/proofserv";
656  argvv[0] = (char *)arg0.c_str();
657  argvv[1] = (char *)(gMaster ? "proofserv" : "proofslave");
658  argvv[2] = 0;
659 
660 #ifndef ROOTPREFIX
661  char *rootsys = new char[9+gConfDir.length()];
662  memset(rootsys, 0, 9 + gConfDir.length());
663  snprintf(rootsys, 9+gConfDir.length(), "ROOTSYS=%s", gConfDir.c_str());
664  putenv(rootsys);
665  if (gDebug > 0)
666  ErrorInfo("ProofdExec: setting: %s", rootsys);
667 #endif
668 #ifndef ROOTLIBDIR
669  char *oldpath, *ldpath;
670 # if defined(__hpux) || defined(_HIUX_SOURCE)
671  if ((oldpath = getenv("SHLIB_PATH")) && strlen(oldpath) > 0) {
672  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
673  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
674  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
675  "SHLIB_PATH=%s/lib:%s", gConfDir.c_str(), oldpath);
676  } else {
677  ldpath = new char[32+gConfDir.length()];
678  memset(ldpath, 0, 32+gConfDir.length());
679  snprintf(ldpath, 32+gConfDir.length(), "SHLIB_PATH=%s/lib", gConfDir.c_str());
680  }
681 # elif defined(_AIX)
682  if ((oldpath = getenv("LIBPATH")) && strlen(oldpath) > 0) {
683  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
684  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
685  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
686  "LIBPATH=%s/lib:%s", gConfDir.c_str(), oldpath);
687  } else {
688  ldpath = new char[32+gConfDir.length()];
689  memset(ldpath, 0, 32+gConfDir.length());
690  snprintf(ldpath, 32+gConfDir.length(), "LIBPATH=%s/lib", gConfDir.c_str());
691  }
692 # elif defined(__APPLE__)
693  if ((oldpath = getenv("DYLD_LIBRARY_PATH")) && strlen(oldpath) > 0) {
694  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
695  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
696  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
697  "DYLD_LIBRARY_PATH=%s/lib:%s", gConfDir.c_str(), oldpath);
698  } else {
699  ldpath = new char[32+gConfDir.length()];
700  memset(ldpath, 0, 32+gConfDir.length());
701  snprintf(ldpath, 32+gConfDir.length(), "DYLD_LIBRARY_PATH=%s/lib", gConfDir.c_str());
702  }
703 # else
704  if ((oldpath = getenv("LD_LIBRARY_PATH")) && strlen(oldpath) > 0) {
705  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
706  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
707  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
708  "LD_LIBRARY_PATH=%s/lib:%s", gConfDir.c_str(), oldpath);
709  } else {
710  ldpath = new char[32+gConfDir.length()];
711  memset(ldpath, 0, 32+gConfDir.length());
712  snprintf(ldpath, 32+gConfDir.length(), "LD_LIBRARY_PATH=%s/lib", gConfDir.c_str());
713  }
714 # endif
715  putenv(ldpath);
716  if (gDebug > 0)
717  ErrorInfo("ProofdExec: setting: %s", ldpath);
718 #endif
719 
720  // Check if a special file for authentication directives
721  // has been given for later use in TAuthenticate; if yes,
722  // set the corresponding environment variable
723  char *authrc = 0;
724  if (gAuthrc.length()) {
725  if (gDebug > 0)
726  ErrorInfo("ProofdExec: setting ROOTAUTHRC to %s",gAuthrc.c_str());
727  authrc = new char[15+gAuthrc.length()];
728  memset(authrc, 0, 15 + gAuthrc.length());
729  snprintf(authrc, 15+gAuthrc.length(), "ROOTAUTHRC=%s", gAuthrc.c_str());
730  putenv(authrc);
731  if (gDebug > 0)
732  ErrorInfo("ProofdExec: setting: %s", authrc);
733  }
734 
735  // For backward compatibility
736  char *keyfile = new char[15+strlen(RpdGetKeyRoot())];
737  memset(keyfile, 0, 15+strlen(RpdGetKeyRoot()));
738  snprintf(keyfile, 15+strlen(RpdGetKeyRoot()), "ROOTKEYFILE=%s",RpdGetKeyRoot());
739  putenv(keyfile);
740  if (gDebug > 2)
741  ErrorInfo("ProofdExec: setting: %s", keyfile);
742 
743  if (gDebug > 0)
744  ErrorInfo("ProofdExec: execv(%s, %s)", argvv[0], argvv[1]);
745 
746  // Start proofserv
747  execv(arg0.c_str(), argvv);
748 
749  // tell client that exec failed
750  msg = "Cannot start PROOF server --- make sure " + arg0 + " exists!";
751  NetSend(msg.c_str());
752 }
753 
754 
755 ////////////////////////////////////////////////////////////////////////////////
756 
757 void Usage(const char* name, int rc)
758 {
759  fprintf(stderr, "\nUsage: %s [options] [rootsys-dir]\n", name);
760  fprintf(stderr, "\nOptions:\n");
761  fprintf(stderr, "\t-A [<rootauthrc>] Use $HOME/.rootauthrc or specified file\n");
762  fprintf(stderr, "\t (see documentation)\n");
763  fprintf(stderr, "\t-b tcpwindowsize Specify the tcp window size in bytes\n");
764 #ifdef R__GLBS
765  fprintf(stderr, "\t-C hostcertfile Specify the location of the Globus host certificate\n");
766 #endif
767  fprintf(stderr, "\t-d level set debug level [0..3]\n");
768  fprintf(stderr, "\t-D rootdaemonrc Use alternate rootdaemonrc file\n");
769  fprintf(stderr, "\t (see documentation)\n");
770  fprintf(stderr, "\t-E Ignored for backward compatibility\n");
771  fprintf(stderr, "\t-f Run in foreground\n");
772 #ifdef R__GLBS
773  fprintf(stderr, "\t-G gridmapfile Specify the location of th Globus gridmap\n");
774 #endif
775  fprintf(stderr, "\t-i Running from inetd\n");
776  fprintf(stderr, "\t-noauth Do not require client authentication\n");
777  fprintf(stderr, "\t-p port# Specify a different port to listen on\n");
778  fprintf(stderr, "\t-s sshd_port# Specify the port for the sshd daemon\n");
779 #ifdef R__KRB5
780  fprintf(stderr, "\t-S keytabfile Use an alternate keytab file\n");
781 #endif
782  fprintf(stderr, "\t-T <tmpdir> Use an alternate temp dir\n");
783  fprintf(stderr, "\t-w Do not check /etc/hosts.equiv and $HOME/.rhosts\n");
784 
785  exit(rc);
786 }
787 
788 ////////////////////////////////////////////////////////////////////////////////
789 
790 int main(int argc, char **argv)
791 {
792  char *s;
793  int checkhostsequiv = 1;
794  int tcpwindowsize = 65535;
795  int sshdport = 22;
796  int port1 = 0;
797  int port2 = 0;
798  int reuseallow = 0x1F;
799  int foregroundflag = 0;
800  std::string altSRPpass = "";
801  std::string daemonrc = "";
802  std::string rootetcdir = "";
803 #ifdef R__GLBS
804  std::string gridmap = "";
805  std::string hostcertconf = "";
806 #endif
807  char *progname = argv[0];
808 
809  // Init error handlers
811 
812  // Init syslog
813  ErrorInit(argv[0]);
814 
815  // Output to syslog ...
816  RpdSetSysLogFlag(1);
817 
818  // ... unless we are running in the foreground and we are
819  // attached to terminal; make also sure that "-i" and "-f"
820  // are not simultaneously specified
821  int i = 1;
822  for (i = 1; i < argc; i++) {
823  if (!strncmp(argv[i],"-f",2))
824  foregroundflag = 1;
825  if (!strncmp(argv[i],"-i",2))
826  gInetdFlag = 1;
827  }
828  if (foregroundflag) {
829  if (isatty(0) && isatty(1)) {
830  RpdSetSysLogFlag(0);
831  ErrorInfo("main: running in foreground mode:"
832  " sending output to stderr");
833  }
834  if (gInetdFlag)
835  Error(ErrFatal,-1,"-i and -f options are incompatible");
836  }
837 
838  // To terminate correctly ... maybe not needed
839  signal(SIGTERM, ProofdTerm);
840  signal(SIGINT, ProofdTerm);
841 
842  while (--argc > 0 && (*++argv)[0] == '-')
843  for (s = argv[0]+1; *s != 0; s++)
844  switch (*s) {
845 
846  case 'A':
847  gReadHomeAuthrc = std::string("1");
848  // Next argument may be the name of a file with the
849  // authentication directives to be used
850  if((*(argv+1)) && (*(argv+1))[0] != '-') {
851  gAuthrc = std::string(*(argv+1));
852  struct stat st;
853  if (stat(gAuthrc.c_str(),&st) == -1 || !S_ISREG(st.st_mode)) {
854  // Not a regular file: discard it
855  gAuthrc.erase();
856  } else {
857  // Got a regular file as argument: go to next
858  argc--;
859  argv++;
860  }
861  }
862  break;
863 
864  case 'b':
865  if (--argc <= 0) {
866  Error(ErrFatal,-1,"-b requires a buffersize in bytes as"
867  " argument");
868  }
869  tcpwindowsize = atoi(*++argv);
870  break;
871 #ifdef R__GLBS
872  case 'C':
873  if (--argc <= 0) {
874  Error(ErrFatal,-1,"-C requires a file name for the host"
875  " certificates file location");
876  }
877  hostcertconf = std::string(*++argv);
878  break;
879 #endif
880  case 'd':
881  if (--argc <= 0) {
882  Error(ErrFatal,-1,"-d requires a debug level as argument");
883  }
884  gDebug = atoi(*++argv);
885  break;
886 
887  case 'D':
888  if (--argc <= 0) {
889  Error(ErrFatal, kErrFatal,"-D requires a file path name"
890  " for the file defining access rules");
891  }
892  daemonrc = std::string(*++argv);
893  break;
894 
895  case 'E':
896  Error(ErrFatal, kErrFatal,"Option '-E' is now dummy"
897  " - ignored (see proofd/src/proofd.cxx for"
898  " additional details)");
899  break;
900 
901  case 'f':
902  if (gInetdFlag) {
903  Error(ErrFatal,-1,"-i and -f options are incompatible");
904  }
905  foregroundflag = 1;
906  break;
907 #ifdef R__GLBS
908  case 'G':
909  if (--argc <= 0) {
910  Error(ErrFatal,-1,"-G requires a file name for the gridmap"
911  " file");
912  }
913  gridmap = std::string(*++argv);
914  break;
915 #endif
916  case 'h':
917  Usage(progname, 0);
918  break;
919 
920  case 'i':
921  if (foregroundflag) {
922  Error(ErrFatal,-1,"-i and -f options are incompatible");
923  }
924  gInetdFlag = 1;
925  break;
926 
927  case 'n':
928  if (!strncmp(argv[0]+1,"noauth",6)) {
929  gRequireAuth = 0;
930  s += 5;
931  }
932  break;
933 
934  case 'p':
935  if (--argc <= 0) {
936  Error(ErrFatal,-1,"-p requires a port number as argument");
937  }
938  char *p;
939  port1 = strtol(*++argv, &p, 10);
940  if (*p == '-') {
941  p++;
942  port2 = strtol(p, &p, 10);
943  } else if (*p == '\0')
944  port2 = port1;
945  if (*p != '\0' || port2 < port1 || port2 < 0) {
946  Error(ErrFatal,kErrFatal,"invalid port number or range: %s",
947  *argv);
948  }
949  break;
950 
951  case 'P':
952  if (--argc <= 0) {
953  Error(ErrFatal,kErrFatal,"-P requires a file name for SRP"
954  " password file");
955  }
956  altSRPpass = std::string(*++argv);
957  break;
958 
959  case 'R':
960  if (--argc <= 0) {
961  Error(ErrFatal,kErrFatal,"-R requires a hex but mask as"
962  " argument");
963  }
964  reuseallow = strtol(*++argv, (char **)0, 16);
965  break;
966 
967  case 's':
968  if (--argc <= 0) {
969  Error(ErrFatal,kErrFatal,"-s requires as argument a port"
970  " number for the sshd daemon");
971  }
972  sshdport = atoi(*++argv);
973  break;
974 #ifdef R__KRB5
975  case 'S':
976  if (--argc <= 0) {
977  Error(ErrFatal,-1,"-S requires a path to your keytab\n");
978  }
979  RpdSetKeytabFile((const char *)(*++argv));
980  break;
981 #endif
982  case 'T':
983  if (--argc <= 0) {
984  Error(ErrFatal,kErrFatal,"-T requires a dir path for"
985  " temporary files [/usr/tmp]");
986  }
987  gTmpDir = std::string(*++argv);
988  break;
989 
990  case 'w':
991  checkhostsequiv = 0;
992  break;
993 
994  default:
995  if (!foregroundflag) fprintf(stderr, "\nUnknown command line option: %c\n", *s);
996  Error(0, -1, "unknown command line option: %c", *s);
997  Usage(progname, 1);
998  }
999 
1000  // dir for temporary files
1001  if (!gTmpDir.length())
1002  gTmpDir = "/usr/tmp";
1003  if (access(gTmpDir.c_str(), W_OK) == -1)
1004  gTmpDir = "/tmp";
1005 
1006  if (argc > 0) {
1007  gConfDir = std::string(*argv);
1008  } else {
1009  // try to guess the config directory...
1010 #ifndef ROOTDATADIR
1011  if (getenv("ROOTSYS")) {
1012  gConfDir = getenv("ROOTSYS");
1013  if (gDebug > 0)
1014  ErrorInfo("main: no config directory specified using ROOTSYS (%s)",
1015  gConfDir.c_str());
1016  } else {
1017  Error(ErrFatal, -1, "main: no config directory specified");
1018  }
1019 #else
1020  gConfDir = ROOTDATADIR;
1021 #endif
1022  }
1023 #ifdef ROOTBINDIR
1024  gRootBinDir= ROOTBINDIR;
1025 #endif
1026 #ifdef ROOTETCDIR
1027  rootetcdir= ROOTETCDIR;
1028 #endif
1029 
1030  // Define gRootBinDir if not done already
1031  if (!gRootBinDir.length())
1032  gRootBinDir = std::string(gConfDir).append("/bin");
1033 
1034  // make sure it contains the executable we want to run
1035  std::string arg0 = std::string(gRootBinDir).append("/proofserv");
1036  if (access(arg0.c_str(), X_OK) == -1) {
1037  Error(ErrFatal,-1,"main: incorrect config directory specified (%s)",
1038  gConfDir.c_str());
1039  }
1040  // Make it available to all the session via env
1041  if (gRootBinDir.length()) {
1042  char *tmp = new char[15 + gRootBinDir.length()];
1043  snprintf(tmp, 15 + gRootBinDir.length(), "ROOTBINDIR=%s", gRootBinDir.c_str());
1044  putenv(tmp);
1045  }
1046 
1047  // Define rootetcdir if not done already
1048  if (!rootetcdir.length())
1049  rootetcdir = std::string(gConfDir).append("/etc");
1050  // Make it available to all the session via env
1051  if (rootetcdir.length()) {
1052  char *tmp = new char[15 + rootetcdir.length()];
1053  snprintf(tmp, 15 + rootetcdir.length(), "ROOTETCDIR=%s", rootetcdir.c_str());
1054  putenv(tmp);
1055  }
1056 
1057  // If specified, set the special daemonrc file to be used
1058  if (daemonrc.length()) {
1059  char *tmp = new char[15+daemonrc.length()];
1060  snprintf(tmp, 15+daemonrc.length(), "ROOTDAEMONRC=%s", daemonrc.c_str());
1061  putenv(tmp);
1062  }
1063 #ifdef R__GLBS
1064  // If specified, set the special gridmap file to be used
1065  if (gridmap.length()) {
1066  char *tmp = new char[15+gridmap.length()];
1067  snprintf(tmp, 15+gridmap.length(), "GRIDMAP=%s", gridmap.c_str());
1068  putenv(tmp);
1069  }
1070  // If specified, set the special hostcert.conf file to be used
1071  if (hostcertconf.length()) {
1072  char *tmp = new char[15+hostcertconf.length()];
1073  snprintf(tmp, 15+hostcertconf.length(), "ROOTHOSTCERT=%s", hostcertconf.c_str());
1074  putenv(tmp);
1075  }
1076 #endif
1077 
1078  // Parent ID
1079  int proofdparentid = -1; // Parent process ID
1080  if (!gInetdFlag)
1081  proofdparentid = getpid(); // Identifies this family
1082  else
1083  proofdparentid = getppid(); // Identifies this family
1084 
1085  // default job options
1086  unsigned int options = kDMN_RQAUTH | kDMN_HOSTEQ | kDMN_SYSLOG ;
1087  // modify them if required
1088  if (!gRequireAuth)
1089  options &= ~kDMN_RQAUTH;
1090  if (!checkhostsequiv)
1091  options &= ~kDMN_HOSTEQ;
1092  if (foregroundflag)
1093  options &= ~kDMN_SYSLOG;
1094  RpdInit(gService, proofdparentid, gProtocol, options,
1095  reuseallow, sshdport,
1096  gTmpDir.c_str(),altSRPpass.c_str(),2);
1097 
1098  // Generate Local RSA keys for the session
1099  if (RpdGenRSAKeys(0)) {
1100  Error(Err, -1, "proofd: unable to generate local RSA keys");
1101  }
1102 
1103  if (!gInetdFlag) {
1104 
1105  // Start proofd up as a daemon process (in the background).
1106  // Also initialize the network connection - create the socket
1107  // and bind our well-know address to it.
1108 
1109  if (!foregroundflag)
1110  DaemonStart(1, 0, gService);
1111 
1112  NetInit(gService, port1, port2, tcpwindowsize);
1113  }
1114 
1115  if (gDebug > 0)
1116  ErrorInfo("main: pid = %d, gInetdFlag = %d", getpid(), gInetdFlag);
1117 
1118  // Concurrent server loop.
1119  // The child created by NetOpen() handles the client's request.
1120  // The parent waits for another request. In the inetd case,
1121  // the parent from NetOpen() never returns.
1122 
1123  while (1) {
1124  if (NetOpen(gInetdFlag, gService) == 0) {
1125 
1126  // Init Session (get protocol, run authentication, login, ...)
1127  if ((gMaster = RpdInitSession(gService, gUser, gRemPid)) < 0) {
1128  if (gMaster == -1)
1129  Error(ErrFatal, -1, "proofd: failure initializing session");
1130  else if (gMaster == -2)
1131  // special session (eg. cleanup): just exit
1132  exit(0);
1133  }
1134 
1135  ProofdExec(); // child processes client's requests
1136  NetClose(); // then we are done
1137  exit(0);
1138  }
1139 
1140  // parent waits for another client to connect
1141 
1142  }
1143 
1144 }
static std::string gUser
Definition: proofd.cxx:236
int GetErrno()
return errno
static std::string gConfDir
Definition: proofd.cxx:231
void Err(int level, const char *msg, int size)
Definition: proofd.cxx:251
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
const int kMaxSlaves
Definition: proofd.cxx:228
TLine * line
static int gInetdFlag
Definition: proofd.cxx:241
void ErrFatal(int level, const char *msg, int size)
Definition: proofd.cxx:258
void Usage(const char *name, int rc)
Definition: proofd.cxx:757
int NetGetSockFd()
return open socket descriptor
const char * RerouteUser()
Look if user should be rerouted to another server node.
Definition: proofd.cxx:307
int NetRecvRaw(void *buf, int len)
Receive a buffer of maximum len bytes.
void ErrorInfo(const char *va_(fmt),...)
Formats a string in a circular formatting buffer and prints the string.
static EService gService
Definition: proofd.cxx:237
static void ProofdTerm(int)
Termination upon receipt of a SIGTERM or SIGINT.
Definition: proofd.cxx:292
int Int_t
Definition: RtypesCore.h:41
int NetRecv(char *msg, int max)
Receive a string of maximum length max.
void RpdInit(EService serv, int pid, int sproto, unsigned int opts, int rumsk, int sshp, const char *tmpd, const char *asrpp, int login=0)
static int gRequireAuth
Definition: proofd.cxx:243
void RpdSetErrorHandler(ErrorHandler_t Err, ErrorHandler_t Sys, ErrorHandler_t Fatal)
void RpdAuthCleanup(const char *sstr, int opt)
static std::string gReadHomeAuthrc
Definition: proofd.cxx:240
static int gRemPid
Definition: proofd.cxx:239
int RpdProofGetAuthSetup(char **abuf)
Receive buffer for final setup of authentication related stuff This is base 64 string to decoded by p...
Definition: proofd.cxx:417
static int gMaster
Definition: proofd.cxx:242
void ResetErrno()
reset errno
static int gProtocol
Definition: proofd.cxx:238
static std::string gRootBinDir
Definition: proofd.cxx:233
int NetSend(int code, EMessageTypes kind)
Send integer. Message will be of type "kind".
EMessageTypes
Definition: MessageTypes.h:27
void ErrSys(int level, const char *msg, int size)
Definition: proofd.cxx:266
static std::string gTmpDir
Definition: proofd.cxx:235
int main(int argc, char **argv)
Definition: proofd.cxx:790
void NetGetRemoteHost(std::string &openhost)
Return name of connected host.
int RpdGenRSAKeys(int)
void ProofdExec()
Authenticate the user and exec the proofserv program.
Definition: proofd.cxx:457
static std::string gAuthrc
Definition: proofd.cxx:230
#define name(a, b)
Definition: linkTestLib0.cpp:5
static std::string gRpdAuthTab
Definition: proofd.cxx:234
void NetClose()
Empty call, for consistency.
static std::string gOpenHost
Definition: proofd.cxx:232
void ErrorInit(const char *ident)
void Perror(char *buf, int size)
Return in buf the message belonging to errno.
bool debug
int gDebug
Definition: proofd.cxx:224
int RpdInitSession(int, std::string &, int &, int &, int &, std::string &)
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.