Logo ROOT   6.10/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 
219 // General globals
220 int gDebug = 0;
221 
222 //--- Local Globals ---------------------------------------------------------
223 
224 const int kMaxSlaves = 32;
225 
226 static std::string gAuthrc;
227 static std::string gConfDir;
228 static std::string gOpenHost;
229 static std::string gRootBinDir;
230 static std::string gRpdAuthTab; // keeps track of authentication info
231 static std::string gTmpDir;
232 static std::string gUser;
233 static EService gService = kPROOFD;
234 static int gProtocol = 14; // increase when protocol changes
235 static int gRemPid = -1; // remote process ID
236 static std::string gReadHomeAuthrc = "0";
237 static int gInetdFlag = 0;
238 static int gMaster =-1;
239 static int gRequireAuth = 1;
240 
241 using namespace ROOT;
242 
243 //--- Error handlers -----------------------------------------------------------
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 
247 void Err(int level, const char *msg, int size)
248 {
249  Perror((char *)msg, size);
250  if (level > -1) NetSend(level, kROOTD_ERR);
251 }
252 ////////////////////////////////////////////////////////////////////////////////
253 
254 void ErrFatal(int level, const char *msg, int size)
255 {
256  Perror((char *)msg, size);
257  if (level > -1) NetSend(msg, kMESS_STRING);
258  exit(1);
259 }
260 ////////////////////////////////////////////////////////////////////////////////
261 
262 void ErrSys(int level, const char *msg, int size)
263 {
264  Perror((char *)msg, size);
265  ErrFatal(level, msg, size);
266 }
267 
268 //--- Proofd routines ----------------------------------------------------------
269 
270 #if defined(__sun)
271 //______________________________________________________________________________
272 extern "C" { void ProofdTerm(int)
273 {
274  // Termination upon receipt of a SIGTERM or SIGINT.
275 
276  ErrorInfo("ProofdTerm: rootd.cxx: got a SIGTERM/SIGINT");
277  // Terminate properly
278  RpdAuthCleanup(0,0);
279  // Close network connection
280  NetClose();
281  // exit
282  exit(0);
283 }}
284 #else
285 ////////////////////////////////////////////////////////////////////////////////
286 /// Termination upon receipt of a SIGTERM or SIGINT.
287 
288 static void ProofdTerm(int)
289 {
290  ErrorInfo("ProofdTerm: rootd.cxx: got a SIGTERM/SIGINT");
291  // Terminate properly
292  RpdAuthCleanup(0,0);
293  // Close network connection
294  NetClose();
295  // exit
296  exit(0);
297 }
298 #endif
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 /// Look if user should be rerouted to another server node.
302 
303 const char *RerouteUser()
304 {
305  std::string conffile = "proof.conf";
306  FILE *proofconf;
307 
308  if (getenv("HOME")) {
309  conffile.insert(0,"/.");
310  conffile.insert(0,getenv("HOME"));
311  // string::insert is buggy on some compilers (eg gcc 2.96):
312  // new length correct but data not always null terminated
313  conffile[conffile.length()] = 0;
314  }
315  if (!(proofconf = fopen(conffile.c_str(), "r"))) {
316  conffile = "/etc/";
317  conffile.insert(0,gConfDir);
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 || (proofconf = fopen(conffile.c_str(), "r")) != 0) {
323 
324  // read configuration file
325  static char user_on_node[32];
326  struct stat statbuf;
327  char line[256];
328  char node_name[kMaxSlaves][32];
329  int nnodes = 0;
330  int i;
331 
332  strncpy(user_on_node, "any", 32);
333  user_on_node[31] = 0;
334 
335  while (fgets(line, sizeof(line), proofconf) != 0) {
336  char word[4][64];
337  if (line[0] == '#') continue; // skip comment lines
338  // coverity[secure_coding]
339  int nword = sscanf(line, "%63s %63s %63s %63s",
340  word[0], word[1], word[2], word[3]);
341 
342  //
343  // all available nodes must be configured by a line
344  // node <name>
345  //
346  if (nword >= 2 && strcmp(word[0], "node") == 0) {
347  if (gethostbyname(word[1]) != 0) {
348  if (nnodes < kMaxSlaves) {
349  if (strlen(word[1]) < 32) {
350  strncpy(node_name[nnodes], word[1], 32);
351  node_name[nnodes][31] = 0;
352  }
353  nnodes++;
354  }
355  }
356  continue;
357  }
358 
359  //
360  // users can be preferrably rerouted to a specific node
361  // user <name> on <node>
362  //
363  if (nword >= 4 && strcmp(word[0], "user") == 0 &&
364  strcmp(word[1], gUser.c_str()) == 0 &&
365  strcmp(word[2], "on") == 0) {
366  // user <name> on <node>
367  if (strlen(word[3]) < 32) {
368  strncpy(user_on_node, word[3], 32);
369  user_on_node[31] = 0;
370  }
371  continue;
372  }
373  }
374  fclose(proofconf);
375 
376  // make sure the node is running
377  for (i = 0; i < nnodes; i++) {
378  if (strcmp(node_name[i], user_on_node) == 0) {
379  return user_on_node;
380  }
381  }
382 
383  //
384  // get the node name from next.node update by a daemon monitoring
385  // the system load; make sure the file is not completely out of date
386  //
387  conffile = gConfDir + "/etc/next.node";
388  proofconf = fopen(conffile.c_str(), "r");
389  if (proofconf) {
390  if (fstat(fileno(proofconf), &statbuf) == 0 &&
391  difftime(time(0), statbuf.st_mtime) < 600) {
392  if (fgets(line, sizeof(line), proofconf) != 0) {
393  strncpy(user_on_node, line, 32);
394  user_on_node[31] = 0;
395  for (i = 0; i < nnodes; i++) {
396  if (strcmp(node_name[i], user_on_node) == 0) {
397  fclose(proofconf);
398  return user_on_node;
399  }
400  }
401  }
402  }
403  fclose(proofconf);
404  }
405  }
406  return 0;
407 }
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 /// Receive buffer for final setup of authentication related stuff
411 /// This is base 64 string to decoded by proofserv, if needed
412 
413 int RpdProofGetAuthSetup(char **abuf)
414 {
415  int nrec = -1;
416 
417  if (RpdGetOffSet() > -1) {
418  if ((nrec = RpdSecureRecv(abuf)) < 0) {
419  ErrorInfo("RpdProofGetAuthSetup: sec: problems receiving buf");
420  return -1;
421  }
422  } else {
423  // No key: receive plainly
424  EMessageTypes kind;
425  char buflen[20];
426  if (NetRecv(buflen, 20, kind) < 0) {
427  ErrorInfo("RpdProofGetAuthSetup: plain: problems receiving buf length");
428  return -1;
429  }
430  int len = atoi(buflen);
431 
432  // receive the buffer
433  *abuf = new char[len + 1];
434  if ((nrec = NetRecvRaw(*abuf, len)) < 0) {
435  ErrorInfo("RpdProofGetAuthSetup: plain: problems receiving buf");
436  delete[] *abuf;
437  return -1;
438  }
439  (*abuf)[len] = 0;
440  }
441 
442  if (gDebug > 1)
443  ErrorInfo("RpdProofGetAuthSetup: proto: %d len: %d",
444  RpdGetAuthProtocol(), nrec);
445 
446  return nrec;
447 }
448 
449 ////////////////////////////////////////////////////////////////////////////////
450 /// Authenticate the user and exec the proofserv program.
451 /// gConfdir is the location where the PROOF config files and binaries live.
452 
454 {
455  char *argvv[3];
456  std::string arg0;
457  std::string msg;
458 
459 #ifdef R__DEBUG
460  int debug = 1;
461  while (debug)
462  ;
463 #endif
464 
465  // Remote Host
467 
468  // Socket descriptor
469  int sockFd = NetGetSockFd();
470 
471  if (gDebug > 0)
472  ErrorInfo("ProofdExec: gOpenHost = %s", gOpenHost.c_str());
473 
474  if (gDebug > 0)
475  ErrorInfo("ProofdExec: gConfDir = %s", gConfDir.c_str());
476 
477  // only reroute in case of master server
478  const char *node_name;
479  if (gMaster && (node_name = RerouteUser()) != 0) {
480  // send a reroute request to the client passing the IP address
481 
482  char host_name[32];
483  gethostname(host_name, sizeof(host_name));
484 
485  // make sure that we are not already on the target node
486  if (strcmp(host_name, node_name) != 0) {
487  struct hostent *host = gethostbyname(host_name);
488  struct hostent *node; // gethostbyname(node_name) would overwrite
489 
490  if (host != 0) {
491  struct in_addr *host_addr = (struct in_addr*)(host->h_addr);
492  char host_numb[32];
493  if (strlen(inet_ntoa(*host_addr)) < 32) {
494  strncpy(host_numb, inet_ntoa(*host_addr), 32);
495  host_numb[31] = 0;
496  }
497 
498  if ((node = gethostbyname(node_name)) != 0) {
499  struct in_addr *node_addr = (struct in_addr*)(node->h_addr);
500  char node_numb[32];
501  strncpy(node_numb, inet_ntoa(*node_addr), 32);
502  node_numb[31] = 0;
503  //
504  // compare the string representation of the IP addresses
505  // to avoid possible problems with host name aliases
506  //
507  if (strcmp(host_numb, node_numb) != 0) {
508  msg = std::string("Reroute:").append(node_numb);
509  NetSend(msg.c_str());
510  exit(0);
511  }
512  }
513  }
514  }
515  }
516 
517  // Receive buffer for final setup of authentication related stuff
518  // This is base 64 string to decoded by proofserv, if needed
519  if (RpdGetClientProtocol() > 12 && gRequireAuth == 1) {
520  char *authbuff = 0;
521  int lab = 0;
522  if ((lab = RpdProofGetAuthSetup(&authbuff)) > 0) {
523  // Save it in an environment variable
524  char *rootproofauthsetup = new char[20 + strlen(authbuff)];
525  memset(rootproofauthsetup, 0, 20 + strlen(authbuff));
526  snprintf(rootproofauthsetup, 20 + strlen(authbuff), "ROOTPROOFAUTHSETUP=%s", authbuff);
527  putenv(rootproofauthsetup);
528  } else if (lab < 0) {
529  ErrorInfo("ProofdExec: problems receiving auth buffer");
530  }
531  if (authbuff) delete[] authbuff;
532  }
533 
534  if(RpdGetClientProtocol() >= 16) {
535  void *vb = 0;
536  Int_t len = 0;
537  EMessageTypes kind = kMESS_ANY;
538 
539  int rc = NetRecvAllocate(vb, len, kind);
540 
541  if (rc < 0) {
542  ErrorInfo("ProofdExec: error receiving kPROOF_SETENV message");
543  return;
544  }
545 
546  if (kind != kPROOF_SETENV) {
547  ErrorInfo("ProofdExec: expecting kPROOF_SETENV, got %d", kind);
548  return;
549 
550  }
551 
552  char *buf = (char *) vb;
553  char *end = buf + len;
554  const char name[] = "PROOF_ALLVARS=";
555  int alen = strlen(name)+len;
556  char *all = new char[alen]; // strlen("PROOF_ALLVARS=") = 14
557  strlcpy(all, name, alen);
558  while (buf < end) {
559  if (gDebug > 0) ErrorInfo("ProofdExec: setting: %s", buf);
560  char *p = index(buf, '=');
561  if (p) {
562  if (buf != (char *) vb) strlcat(all, ",", alen); // skip the first one
563  strlcat(all, buf, alen);
564  putenv(buf);
565  }
566  buf += strlen(buf) + 1;
567  }
568  if (gDebug > 0) ErrorInfo("ProofdExec: setting: %s", all);
569  putenv(all);
570  }
571 
572  if (gDebug > 0)
573  ErrorInfo("ProofdExec: send Okay (SockFd: %d)", sockFd);
574  NetSend("Okay");
575 
576  // Find a free filedescriptor outside the standard I/O range
577  if (sockFd == 0 || sockFd == 1 || sockFd == 2) {
578  Int_t fd;
579  struct stat stbuf;
580  for (fd = 3; fd < NOFILE; fd++) {
581  ResetErrno();
582  if (fstat(fd, &stbuf) == -1 && GetErrno() == EBADF) {
583  if (dup2(sockFd, fd) < 0)
584  ErrorInfo("ProofdExec: problems executing 'dup2' (errno: %d)", errno);
585  close(sockFd);
586  sockFd = fd;
587  close(2);
588  close(1);
589  close(0);
590  RpdSetSysLogFlag(1); //syslog only from here
591  break;
592  }
593  }
594 
595  if (fd == NOFILE) {
596  NetSend("Cannot start proofserver -- no free filedescriptor");
597  return;
598  }
599  }
600 
601  //
602  // Set environments vars for proofserv
603  // Config dir
604  char *rootconf = new char[13+gConfDir.length()];
605  memset(rootconf, 0, 13 + gConfDir.length());
606  snprintf(rootconf, 13 + gConfDir.length(), "ROOTCONFDIR=%s", gConfDir.c_str());
607  putenv(rootconf);
608  if (gDebug > 0)
609  ErrorInfo("ProofdExec: setting: %s", rootconf);
610  // Temp dir
611  char *roottmp = new char[12+gTmpDir.length()];
612  memset(roottmp, 0, 12 + gTmpDir.length());
613  snprintf(roottmp, 12+gTmpDir.length(), "ROOTTMPDIR=%s", gTmpDir.c_str());
614  putenv(roottmp);
615  if (gDebug > 0)
616  ErrorInfo("ProofdExec: setting: %s", roottmp);
617  // User, host, rpid
618  char *rootentity = new char[gUser.length()+gOpenHost.length()+33];
619  memset(rootentity, 0, gUser.length()+gOpenHost.length()+33);
620  snprintf(rootentity, gUser.length()+gOpenHost.length()+33,
621  "ROOTENTITY=%s:%d@%s", gUser.c_str(), gRemPid, gOpenHost.c_str());
622  putenv(rootentity);
623  if (gDebug > 2)
624  ErrorInfo("ProofdExec: setting: %s", rootentity);
625  // Open socket
626  char *rootopensock = new char[33];
627  memset(rootopensock, 0, 33);
628  snprintf(rootopensock, 33, "ROOTOPENSOCK=%d", sockFd);
629  putenv(rootopensock);
630  if (gDebug > 0)
631  ErrorInfo("ProofdExec: setting: %s", rootopensock);
632  // ReadHomeAuthrc option
633  char *roothomeauthrc = new char[20];
634  memset(roothomeauthrc, 0, 20);
635  snprintf(roothomeauthrc, 20, "ROOTHOMEAUTHRC=%s", gReadHomeAuthrc.c_str());
636  putenv(roothomeauthrc);
637  if (gDebug > 0)
638  ErrorInfo("ProofdExec: setting: %s", roothomeauthrc);
639 
640 #ifdef R__GLBS
641  // ID of shm with exported credentials
642  char *shmidcred = new char[25];
643  memset(shmidcred, 0, 25);
644  snprintf(shmidcred, 25, "ROOTSHMIDCRED=%d", RpdGetShmIdCred());
645  putenv(shmidcred);
646  if (gDebug > 0)
647  ErrorInfo("ProofdExec: setting: %s", shmidcred);
648 #endif
649 
650  // start server version
651  arg0 = gRootBinDir + "/proofserv";
652  argvv[0] = (char *)arg0.c_str();
653  argvv[1] = (char *)(gMaster ? "proofserv" : "proofslave");
654  argvv[2] = 0;
655 
656 #ifndef ROOTPREFIX
657  char *rootsys = new char[9+gConfDir.length()];
658  memset(rootsys, 0, 9 + gConfDir.length());
659  snprintf(rootsys, 9+gConfDir.length(), "ROOTSYS=%s", gConfDir.c_str());
660  putenv(rootsys);
661  if (gDebug > 0)
662  ErrorInfo("ProofdExec: setting: %s", rootsys);
663 #endif
664 #ifndef ROOTLIBDIR
665  char *oldpath, *ldpath;
666 # if defined(__hpux) || defined(_HIUX_SOURCE)
667  if ((oldpath = getenv("SHLIB_PATH")) && strlen(oldpath) > 0) {
668  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
669  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
670  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
671  "SHLIB_PATH=%s/lib:%s", gConfDir.c_str(), oldpath);
672  } else {
673  ldpath = new char[32+gConfDir.length()];
674  memset(ldpath, 0, 32+gConfDir.length());
675  snprintf(ldpath, 32+gConfDir.length(), "SHLIB_PATH=%s/lib", gConfDir.c_str());
676  }
677 # elif defined(_AIX)
678  if ((oldpath = getenv("LIBPATH")) && strlen(oldpath) > 0) {
679  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
680  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
681  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
682  "LIBPATH=%s/lib:%s", gConfDir.c_str(), oldpath);
683  } else {
684  ldpath = new char[32+gConfDir.length()];
685  memset(ldpath, 0, 32+gConfDir.length());
686  snprintf(ldpath, 32+gConfDir.length(), "LIBPATH=%s/lib", gConfDir.c_str());
687  }
688 # elif defined(__APPLE__)
689  if ((oldpath = getenv("DYLD_LIBRARY_PATH")) && strlen(oldpath) > 0) {
690  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
691  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
692  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
693  "DYLD_LIBRARY_PATH=%s/lib:%s", gConfDir.c_str(), oldpath);
694  } else {
695  ldpath = new char[32+gConfDir.length()];
696  memset(ldpath, 0, 32+gConfDir.length());
697  snprintf(ldpath, 32+gConfDir.length(), "DYLD_LIBRARY_PATH=%s/lib", gConfDir.c_str());
698  }
699 # else
700  if ((oldpath = getenv("LD_LIBRARY_PATH")) && strlen(oldpath) > 0) {
701  ldpath = new char[32+gConfDir.length()+strlen(oldpath)];
702  memset(ldpath, 0, 32+gConfDir.length()+strlen(oldpath));
703  snprintf(ldpath, 32+gConfDir.length()+strlen(oldpath),
704  "LD_LIBRARY_PATH=%s/lib:%s", gConfDir.c_str(), oldpath);
705  } else {
706  ldpath = new char[32+gConfDir.length()];
707  memset(ldpath, 0, 32+gConfDir.length());
708  snprintf(ldpath, 32+gConfDir.length(), "LD_LIBRARY_PATH=%s/lib", gConfDir.c_str());
709  }
710 # endif
711  putenv(ldpath);
712  if (gDebug > 0)
713  ErrorInfo("ProofdExec: setting: %s", ldpath);
714 #endif
715 
716  // Check if a special file for authentication directives
717  // has been given for later use in TAuthenticate; if yes,
718  // set the corresponding environment variable
719  char *authrc = 0;
720  if (gAuthrc.length()) {
721  if (gDebug > 0)
722  ErrorInfo("ProofdExec: setting ROOTAUTHRC to %s",gAuthrc.c_str());
723  authrc = new char[15+gAuthrc.length()];
724  memset(authrc, 0, 15 + gAuthrc.length());
725  snprintf(authrc, 15+gAuthrc.length(), "ROOTAUTHRC=%s", gAuthrc.c_str());
726  putenv(authrc);
727  if (gDebug > 0)
728  ErrorInfo("ProofdExec: setting: %s", authrc);
729  }
730 
731  // For backward compatibility
732  char *keyfile = new char[15+strlen(RpdGetKeyRoot())];
733  memset(keyfile, 0, 15+strlen(RpdGetKeyRoot()));
734  snprintf(keyfile, 15+strlen(RpdGetKeyRoot()), "ROOTKEYFILE=%s",RpdGetKeyRoot());
735  putenv(keyfile);
736  if (gDebug > 2)
737  ErrorInfo("ProofdExec: setting: %s", keyfile);
738 
739  if (gDebug > 0)
740  ErrorInfo("ProofdExec: execv(%s, %s)", argvv[0], argvv[1]);
741 
742  // Start proofserv
743  execv(arg0.c_str(), argvv);
744 
745  // tell client that exec failed
746  msg = "Cannot start PROOF server --- make sure " + arg0 + " exists!";
747  NetSend(msg.c_str());
748 }
749 
750 
751 ////////////////////////////////////////////////////////////////////////////////
752 
753 void Usage(const char* name, int rc)
754 {
755  fprintf(stderr, "\nUsage: %s [options] [rootsys-dir]\n", name);
756  fprintf(stderr, "\nOptions:\n");
757  fprintf(stderr, "\t-A [<rootauthrc>] Use $HOME/.rootauthrc or specified file\n");
758  fprintf(stderr, "\t (see documentation)\n");
759  fprintf(stderr, "\t-b tcpwindowsize Specify the tcp window size in bytes\n");
760 #ifdef R__GLBS
761  fprintf(stderr, "\t-C hostcertfile Specify the location of the Globus host certificate\n");
762 #endif
763  fprintf(stderr, "\t-d level set debug level [0..3]\n");
764  fprintf(stderr, "\t-D rootdaemonrc Use alternate rootdaemonrc file\n");
765  fprintf(stderr, "\t (see documentation)\n");
766  fprintf(stderr, "\t-E Ignored for backward compatibility\n");
767  fprintf(stderr, "\t-f Run in foreground\n");
768 #ifdef R__GLBS
769  fprintf(stderr, "\t-G gridmapfile Specify the location of th Globus gridmap\n");
770 #endif
771  fprintf(stderr, "\t-i Running from inetd\n");
772  fprintf(stderr, "\t-noauth Do not require client authentication\n");
773  fprintf(stderr, "\t-p port# Specify a different port to listen on\n");
774  fprintf(stderr, "\t-s sshd_port# Specify the port for the sshd daemon\n");
775 #ifdef R__KRB5
776  fprintf(stderr, "\t-S keytabfile Use an alternate keytab file\n");
777 #endif
778  fprintf(stderr, "\t-T <tmpdir> Use an alternate temp dir\n");
779  fprintf(stderr, "\t-w Do not check /etc/hosts.equiv and $HOME/.rhosts\n");
780 
781  exit(rc);
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 
786 int main(int argc, char **argv)
787 {
788  char *s;
789  int checkhostsequiv = 1;
790  int tcpwindowsize = 65535;
791  int sshdport = 22;
792  int port1 = 0;
793  int port2 = 0;
794  int reuseallow = 0x1F;
795  int foregroundflag = 0;
796  std::string altSRPpass = "";
797  std::string daemonrc = "";
798  std::string rootetcdir = "";
799 #ifdef R__GLBS
800  std::string gridmap = "";
801  std::string hostcertconf = "";
802 #endif
803  char *progname = argv[0];
804 
805  // Init error handlers
806  RpdSetErrorHandler(Err, ErrSys, ErrFatal);
807 
808  // Init syslog
809  ErrorInit(argv[0]);
810 
811  // Output to syslog ...
812  RpdSetSysLogFlag(1);
813 
814  // ... unless we are running in the foreground and we are
815  // attached to terminal; make also sure that "-i" and "-f"
816  // are not simultaneously specified
817  int i = 1;
818  for (i = 1; i < argc; i++) {
819  if (!strncmp(argv[i],"-f",2))
820  foregroundflag = 1;
821  if (!strncmp(argv[i],"-i",2))
822  gInetdFlag = 1;
823  }
824  if (foregroundflag) {
825  if (isatty(0) && isatty(1)) {
826  RpdSetSysLogFlag(0);
827  ErrorInfo("main: running in foreground mode:"
828  " sending output to stderr");
829  }
830  if (gInetdFlag)
831  Error(ErrFatal,-1,"-i and -f options are incompatible");
832  }
833 
834  // To terminate correctly ... maybe not needed
835  signal(SIGTERM, ProofdTerm);
836  signal(SIGINT, ProofdTerm);
837 
838  while (--argc > 0 && (*++argv)[0] == '-')
839  for (s = argv[0]+1; *s != 0; s++)
840  switch (*s) {
841 
842  case 'A':
843  gReadHomeAuthrc = std::string("1");
844  // Next argument may be the name of a file with the
845  // authentication directives to be used
846  if((*(argv+1)) && (*(argv+1))[0] != '-') {
847  gAuthrc = std::string(*(argv+1));
848  struct stat st;
849  if (stat(gAuthrc.c_str(),&st) == -1 || !S_ISREG(st.st_mode)) {
850  // Not a regular file: discard it
851  gAuthrc.erase();
852  } else {
853  // Got a regular file as argument: go to next
854  argc--;
855  argv++;
856  }
857  }
858  break;
859 
860  case 'b':
861  if (--argc <= 0) {
862  Error(ErrFatal,-1,"-b requires a buffersize in bytes as"
863  " argument");
864  }
865  tcpwindowsize = atoi(*++argv);
866  break;
867 #ifdef R__GLBS
868  case 'C':
869  if (--argc <= 0) {
870  Error(ErrFatal,-1,"-C requires a file name for the host"
871  " certificates file location");
872  }
873  hostcertconf = std::string(*++argv);
874  break;
875 #endif
876  case 'd':
877  if (--argc <= 0) {
878  Error(ErrFatal,-1,"-d requires a debug level as argument");
879  }
880  gDebug = atoi(*++argv);
881  break;
882 
883  case 'D':
884  if (--argc <= 0) {
885  Error(ErrFatal, kErrFatal,"-D requires a file path name"
886  " for the file defining access rules");
887  }
888  daemonrc = std::string(*++argv);
889  break;
890 
891  case 'E':
892  Error(ErrFatal, kErrFatal,"Option '-E' is now dummy"
893  " - ignored (see proofd/src/proofd.cxx for"
894  " additional details)");
895  break;
896 
897  case 'f':
898  if (gInetdFlag) {
899  Error(ErrFatal,-1,"-i and -f options are incompatible");
900  }
901  foregroundflag = 1;
902  break;
903 #ifdef R__GLBS
904  case 'G':
905  if (--argc <= 0) {
906  Error(ErrFatal,-1,"-G requires a file name for the gridmap"
907  " file");
908  }
909  gridmap = std::string(*++argv);
910  break;
911 #endif
912  case 'h':
913  Usage(progname, 0);
914  break;
915 
916  case 'i':
917  if (foregroundflag) {
918  Error(ErrFatal,-1,"-i and -f options are incompatible");
919  }
920  gInetdFlag = 1;
921  break;
922 
923  case 'n':
924  if (!strncmp(argv[0]+1,"noauth",6)) {
925  gRequireAuth = 0;
926  s += 5;
927  }
928  break;
929 
930  case 'p':
931  if (--argc <= 0) {
932  Error(ErrFatal,-1,"-p requires a port number as argument");
933  }
934  char *p;
935  port1 = strtol(*++argv, &p, 10);
936  if (*p == '-') {
937  p++;
938  port2 = strtol(p, &p, 10);
939  } else if (*p == '\0')
940  port2 = port1;
941  if (*p != '\0' || port2 < port1 || port2 < 0) {
942  Error(ErrFatal,kErrFatal,"invalid port number or range: %s",
943  *argv);
944  }
945  break;
946 
947  case 'P':
948  if (--argc <= 0) {
949  Error(ErrFatal,kErrFatal,"-P requires a file name for SRP"
950  " password file");
951  }
952  altSRPpass = std::string(*++argv);
953  break;
954 
955  case 'R':
956  if (--argc <= 0) {
957  Error(ErrFatal,kErrFatal,"-R requires a hex but mask as"
958  " argument");
959  }
960  reuseallow = strtol(*++argv, (char **)0, 16);
961  break;
962 
963  case 's':
964  if (--argc <= 0) {
965  Error(ErrFatal,kErrFatal,"-s requires as argument a port"
966  " number for the sshd daemon");
967  }
968  sshdport = atoi(*++argv);
969  break;
970 #ifdef R__KRB5
971  case 'S':
972  if (--argc <= 0) {
973  Error(ErrFatal,-1,"-S requires a path to your keytab\n");
974  }
975  RpdSetKeytabFile((const char *)(*++argv));
976  break;
977 #endif
978  case 'T':
979  if (--argc <= 0) {
980  Error(ErrFatal,kErrFatal,"-T requires a dir path for"
981  " temporary files [/usr/tmp]");
982  }
983  gTmpDir = std::string(*++argv);
984  break;
985 
986  case 'w':
987  checkhostsequiv = 0;
988  break;
989 
990  default:
991  if (!foregroundflag) fprintf(stderr, "\nUnknown command line option: %c\n", *s);
992  Error(0, -1, "unknown command line option: %c", *s);
993  Usage(progname, 1);
994  }
995 
996  // dir for temporary files
997  if (!gTmpDir.length())
998  gTmpDir = "/usr/tmp";
999  if (access(gTmpDir.c_str(), W_OK) == -1)
1000  gTmpDir = "/tmp";
1001 
1002  if (argc > 0) {
1003  gConfDir = std::string(*argv);
1004  }
1005 
1006 #ifdef ROOTPREFIX
1007  if (getenv("IGNOREROOTPREFIX")) {
1008 #endif
1009  if (!gConfDir.length()) {
1010  // try to guess the config directory...
1011  if (getenv("ROOTSYS")) {
1012  gConfDir = getenv("ROOTSYS");
1013  if (gDebug > 0)
1014  ErrorInfo("main: no config directory specified using"
1015  " ROOTSYS (%s)", gConfDir.c_str());
1016  } else {
1017  Error(ErrFatal, -1, "main: no config directory specified");
1018  }
1019  }
1020  gRootBinDir = std::string(gConfDir).append("/bin");
1021  rootetcdir = std::string(gConfDir).append("/etc");
1022 #ifdef ROOTPREFIX
1023  }
1024  else {
1025  if (!gConfDir.length())
1026  gConfDir = ROOTPREFIX;
1027  gRootBinDir = ROOTBINDIR;
1028  rootetcdir = ROOTETCDIR;
1029  }
1030 #endif
1031 
1032  // make sure gRootBinDir contains the executable we want to run
1033  std::string arg0 = std::string(gRootBinDir).append("/proofserv");
1034  if (access(arg0.c_str(), X_OK) == -1) {
1035  Error(ErrFatal,-1,"main: incorrect config directory specified (%s)",
1036  gConfDir.c_str());
1037  }
1038  // Make gRootBinDir available to all the session via env
1039  if (gRootBinDir.length()) {
1040  char *tmp = new char[15 + gRootBinDir.length()];
1041  snprintf(tmp, 15 + gRootBinDir.length(), "ROOTBINDIR=%s", gRootBinDir.c_str());
1042  putenv(tmp);
1043  }
1044 
1045  // Make rootetcdir available to all the session via env
1046  if (rootetcdir.length()) {
1047  char *tmp = new char[15 + rootetcdir.length()];
1048  snprintf(tmp, 15 + rootetcdir.length(), "ROOTETCDIR=%s", rootetcdir.c_str());
1049  putenv(tmp);
1050  }
1051 
1052  // If specified, set the special daemonrc file to be used
1053  if (daemonrc.length()) {
1054  char *tmp = new char[15+daemonrc.length()];
1055  snprintf(tmp, 15+daemonrc.length(), "ROOTDAEMONRC=%s", daemonrc.c_str());
1056  putenv(tmp);
1057  }
1058 #ifdef R__GLBS
1059  // If specified, set the special gridmap file to be used
1060  if (gridmap.length()) {
1061  char *tmp = new char[15+gridmap.length()];
1062  snprintf(tmp, 15+gridmap.length(), "GRIDMAP=%s", gridmap.c_str());
1063  putenv(tmp);
1064  }
1065  // If specified, set the special hostcert.conf file to be used
1066  if (hostcertconf.length()) {
1067  char *tmp = new char[15+hostcertconf.length()];
1068  snprintf(tmp, 15+hostcertconf.length(), "ROOTHOSTCERT=%s", hostcertconf.c_str());
1069  putenv(tmp);
1070  }
1071 #endif
1072 
1073  // Parent ID
1074  int proofdparentid = -1; // Parent process ID
1075  if (!gInetdFlag)
1076  proofdparentid = getpid(); // Identifies this family
1077  else
1078  proofdparentid = getppid(); // Identifies this family
1079 
1080  // default job options
1081  unsigned int options = kDMN_RQAUTH | kDMN_HOSTEQ | kDMN_SYSLOG ;
1082  // modify them if required
1083  if (!gRequireAuth)
1084  options &= ~kDMN_RQAUTH;
1085  if (!checkhostsequiv)
1086  options &= ~kDMN_HOSTEQ;
1087  if (foregroundflag)
1088  options &= ~kDMN_SYSLOG;
1089  RpdInit(gService, proofdparentid, gProtocol, options,
1090  reuseallow, sshdport,
1091  gTmpDir.c_str(),altSRPpass.c_str(),2);
1092 
1093  // Generate Local RSA keys for the session
1094  if (RpdGenRSAKeys(0)) {
1095  Error(Err, -1, "proofd: unable to generate local RSA keys");
1096  }
1097 
1098  if (!gInetdFlag) {
1099 
1100  // Start proofd up as a daemon process (in the background).
1101  // Also initialize the network connection - create the socket
1102  // and bind our well-know address to it.
1103 
1104  if (!foregroundflag)
1105  DaemonStart(1, 0, gService);
1106 
1107  NetInit(gService, port1, port2, tcpwindowsize);
1108  }
1109 
1110  if (gDebug > 0)
1111  ErrorInfo("main: pid = %d, gInetdFlag = %d", getpid(), gInetdFlag);
1112 
1113  // Concurrent server loop.
1114  // The child created by NetOpen() handles the client's request.
1115  // The parent waits for another request. In the inetd case,
1116  // the parent from NetOpen() never returns.
1117 
1118  while (1) {
1119  if (NetOpen(gInetdFlag, gService) == 0) {
1120 
1121  // Init Session (get protocol, run authentication, login, ...)
1122  if ((gMaster = RpdInitSession(gService, gUser, gRemPid)) < 0) {
1123  if (gMaster == -1)
1124  Error(ErrFatal, -1, "proofd: failure initializing session");
1125  else if (gMaster == -2)
1126  // special session (eg. cleanup): just exit
1127  exit(0);
1128  }
1129 
1130  ProofdExec(); // child processes client's requests
1131  NetClose(); // then we are done
1132  exit(0);
1133  }
1134 
1135  // parent waits for another client to connect
1136 
1137  }
1138 
1139 }
static std::string gUser
Definition: proofd.cxx:232
int GetErrno()
return errno
static std::string gConfDir
Definition: proofd.cxx:227
void Err(int level, const char *msg, int size)
Definition: proofd.cxx:247
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
const int kMaxSlaves
Definition: proofd.cxx:224
TLine * line
static int gInetdFlag
Definition: proofd.cxx:237
void ErrFatal(int level, const char *msg, int size)
Definition: proofd.cxx:254
void Usage(const char *name, int rc)
Definition: proofd.cxx:753
int NetGetSockFd()
return open socket descriptor
const char * RerouteUser()
Look if user should be rerouted to another server node.
Definition: proofd.cxx:303
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:233
static void ProofdTerm(int)
Termination upon receipt of a SIGTERM or SIGINT.
Definition: proofd.cxx:288
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:239
static std::string gReadHomeAuthrc
Definition: proofd.cxx:236
static int gRemPid
Definition: proofd.cxx:235
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:413
static int gMaster
Definition: proofd.cxx:238
void ResetErrno()
reset errno
static int gProtocol
Definition: proofd.cxx:234
static std::string gRootBinDir
Definition: proofd.cxx:229
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:262
static std::string gTmpDir
Definition: proofd.cxx:231
int main(int argc, char **argv)
Definition: proofd.cxx:786
void NetGetRemoteHost(std::string &openhost)
Return name of connected host.
void ProofdExec()
Authenticate the user and exec the proofserv program.
Definition: proofd.cxx:453
static std::string gAuthrc
Definition: proofd.cxx:226
static std::string gRpdAuthTab
Definition: proofd.cxx:230
void NetClose()
Empty call, for consistency.
static std::string gOpenHost
Definition: proofd.cxx:228
#define snprintf
Definition: civetweb.c:822
void Perror(char *buf, int size)
Return in buf the message belonging to errno.
bool debug
int gDebug
Definition: proofd.cxx:220
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.