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