Logo ROOT   6.10/09
Reference Guide
proofexecv.cxx
Go to the documentation of this file.
1 // @(#)root/main:$Id$
2 // Author: Gerardo Ganis Mar 2011
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 // proofexecv //
15 // //
16 // Program executed via system starting proofserv instances. //
17 // It also performs other actions requiring a separate process, e.g. //
18 // XrdProofAdmin file system requests. //
19 // //
20 //////////////////////////////////////////////////////////////////////////
21 
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <syslog.h>
26 #include <errno.h>
27 #include <pwd.h>
28 #include <ios>
29 #include <fstream>
30 #include <list>
31 #include <string>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <grp.h>
37 #include <dirent.h>
38 
39 #include "Varargs.h"
40 #include "rpdconn.h"
41 #include "rpdpriv.h"
42 
43 #ifdef R__GLOBALSTL
44 namespace std { using ::string; }
45 #endif
46 
47 static int gType = 0;
48 static int gDebug = 0;
49 static FILE *gLogger = 0;
50 
51 #define kMAXPATHLEN 4096
52 
53 int assertdir(const std::string &path, uid_t u, gid_t g, unsigned int mode);
54 int changeown(const std::string &path, uid_t u, gid_t g);
55 int exportsock(rpdunix *conn);
56 int loginuser(const std::string &home, const std::string &user, uid_t u, gid_t g);
57 int mvfile(const std::string &from, const std::string &to, uid_t u, gid_t g, unsigned int mode);
58 int completercfile(const std::string &rcfile, const std::string &sessdir,
59  const std::string &stag, const std::string &adminpath);
60 int setownerships(int euid, const std::string &us, const std::string &gr,
61  const std::string &creds, const std::string &dsrcs,
62  const std::string &ddir, const std::string &ddiro,
63  const std::string &ord, const std::string &stag);
64 int setproofservenv(const std::string &envfile,
65  const std::string &logfile, const std::string &rcfile);
66 int redirectoutput(const std::string &logfile);
67 
68 void start_ps(int argc, char **argv);
69 void start_rootd(int argc, char **argv);
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 /// Write info message to syslog.
73 
74 void Info(const char *va_(fmt), ...)
75 {
76  char buf[kMAXPATHLEN];
77  va_list ap;
78 
79  va_start(ap,va_(fmt));
80  vsnprintf(buf, sizeof(buf), fmt, ap);
81  va_end(ap);
82 
83  if (gLogger)
84  fprintf(gLogger, "proofexecv: %s\n", buf);
85  else
86  fprintf(stderr, "proofexecv: %s\n", buf);
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// Program executed via system starting proofserv instances.
91 /// It also performs other actions requiring a separate process, e.g.
92 /// XrdProofAdmin file system requests.
93 
94 int main(int argc, char **argv)
95 {
96  // Default logger
97  gLogger = stderr;
98  if (argc < 3) {
99  Info("argc=%d: at least 2 additional argument (the process type and debug level) are required - exit",
100  argc);
101  exit(1);
102  }
103  if ((gType = atoi(argv[1])) < 0) {
104  Info("ERROR: invalid process type %d (must be > 0) - exit", gType);
105  exit(1);
106  }
107  gDebug = atoi(argv[2]);
108 
109  if (gType <= 3) {
110  // Start a proofserv process
111  start_ps(argc, argv);
112  exit(1);
113  } else if (gType == 20) {
114  // Start a rootd to serve a file
115  start_rootd(argc, argv);
116  exit(1);
117  } else {
118  Info("ERROR: process type %d not yet implemented", gType);
119  exit(1);
120  }
121 
122  // Done
123  exit(0);
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Process a request to start a rootd server
128 
129 void start_rootd(int argc, char **argv)
130 {
131  if (argc < 6) {
132  Info("argc=%d: at least 5 additional arguments required - exit", argc);
133  return;
134  }
135 
136  // Parse arguments:
137  // 1 process type (2=top-master, 1=sub-master 0=worker, 3=test, 10=admin, 20=rootd)
138  // 2 debug level
139  // 3 path to unix socket to the parent to receive the open descriptor
140  // 4 path to rootd executable
141  // >=5 arguments to rootd
142 
143  // Call back the parent, so that it can move to other processes
144  std::string sockpath = argv[3];
145  rpdunix *uconn = new rpdunix(sockpath.c_str());
146  if (!uconn || (uconn && !uconn->isvalid(0))) {
147  Info("ERROR: failure calling back parent on '%s'", sockpath.c_str());
148  return;
149  }
150 
151  int rcc = 0;
152  // Receive the open descriptor to be used in rootd
153  int fd = -1;
154  if ((rcc = uconn->recvdesc(fd)) != 0) {
155  Info("ERROR: failure receiving open descriptor from parent (errno: %d)", -rcc);
156  delete uconn;
157  return;
158  }
159  // Close the connection to the parent
160  delete uconn;
161 
162  // Force stdin/out to point to the socket FD (this will also bypass the
163  // close on exec setting for the socket)
164  if (dup2(fd, STDIN_FILENO) != 0)
165  Info("WARNING: failure duplicating STDIN (errno: %d)", errno);
166  if (dup2(fd, STDOUT_FILENO) != 0)
167  Info("WARNING: failure duplicating STDOUT (errno: %d)", errno);
168 
169  // Prepare execv
170  int na = argc - 4;
171  char **argvv = new char *[na + 1];
172 
173  // Fill arguments
174  argvv[0] = argv[4];
175  int ia = 5, ka = 1;
176  while (ia < argc) {
177  argvv[ka] = argv[ia];
178  ka++; ia++;
179  }
180  argvv[na] = 0;
181 
182  // Run the program
183  execv(argv[4], argvv);
184 
185  // We should not be here!!!
186  Info("ERROR: returned from execv: bad, bad sign !!!");
187  delete [] argvv;
188  return;
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 /// Process a request to start a proofserv process
193 
194 void start_ps(int argc, char **argv)
195 {
196  if (argc < 6) {
197  Info("argc=%d: at least 5 additional arguments required - exit", argc);
198  return;
199  }
200 
201  // Parse arguments:
202  // 1 process type (2=top-master, 1=sub-master 0=worker, 3=test, 10=admin, 20=rootd)
203  // 2 debug level
204  // 3 user name
205  // 4 root path for relevant directories and files (to be completed with PID)
206  // 5 path to unix socket to be used to call back the parent
207  // 6 log files for errors (prior to final log redirection)
208 
209 #if 0
210  int dbg = 1;
211  while (dbg) {}
212 #endif
213 
214  // Open error logfile
215  std::string errlog(argv[6]);
216  if (!(gLogger = fopen(errlog.c_str(), "a"))) {
217  Info("FATAL: could not open '%s' for error logging - errno: %d",
218  errlog.c_str(), (int) errno);
219  return;
220  }
221 
222  // Pid string
223  char spid[20];
224  snprintf(spid, 20, "%d", (int)getpid());
225 
226  // Identity of session's owner
227  std::string user = argv[3];
228  struct passwd *pw = getpwnam(user.c_str());
229  if (!pw) {
230  Info("ERROR: could noy get identity info for '%s' - errno: %d", user.c_str(), (int) errno);
231  return;
232  }
233  uid_t uid = pw->pw_uid;
234  uid_t gid = pw->pw_gid;
235 
236  std::string::size_type loc = 0;
237 
238  // All relevant files an directories derived from argv[4], inclusing base-path for temporary
239  // env- and rc-files
240  std::string sessdir(argv[4]), logfile(argv[4]), tenvfile, trcfile;
241  if (gType == 2) {
242  // Top master
243  if ((loc = sessdir.rfind('/')) != std::string::npos) sessdir.erase(loc, std::string::npos);
244  tenvfile = sessdir;
245  } else {
246  // Sub-masters, workers (the session dir is already fully defined ...)
247  tenvfile = sessdir;
248  if ((loc = sessdir.rfind('/')) != std::string::npos) sessdir.erase(loc, std::string::npos);
249  }
250  if ((loc = tenvfile.rfind("<pid>")) != std::string::npos) tenvfile.erase(loc, std::string::npos);
251  trcfile = tenvfile;
252  tenvfile += ".env";
253  trcfile += ".rootrc";
254 
255  // Complete the session dir path and assert it
256  if ((loc = sessdir.find("<pid>")) != std::string::npos) sessdir.replace(loc, 5, spid);
257  if (assertdir(sessdir, uid, gid, 0755) != 0) {
258  Info("ERROR: could not assert dir '%s'", sessdir.c_str());
259  return;
260  }
261  Info("session dir: %s", sessdir.c_str());
262 
263  // The session files now
264  while ((loc = logfile.find("<pid>")) != std::string::npos) { logfile.replace(loc, 5, spid); }
265  std::string stag(logfile), envfile(logfile), userdir(logfile), rcfile(logfile);
266  logfile += ".log";
267  envfile += ".env";
268  rcfile += ".rootrc";
269 
270  // Assert working directory
271  if (assertdir(userdir, uid, gid, 0755) != 0) {
272  Info("ERROR: could not assert dir '%s'", userdir.c_str());
273  return;
274  }
275 
276  // The session tag
277  if ((loc = stag.rfind('/')) != std::string::npos) stag.erase(0, loc);
278  if ((loc = stag.find('-')) != std::string::npos) loc = stag.find('-', loc+1);
279  if (loc != std::string::npos) stag.erase(0, loc+1);
280  Info("session tag: %s", stag.c_str());
281 
282  // Call back the parent, so that it can move to other processes
283  std::string sockpath = argv[5];
284  rpdunix *uconn = new rpdunix(sockpath.c_str());
285  if (!uconn || (uconn && !uconn->isvalid(0))) {
286  Info("ERROR: failure calling back parent on '%s'", sockpath.c_str());
287  if (uconn) delete uconn;
288  return;
289  }
290 
291  // Send the pid
292  int rcc = 0;
293  if ((rcc = uconn->send((int) getpid())) != 0) {
294  Info("ERROR: failure sending pid to parent (errno: %d)", -rcc);
295  delete uconn;
296  return;
297  }
298 
299  // Receive the adminpath and the executable path
300  rpdmsg msg;
301  if ((rcc = uconn->recv(msg)) != 0) {
302  Info("ERROR: failure receiving admin path and executable from parent (errno: %d)", -rcc);
303  delete uconn;
304  return;
305  }
306  int ppid;
307  std::string srvadmin, adminpath, pspath;
308  msg >> srvadmin >> adminpath >> pspath >> ppid;
309  Info("srv admin path: %s", srvadmin.c_str());
310  Info("partial admin path: %s", adminpath.c_str());
311  Info("executable: %s", pspath.c_str());
312  Info("parent pid: %d", ppid);
313 
314  // Receive information about dataset and data dir(s)
315  msg.reset();
316  if ((rcc = uconn->recv(msg)) != 0) {
317  Info("ERROR: failure receiving information about dataset and data dir(s) from parent (errno: %d)", -rcc);
318  delete uconn;
319  return;
320  }
321  int euid;
322  std::string group, creds, ord, datadir, ddiropts, datasetsrcs;
323  msg >> euid >> group >> creds >> ord >> datadir >> ddiropts >> datasetsrcs;
324  Info("euid at startup: %d", euid);
325  Info("group, ord: %s, %s", group.c_str(), ord.c_str());
326  Info("datadir: %s", datadir.c_str());
327  Info("datasetsrcs: %s", datasetsrcs.c_str());
328 
329  // Set user ownerships
330  if (setownerships(euid, user, group, creds, datasetsrcs, datadir, ddiropts,
331  ord, stag) != 0) {
332  Info("ERROR: problems setting relevant user ownerships");
333  delete uconn;
334  return;
335  }
336 
337  // Move the environment configuration file in the session directory
338  if (mvfile(tenvfile, envfile, uid, gid, 0644) != 0) {
339  Info("ERROR: problems renaming '%s' to '%s' (errno: %d)",
340  tenvfile.c_str(), envfile.c_str(), errno);
341  delete uconn;
342  return;
343  }
344  // Move the rootrc file in the session directory
345  if (mvfile(trcfile, rcfile, uid, gid, 0644) != 0) {
346  Info("ERROR: problems renaming '%s' to '%s' (errno: %d)",
347  trcfile.c_str(), rcfile.c_str(), errno);
348  delete uconn;
349  return;
350  }
351 
352  // Add missing information to the rc file
353  if (completercfile(rcfile, userdir, stag, adminpath) != 0) {
354  Info("ERROR: problems completing '%s'", rcfile.c_str());
355  delete uconn;
356  return;
357  }
358  // Set the environment following the content of the env file
359  if (setproofservenv(envfile, logfile, rcfile) != 0) {
360  Info("ERROR: problems setting environment from '%s'", envfile.c_str());
361  delete uconn;
362  return;
363  }
364 
365  // Export the file descriptor
366  if (exportsock(uconn) != 0) {
367  Info("ERROR: problems exporting file descriptor");
368  delete uconn;
369  return;
370  }
371  delete uconn;
372 
373  // Login now
374  if (loginuser(userdir, user, uid, gid) != 0) {
375  Info("ERROR: problems login user '%s' in", user.c_str());
376  return;
377  }
378 
379 #if 1
380  // Redirect the logs now
381  if (redirectoutput(logfile) != 0) {
382  Info("ERROR: problems redirecting logs to '%s'", logfile.c_str());
383  return;
384  }
385 #endif
386 
387  // Prepare for execv
388  char *argvv[6] = {0};
389 
390  char *sxpd = 0;
391  if (adminpath.length() > 0) {
392  // We add our admin path to be able to identify processes coming from us
393  int len = srvadmin.length() + strlen("xpdpath:") + 1;
394  sxpd = new char[len];
395  snprintf(sxpd, len, "xpdpath:%s", adminpath.c_str());
396  } else {
397  // We add our PID to be able to identify processes coming from us
398  sxpd = new char[10];
399  snprintf(sxpd, 10, "%d", ppid);
400  }
401 
402  // Log level
403  char slog[10] = {0};
404  snprintf(slog, 10, "%d", gDebug);
405 
406  // Fill arguments
407  argvv[0] = (char *) pspath.c_str();
408  argvv[1] = (char *)((gType == 0) ? "proofslave" : "proofserv");
409  argvv[2] = (char *)"xpd";
410  argvv[3] = (char *)sxpd;
411  argvv[4] = (char *)slog;
412  argvv[5] = 0;
413 
414  // Unblock SIGUSR1 and SIGUSR2
415  sigset_t myset;
416  sigemptyset(&myset);
417  sigaddset(&myset, SIGUSR1);
418  sigaddset(&myset, SIGUSR2);
419  pthread_sigmask(SIG_UNBLOCK, &myset, 0);
420 
421  Info("%d: uid: %d, euid: %d", (int)getpid(), getuid(), geteuid());
422  Info("argvv: '%s' '%s' '%s' '%s' '%s'", argvv[0], argvv[1], argvv[2], argvv[3], argvv[4]);
423 
424  // Run the program
425  execv(pspath.c_str(), argvv);
426 
427  // We should not be here!!!
428  Info("ERROR: returned from execv: bad, bad sign !!!");
429  return;
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// Login the user in its space
434 
435 int loginuser(const std::string &home, const std::string &user, uid_t uid, gid_t gid)
436 {
437  if (chdir(home.c_str()) != 0) {
438  Info("loginuser: ERROR: can't change directory to %s, euid: %d, uid: %d; errno: %d",
439  home.c_str(), geteuid(), getuid(), errno);
440  return -1;
441  }
442 
443  // set HOME env
444  size_t len = home.length() + 8;
445  char *h = new char[len];
446  snprintf(h, len, "HOME=%s", home.c_str());
447  putenv(h);
448  if (gDebug > 0) Info("loginuser: set '%s'", h);
449 
450  // set USER env
451  char *u = new char[len];
452  snprintf(u, len, "USER=%s", user.c_str());
453  putenv(u);
454  if (gDebug > 0) Info("loginuser: set '%s'", u);
455 
456  // Set access control list from /etc/initgroup
457  // (super-user privileges required)
458  if (geteuid() != uid) {
459  rpdprivguard pguard((uid_t)0, (gid_t)0);
460  if (rpdbadpguard(pguard, uid)) {
461  Info("loginuser: ERROR: could not get required privileges");
462  return -1;
463  }
464  initgroups(user.c_str(), gid);
465  }
466 
467  // acquire permanently target user privileges
468  if (gDebug > 0)
469  Info("loginuser: acquiring target user identity (%d,%d)", uid, gid);
470  if (rpdpriv::changeperm(uid, gid) != 0) {
471  Info("loginuser: ERROR: can't acquire '%s' identity", user.c_str());
472  return -1;
473  }
474 
475  // Done
476  return 0;
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 /// Make sure that 'path' exists, it is owned by the entity
481 /// described by {u,g} and its mode is 'mode'.
482 /// Return 0 in case of success, -1 in case of error
483 
484 int assertdir(const std::string &path, uid_t u, gid_t g, unsigned int mode)
485 {
486  if (path.length() <= 0) return -1;
487 
488  rpdprivguard pguard((uid_t)0, (gid_t)0);
489  if (rpdbadpguard(pguard, u)) {
490  Info("assertdir: ERROR: could not get privileges (errno: %d)", errno);
491  return -1;
492  }
493 
494  // Make the directory: ignore failure if already existing ...
495  if (mkdir(path.c_str(), mode) != 0 && (errno != EEXIST)) {
496  Info("assertdir: ERROR: unable to create path: %s (errno: %d)", path.c_str(), errno);
497  return -1;
498  }
499  // Set ownership of the path to the client
500  if (chown(path.c_str(), u, g) == -1) {
501  Info("assertdir: ERROR: unable to set ownership on path: %s (errno: %d)", path.c_str(), errno);
502  return -1;
503  }
504 
505  // We are done
506  return 0;
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// Move file form 'from' to 'to', making sure that it is owned by the entity
511 /// described by {u,g} and its mode is 'mode' (at the final destination).
512 /// Return 0 in case of success, -1 in case of error
513 
514 int mvfile(const std::string &from, const std::string &to, uid_t u, gid_t g, unsigned int mode)
515 {
516  if (from.length() <= 0 || to.length() <= 0) return -1;
517 
518  rpdprivguard pguard((uid_t)0, (gid_t)0);
519  if (rpdbadpguard(pguard, u)) {
520  Info("mvfile: ERROR: could not get privileges (errno: %d)", errno);
521  return -1;
522  }
523 
524  // Rename the file
525  if (rename(from.c_str(), to.c_str()) != 0) {
526  Info("mvfile: ERROR: unable to rename '%s' to '%s' (errno: %d)", from.c_str(), to.c_str(), errno);
527  return -1;
528  }
529 
530  // Set ownership of the path to the client
531  if (chmod(to.c_str(), mode) == -1) {
532  Info("mvfile: ERROR: unable to set mode %o on path: %s (errno: %d)", mode, to.c_str(), errno);
533  return -1;
534  }
535 
536  // Make sure the ownership is right
537  if (chown(to.c_str(), u, g) == -1) {
538  Info("mvfile: ERROR: unable to set ownership on path: %s (errno: %d)", to.c_str(), errno);
539  return -1;
540  }
541 
542  // We are done
543  return 0;
544 }
545 
546 ////////////////////////////////////////////////////////////////////////////////
547 /// Finalize the rc file with the missing pieces
548 
549 int completercfile(const std::string &rcfile, const std::string &sessdir,
550  const std::string &stag, const std::string &adminpath)
551 {
552  FILE *frc = fopen(rcfile.c_str(), "a");
553  if (!frc) {
554  Info("completercfile: ERROR: unable to open rc file: '%s' (errno: %d)", rcfile.c_str(), errno);
555  return -1;
556  }
557 
558  fprintf(frc, "# The session working dir\n");
559  fprintf(frc, "ProofServ.SessionDir: %s\n", sessdir.c_str());
560 
561  fprintf(frc, "# Session tag\n");
562  fprintf(frc, "ProofServ.SessionTag: %s\n", stag.c_str());
563 
564  fprintf(frc, "# Admin path\n");
565  fprintf(frc, "ProofServ.AdminPath: %s%d.status\n", adminpath.c_str(), (int)getpid());
566 
567  fclose(frc);
568 
569  // Done
570  return 0;
571 }
572 
573 ////////////////////////////////////////////////////////////////////////////////
574 /// Initialize the environment following the content of 'envfile'
575 
576 int setproofservenv(const std::string &envfile,
577  const std::string &logfile, const std::string &rcfile)
578 {
579  if (envfile.length() <= 0) return -1;
580 
581  int len = 0;
582  char *h = 0;
583  // The logfile path
584  len = logfile.length() + strlen("ROOTPROOFLOGFILE") + 4;
585  h = new char[len + 1];
586  snprintf(h, len + 1, "ROOTPROOFLOGFILE=%s", logfile.c_str());
587  putenv(h);
588  if (gDebug > 0)
589  Info("setproofservenv: set '%s'", h);
590  // The rcfile path
591  len = rcfile.length() + strlen("ROOTRCFILE") + 4;
592  h = new char[len + 1];
593  snprintf(h, len + 1, "ROOTRCFILE=%s", rcfile.c_str());
594  putenv(h);
595  if (gDebug > 0)
596  Info("setproofservenv: set '%s'", h);
597 
598  std::fstream fin(envfile.c_str(), std::ios::in);
599  if (!fin.good()) {
600  Info("setproofservenv: ERROR: unable to open env file: %s (errno: %d)", envfile.c_str(), errno);
601  return -1;
602  }
603 
604  std::string line;
605  while (!fin.eof()) {
606  std::getline(fin, line);
607  if (line[line.length()-1] == '\n') line.erase(line.length()-1);
608  if (line.length() > 0) {
609  h = new char[line.length() + 1];
610  snprintf(h, line.length()+1, "%s", line.c_str());
611  putenv(h);
612  if (gDebug > 0)
613  Info("setproofservenv: set '%s'", h);
614  }
615  }
616  // Close the stream
617  fin.close();
618  // Done
619  return 0;
620 }
621 
622 ////////////////////////////////////////////////////////////////////////////////
623 /// Export the descriptor of 'conn' so that it can used in the execv application.
624 /// Make sure it duplicates to a reasonable value first.
625 /// Return 0 on success, -1 on error
626 
627 int exportsock(rpdunix *conn)
628 {
629  // Check the input connection
630  if (!conn || (conn && !conn->isvalid(0))) {
631  Info("exportsock: ERROR: connection is %s", (conn ? "invalid" : "undefined"));
632  return -1;
633  }
634 
635  // Get the descriptor
636  int d = conn->exportfd();
637 
638  // Make sure it is outside the standard I/O range
639  if (d == 0 || d == 1 || d == 2) {
640  int fd = -1;
641  int natt = 1000;
642  while (natt > 0 && (fd = dup(d)) <= 2) {
643  if (fd != d) close(fd);
644  fd = -1;
645  natt--;
646  }
647  if (natt <= 0 && fd <= 2) {
648  Info("exportsock: ERROR: no free filedescriptor!");
649  close(d);
650  return -1;
651  }
652  close(d);
653  d = fd;
654  close(2);
655  close(1);
656  close(0);
657  }
658 
659  // Export the descriptor in the env ROOTOPENSOCK
660  char *rootopensock = new char[33];
661  snprintf(rootopensock, 33, "ROOTOPENSOCK=%d", d);
662  putenv(rootopensock);
663 
664  // Done
665  return 0;
666 }
667 
668 ////////////////////////////////////////////////////////////////////////////////
669 /// Redirect stdout to 'logfile'
670 /// On success return 0. Return -1 on failure.
671 
672 int redirectoutput(const std::string &logfile)
673 {
674  if (gDebug > 0)
675  Info("redirectoutput: enter: %s", logfile.c_str());
676 
677  if (logfile.length() <= 0) {
678  Info("redirectoutput: ERROR: logfile path undefined");
679  return -1;
680  }
681 
682  if (gDebug > 0)
683  Info("redirectoutput: reopen %s", logfile.c_str());
684  FILE *flog = freopen(logfile.c_str(), "a", stdout);
685  if (!flog) {
686  Info("redirectoutput: ERROR: could not freopen stdout (errno: %d)", errno);
687  return -1;
688  }
689 
690  if (gDebug > 0)
691  Info("redirectoutput: dup2 ...");
692  if ((dup2(fileno(stdout), fileno(stderr))) < 0) {
693  Info("redirectoutput: ERROR: could not redirect stderr (errno: %d)", errno);
694  return -1;
695  }
696 
697  // Close the error logger
698  if (gLogger != stderr) fclose(gLogger);
699  gLogger = 0;
700 
701  // Export the descriptor in the env ROOTPROOFDONOTREDIR
702  int len = strlen("ROOTPROOFDONOTREDIR=2");
703  char *notredir = new char[len + 1];
704  snprintf(notredir, len+1, "ROOTPROOFDONOTREDIR=2");
705  putenv(notredir);
706 
707  if (gDebug > 0)
708  Info("redirectoutput: done!");
709  // We are done
710  return 0;
711 }
712 
713 ////////////////////////////////////////////////////////////////////////////////
714 /// Set user ownerships on some critical files or directories.
715 /// Return 0 on success, -1 if enything goes wrong.
716 
717 int setownerships(int euid, const std::string &us, const std::string &gr,
718  const std::string &creds, const std::string &dsrcs,
719  const std::string &ddir, const std::string &ddiro,
720  const std::string &ord, const std::string &stag)
721 {
722  // Get identities
723  struct passwd *pwad, *pwus;
724  if (!(pwad = getpwuid(euid))) {
725  Info("setownerships: ERROR: problems getting 'struct passwd' for"
726  " uid: %d (errno: %d)", euid, (int)errno);
727  return -1;
728  }
729  if (!(pwus = getpwnam(us.c_str()))) {
730  Info("setownerships: ERROR: problems getting 'struct passwd' for"
731  " user: '%s' (errno: %d)", us.c_str(), (int)errno);
732  return -1;
733  }
734 
735  // If applicable, make sure that the private dataset dir for this user exists
736  // and has the right permissions
737  if (dsrcs.length() > 0) {
738  std::string dsrc(dsrcs);
739  std::string::size_type loc = dsrcs.find(',', 0);
740  do {
741  if (loc != std::string::npos) dsrc.erase(loc, std::string::npos);
742  if (dsrc.length() > 0) {
743  std::string d(dsrc);
744  // Analyse now
745  d += "/"; d += gr;
746  if (assertdir(d, pwad->pw_uid, pwad->pw_gid, 0777) == 0) {
747  d += "/"; d += us;
748  if (assertdir(d, pwus->pw_uid, pwus->pw_gid, 0755) != 0) {
749  Info("setownerships: ERROR: problems asserting '%s' in mode 0755"
750  " (errno: %d)", d.c_str(), (int)errno);
751  }
752  } else {
753  Info("setownerships: ERROR: problems asserting '%s' in mode 0777"
754  " (errno: %d)", d.c_str(), (int)errno);
755  }
756  }
757  dsrc.assign(dsrcs, loc + 1, dsrcs.length() - loc);
758  loc++;
759  } while ((loc = dsrcs.find(',', loc)) != std::string::npos);
760  }
761 
762  // If applicable, make sure that the private data dir for this user exists
763  // and has the right permissions
764  if (ddir.length() > 0 && ord.length() > 0 && stag.length() > 0) {
765  std::string dgr(ddir);
766  dgr += "/"; dgr += gr;
767  if (assertdir(dgr, pwad->pw_uid, pwad->pw_gid, 0777) == 0) {
768  int drc = -1;
769  unsigned int mode = 0755;
770  if (ddiro.find('g') != std::string::npos) mode = 0775;
771  if (ddiro.find('a') != std::string::npos ||
772  ddiro.find('o') != std::string::npos) mode = 0777;
773  std::string dus(dgr);
774  dus += "/"; dus += us;
775  if (assertdir(dus, pwus->pw_uid, pwus->pw_gid, mode) == 0) {
776  dus += "/"; dus += ord;
777  if (assertdir(dus, pwus->pw_uid, pwus->pw_gid, mode) == 0) {
778  dus += "/"; dus += stag;
779  if (assertdir(dus, pwus->pw_uid, pwus->pw_gid, mode) == 0) drc = 0;
780  }
781  }
782  if (drc == -1)
783  Info("setownerships: ERROR: problems asserting '%s' in mode %o"
784  " (errno: %d)", dus.c_str(), mode, (int)errno);
785  } else {
786  Info("setownerships: ERROR: problems asserting '%s' in mode 0777"
787  " (errno: %d)", dgr.c_str(), (int)errno);
788  }
789  }
790 
791  // The credential directory
792  if (creds.length() > 0) {
793  if (changeown(creds, pwus->pw_uid, pwus->pw_gid) != 0) {
794  Info("setownerships: ERROR: problems changing owenership of '%s'", creds.c_str());
795  return -1;
796  }
797  }
798 
799  // Done
800  return 0;
801 }
802 
803 ////////////////////////////////////////////////////////////////////////////////
804 /// Change the ownership of 'path' to the entity described by {u,g}.
805 /// If 'path' is a directory, go through the paths inside it recursively.
806 /// Return 0 in case of success, -1 in case of error
807 
808 int changeown(const std::string &path, uid_t u, gid_t g)
809 {
810  if (path.length() <= 0) return -1;
811 
812  // If is a directory apply this on it
813  DIR *dir = opendir(path.c_str());
814  if (dir) {
815  // Loop over the dir
816  std::string proot(path);
817  if (!(proot.rfind('/') != proot.length() - 1)) proot += "/";
818 
819  struct dirent *ent = 0;
820  while ((ent = readdir(dir))) {
821  if (ent->d_name[0] == '.' || !strcmp(ent->d_name, "..")) continue;
822  std::string fn(proot);
823  fn += ent->d_name;
824 
825  // Apply recursively
826  if (changeown(fn.c_str(), u, g) != 0) {
827  Info("changeown: ERROR: problems changing recursively ownership of '%s'",
828  fn.c_str());
829  closedir(dir);
830  return -1;
831  }
832 
833  }
834  // Close the directory
835  closedir(dir);
836  } else {
837  // If it was a directory and opening failed, we fail
838  if (errno != 0 && (errno != ENOTDIR)) {
839  Info("changeown: ERROR: problems opening '%s' (errno: %d)",
840  path.c_str(), (int)errno);
841  return -1;
842  }
843  // Else it may be a file ... get the privileges, if needed
844  rpdprivguard pguard((uid_t)0, (gid_t)0);
845  if (rpdbadpguard(pguard, u)) {
846  Info("changeown: ERROR: could not get privileges (errno: %d)", errno);
847  return -1;
848  }
849  // Set ownership of the path to the client
850  if (chown(path.c_str(), u, g) == -1) {
851  Info("changeown: ERROR: cannot set user ownership on path '%s' (errno: %d)",
852  path.c_str(), errno);
853  return -1;
854  }
855  }
856 
857  // We are done
858  return 0;
859 }
int pw_uid
Definition: TWinNTSystem.h:50
void start_rootd(int argc, char **argv)
Process a request to start a rootd server.
Definition: proofexecv.cxx:129
void Info(const char *va_(fmt),...)
Write info message to syslog.
Definition: proofexecv.cxx:74
TLine * line
TH1 * h
Definition: legend2.C:5
static FILE * gLogger
Definition: proofexecv.cxx:49
STL namespace.
void start_ps(int argc, char **argv)
Process a request to start a proofserv process.
Definition: proofexecv.cxx:194
int setownerships(int euid, const std::string &us, const std::string &gr, const std::string &creds, const std::string &dsrcs, const std::string &ddir, const std::string &ddiro, const std::string &ord, const std::string &stag)
Set user ownerships on some critical files or directories.
Definition: proofexecv.cxx:717
int redirectoutput(const std::string &logfile)
Redirect stdout to &#39;logfile&#39; On success return 0.
Definition: proofexecv.cxx:672
int setproofservenv(const std::string &envfile, const std::string &logfile, const std::string &rcfile)
Initialize the environment following the content of &#39;envfile&#39;.
Definition: proofexecv.cxx:576
static int gDebug
Definition: proofexecv.cxx:48
int loginuser(const std::string &home, const std::string &user, uid_t u, gid_t g)
Login the user in its space.
Definition: proofexecv.cxx:435
#define va_(arg)
Definition: Varargs.h:41
TString flog
Definition: pq2main.cxx:37
int exportsock(rpdunix *conn)
Export the descriptor of &#39;conn&#39; so that it can used in the execv application.
Definition: proofexecv.cxx:627
int mvfile(const std::string &from, const std::string &to, uid_t u, gid_t g, unsigned int mode)
Move file form &#39;from&#39; to &#39;to&#39;, making sure that it is owned by the entity described by {u...
Definition: proofexecv.cxx:514
int assertdir(const std::string &path, uid_t u, gid_t g, unsigned int mode)
Make sure that &#39;path&#39; exists, it is owned by the entity described by {u,g} and its mode is &#39;mode&#39;...
Definition: proofexecv.cxx:484
int changeown(const std::string &path, uid_t u, gid_t g)
Change the ownership of &#39;path&#39; to the entity described by {u,g}.
Definition: proofexecv.cxx:808
static int gType
Definition: proofexecv.cxx:47
TGraphErrors * gr
Definition: legend1.C:25
int completercfile(const std::string &rcfile, const std::string &sessdir, const std::string &stag, const std::string &adminpath)
Finalize the rc file with the missing pieces.
Definition: proofexecv.cxx:549
int pw_gid
Definition: TWinNTSystem.h:51
#define snprintf
Definition: civetweb.c:822
int main(int argc, char **argv)
Program executed via system starting proofserv instances.
Definition: proofexecv.cxx:94
#define kMAXPATHLEN
Definition: proofexecv.cxx:51