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