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