Logo ROOT   6.18/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
43static int gType = 0;
44static int gDebug = 0;
45static FILE *gLogger = 0;
46
47#define kMAXPATHLEN 4096
48
49int assertdir(const std::string &path, uid_t u, gid_t g, unsigned int mode);
50int changeown(const std::string &path, uid_t u, gid_t g);
51int exportsock(rpdunix *conn);
52int loginuser(const std::string &home, const std::string &user, uid_t u, gid_t g);
53int mvfile(const std::string &from, const std::string &to, uid_t u, gid_t g, unsigned int mode);
54int completercfile(const std::string &rcfile, const std::string &sessdir,
55 const std::string &stag, const std::string &adminpath);
56int 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);
60int setproofservenv(const std::string &envfile,
61 const std::string &logfile, const std::string &rcfile);
62int redirectoutput(const std::string &logfile);
63
64void start_ps(int argc, char **argv);
65
66////////////////////////////////////////////////////////////////////////////////
67/// Write info message to syslog.
68
69void 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
89int 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
124void 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
365int 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
414int 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
444int 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
479int 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
506int 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
557int 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
602int 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
647int 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
738int 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}
#define d(i)
Definition: RSha256.hxx:102
#define g(i)
Definition: RSha256.hxx:105
#define h(i)
Definition: RSha256.hxx:106
#define va_(arg)
Definition: Varargs.h:41
#define snprintf
Definition: civetweb.c:1540
TLine * line
TGraphErrors * gr
Definition: legend1.C:25
static constexpr double us
static int gType
Definition: proofexecv.cxx:43
int exportsock(rpdunix *conn)
Export the descriptor of 'conn' so that it can used in the execv application.
Definition: proofexecv.cxx:557
int main(int argc, char **argv)
Program executed via system starting proofserv instances.
Definition: proofexecv.cxx:89
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:647
static FILE * gLogger
Definition: proofexecv.cxx:45
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:479
int setproofservenv(const std::string &envfile, const std::string &logfile, const std::string &rcfile)
Initialize the environment following the content of 'envfile'.
Definition: proofexecv.cxx:506
int redirectoutput(const std::string &logfile)
Redirect stdout to 'logfile' On success return 0.
Definition: proofexecv.cxx:602
#define kMAXPATHLEN
Definition: proofexecv.cxx:47
int assertdir(const std::string &path, uid_t u, gid_t g, unsigned int mode)
Make sure that 'path' exists, it is owned by the entity described by {u,g} and its mode is 'mode'.
Definition: proofexecv.cxx:414
int mvfile(const std::string &from, const std::string &to, uid_t u, gid_t g, unsigned int mode)
Move file form 'from' to 'to', making sure that it is owned by the entity described by {u,...
Definition: proofexecv.cxx:444
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:365
void start_ps(int argc, char **argv)
Process a request to start a proofserv process.
Definition: proofexecv.cxx:124
static int gDebug
Definition: proofexecv.cxx:44
int changeown(const std::string &path, uid_t u, gid_t g)
Change the ownership of 'path' to the entity described by {u,g}.
Definition: proofexecv.cxx:738
void Info(const char *va_(fmt),...)
Write info message to syslog.
Definition: proofexecv.cxx:69
int pw_gid
Definition: TWinNTSystem.h:51
int pw_uid
Definition: TWinNTSystem.h:50