/* $Id: init.c,v 3.21 2008/11/17 18:59:05 ksb Exp $ * build a linked list of all the files entombed for this user. (becker) * use the table of filesystem names generated by "fslist." */ #include #include #include #include #include #include #include #include #include "machine.h" #include "libtomb.h" #include "machine.h" #include "lists.h" #include "init.h" #include "main.h" #include "fslist.h" #if USE_STRINGS #include #else #include #endif #if HAVE_NDIR #include #else #if HAVE_DIRENT #include #else #include #endif #endif #if USE_SYSEXITS_H #include #else #define EX_SOFTWARE 99 #endif #if USE_STDLIB_H #include #else #if USE_MALLOC_H #include #else extern char *malloc(); #endif #endif #if !HAVE_STRERROR extern char *sys_errlist[]; #define strerror(Me) (sys_errlist[Me]) #endif #if !defined(MODDOTS) #define MODDOTS (10) /* a dot for every 10 files */ #endif /* functions defined in and local to this file */ static time_t remove_date(); static int datecmp(); char acUid[16] = {"-1"}; int iUserUid = -1; int iUserGid = -1; int iTombUid = -1; int iTombGid = -1; LE *pLEFilesList = nilLE; extern void original(); static TombInfo *pTIHead = (TombInfo *)0; static int tInit = 0; /* setup the runtime structures */ void Init(fDots) int fDots; /* to dot or not to dot */ { static char acTombedFile[MAXPATHLEN+MAXNAMLEN+1], *pchFileStart; static char acUTombDir[MAXPATHLEN]; register TombInfo *pTI; register int iDots = 0; register DIR *pD; register LE *pLE; register struct DIRENT *pdEntry; auto struct stat statBuf; if (tInit) { return; } tInit = 1; if (-1 == (iUserUid = getuid())) { (void)fprintf(stderr, "%s: getuid: %s\n", progname, strerror(errno)); exit(1); } if (-1 == (iUserGid = getgid())) { (void)fprintf(stderr, "%s: getgid: %s\n", progname, strerror(errno)); exit(1); } if (-1 == (iTombUid = geteuid())) { (void)fprintf(stderr, "%s: geteuid: %s\n", progname, strerror(errno)); exit(1); } if (-1 == (iTombGid = getegid())) { (void)fprintf(stderr, "%s: getegid: %s\n", progname, strerror(errno)); exit(1); } (void)sprintf(acUid, "%d", iUserUid); /* get the list of filesystems */ pTIHead = FsList(iTombGid, NOT_A_DEV); /* * zip through the array of filesystem names, opening our tomb * directory in each, and adding the entombed files we find there to * the linked list. */ if (Verbose && fDots) { (void)fprintf(stdout, "(Reading tombs; please wait..."); (void)fflush(stdout); } for (pTI = pTIHead; (TombInfo *)0 != pTI; pTI = pTI->pTINext) { register int iErr; (void)strcpy(acUTombDir, pTI->pcDir); (void)strcat(acUTombDir, "/"); (void)strcat(acUTombDir, acUid); /* become charon to look at the tomb, if he can't * try the original */ charon(); pD = opendir(acUTombDir); if ((DIR *)0 == pD) { if (ENOENT == errno) { continue; } #if DEBUG (void)fprintf(stderr, "%s: effective %d.%d, real %d.%d\n", progname, geteuid(), getegid(), getuid(), getgid()); #endif /* the user may have removed no files on this filesys */ original(); pD = opendir(acUTombDir); iErr = errno; charon(); /* something is wrong, we can't read the tomb, * we're probably not setuid, or it just got rmdir'd */ if ((DIR *)0 == pD) { if (ENOENT == iErr) continue; (void)fprintf(stderr, "\n%s: Internal error: can't open tomb `%s\': %s\n", progname, acUTombDir, strerror(errno)); (void)fprintf(stderr, "%s: Seek assistance from a system admin\n", progname); (void)fprintf(stderr, "%s: Possible NFS or uid/gid mapping problem.\n", progname); (void)fprintf(stderr, "%s: effective %d.%d, real %d.%d\n", progname, geteuid(), getegid(), getuid(), getgid()); (void)fflush(stderr); exit(45); } } #if USE_CLOSE_ON_EXEC /* This prevents forked children from reading the crypt * (no call in this loop forks, so we really don't need it). */ #if EMU_DIRFD #if !defined(dirfd) #define dirfd(dirp) ((dirp)->dd_fd) #endif #endif if (-1 == fcntl(dirfd(pD), F_SETFD, 0x01)) { (void)fprintf(stderr, "%s: fcntl: %s\n", progname, strerror(errno)); exit(1); } #endif (void)strcpy(acTombedFile, acUTombDir); (void)strcat(acTombedFile, "/"); pchFileStart = acTombedFile + strlen(acTombedFile); while ((struct DIRENT *)0 != (pdEntry = readdir(pD))) { acUTombDir[0] = '\000'; /* ignore deleted files */ if (0 == pdEntry->d_ino) continue; if (0 == strcmp("..", pdEntry->d_name)) continue; if (0 == strcmp(".", pdEntry->d_name)) continue; (void) strcat(acUTombDir, pdEntry->d_name); (void) strcpy(pchFileStart, pdEntry->d_name); if (stat(acTombedFile, &statBuf) < 0) { (void)fprintf(stderr, "%s: stat: %s: %s\n", progname, acTombedFile, strerror(errno)); } if (Verbose && fDots && MODDOTS == ++iDots) { putchar('.'); (void)fflush(stdout); iDots = 0; } pLE = newLE(); pLE->next = nilLE; pLE->size = statBuf.st_size; pLE->date = remove_date(acUTombDir); pLE->pTI = pTI; pLE->mark = 0; pLE->name = malloc((unsigned)strlen(acUTombDir)+1); if (NULL == pLE->name) { exit(12); /*ENOMEM*/ } (void) strcpy(pLE->name, acUTombDir); SLInsert(& pLEFilesList, pLE, datecmp); } (void)closedir(pD); } if (Verbose && fDots) { (void)fprintf(stdout, "done)\n"); (void)fflush(stdout); } } /* show the user which tombs we see (ksb) */ void ShowTombs(fp) FILE *fp; { register TombInfo *pTI; if (! tInit) { Init(DOTS_NO); } for (pTI = pTIHead; (TombInfo *)0 != pTI; pTI = pTI->pTINext) { fprintf(fp, "%s: tomb: %s\n", progname, pTI->pcDir); } } /* show the use which crypts we see in the tombs we see (ksb) */ void ShowCrypts(fp) FILE *fp; { register TombInfo *pTI; auto char acCrypt[MAXPATHLEN+1]; auto struct stat stCrypt; if (! tInit) { Init(DOTS_NO); } for (pTI = pTIHead; (TombInfo *)0 != pTI; pTI = pTI->pTINext) { sprintf(acCrypt, "%s/%s", pTI->pcDir, acUid); if (0 != stat(acCrypt, & stCrypt)) { continue; } fprintf(fp, "%s: crypt: %s\n", progname, acCrypt); } } static int datecmp(pLElist, pLEelem) LE *pLElist, *pLEelem; { return pLEelem->date - pLElist->date; } /* for use [for instance] when joe user types "restore foo" (ksb) * to translate the "foo" into "/usera/tomb/joe/foo@23432423". * pLE = Retrieve(pLEFilesList, namecmp, pchFile); * pcBuf = ac1024; * NB: should be in lists.c */ char * real_name(pcBuf, pLE) char *pcBuf; register LE *pLE; { if (NULL == pLE) { return NULL; } (void)sprintf(pcBuf, "%s/%s/%s@%d", pLE->pTI->pcDir, acUid, pLE->name, pLE->date); return pcBuf; } /* * remove_date - takes a file name of the form @, (mjb) * replaces the '@' with \0, and returns the time_t associated * with . */ static time_t remove_date(pcFile) char *pcFile; { register char *pc; if (NULL == (pc = strrchr(pcFile, '@'))) { /* return Jan 1 1970 for mis-formed filenames */ return 0; } *pc = '\000'; return (time_t)atol(pc + 1); } /* revoke our super powers for all time (ksb) */ void drop() { #if USE_SAVED_UID if (iTombUid != iUserUid) { setuid(iUserUid); } if (iTombGid != iUserGid) { setgid(iUserGid); } #else if (iTombUid != iUserUid || 0 == iUserUid) { (void)setuid(iUserUid); } if (iTombGid != iUserGid || 0 == iUserUid || 0 == iTombUid) { (void)setgid(iUserGid); } #endif } /* change effective group to charon (becker) * real `joe.group', effective `???.charon' */ void charon() { #if USE_SAVED_UID /* if we drop from root we cannot get back... */ if (0 != iUserUid) { setuid(iTombUid); } setgid(iTombGid); #else /* if we can become charon and still get back to joe, do it */ if (0 == iTombUid || TOMB_UID == iTombUid || 0 == iUserUid) { (void)setreuid(iUserUid, TOMB_UID); } else if (iTombUid != iUserUid) { (void)setreuid(iUserUid, iTombUid); } /* if we can be group charon, do it */ if (0 == iTombUid || TOMB_GID == iTombGid || 0 == iUserUid) { (void)setregid(iUserGid, TOMB_GID); } else if (-1 == setregid(iUserGid, iTombGid)) { fprintf(stderr, "%S: setregid: %s\n", progname, strerror(errno)); exit(NOT_ENTOMBED); } #endif } /* change effective group to the user (becker) * real `???.charon', effective `joe.group' */ void user() { #if USE_SAVED_UID setgid(iUserGid); setuid(iUserUid); #else if (iTombUid != iUserUid || 0 == iUserUid) { (void)setreuid(iTombUid, iUserUid); } if (-1 == setregid(iTombGid, iUserGid)) { fprintf(stderr, "%s: setregid: %s\n", progname, strerror(errno)); exit(NOT_ENTOMBED); } #endif } /* change effective user to root for chown, if we can (ksb) * real `root.group', effective `root.charon' */ int root() { register int iRet = -1; if (0 == iTombUid || 0 == iUserUid) { iRet = setuid(0); } #if USE_SAVED_UID (void)setgid(iTombGid); #else (void)setregid(iUserGid, iTombGid); #endif return iRet; } /* change back to the original calling effective/real user/group (ksb) * real `joe.group', effective `???.charon' */ void original() { #if USE_SAVED_UID (void)setgid(iUserGid); (void)setuid(iUserUid); #else if (-1 == setreuid(iTombUid, iUserUid)) { fprintf(stderr, "%s: setreuid: %s\n", progname, strerror(errno)); exit(1); } if (-1 == setregid(iTombGid, iUserGid)) { fprintf(stderr, "%s: setregid: %s\n", progname, strerror(errno)); exit(1); } #endif }