Example #1
0
/* returns	0	on success
 *		-1	on syntax error
 *		-2	on install error
 */
static int
replace_cmd(void) {
	char n[MAX_FNAME], n2[MAX_FNAME], envstr[MAX_ENVSTR], lastch;
	FILE *tmp, *fmaxtabsize;
	int ch, eof, fd;
	int error = 0;
	entry *e;
	sig_t oint, oabrt, oquit, ohup;
	uid_t file_owner;
	time_t now = time(NULL);
	char **envp = env_init();
	size_t	maxtabsize;
	struct	stat statbuf;

	if (envp == NULL) {
		warn("Cannot allocate memory.");
		return (-2);
	}

	if (!glue_strings(TempFilename, sizeof TempFilename, SPOOL_DIR,
	    "tmp.XXXXXXXXXX", '/')) {
		TempFilename[0] = '\0';
		warnx("path too long");
		return (-2);
	}
	if ((fd = mkstemp(TempFilename)) == -1 || !(tmp = fdopen(fd, "w+"))) {
		warn("cannot create `%s'", TempFilename);
		if (fd != -1) {
			(void)close(fd);
			(void)unlink(TempFilename);
		}
		TempFilename[0] = '\0';
		return (-2);
	}

	ohup = signal(SIGHUP, SIG_IGN);
	oint = signal(SIGINT, SIG_IGN);
	oquit = signal(SIGQUIT, SIG_IGN);
	oabrt = signal(SIGABRT, SIG_IGN);

	/* Make sure that the crontab is not an unreasonable size.
	 *
	 * XXX This is subject to a race condition--the user could
	 * add stuff to the file after we've checked the size but
	 * before we slurp it in and write it out. We can't just move
	 * the test to test the temp file we later create, because by
	 * that time we've already filled up the crontab disk. Probably
	 * the right thing to do is to do a bytecount in the copy loop
	 * rather than stating the file we're about to read.
	 */
	(void)snprintf(n2, sizeof(n2), "%s/%s", CRONDIR, MAXTABSIZE_FILE);
	if ((fmaxtabsize = fopen(n2, "r")) != NULL)  {
	    if (fgets(n2, (int)sizeof(n2), fmaxtabsize) == NULL)  {
		maxtabsize = 0;
	    } else {
		maxtabsize = atoi(n2);
	    }
	    (void)fclose(fmaxtabsize);
	} else {
	    maxtabsize = MAXTABSIZE_DEFAULT;
	}

	if (fstat(fileno(NewCrontab), &statbuf))  {
	    warn("error stat'ing crontab input");
	    error = -2;
	    goto done;
	}
	if ((uintmax_t)statbuf.st_size > (uintmax_t)maxtabsize)  {
	    warnx("%ld bytes is larger than the maximum size of %ld bytes",
		(long) statbuf.st_size, (long) maxtabsize);
	    error = -2;
	    goto done;
	}

	/* write a signature at the top of the file.
	 *
	 * VERY IMPORTANT: make sure NHEADER_LINES agrees with this code.
	 */
	(void)fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
	(void)fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
	(void)fprintf(tmp, "# (Cron version %s -- %s)\n", CRON_VERSION, "$NetBSD: crontab.c,v 1.3.8.1 2012/03/07 23:41:17 riz Exp $");

	/* copy the crontab to the tmp
	 */
	(void)rewind(NewCrontab);
	Set_LineNum(1);
	lastch = EOF;
	while (EOF != (ch = get_char(NewCrontab)))
		(void)putc(lastch = ch, tmp);

	if (lastch != (char)EOF && lastch != '\n') {
		warnx("missing trailing newline in `%s'", Filename);
		error = -1;
		goto done;
	}

	if (ferror(NewCrontab)) {
		warn("error while reading `%s'", Filename);
		error = -2;
		goto done;
	}

	(void)ftruncate(fileno(tmp), ftell(tmp));
	/* XXX this should be a NOOP - is */
	(void)fflush(tmp);

	if (ferror(tmp)) {
		(void)fclose(tmp);
		warn("error while writing new crontab to `%s'", TempFilename);
		error = -2;
		goto done;
	}

	/* check the syntax of the file being installed.
	 */

	/* BUG: was reporting errors after the EOF if there were any errors
	 * in the file proper -- kludged it by stopping after first error.
	 *		vix 31mar87
	 */
	Set_LineNum(1 - NHEADER_LINES);
	CheckErrorCount = 0;  eof = FALSE;
	while (!CheckErrorCount && !eof) {
		switch (load_env(envstr, tmp)) {
		case ERR:
			/* check for data before the EOF */
			if (envstr[0] != '\0') {
				Set_LineNum(LineNumber + 1);
				check_error("premature EOF");
			}
			eof = TRUE;
			break;
		case FALSE:
			e = load_entry(tmp, check_error, pw, envp);
			if (e)
				free(e);
			break;
		case TRUE:
			break;
		}
	}

	if (CheckErrorCount != 0) {
		warnx("errors in crontab file, can't install.");
		(void)fclose(tmp);
		error = -1;
		goto done;
	}

	file_owner = (getgid() == getegid()) ? ROOT_UID : pw->pw_uid;

#ifdef HAVE_FCHOWN
	error = fchown(fileno(tmp), file_owner, (uid_t)-1);
#else
	error = chown(TempFilename, file_owner, (gid_t)-1);
#endif
	if (error < OK) {
		warn("cannot chown `%s'", TempFilename);
		(void)fclose(tmp);
		error = -2;
		goto done;
	}

	if (fclose(tmp) == EOF) {
		warn("error closing file");
		error = -2;
		goto done;
	}

	if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) {
		warnx("path too long");
		error = -2;
		goto done;
	}
	if (rename(TempFilename, n)) {
		warn("error renaming `%s' to `%s'", TempFilename, n);
		error = -2;
		goto done;
	}
	TempFilename[0] = '\0';
	log_it(RealUser, Pid, "REPLACE", User);

	poke_daemon();

done:
	(void)signal(SIGHUP, ohup);
	(void)signal(SIGINT, oint);
	(void)signal(SIGQUIT, oquit);
	(void)signal(SIGABRT, oabrt);
	if (TempFilename[0]) {
		(void) unlink(TempFilename);
		TempFilename[0] = '\0';
	}
	return (error);
}
Example #2
0
/*
 * Reads the currect terminal path and initialize cxt->tty_* variables.
 */
static void init_tty(struct login_context *cxt)
{
	const char *p;
	struct stat st;
	struct termios tt, ttt;

	cxt->tty_mode = (mode_t) getlogindefs_num("TTYPERM", TTY_MODE);

	cxt->tty_path = ttyname(0);		/* libc calls istty() here */

	/*
	 * In case login is suid it was possible to use a hardlink as stdin
	 * and exploit races for a local root exploit. (Wojciech Purczynski).
	 *
	 * More precisely, the problem is  ttyn := ttyname(0); ...; chown(ttyn);
	 * here ttyname() might return "/tmp/x", a hardlink to a pseudotty.
	 * All of this is a problem only when login is suid, which it isnt.
	 */
	if (!cxt->tty_path || !*cxt->tty_path ||
	    lstat(cxt->tty_path, &st) != 0 || !S_ISCHR(st.st_mode) ||
	    (st.st_nlink > 1 && strncmp(cxt->tty_path, "/dev/", 5)) ||
	    access(cxt->tty_path, R_OK | W_OK) != 0) {

		syslog(LOG_ERR, _("FATAL: bad tty"));
		sleepexit(EXIT_FAILURE);
	}

	if (strncmp(cxt->tty_path, "/dev/", 5) == 0)
		cxt->tty_name = cxt->tty_path + 5;
	else
		cxt->tty_name = cxt->tty_path;

	for (p = cxt->tty_name; p && *p; p++) {
		if (isdigit(*p)) {
			cxt->tty_number = p;
			break;
		}
	}

#ifdef LOGIN_CHOWN_VCS
	if (cxt->tty_number) {
		/* find names of Virtual Console devices, for later mode change */
		snprintf(cxt->vcsn, sizeof(cxt->vcsn), "/dev/vcs%s", cxt->tty_number);
		snprintf(cxt->vcsan, sizeof(cxt->vcsan), "/dev/vcsa%s", cxt->tty_number);
	}
#endif

	tcgetattr(0, &tt);
	ttt = tt;
	ttt.c_cflag &= ~HUPCL;

	if ((fchown(0, 0, 0) || fchmod(0, cxt->tty_mode)) && errno != EROFS) {

		syslog(LOG_ERR, _("FATAL: %s: change permissions failed: %m"),
				cxt->tty_path);
		sleepexit(EXIT_FAILURE);
	}

	/* Kill processes left on this tty */
	tcsetattr(0, TCSAFLUSH, &ttt);

	signal(SIGHUP, SIG_IGN);	/* so vhangup() wont kill us */
	vhangup();
	signal(SIGHUP, SIG_DFL);

	/* open stdin,stdout,stderr to the tty */
	open_tty(cxt->tty_path);

	/* restore tty modes */
	tcsetattr(0, TCSAFLUSH, &tt);
}
Example #3
0
CK_RV CreateXProcLock(void)
{
	CK_BYTE lockfile[PATH_MAX];
	struct group *grp;
	struct stat statbuf;
	mode_t mode = (S_IRUSR | S_IRGRP);

	if (spinxplfd == -1) {

		if (token_specific.t_creatlock != NULL) {
			spinxplfd = token_specific.t_creatlock();
			if (spinxplfd != -1)
				return CKR_OK;
			else
				return CKR_FUNCTION_FAILED;
		}

		/* create user lock file */
		sprintf(lockfile, "%s/%s/LCK..%s",
			LOCKDIR_PATH, SUB_DIR, SUB_DIR);

		if (stat(lockfile, &statbuf) == 0)
			spinxplfd = open(lockfile, O_RDONLY, mode);
		else {
			spinxplfd = open(lockfile, O_CREAT | O_RDONLY, mode);
			if (spinxplfd != -1) {
				/* umask may prevent correct mode,so set it. */
				if (fchmod(spinxplfd, mode) == -1) {
					OCK_SYSLOG(LOG_ERR, "fchmod(%s): %s\n",
						   lockfile, strerror(errno));
					goto err;
				}

				grp = getgrnam("pkcs11");
				if (grp != NULL) {
					if (fchown(spinxplfd, -1, grp->gr_gid)
					    == -1) {
						OCK_SYSLOG(LOG_ERR,
							   "fchown(%s): %s\n",
							   lockfile,
							   strerror(errno));
						goto err;
					}
				} else {
					OCK_SYSLOG(LOG_ERR, "getgrnam(): %s\n",
						   strerror(errno));
					goto err;
				}
			}
		}
		if (spinxplfd == -1) {
			OCK_SYSLOG(LOG_ERR, "open(%s): %s\n",
				   lockfile, strerror(errno));
			return CKR_FUNCTION_FAILED;
		}
	}

	return CKR_OK;

err:
	if (spinxplfd != -1)
		close(spinxplfd);
	return CKR_FUNCTION_FAILED;
}
Example #4
0
File: tls-gnu.c Project: fanf2/exim
static int
init_dh(host_item *host)
{
int fd;
int ret;
gnutls_datum m;
uschar filename[200];

/* Initialize the data structures for holding the parameters */

ret = gnutls_dh_params_init(&dh_params);
if (ret < 0) return tls_error(US"init dh_params", host, gnutls_strerror(ret));

/* Set up the name of the cache file */

if (!string_format(filename, sizeof(filename), "%s/gnutls-params",
      spool_directory))
  return tls_error(US"overlong filename", host, NULL);

/* Open the cache file for reading and if successful, read it and set up the
parameters. */

fd = Uopen(filename, O_RDONLY, 0);
if (fd >= 0)
  {
  struct stat statbuf;
  if (fstat(fd, &statbuf) < 0)
    {
    (void)close(fd);
    return tls_error(US"TLS cache stat failed", host, strerror(errno));
    }

  m.size = statbuf.st_size;
  m.data = malloc(m.size);
  if (m.data == NULL)
    return tls_error(US"memory allocation failed", host, strerror(errno));
  errno = 0;
  if (read(fd, m.data, m.size) != m.size)
    return tls_error(US"TLS cache read failed", host, strerror(errno));
  (void)close(fd);

  ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
  if (ret < 0)
    return tls_error(US"DH params import", host, gnutls_strerror(ret));
  DEBUG(D_tls) debug_printf("read D-H parameters from file\n");

  free(m.data);
  }

/* If the file does not exist, fall through to compute new data and cache it.
If there was any other opening error, it is serious. */

else if (errno == ENOENT)
  {
  ret = -1;
  DEBUG(D_tls)
    debug_printf("parameter cache file %s does not exist\n", filename);
  }
else
  return tls_error(string_open_failed(errno, "%s for reading", filename),
    host, NULL);

/* If ret < 0, either the cache file does not exist, or the data it contains
is not useful. One particular case of this is when upgrading from an older
release of Exim in which the data was stored in a different format. We don't
try to be clever and support both formats; we just regenerate new data in this
case. */

if (ret < 0)
  {
  uschar tempfilename[sizeof(filename) + 10];

  DEBUG(D_tls) debug_printf("generating %d bit Diffie-Hellman key...\n",
    DH_BITS);
  ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
  if (ret < 0) return tls_error(US"D-H key generation", host, gnutls_strerror(ret));

  /* Write the parameters to a file in the spool directory so that we
  can use them from other Exim processes. */

  sprintf(CS tempfilename, "%s-%d", filename, (int)getpid());
  fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
  if (fd < 0)
    return tls_error(string_open_failed(errno, "%s for writing", filename),
      host, NULL);
  (void)fchown(fd, exim_uid, exim_gid);   /* Probably not necessary */

  /* export the parameters in a format that can be generated using GNUTLS'
   * certtool or other programs.
   *
   * The commands for certtool are:
   * $ certtool --generate-dh-params --bits 1024 > params
   */

  m.size = PARAM_SIZE;
  m.data = malloc(m.size);
  if (m.data == NULL)
    return tls_error(US"memory allocation failed", host, strerror(errno));

  m.size = PARAM_SIZE;
  ret = gnutls_dh_params_export_pkcs3(dh_params, GNUTLS_X509_FMT_PEM, m.data,
    &m.size);
  if (ret < 0)
    return tls_error(US"DH params export", host, gnutls_strerror(ret));

  m.size = Ustrlen(m.data);
  errno = 0;
  if (write(fd, m.data, m.size) != m.size || write(fd, "\n", 1) != 1)
    return tls_error(US"TLS cache write failed", host, strerror(errno));

  free(m.data);
  (void)close(fd);

  if (rename(CS tempfilename, CS filename) < 0)
    return tls_error(string_sprintf("failed to rename %s as %s",
      tempfilename, filename), host, strerror(errno));

  DEBUG(D_tls) debug_printf("wrote D-H parameters to file %s\n", filename);
  }

DEBUG(D_tls) debug_printf("initialized D-H parameters\n");
return OK;
}
Example #5
0
/*
 * Function: setfile
 *
 * Purpose:
 *   Set the owner/group/permissions for the "to" file to the information
 *   in the stat structure.  If fd is zero, also call set_utimes() to set
 *   the mod/access times.  If fd is non-zero, the caller must do a utimes
 *   itself after close(fd).
 */
int
setfile(struct stat *fs, int fd)
{
	int rval = 0;
#ifdef BSD
	int islink = S_ISLNK(fs->st_mode);
#endif

	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;

	/*
	 * Changing the ownership probably won't succeed, unless we're root
	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
	 * the mode; current BSD behavior is to remove all setuid bits on
	 * chown.  If chown fails, lose setuid/setgid bits.
	 */
	if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
	    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
		if (errno != EPERM) {
			warn("chown: %s", to.p_path);
			rval = 1;
		}
		fs->st_mode &= ~(S_ISUID | S_ISGID);
	}
#ifndef BSD
    if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
#else
    if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
#endif
        warn("chmod: %s", to.p_path);
        rval = 1;
    }

#ifdef BSD
	if (!islink && !Nflag) {
		unsigned long fflags = fs->st_flags;
		/*
		 * XXX
		 * NFS doesn't support chflags; ignore errors unless
		 * there's reason to believe we're losing bits.
		 * (Note, this still won't be right if the server
		 * supports flags and we were trying to *remove* flags
		 * on a file that we copied, i.e., that we didn't create.)
		 */
		errno = 0;
		if ((fd ? fchflags(fd, fflags) :
		    chflags(to.p_path, fflags)) == -1)
			if (errno != EOPNOTSUPP || fs->st_flags != 0) {
				warn("chflags: %s", to.p_path);
				rval = 1;
			}
	}
#endif
	/* if fd is non-zero, caller must call set_utimes() after close() */
	if (fd == 0 && set_utimes(to.p_path, fs))
	    rval = 1;
	return (rval);
}

void
cp_usage(void)
{
	(void)fprintf(stderr,
	    "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
	    "       cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n");
	exit(1);
	/* NOTREACHED */
}
Example #6
0
int
setfile(struct stat *fs, int fd)
{
	static struct timeval tv[2];
	struct stat ts;
	int rval, gotstat, islink, fdval;

	rval = 0;
	fdval = fd != -1;
	islink = !fdval && S_ISLNK(fs->st_mode);
	fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX |
		       S_IRWXU | S_IRWXG | S_IRWXO;

	TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim);
	TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim);
	if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) {
		warn("%sutimes: %s", islink ? "l" : "", to.p_path);
		rval = 1;
	}
	if (fdval ? fstat(fd, &ts) :
	    (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
		gotstat = 0;
	else {
		gotstat = 1;
		ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
			      S_IRWXU | S_IRWXG | S_IRWXO;
	}
	/*
	 * Changing the ownership probably won't succeed, unless we're root
	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
	 * the mode; current BSD behavior is to remove all setuid bits on
	 * chown.  If chown fails, lose setuid/setgid bits.
	 */
	if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
		if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) :
		    (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) :
		    chown(to.p_path, fs->st_uid, fs->st_gid))) {
			if (errno != EPERM) {
				warn("chown: %s", to.p_path);
				rval = 1;
			}
			fs->st_mode &= ~(S_ISUID | S_ISGID);
		}

	if (!gotstat || fs->st_mode != ts.st_mode)
		if (fdval ? fchmod(fd, fs->st_mode) :
		    (islink ? lchmod(to.p_path, fs->st_mode) :
		    chmod(to.p_path, fs->st_mode))) {
			warn("chmod: %s", to.p_path);
			rval = 1;
		}

	if (!gotstat || fs->st_flags != ts.st_flags)
		if (fdval ?
		    fchflags(fd, fs->st_flags) :
		    (islink ? lchflags(to.p_path, fs->st_flags) :
		    chflags(to.p_path, fs->st_flags))) {
			warn("chflags: %s", to.p_path);
			rval = 1;
		}

	return (rval);
}
Example #7
0
void UnistdFchown(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = fchown(Param[0]->Val->Integer, Param[1]->Val->Integer, Param[2]->Val->Integer);
}
Example #8
0
static int start_daemon(int inetd,int port,const char *addr) {
    static const int optval=1;
    KBS_SOCKADDR_IN sin;
    KBS_IN_ADDR inaddr;
    char pid_file_name[PATHLEN],pid_string[16];
    int sockfd,fd,maxfd;
    if (chdir(BBSHOME)==-1)
        exit(3);
    umask(0007);
    mport=port;
    if (inetd) {
        if ((fd=open("/dev/null",O_RDWR,0660))==-1||dup2(fd,1)==-1||dup2(fd,2)==-1)
            exit(2);
        if (fd>2)
            close(fd);
    } else {
        if (!no_fork) {
            switch (fork()) {
                case -1:
                    exit(2);
                case 0:
                    break;
                default:
                    exit(0);
            }
            setsid();
            switch (fork()) {
                case -1:
                    exit(2);
                case 0:
                    break;
                default:
                    exit(0);
            }
        }
        KBS_SET_SIN_FAMILY(sin);
        if (!addr||!(inet_pton(KBS_SIN_FAMILY,addr,&inaddr)>0)) {
            KBS_SET_SIN_ADDR(sin,KBS_SIN_ADDR_DEFAULT);
            snprintf(pid_file_name,PATHLEN,"var/bbsd.%d.pid",port);
        } else {
            KBS_SET_SIN_ADDR(sin,inaddr);
            snprintf(pid_file_name,PATHLEN,"var/bbsd.%d_%s.pid",port,addr);
        }
        KBS_SET_SIN_PORT(sin,port);
        if ((fd=open(pid_file_name,O_RDWR|O_CREAT|O_TRUNC,0660))==-1)
            exit(2);
        if (fd!=4) {
            if (dup2(fd,4)==-1) /* file descriptor 4 statically means the opened pid file with exclusive lock ! */
                exit(2);
            close(fd);
        }
        fchown(4,BBSUID,BBSGID);
        if (write_lock(4,0,SEEK_SET,0)==-1) {
            switch (errno) {
                case EACCES:
                case EAGAIN:
                    fprintf(stderr,"BBS daemon on port <%d> had already been started!\n",port);
                    break;
                default:
                    fprintf(stderr,"Could not get exclusive lock on pid file: %s/%s\n",BBSHOME,pid_file_name);
                    break;
            }
            exit(0);
        }
#ifdef NOFILE
        maxfd=(!(NOFILE+0)?(256):(NOFILE));
#else /* ! NOFILE */
        maxfd=256;
#endif /* NOFILE */
        close(0);close(1);close(2);close(3);
        for (fd=5;fd<maxfd;fd++)
            close(fd);
#define SD_EXIT(_status) do{unlink(pid_file_name);exit(_status);}while(0)
        if ((fd=open("/dev/null",O_RDWR,0660))==-1||dup2(fd,0)==-1||dup2(fd,1)==-1||dup2(fd,2)==-1)
            SD_EXIT(2);    /* file descriptor 0 and 1 and 2 statically means the opened character file /dev/null ! */
        if (fd>4)
            close(fd);
        snprintf(pid_string,sizeof(pid_string),"%d\n",(server_pid=getpid()));
        write(4,pid_string,strlen(pid_string));
        if ((sockfd=socket(KBS_SIN_FAMILY,SOCK_STREAM,IPPROTO_TCP))==-1)
            SD_EXIT(1);
        if (sockfd!=SOCKFD) {
            if (dup2(sockfd,SOCKFD)==-1)
                SD_EXIT(2);
            close(sockfd);
        }
        if (setsockopt(SOCKFD,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(const int))==-1)
            SD_EXIT(1);
        if (bind(SOCKFD,(struct sockaddr*)&sin,sizeof(KBS_SOCKADDR_IN))==-1)
            SD_EXIT(1);
        if (listen(SOCKFD,MAX_PENDING_CONNECTIONS)==-1)
            SD_EXIT(1);
#undef SD_EXIT
    }
#ifndef CYGWIN
    if (setgid(BBSGID)==-1)
        exit(8);
    if (setuid(BBSUID)==-1)
        exit(8);
#endif
    return 0;
}
Example #9
0
/* The reason for not putting this into create_homedir
 * is better granularity when it comes to reporting error
 * messages and tracebacks in pysss
 */
int create_mail_spool(TALLOC_CTX *mem_ctx,
                      const char *username,
                      const char *maildir,
                      uid_t uid, gid_t gid)
{
    char *spool_file = NULL;
    int fd = -1;
    int ret;

    spool_file = talloc_asprintf(mem_ctx, "%s/%s", maildir, username);
    if (spool_file == NULL) {
        ret = ENOMEM;
        goto fail;
    }

    selinux_file_context(spool_file);

    fd = open(spool_file, O_CREAT | O_WRONLY | O_EXCL, 0);
    if (fd < 0) {
        ret = errno;
        DEBUG(1, ("Cannot open() the spool file: [%d][%s]\n",
                  ret, strerror(ret)));
        goto fail;
    }

    ret = fchmod(fd, 0600);
    if (ret != 0) {
        ret = errno;
        DEBUG(1, ("Cannot fchmod() the spool file: [%d][%s]\n",
                  ret, strerror(ret)));
        goto fail;
    }

    ret = fchown(fd, uid, gid);
    if (ret != 0) {
        ret = errno;
        DEBUG(1, ("Cannot fchown() the spool file: [%d][%s]\n",
                  ret, strerror(ret)));
        goto fail;
    }

    ret = fsync(fd);
    if (ret != 0) {
        ret = errno;
        DEBUG(1, ("Cannot fsync() the spool file: [%d][%s]\n",
                  ret, strerror(ret)));
    }

fail:
    if (fd >= 0) {
        ret = close(fd);
        if (ret != 0) {
            ret = errno;
            DEBUG(1, ("Cannot close() the spool file: [%d][%s]\n",
                      ret, strerror(ret)));
        }
    }

    reset_selinux_file_context();
    talloc_free(spool_file);
    return ret;
}
Example #10
0
File: log.c Project: aosm/cups
int					/* O  - 1 if log file open */
cupsdCheckLogFile(cups_file_t **lf,	/* IO - Log file */
	          const char  *logname)	/* I  - Log filename */
{
  char		backname[1024],		/* Backup log filename */
		filename[1024],		/* Formatted log filename */
		*ptr;			/* Pointer into filename */
  const char	*logptr;		/* Pointer into log filename */


 /*
  * See if we have a log file to check...
  */

  if (!lf || !logname || !logname[0])
    return (1);

 /*
  * Format the filename as needed...
  */

  if (!*lf ||
      (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
       MaxLogSize > 0))
  {
   /*
    * Handle format strings...
    */

    filename[sizeof(filename) - 1] = '\0';

    if (logname[0] != '/')
    {
      strlcpy(filename, ServerRoot, sizeof(filename));
      strlcat(filename, "/", sizeof(filename));
    }
    else
      filename[0] = '\0';

    for (logptr = logname, ptr = filename + strlen(filename);
         *logptr && ptr < (filename + sizeof(filename) - 1);
	 logptr ++)
      if (*logptr == '%')
      {
       /*
        * Format spec...
	*/

        logptr ++;
	if (*logptr == 's')
	{
	 /*
	  * Insert the server name...
	  */

	  strlcpy(ptr, ServerName, sizeof(filename) - (size_t)(ptr - filename));
	  ptr += strlen(ptr);
	}
        else
	{
	 /*
	  * Otherwise just insert the character...
	  */

	  *ptr++ = *logptr;
	}
      }
      else
	*ptr++ = *logptr;

    *ptr = '\0';
  }

 /*
  * See if the log file is open...
  */

  if (!*lf)
  {
   /*
    * Nope, open the log file...
    */

    if ((*lf = cupsFileOpen(filename, "a")) == NULL)
    {
     /*
      * If the file is in CUPS_LOGDIR then try to create a missing directory...
      */

      if (!strncmp(filename, CUPS_LOGDIR, strlen(CUPS_LOGDIR)))
      {
       /*
        * Try updating the permissions of the containing log directory, using
	* the log file permissions as a basis...
	*/

        mode_t log_dir_perm = (mode_t)(0300 | LogFilePerm);
					/* LogFilePerm + owner write/search */
	if (log_dir_perm & 0040)
	  log_dir_perm |= 0010;		/* Add group search */
	if (log_dir_perm & 0004)
	  log_dir_perm |= 0001;		/* Add other search */

        cupsdCheckPermissions(CUPS_LOGDIR, NULL, log_dir_perm, RunUser, Group, 1, -1);

        *lf = cupsFileOpen(filename, "a");
      }

      if (*lf == NULL)
      {
	syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
	       strerror(errno));

        if (FatalErrors & CUPSD_FATAL_LOG)
	  cupsdEndProcess(getpid(), 0);

	return (0);
      }
    }

    if (strncmp(filename, "/dev/", 5))
    {
     /*
      * Change ownership and permissions of non-device logs...
      */

      fchown(cupsFileNumber(*lf), RunUser, Group);
      fchmod(cupsFileNumber(*lf), LogFilePerm);
    }
  }

 /*
  * Do we need to rotate the log?
  */

  if (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
      MaxLogSize > 0)
  {
   /*
    * Rotate log file...
    */

    cupsFileClose(*lf);

    strlcpy(backname, filename, sizeof(backname));
    strlcat(backname, ".O", sizeof(backname));

    unlink(backname);
    rename(filename, backname);

    if ((*lf = cupsFileOpen(filename, "a")) == NULL)
    {
      syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
             strerror(errno));

      if (FatalErrors & CUPSD_FATAL_LOG)
	cupsdEndProcess(getpid(), 0);

      return (0);
    }

   /*
    * Change ownership and permissions of non-device logs...
    */

    fchown(cupsFileNumber(*lf), RunUser, Group);
    fchmod(cupsFileNumber(*lf), LogFilePerm);
  }

  return (1);
}
/*
 * Arguments:
 *  argv[2] - wlan interface
 *  argv[3] - SSID
 *  argv[4] - Broadcast/Hidden
 *  argv[5] - Channel
 *  argv[6] - Security
 *  argv[7] - Key
 */
int SoftapController::setSoftap(int argc, char *argv[]) {
    char psk_str[2*SHA256_DIGEST_LENGTH+1];
    int ret = ResponseCode::SoftapStatusResult;
    int fd;
    int hidden = 0;
    int channel = AP_CHANNEL_DEFAULT;
    char *wbuf = NULL;
    char *fbuf = NULL;

    if (argc < 5) {
        ALOGE("Softap set is missing arguments. Please use:");
        ALOGE("softap <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>");
        return ResponseCode::CommandSyntaxError;
    }

    if (!strcasecmp(argv[4], "hidden"))
        hidden = 1;

    if (argc >= 5) {
        channel = atoi(argv[5]);
        if (channel <= 0)
            channel = AP_CHANNEL_DEFAULT;
    }

    asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
            "/data/misc/wifi/hostapd\nssid=%s\nchannel=%d\nieee80211n=1\n"
            "hw_mode=g\nignore_broadcast_ssid=%d\nwowlan_triggers=any\n",
            argv[2], argv[3], channel, hidden);

    if (argc > 7) {
        if (!strcmp(argv[6], "wpa-psk")) {
            generatePsk(argv[3], argv[7], psk_str);
            asprintf(&fbuf, "%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
        } else if (!strcmp(argv[6], "wpa2-psk")) {
            generatePsk(argv[3], argv[7], psk_str);
            asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
        } else if (!strcmp(argv[6], "open")) {
            asprintf(&fbuf, "%s", wbuf);
        }
    } else if (argc > 6) {
        if (!strcmp(argv[6], "open")) {
            asprintf(&fbuf, "%s", wbuf);
        }
    } else {
        asprintf(&fbuf, "%s", wbuf);
    }

    fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660);
    if (fd < 0) {
        ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
        free(wbuf);
        free(fbuf);
        return ResponseCode::OperationFailed;
    }
    if (write(fd, fbuf, strlen(fbuf)) < 0) {
        ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
        ret = ResponseCode::OperationFailed;
    }
    free(wbuf);
    free(fbuf);

    /* Note: apparently open can fail to set permissions correctly at times */
    if (fchmod(fd, 0660) < 0) {
        ALOGE("Error changing permissions of %s to 0660: %s",
                HOSTAPD_CONF_FILE, strerror(errno));
        close(fd);
        unlink(HOSTAPD_CONF_FILE);
        return ResponseCode::OperationFailed;
    }

    if (fchown(fd, AID_SYSTEM, AID_WIFI) < 0) {
        ALOGE("Error changing group ownership of %s to %d: %s",
                HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno));
        close(fd);
        unlink(HOSTAPD_CONF_FILE);
        return ResponseCode::OperationFailed;
    }

    close(fd);
    return ret;
}
Example #12
0
/* Do the actual work of creating a home dir */
static int
create_homedir(const struct passwd *pwd,
	       const char *source, const char *dest)
{
   char remark[BUFSIZ];
   DIR *d;
   struct dirent *dent;
   int retval = PAM_SESSION_ERR;

   /* Create the new directory */
   if (rec_mkdir(dest, 0755) != 0)
   {
      pam_syslog(NULL, LOG_ERR, "unable to create directory %s: %m", dest);
      return PAM_PERM_DENIED;
   }

   /* See if we need to copy the skel dir over. */
   if ((source == NULL) || (strlen(source) == 0))
   {
      retval = PAM_SUCCESS;
      goto go_out;
   }

   /* Scan the directory */
   d = opendir(source);
   if (d == NULL)
   {
      pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m", source);
      retval = PAM_PERM_DENIED;
      goto go_out;
   }

   for (dent = readdir(d); dent != NULL; dent = readdir(d))
   {
      int srcfd;
      int destfd;
      int res;
      struct stat st;
#ifndef PATH_MAX
      char *newsource = NULL, *newdest = NULL;
      /* track length of buffers */
      int nslen = 0, ndlen = 0;
      int slen = strlen(source), dlen = strlen(dest);
#else
      char newsource[PATH_MAX], newdest[PATH_MAX];
#endif

      /* Skip some files.. */
      if (strcmp(dent->d_name,".") == 0 ||
	  strcmp(dent->d_name,"..") == 0)
	 continue;

      /* Determine what kind of file it is. */
#ifndef PATH_MAX
      nslen = slen + strlen(dent->d_name) + 2;

      if (nslen <= 0)
	{
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      if ((newsource = malloc(nslen)) == NULL)
	{
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      sprintf(newsource, "%s/%s", source, dent->d_name);
#else
      snprintf(newsource, sizeof(newsource), "%s/%s", source, dent->d_name);
#endif

      if (lstat(newsource, &st) != 0)
#ifndef PATH_MAX
      {
	      free(newsource);
	      newsource = NULL;
         continue;
      }
#else
      continue;
#endif


      /* We'll need the new file's name. */
#ifndef PATH_MAX
      ndlen = dlen + strlen(dent->d_name)+2;

      if (ndlen <= 0)
	{
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      if ((newdest = malloc(ndlen)) == NULL)
	{
	  free (newsource);
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      sprintf (newdest, "%s/%s", dest, dent->d_name);
#else
      snprintf (newdest, sizeof (newdest), "%s/%s", dest, dent->d_name);
#endif

      /* If it's a directory, recurse. */
      if (S_ISDIR(st.st_mode))
      {
         retval = create_homedir(pwd, newsource, newdest);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

         if (retval != PAM_SUCCESS)
	   {
	     closedir(d);
	     goto go_out;
	   }
         continue;
      }

      /* If it's a symlink, create a new link. */
      if (S_ISLNK(st.st_mode))
      {
	 int pointedlen = 0;
#ifndef PATH_MAX
	 char *pointed = NULL;
           {
		   int size = 100;

		   while (1) {
			   pointed = malloc(size);
			   if (pointed == NULL) {
				   free(newsource);
				   free(newdest);
				   return PAM_BUF_ERR;
			   }
			   pointedlen = readlink(newsource, pointed, size);
			   if (pointedlen < 0) break;
			   if (pointedlen < size) break;
			   free(pointed);
			   size *= 2;
		   }
	   }
	   if (pointedlen < 0)
		   free(pointed);
	   else
		   pointed[pointedlen] = 0;
#else
         char pointed[PATH_MAX];
         memset(pointed, 0, sizeof(pointed));

         pointedlen = readlink(newsource, pointed, sizeof(pointed) - 1);
#endif

	 if (pointedlen >= 0) {
            if(symlink(pointed, newdest) == 0)
            {
               if (lchown(newdest, pwd->pw_uid, pwd->pw_gid) != 0)
               {
                   pam_syslog(NULL, LOG_DEBUG,
			      "unable to change perms on link %s: %m", newdest);
                   closedir(d);
#ifndef PATH_MAX
		   free(pointed);
		   free(newsource);
		   free(newdest);
#endif
                   return PAM_PERM_DENIED;
               }
            }
#ifndef PATH_MAX
	    free(pointed);
#endif
         }
#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif
         continue;
      }

      /* If it's not a regular file, it's probably not a good idea to create
       * the new device node, FIFO, or whatever it is. */
      if (!S_ISREG(st.st_mode))
      {
#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif
         continue;
      }

      /* Open the source file */
      if ((srcfd = open(newsource, O_RDONLY)) < 0 || fstat(srcfd, &st) != 0)
      {
         pam_syslog(NULL, LOG_DEBUG,
		    "unable to open src file %s: %m", newsource);
         closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

	 return PAM_PERM_DENIED;
      }
      if (stat(newsource, &st) != 0)
	{
	  pam_syslog(NULL, LOG_DEBUG, "unable to stat src file %s: %m",
		     newsource);
	  close(srcfd);
	  closedir(d);

#ifndef PATH_MAX
	  free(newsource); newsource = NULL;
	  free(newdest); newdest = NULL;
#endif

	  return PAM_PERM_DENIED;
	}

      /* Open the dest file */
      if ((destfd = open(newdest, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0)
      {
         pam_syslog(NULL, LOG_DEBUG,
		    "unable to open dest file %s: %m", newdest);
	 close(srcfd);
	 closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif
	 return PAM_PERM_DENIED;
      }

      /* Set the proper ownership and permissions for the module. We make
       	 the file a+w and then mask it with the set mask. This preseves
       	 execute bits */
      if (fchmod(destfd, (st.st_mode | 0222) & (~u_mask)) != 0 ||
	  fchown(destfd, pwd->pw_uid, pwd->pw_gid) != 0)
      {
         pam_syslog(NULL, LOG_DEBUG,
		    "unable to change perms on copy %s: %m", newdest);
         close(srcfd);
         close(destfd);
         closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

	 return PAM_PERM_DENIED;
      }

      /* Copy the file */
      do
      {
	 res = pam_modutil_read(srcfd, remark, sizeof(remark));

	 if (res == 0)
	     continue;

	 if (res > 0) {
	     if (pam_modutil_write(destfd, remark, res) == res)
		continue;
	 }

	 /* If we get here, pam_modutil_read returned a -1 or
	    pam_modutil_write returned something unexpected. */
	 pam_syslog(NULL, LOG_DEBUG, "unable to perform IO: %m");
	 close(srcfd);
	 close(destfd);
	 closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

	 return PAM_PERM_DENIED;
      }
      while (res != 0);
      close(srcfd);
      close(destfd);

#ifndef PATH_MAX
      free(newsource); newsource = NULL;
      free(newdest); newdest = NULL;
#endif

   }
   closedir(d);

   retval = PAM_SUCCESS;

 go_out:

   if (chmod(dest, 0777 & (~u_mask)) != 0 ||
       chown(dest, pwd->pw_uid, pwd->pw_gid) != 0)
   {
      pam_syslog(NULL, LOG_DEBUG,
		 "unable to change perms on directory %s: %m", dest);
      return PAM_PERM_DENIED;
   }

   return retval;
}
Example #13
0
static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_img *img)
{
	int gfd, ghost_flags, ret;
	char path[PATH_MAX];

	ret = rst_get_mnt_root(gf->remap.rmnt_id, path, sizeof(path));
	if (ret < 0) {
		pr_err("The %d mount is not found for ghost\n", gf->remap.rmnt_id);
		goto err;
	}

	snprintf(path + ret, sizeof(path) - ret, "/%s", gf->remap.rpath);
	ret = -1;

	if (S_ISFIFO(gfe->mode)) {
		if (mknod(path, gfe->mode, 0)) {
			pr_perror("Can't create node for ghost file");
			goto err;
		}
		ghost_flags = O_RDWR; /* To not block */
	} else if (S_ISCHR(gfe->mode) || S_ISBLK(gfe->mode)) {
		if (!gfe->has_rdev) {
			pr_err("No rdev for ghost device\n");
			goto err;
		}

		if (mknod(path, gfe->mode, gfe->rdev)) {
			pr_perror("Can't create node for ghost dev");
			goto err;
		}
		ghost_flags = O_WRONLY;
	} else if (S_ISDIR(gfe->mode)) {
		if (mkdir(path, gfe->mode)) {
			pr_perror("Can't make ghost dir");
			goto err;
		}
		ghost_flags = O_DIRECTORY;
	} else
		ghost_flags = O_WRONLY | O_CREAT | O_EXCL;

	gfd = open(path, ghost_flags, gfe->mode);
	if (gfd < 0) {
		pr_perror("Can't open ghost file %s", path);
		goto err;
	}

	if (fchown(gfd, gfe->uid, gfe->gid) < 0) {
		pr_perror("Can't reset user/group on ghost %s", path);
		goto err_c;
	}

	if (S_ISREG(gfe->mode)) {
		if (copy_file(img_raw_fd(img), gfd, 0) < 0)
			goto err_c;
	}

	ret = 0;
err_c:
	close(gfd);
err:
	return ret;
}
Example #14
0
/*
 * display --
 *	print out the file for the user to edit; strange side-effect:
 *	set conditional flag if the user gets to edit the shell.
 */
static int
display(const char *tfn, struct passwd *pw)
{
	FILE *fp;
	char *bp, *gecos, *p;

	if ((fp = fopen(tfn, "w")) == NULL) {
		warn("%s", tfn);
		return (-1);
	}

	(void)fprintf(fp,
	    "#Changing user information for %s.\n", pw->pw_name);
	if (master_mode) {
		(void)fprintf(fp, "Login: %s\n", pw->pw_name);
		(void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
		(void)fprintf(fp, "Uid [#]: %lu\n", (unsigned long)pw->pw_uid);
		(void)fprintf(fp, "Gid [# or name]: %lu\n",
		    (unsigned long)pw->pw_gid);
		(void)fprintf(fp, "Change [month day year]: %s\n",
		    ttoa(pw->pw_change));
		(void)fprintf(fp, "Expire [month day year]: %s\n",
		    ttoa(pw->pw_expire));
		(void)fprintf(fp, "Class: %s\n", pw->pw_class);
		(void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
		(void)fprintf(fp, "Shell: %s\n",
		    *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
	}
	/* Only admin can change "restricted" shells. */
#if 0
	else if (ok_shell(pw->pw_shell))
		/*
		 * Make shell a restricted field.  Ugly with a
		 * necklace, but there's not much else to do.
		 */
#else
	else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) ||
	    master_mode)
		/*
		 * If change not restrict (table.c) and standard shell
		 *	OR if root, then allow editing of shell.
		 */
#endif
		(void)fprintf(fp, "Shell: %s\n",
		    *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
	else
		list[E_SHELL].restricted = 1;

	if ((bp = gecos = strdup(pw->pw_gecos)) == NULL) {
		warn(NULL);
		fclose(fp);
		return (-1);
	}

	p = strsep(&bp, ",");
	p = strdup(p ? p : "");
	list[E_NAME].save = p;
	if (!list[E_NAME].restricted || master_mode)
	  (void)fprintf(fp, "Full Name: %s\n", p);

	p = strsep(&bp, ",");
	p = strdup(p ? p : "");
	list[E_LOCATE].save = p;
	if (!list[E_LOCATE].restricted || master_mode)
	  (void)fprintf(fp, "Office Location: %s\n", p);

	p = strsep(&bp, ",");
	p = strdup(p ? p : "");
	list[E_BPHONE].save = p;
	if (!list[E_BPHONE].restricted || master_mode)
	  (void)fprintf(fp, "Office Phone: %s\n", p);

	p = strsep(&bp, ",");
	p = strdup(p ? p : "");
	list[E_HPHONE].save = p;
	if (!list[E_HPHONE].restricted || master_mode)
	  (void)fprintf(fp, "Home Phone: %s\n", p);

	bp = strdup(bp ? bp : "");
	list[E_OTHER].save = bp;
	if (!list[E_OTHER].restricted || master_mode)
	  (void)fprintf(fp, "Other information: %s\n", bp);

	free(gecos);

	(void)fchown(fileno(fp), getuid(), getgid());
	(void)fclose(fp);
	return (0);
}
Example #15
0
/**
 * nsm_drop_privileges - drop root privileges
 * @pidfd: file descriptor of a pid file
 *
 * Returns true if successful, or false if some error occurred.
 *
 * Set our effective UID and GID to that of our on-disk database.
 */
_Bool
nsm_drop_privileges(const int pidfd)
{
	struct stat st;

	(void)umask(S_IRWXO);

	/*
	 * XXX: If we can't stat dirname, or if dirname is owned by
	 *      root, we should use "statduser" instead, which is set up
	 *      by configure.ac.  Nothing in nfs-utils seems to use
	 *      "statduser," though.
	 */
	if (lstat(nsm_base_dirname, &st) == -1) {
		xlog(L_ERROR, "Failed to stat %s: %m", nsm_base_dirname);
		return false;
	}

	if (st.st_uid == 0) {
		xlog_warn("Running as root.  "
			"chown %s to choose different user", nsm_base_dirname);
		return true;
	}

	if (chdir(nsm_base_dirname) == -1) {
		xlog(L_ERROR, "Failed to change working directory to %s: %m",
				nsm_base_dirname);
		return false;
	}

	/*
	 * If the pidfile happens to reside on NFS, dropping privileges
	 * will probably cause us to lose access, even though we are
	 * holding it open.  Chown it to prevent this.
	 */
	if (pidfd >= 0)
		if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
			xlog_warn("Failed to change owner of pidfile: %m");

	/*
	 * Don't clear capabilities when dropping root.
	 */
        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
                xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
		return 0;
	}

	if (setgroups(0, NULL) == -1) {
		xlog(L_ERROR, "Failed to drop supplementary groups: %m");
		return false;
	}

	/*
	 * ORDER
	 *
	 * setgid(2) first, as setuid(2) may remove privileges needed
	 * to set the group id.
	 */
	if (setgid(st.st_gid) == -1 || setuid(st.st_uid) == -1) {
		xlog(L_ERROR, "Failed to drop privileges: %m");
		return false;
	}

	xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);

	return nsm_clear_capabilities();
}
Example #16
0
int
main(int argc, char **argv)
{
    int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
    mode_t mode = 0755;
    char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ];
    uid_t uid;
    gid_t gid;
    struct stat sb, tosb;
    struct utimbuf utb;

    program = argv[0];
    cwd = linkname = linkprefix = owner = group = 0;
    onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0;

    while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
	switch (opt) {
	  case 'C':
	    cwd = optarg;
	    break;
	  case 'D':
	    onlydir = 1;
	    break;
	  case 'd':
	    dodir = 1;
	    break;
	  case 'l':
	    dolink = 1;
	    break;
	  case 'L':
	    linkprefix = optarg;
	    lplen = strlen(linkprefix);
	    dolink = 1;
	    break;
	  case 'R':
	    dolink = dorelsymlink = 1;
	    break;
	  case 'm':
	    mode = strtoul(optarg, &cp, 8);
	    if (mode == 0 && cp == optarg)
		usage();
	    break;
	  case 'o':
	    owner = optarg;
	    break;
	  case 'g':
	    group = optarg;
	    break;
	  case 't':
	    dotimes = 1;
	    break;
	  default:
	    usage();
	}
    }

    argc -= optind;
    argv += optind;
    if (argc < 2 - onlydir)
	usage();

    todir = argv[argc-1];
    if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
	mkdirs(todir, 0777) < 0) {
	fail("cannot make directory %s", todir);
    }
    if (onlydir)
	return 0;

    if (!cwd) {
#ifdef GETCWD_CAN_MALLOC
	cwd = getcwd(0, PATH_MAX);
#else
	cwd = malloc(PATH_MAX + 1);
	cwd = getcwd(cwd, PATH_MAX);
#endif
    }
    xchdir(todir);
#ifdef GETCWD_CAN_MALLOC
    todir = getcwd(0, PATH_MAX);
#else
    todir = malloc(PATH_MAX + 1);
    todir = getcwd(todir, PATH_MAX);
#endif
    tdlen = strlen(todir);
    xchdir(cwd);
    tdlen = strlen(todir);

    uid = owner ? touid(owner) : -1;
    gid = group ? togid(group) : -1;

    while (--argc > 0) {
	name = *argv++;
	len = strlen(name);
	base = xbasename(name);
	bnlen = strlen(base);
	toname = (char*)xmalloc(tdlen + 1 + bnlen + 1);
	sprintf(toname, "%s/%s", todir, base);
	exists = (lstat(toname, &tosb) == 0);

	if (dodir) {
	    /* -d means create a directory, always */
	    if (exists && !S_ISDIR(tosb.st_mode)) {
		(void) unlink(toname);
		exists = 0;
	    }
	    if (!exists && mkdir(toname, mode) < 0)
		fail("cannot make directory %s", toname);
	    if ((owner || group) && chown(toname, uid, gid) < 0)
		fail("cannot change owner of %s", toname);
	} else if (dolink) {
	    if (*name == '/') {
		/* source is absolute pathname, link to it directly */
		linkname = 0;
	    } else {
		if (linkprefix) {
		    /* -L implies -l and prefixes names with a $cwd arg. */
		    len += lplen + 1;
		    linkname = (char*)xmalloc(len + 1);
		    sprintf(linkname, "%s/%s", linkprefix, name);
		} else if (dorelsymlink) {
		    /* Symlink the relative path from todir to source name. */
		    linkname = (char*)xmalloc(PATH_MAX);

		    if (*todir == '/') {
			/* todir is absolute: skip over common prefix. */
			lplen = relatepaths(todir, cwd, linkname);
			strcpy(linkname + lplen, name);
		    } else {
			/* todir is named by a relative path: reverse it. */
			reversepath(todir, name, len, linkname);
			xchdir(cwd);
		    }

		    len = strlen(linkname);
		}
		name = linkname;
	    }

	    /* Check for a pre-existing symlink with identical content. */
	    if (exists &&
		(!S_ISLNK(tosb.st_mode) ||
		 readlink(toname, buf, sizeof buf) != len ||
		 strncmp(buf, name, len) != 0)) {
		(void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
		exists = 0;
	    }
	    if (!exists && symlink(name, toname) < 0)
		fail("cannot make symbolic link %s", toname);
#ifdef HAVE_LCHOWN
	    if ((owner || group) && lchown(toname, uid, gid) < 0)
		fail("cannot change owner of %s", toname);
#endif

	    if (linkname) {
		free(linkname);
		linkname = 0;
	    }
	} else {
	    /* Copy from name to toname, which might be the same file. */
	    fromfd = open(name, O_RDONLY);
	    if (fromfd < 0 || fstat(fromfd, &sb) < 0)
		fail("cannot access %s", name);
	    if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0))
		(void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
	    tofd = open(toname, O_CREAT | O_WRONLY, 0666);
	    if (tofd < 0)
		fail("cannot create %s", toname);

	    bp = buf;
	    while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
		while ((wc = write(tofd, bp, cc)) > 0) {
		    if ((cc -= wc) == 0)
			break;
		    bp += wc;
		}
		if (wc < 0)
		    fail("cannot write to %s", toname);
	    }
	    if (cc < 0)
		fail("cannot read from %s", name);

	    if (ftruncate(tofd, sb.st_size) < 0)
		fail("cannot truncate %s", toname);
	    if (dotimes) {
		utb.actime = sb.st_atime;
		utb.modtime = sb.st_mtime;
		if (utime(toname, &utb) < 0)
		    fail("cannot set times of %s", toname);
	    }
#ifdef HAVE_FCHMOD
	    if (fchmod(tofd, mode) < 0)
#else
	    if (chmod(toname, mode) < 0)
#endif
		fail("cannot change mode of %s", toname);
	    if ((owner || group) && fchown(tofd, uid, gid) < 0)
		fail("cannot change owner of %s", toname);

	    /* Must check for delayed (NFS) write errors on close. */
	    if (close(tofd) < 0)
		fail("cannot write to %s", toname);
	    close(fromfd);
	}

	free(toname);
    }

    free(cwd);
    free(todir);
    return 0;
}
Example #17
0
int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
{
	struct timeval times[2];
	struct timespec atime_ts, mtime_ts;
	int err, ma;

	if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
		if (fd >= 0) {
			if (fchmod(fd, attrs->ia_mode) != 0)
				return (-errno);
		} else if (chmod(file, attrs->ia_mode) != 0) {
			return -errno;
		}
	}
	if (attrs->ia_valid & HOSTFS_ATTR_UID) {
		if (fd >= 0) {
			if (fchown(fd, attrs->ia_uid, -1))
				return -errno;
		} else if (chown(file, attrs->ia_uid, -1)) {
			return -errno;
		}
	}
	if (attrs->ia_valid & HOSTFS_ATTR_GID) {
		if (fd >= 0) {
			if (fchown(fd, -1, attrs->ia_gid))
				return -errno;
		} else if (chown(file, -1, attrs->ia_gid)) {
			return -errno;
		}
	}
	if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
		if (fd >= 0) {
			if (ftruncate(fd, attrs->ia_size))
				return -errno;
		} else if (truncate(file, attrs->ia_size)) {
			return -errno;
		}
	}

	/*
	 * Update accessed and/or modified time, in two parts: first set
	 * times according to the changes to perform, and then call futimes()
	 * or utimes() to apply them.
	 */
	ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
	if (attrs->ia_valid & ma) {
		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
				&atime_ts, &mtime_ts, NULL, NULL, NULL, fd);
		if (err != 0)
			return err;

		times[0].tv_sec = atime_ts.tv_sec;
		times[0].tv_usec = atime_ts.tv_nsec / 1000;
		times[1].tv_sec = mtime_ts.tv_sec;
		times[1].tv_usec = mtime_ts.tv_nsec / 1000;

		if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
			times[0].tv_sec = attrs->ia_atime.tv_sec;
			times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000;
		}
		if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
			times[1].tv_sec = attrs->ia_mtime.tv_sec;
			times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000;
		}

		if (fd >= 0) {
			if (futimes(fd, times) != 0)
				return -errno;
		} else if (utimes(file, times) != 0) {
			return -errno;
		}
	}

	/* Note: ctime is not handled */
	if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) {
		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
				&attrs->ia_atime, &attrs->ia_mtime, NULL,
				NULL, NULL, fd);
		if (err != 0)
			return err;
	}
	return 0;
}
Example #18
0
File: logging.c Project: aosm/bind
FILE *
log_open_stream(log_channel chan) {
	FILE *stream;
	int fd, flags;
	struct stat sb;
	int regular;

	if (chan == NULL || chan->type != log_file) {
		errno = EINVAL;
		return (NULL);
	}
	
	/*
	 * Don't open already open streams
	 */
	if (chan->out.file.stream != NULL)
		return (chan->out.file.stream);

	if (stat(chan->out.file.name, &sb) < 0) {
		if (errno != ENOENT) {
			syslog(LOG_ERR,
			       "log_open_stream: stat of %s failed: %s",
			       chan->out.file.name, strerror(errno));
			chan->flags |= LOG_CHANNEL_BROKEN;
			return (NULL);
		}
		regular = 1;
	} else
		regular = (sb.st_mode & S_IFREG);

	if (chan->out.file.versions) {
		if (!regular) {
			syslog(LOG_ERR,
       "log_open_stream: want versions but %s isn't a regular file",
			       chan->out.file.name);
			chan->flags |= LOG_CHANNEL_BROKEN;
			errno = EINVAL;
			return (NULL);
		}
	}

	flags = O_WRONLY|O_CREAT|O_APPEND;

	if ((chan->flags & LOG_TRUNCATE) != 0) {
		if (regular) {
			(void)unlink(chan->out.file.name);
			flags |= O_EXCL;
		} else {
			syslog(LOG_ERR,
       "log_open_stream: want truncation but %s isn't a regular file",
			       chan->out.file.name);
			chan->flags |= LOG_CHANNEL_BROKEN;
			errno = EINVAL;
			return (NULL);
		}
	}

	fd = open(chan->out.file.name, flags,
		  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	if (fd < 0) {
		syslog(LOG_ERR, "log_open_stream: open(%s) failed: %s",
		       chan->out.file.name, strerror(errno));
		chan->flags |= LOG_CHANNEL_BROKEN;
		return (NULL);
	}
	stream = fdopen(fd, "a");
	if (stream == NULL) {
		syslog(LOG_ERR, "log_open_stream: fdopen() failed");
		chan->flags |= LOG_CHANNEL_BROKEN;
		return (NULL);
	}
	(void) fchown(fd, chan->out.file.owner, chan->out.file.group);

	chan->out.file.stream = stream;
	return (stream);
}
Example #19
0
/** Only copy regular file
 * --> Any character special file, block special file, FIFO or SOCKET is ignored.
 */
int copy_file(const char *fpath, const struct stat *sb)
{
	INFO(printf("copy_file(%s, %s/%s)\n", fpath, current_timestamp, fpath));
	if (! S_ISREG(sb->st_mode)) {
		WARN(printf("%s is ignored as it's not a regular file\n", fpath));
		// 0 == continue
		return 0;
	}

	sprintf(dst_fpath, "%s/%s", current_timestamp, fpath);

	// Check if previous file is same than src
	if (previous_timestamp[0]) {
		char dst_fpath_previous[PATH_MAX];
		sprintf(dst_fpath_previous, "%s/%s", previous_timestamp, fpath);

		struct stat sb_previous;
		stat(dst_fpath_previous, &sb_previous);

		int same_uid = (sb_previous.st_uid == sb->st_uid);
		int same_gid = (sb_previous.st_gid == sb->st_gid);
		int same_size = (sb_previous.st_size == sb->st_size);
		int same_mode = (sb_previous.st_mode == sb->st_mode);
		int same_mtime = (sb_previous.st_mtime == sb->st_mtime);

		INFO(printf("same_uid:%d,same_gid:%d,same_size:%d,same_mode:%d,same_mtime:%d\n", same_uid, same_gid, same_size, same_mode, same_mtime));
		if (same_uid && same_gid && same_size && same_mode && same_mtime) {
			// The files are the same, hardlink instead of copy
			INFO(printf("link(%s, %s)\n", dst_fpath_previous, current_timestamp));
			link(dst_fpath_previous, dst_fpath);
			return 0;
		}
	}

	int src = open(fpath, O_RDONLY, 0);
	int dst = open(dst_fpath, O_WRONLY | O_CREAT, 0644);

	if (dst < 0) return 1;

#if 0
	// Add some hints for the OS
	off_t START_FILE = 0;
	off_t ALL_FILE = 0;
	posix_fadvise(src, START_FILE, ALL_FILE, POSIX_FADV_SEQUENTIAL | POSIX_FADV_WILLNEED | POSIX_FADV_NOREUSE);
#endif

	size_t size;
	while ((size = read(src, buffer, BUFFER_SIZE)) > 0) {
		// assume one can write the whole buffer at once
		write(dst, buffer, size);

#if 0
		// We don't need to keep the buffers on dst
		posix_fadvise(dst, START_FILE, ALL_FILE, POSIX_FADV_DONTNEED);
#endif
	}

	// Copy the metadata
	{
		// same uid/gid
		fchown(dst, sb->st_uid, sb->st_gid);
		// same file perms
		fchmod(dst, sb->st_mode);
	}

	close(src);
	close(dst);

	// same time
	struct utimbuf tb;
	tb.actime = sb->st_atime;
	tb.modtime = sb->st_mtime;
	utime(dst_fpath, &tb);

	return 0;
}
Example #20
0
static int
writepidfile(const char *fname, int pid, uid_t uid)
{
	FILE *pidfile;
	struct stat st;
	char path[PATH_MAX], *dir;
	int ret = 0;

	if(!fname || *fname == '\0')
		return -1;

	/* Create parent directory if it doesn't already exist */
	strncpyt(path, fname, sizeof(path));
	dir = dirname(path);
	if (stat(dir, &st) == 0)
	{
		if (!S_ISDIR(st.st_mode))
		{
			DPRINTF(E_ERROR, L_GENERAL, "Pidfile path is not a directory: %s\n",
			        fname);
			return -1;
		}
	}
	else
	{
		if (make_dir(dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0)
		{
			DPRINTF(E_ERROR, L_GENERAL, "Unable to create pidfile directory: %s\n",
			        fname);
			return -1;
		}
		if (uid >= 0)
		{
			if (chown(dir, uid, -1) != 0)
				DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile ownership: %s\n",
				        dir, strerror(errno));
		}
	}
	
	pidfile = fopen(fname, "w");
	if (!pidfile)
	{
		DPRINTF(E_ERROR, L_GENERAL, "Unable to open pidfile for writing %s: %s\n",
		        fname, strerror(errno));
		return -1;
	}

	if (fprintf(pidfile, "%d\n", pid) <= 0)
	{
		DPRINTF(E_ERROR, L_GENERAL, 
			"Unable to write to pidfile %s: %s\n", fname);
		ret = -1;
	}
	if (uid >= 0)
	{
		if (fchown(fileno(pidfile), uid, -1) != 0)
			DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile ownership: %s\n",
			        pidfile, strerror(errno));
	}

	fclose(pidfile);

	return ret;
}
Example #21
0
static void
fscreate(Chan *c, char *name, int mode, ulong perm)
{
	char *path, *path0;
	int fd, mm;
	UnixFd *ufd;
	struct stat st;

	ufd = c->aux;
	if(Trace)
		print("fscreate %s %#x %#o\n", ufd->path->s, mode, perm);

	if(!(c->qid.type & QTDIR))
		error(Enotdir);

	if(mode & ~(OTRUNC|ORCLOSE|3))
		error(Ebadarg);

	if(perm & ~(DMDIR|0777))
		error(Ebadarg);

	path0 = fspath(c, nil);
	path = fspath(c, name);
	if(waserror()){
		free(path);
		free(path0);
		nexterror();
	}
	
	if(stat(path0, &st) < 0)
		oserror();

	if(perm & DMDIR){
		if(mode != OREAD)
			error(Eperm);
		/* have to do the minimum 0400 so we can open it */
		if(mkdir(path, 0400 | perm & 0777) < 0)
			oserror();
		if((fd = open(path, 0)) < 0)
			oserror();
		fchown(fd, -1, st.st_gid);
		if(fstat(fd, &st) < 0){
			close(fd);
			oserror();
		}
		close(fd);
		if((ufd->dir = opendir(path)) == nil)
			oserror();
		// Be like Plan 9 file servers: inherit mode bits 
		// and group from parent.
		fchmod(ufd->dir, perm & st.st_mode & 0777);
		ufd->diroffset = 0;
		ufd->nextde = nil;
	}else{
		mm = mode & 3;
		if(mode & OTRUNC)
			mm |= O_TRUNC;
		if((fd = open(path, mm|O_CREAT, 0666)) < 0)
			oserror();
		// Be like Plan 9 file servers: inherit mode bits 
		// and group from parent.
		fchmod(fd, perm & st.st_mode & 0777);
		fchown(fd, -1, st.st_gid);
		if(fstat(fd, &st) < 0){
			close(fd);
			oserror();
		}
		ufd->fd = fd;
	}
	free(path);
	free(path0);
	poperror();
	
	ufd->path = addelem(ufd->path, name, nil);
	c->qid = fsqid(&st);
	c->offset = 0;
	c->flag |= COPEN;
	c->mode = openmode(mode);
}
Example #22
0
/**
 * VFSFSAL_setattrs:
 * Set attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param attrib_set (mandatory input):
 *        The attributes to be set for the object.
 *        It defines the attributes that the caller
 *        wants to set and their values.
 * \param object_attributes (optionnal input/output):
 *        The post operation attributes for the object.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t VFSFSAL_setattrs(fsal_handle_t * p_filehandle,       /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            fsal_attrib_list_t * p_attrib_set,  /* IN */
                            fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
    )
{
  vfsfsal_op_context_t * vfs_context = (vfsfsal_op_context_t *) p_context;
  int rc, errsv;
  unsigned int i;
  fsal_status_t status;
  fsal_attrib_list_t attrs;

  int fd;
  struct stat buffstat;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_filehandle || !p_context || !p_attrib_set)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);

  /* local copy of attributes */
  attrs = *p_attrib_set;

  /* It does not make sense to setattr on a symlink */
  /* if(p_filehandle->type == DT_LNK)
     return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set,
     p_object_attributes);
   */
  /* First, check that FSAL attributes changes are allowed. */

  /* Is it allowed to change times ? */

  if(!global_fs_info.cansettime)
    {

      if(attrs.asked_attributes
         & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
        {
          /* handled as an unsettable attribute. */
          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
        }
    }

  /* apply umask, if mode attribute is to be changed */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {
      attrs.mode &= (~global_fs_info.umask);
    }

  TakeTokenFSCall();
  status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
   {
     /* Symbolic link are handled here, they are to be opened as O_PATH */
     if( status.minor == ELOOP )
      {
           if(p_object_attributes)
             {
               status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

               /* on error, we set a special bit in the mask. */
               if(FSAL_IS_ERROR(status))
                 {
                   FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
                   FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
                 }
             }
           Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
      }

     ReturnStatus( status, INDEX_FSAL_setattrs);
   }

  /* get current attributes */
  TakeTokenFSCall();
  rc = fstat(fd, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc != 0)
    {
      close(fd);

      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
    }

  /***********
   *  CHMOD  *
   ***********/
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {

      /* The POSIX chmod call don't affect the symlink object, but
       * the entry it points to. So we must ignore it.
       */
      if(!S_ISLNK(buffstat.st_mode))
        {

          /* For modifying mode, user must be root or the owner */
          if((vfs_context->credential.user != 0)
             && (vfs_context->credential.user != buffstat.st_uid))
            {
              LogFullDebug(COMPONENT_FSAL,
                           "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
                           buffstat.st_uid, vfs_context->credential.user);
              close(fd);
              Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
            }

          TakeTokenFSCall();
          rc = fchmod(fd, fsal2unix_mode(attrs.mode));
          errsv = errno;
          ReleaseTokenFSCall();

          if(rc)
            {
              close(fd);
              Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
            }

        }

    }

  /***********
   *  CHOWN  *
   ***********/
  /* Only root can change uid and A normal user must be in the group he wants to set */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER))
    {

      /* For modifying owner, user must be root or current owner==wanted==client */
      if((vfs_context->credential.user != 0) &&
         ((vfs_context->credential.user != buffstat.st_uid) ||
          (vfs_context->credential.user != attrs.owner)))
        {
          LogFullDebug(COMPONENT_FSAL,
                       "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
                       buffstat.st_uid, vfs_context->credential.user, attrs.owner);
          close(fd);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP))
    {

      /* For modifying group, user must be root or current owner */
      if((vfs_context->credential.user != 0)
         && (vfs_context->credential.user != buffstat.st_uid))
        {
          close(fd);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }

      int in_grp = 0;
      /* set in_grp */
      if(vfs_context->credential.group == attrs.group)
        in_grp = 1;
      else
        for(i = 0; i < vfs_context->credential.nbgroups; i++)
          {
            if((in_grp = (attrs.group == vfs_context->credential.alt_groups[i])))
              break;
          }

      /* it must also be in target group */
      if(vfs_context->credential.user != 0 && !in_grp)
        {
          LogFullDebug(COMPONENT_FSAL,
                       "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
                       buffstat.st_gid, vfs_context->credential.group, attrs.group);
          close(fd);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
    {
      /*      LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)",
                        fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes,
                                                      FSAL_ATTR_OWNER) ? (int)attrs.owner
                        : -1, FSAL_TEST_MASK(attrs.asked_attributes,
			FSAL_ATTR_GROUP) ? (int)attrs.group : -1);*/

      TakeTokenFSCall();
      rc = fchown(fd,
                  FSAL_TEST_MASK(attrs.asked_attributes,
                                 FSAL_ATTR_OWNER) ? (int)attrs.owner : -1,
                  FSAL_TEST_MASK(attrs.asked_attributes,
                                 FSAL_ATTR_GROUP) ? (int)attrs.group : -1);
      ReleaseTokenFSCall();
      if(rc)
        {
          close(fd);
          Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
        }
    }

  /***********
   *  UTIME  *
   ***********/

  /* user must be the owner or have read access to modify 'atime' */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)
     && (vfs_context->credential.user != 0)
     && (vfs_context->credential.user != buffstat.st_uid)
     && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major
         != ERR_FSAL_NO_ERROR))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }
  /* user must be the owner or have write access to modify 'mtime' */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)
     && (vfs_context->credential.user != 0)
     && (vfs_context->credential.user != buffstat.st_uid)
     && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major
         != ERR_FSAL_NO_ERROR))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
    {

      struct timeval timebuf[2];

      /* Atime */
      timebuf[0].tv_sec =
          (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs.
           atime.seconds : buffstat.st_atime);
      timebuf[0].tv_usec = 0;

      /* Mtime */
      timebuf[1].tv_sec =
          (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs.
           mtime.seconds : buffstat.st_mtime);
      timebuf[1].tv_usec = 0;

      TakeTokenFSCall();
      rc = futimes(fd, timebuf);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        {
          close(fd);
          Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
        }
    }

  /* Optionaly fills output attributes. */

  if(p_object_attributes)
    {
      status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  close(fd);
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}
Example #23
0
static int CloneChrootHelperProcess(void)
{
    int sv[2] = { -1, -1 };
    const char * temp_dir = NULL;
    int chroot_dir_fd = -1;
    char proc_self_fd_str[128];
    int printed;
    pid_t pid;
    int rc = -1;	/* assume failure */

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
	perror("socketpair");
	goto exit;
    }

    /*
     * We create a temp directory for our chroot. Nobody should ever write into
     * it, so it's root:root mode 000.
     */
    temp_dir = mkdtemp(tempdirTemplate);
    if (!temp_dir) {
	perror("Failed to create temp directory for chroot");
	goto exit;
    }

    chroot_dir_fd = open(temp_dir, O_DIRECTORY | O_RDONLY);
    if (chroot_dir_fd < 0) {
	rmdir(temp_dir);
	perror("Failed to open chroot temp directory");
	goto exit;
    }

    if (rmdir(temp_dir)) {
	perror("rmdir");
	goto exit;
    }

    printed = snprintf(proc_self_fd_str, sizeof(proc_self_fd_str),
                         "/proc/self/fd/%d", chroot_dir_fd);
    if (printed < 0 || printed >= (int)sizeof(proc_self_fd_str)) {
	fprintf(stderr, "Error in snprintf");
	goto exit;
    }

    if (fchown(chroot_dir_fd, 0 /* root */, 0 /* root */)) {
	perror("fchown");
	goto exit;
    }

    if (fchmod(chroot_dir_fd, 0000 /* no-access */)) {
	perror("fchmod");
	goto exit;
    }

    pid = syscall(__NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0);
    if (pid == -1) {
	perror("clone");
	close(sv[0]);
	close(sv[1]);
	goto exit;
    }

    if (pid == 0) {
	static const struct rlimit nofile = { 0, 0 };
	ssize_t bytes;
	struct stat st;
	char msg;
	char reply;

	/*
	 * The files structure is shared with an untrusted process.
	 * For additional security, the file resource limits are set to 0.
	 * TODO: drop CAP_SYS_RESOURCE / use SECURE_NOROOT
	 */
	if (setrlimit(RLIMIT_NOFILE, &nofile))
	    _err(EXIT_FAILURE, "Setting RLIMIT_NOFILE");

	if (close(sv[1]))
	    _err(EXIT_FAILURE, "close");

	/* wait for message */
	do {
	    bytes = read(sv[0], &msg, 1);
	} while (bytes == -1 && errno == EINTR);

	if (bytes == 0)
	    _exit(EXIT_SUCCESS);
	if (bytes != 1)
	    err(1, "read");

	/* do chrooting */
	if (msg != 'C')
	    _err(EXIT_FAILURE, "Unknown message from sandboxed process");

	if (fchdir(chroot_dir_fd))
	    _err(EXIT_FAILURE, "Cannot chdir into chroot temp directory");

	if (fstat(chroot_dir_fd, &st))
	    _err(EXIT_FAILURE, "stat");

	if (st.st_uid || st.st_gid || st.st_mode & 0777)
	    _err(EXIT_FAILURE, "Bad permissions on chroot temp directory");

	if (chroot(proc_self_fd_str))
	    _err(EXIT_FAILURE, "Cannot chroot into temp directory");

	if (chdir("/"))
	    _err(EXIT_FAILURE, "Cannot chdir to / after chroot");

	reply = 'O';
	do {
	    bytes = write(sv[0], &reply, 1);
	} while (bytes == -1 && errno == EINTR);

	if (bytes != 1)
	    _err(EXIT_FAILURE, "Writing reply");

	_exit(EXIT_SUCCESS);
    }

    if (close(chroot_dir_fd)) {
	close(sv[0]);
	close(sv[1]);
	perror("close(chroot_dir_fd)");
	goto exit;
    }

    if (close(sv[0])) {
	close(sv[1]);
	perror("close");
	goto exit;
    }
    rc = sv[1];

exit:
    return rc;
}
int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
        const char *key, const int ownerUid, bool isExternal) {
    struct asec_superblock sb;
    memset(&sb, 0, sizeof(sb));

    const bool wantFilesystem = strcmp(fstype, "none");
    bool usingExt4 = false;
    if (wantFilesystem) {
        usingExt4 = !strcmp(fstype, "ext4");
        if (usingExt4) {
            sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
        } else if (strcmp(fstype, "fat")) {
            SLOGE("Invalid filesystem type %s", fstype);
            errno = EINVAL;
            return -1;
        }
    }

    sb.magic = ASEC_SB_MAGIC;
    sb.ver = ASEC_SB_VER;

    if (numSectors < ((1024*1024)/512)) {
        SLOGE("Invalid container size specified (%d sectors)", numSectors);
        errno = EINVAL;
        return -1;
    }

    if (lookupVolume(id)) {
        SLOGE("ASEC id '%s' currently exists", id);
        errno = EADDRINUSE;
        return -1;
    }

    char asecFileName[255];

    if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
        SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
                asecFileName, strerror(errno));
        errno = EADDRINUSE;
        return -1;
    }

    const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;

    int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
    if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
        errno = EINVAL;
        return -1;
    }

    if (!access(asecFileName, F_OK)) {
        SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
                asecFileName, strerror(errno));
        errno = EADDRINUSE;
        return -1;
    }

    /*
     * Add some headroom
     */
    unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
    unsigned numImgSectors = numSectors + fatSize + 2;

    if (numImgSectors % 63) {
        numImgSectors += (63 - (numImgSectors % 63));
    }

    // Add +1 for our superblock which is at the end
    if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
        SLOGE("ASEC image file creation failed (%s)", strerror(errno));
        return -1;
    }

    char idHash[33];
    if (!asecHash(id, idHash, sizeof(idHash))) {
        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
        unlink(asecFileName);
        return -1;
    }

    char loopDevice[255];
    if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
        SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
        unlink(asecFileName);
        return -1;
    }

    char dmDevice[255];
    bool cleanupDm = false;

    if (strcmp(key, "none")) {
        // XXX: This is all we support for now
        sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
        if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
                             sizeof(dmDevice))) {
            SLOGE("ASEC device mapping failed (%s)", strerror(errno));
            Loop::destroyByDevice(loopDevice);
            unlink(asecFileName);
            return -1;
        }
        cleanupDm = true;
    } else {
        sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
        strcpy(dmDevice, loopDevice);
    }

    /*
     * Drop down the superblock at the end of the file
     */

    int sbfd = open(loopDevice, O_RDWR);
    if (sbfd < 0) {
        SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
        if (cleanupDm) {
            Devmapper::destroy(idHash);
        }
        Loop::destroyByDevice(loopDevice);
        unlink(asecFileName);
        return -1;
    }

    if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
        close(sbfd);
        SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
        if (cleanupDm) {
            Devmapper::destroy(idHash);
        }
        Loop::destroyByDevice(loopDevice);
        unlink(asecFileName);
        return -1;
    }

    if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
        close(sbfd);
        SLOGE("Failed to write superblock (%s)", strerror(errno));
        if (cleanupDm) {
            Devmapper::destroy(idHash);
        }
        Loop::destroyByDevice(loopDevice);
        unlink(asecFileName);
        return -1;
    }
    close(sbfd);

    if (wantFilesystem) {
        int formatStatus;
        char mountPoint[255];

        int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
        if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
            SLOGE("ASEC fs format failed: couldn't construct mountPoint");
            if (cleanupDm) {
                Devmapper::destroy(idHash);
            }
            Loop::destroyByDevice(loopDevice);
            unlink(asecFileName);
            return -1;
        }

        if (usingExt4) {
            formatStatus = Ext4::format(dmDevice, mountPoint);
        } else {
            formatStatus = Fat::format(dmDevice, numImgSectors);
        }

        if (formatStatus < 0) {
            SLOGE("ASEC fs format failed (%s)", strerror(errno));
            if (cleanupDm) {
                Devmapper::destroy(idHash);
            }
            Loop::destroyByDevice(loopDevice);
            unlink(asecFileName);
            return -1;
        }

        if (mkdir(mountPoint, 0000)) {
            if (errno != EEXIST) {
                SLOGE("Mountpoint creation failed (%s)", strerror(errno));
                if (cleanupDm) {
                    Devmapper::destroy(idHash);
                }
                Loop::destroyByDevice(loopDevice);
                unlink(asecFileName);
                return -1;
            }
        }

        int mountStatus;
        if (usingExt4) {
            mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
        } else {
            mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
                    false);
        }

        if (mountStatus) {
            SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
            if (cleanupDm) {
                Devmapper::destroy(idHash);
            }
            Loop::destroyByDevice(loopDevice);
            unlink(asecFileName);
            return -1;
        }

        if (usingExt4) {
            int dirfd = open(mountPoint, O_DIRECTORY);
            if (dirfd >= 0) {
                if (fchown(dirfd, ownerUid, AID_SYSTEM)
                        || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
                    SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
                }
                close(dirfd);
            }
        }
    } else {
        SLOGI("Created raw secure container %s (no filesystem)", id);
    }

    mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
    return 0;
}
Example #25
0
static void
writefile(time_t runtimer, char queue)
{
    /* This does most of the work if at or batch are invoked for writing a job.
     */
    long jobno;
    char *ap, *ppos, *mailname;
    struct passwd *pass_entry;
    struct stat statbuf;
    int fdes, lockdes, fd2;
    FILE *fp, *fpin;
    struct sigaction act;
    char **atenv;
    int ch;
    mode_t cmask;
    struct flock lock;

#ifdef __FreeBSD__
    (void) setlocale(LC_TIME, "");
#endif

    /* Install the signal handler for SIGINT; terminate after removing the
     * spool file if necessary
     */
    act.sa_handler = sigc;
    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;

    sigaction(SIGINT, &act, NULL);

    ppos = atfile + strlen(ATJOB_DIR);

    /* Loop over all possible file names for running something at this
     * particular time, see if a file is there; the first empty slot at any
     * particular time is used.  Lock the file LFILE first to make sure
     * we're alone when doing this.
     */

    PRIV_START

    if ((lockdes = open(LFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
        perr("cannot open lockfile " LFILE);

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    act.sa_handler = alarmc;
    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;

    /* Set an alarm so a timeout occurs after ALARMC seconds, in case
     * something is seriously broken.
     */
    sigaction(SIGALRM, &act, NULL);
    alarm(ALARMC);
    fcntl(lockdes, F_SETLKW, &lock);
    alarm(0);

    if ((jobno = nextjob()) == EOF)
        perr("cannot generate job number");

    sprintf(ppos, "%c%5lx%8lx", queue,
            jobno, (unsigned long) (runtimer/60));

    for(ap=ppos; *ap != '\0'; ap ++)
        if (*ap == ' ')
            *ap = '0';

    if (stat(atfile, &statbuf) != 0)
        if (errno != ENOENT)
            perr("cannot access " ATJOB_DIR);

    /* Create the file. The x bit is only going to be set after it has
     * been completely written out, to make sure it is not executed in the
     * meantime.  To make sure they do not get deleted, turn off their r
     * bit.  Yes, this is a kluge.
     */
    cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
    if ((fdes = creat(atfile, O_WRONLY)) == -1)
        perr("cannot create atjob file");

    if ((fd2 = dup(fdes)) <0)
        perr("error in dup() of job file");

    if(fchown(fd2, real_uid, real_gid) != 0)
        perr("cannot give away file");

    PRIV_END

    /* We no longer need suid root; now we just need to be able to write
     * to the directory, if necessary.
     */

    REDUCE_PRIV(DAEMON_UID, DAEMON_GID)

    /* We've successfully created the file; let's set the flag so it
     * gets removed in case of an interrupt or error.
     */
    fcreated = 1;

    /* Now we can release the lock, so other people can access it
     */
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    fcntl(lockdes, F_SETLKW, &lock);
    close(lockdes);

    if((fp = fdopen(fdes, "w")) == NULL)
        panic("cannot reopen atjob file");

    /* Get the userid to mail to, first by trying getlogin(),
     * then from LOGNAME, finally from getpwuid().
     */
    mailname = getlogin();
    if (mailname == NULL)
        mailname = getenv("LOGNAME");

    if ((mailname == NULL) || (mailname[0] == '\0')
            || (strlen(mailname) >= MAXLOGNAME) || (getpwnam(mailname)==NULL))
    {
        pass_entry = getpwuid(real_uid);
        if (pass_entry != NULL)
            mailname = pass_entry->pw_name;
    }

    if (atinput != (char *) NULL)
    {
        fpin = freopen(atinput, "r", stdin);
        if (fpin == NULL)
            perr("cannot open input file");
    }
    fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %*s %d\n",
            (long) real_uid, (long) real_gid, MAXLOGNAME - 1, mailname,
            send_mail);

    /* Write out the umask at the time of invocation
     */
    fprintf(fp, "umask %lo\n", (unsigned long) cmask);

    /* Write out the environment. Anything that may look like a
     * special character to the shell is quoted, except for \n, which is
     * done with a pair of "'s.  Don't export the no_export list (such
     * as TERM or DISPLAY) because we don't want these.
     */
    for (atenv= environ; *atenv != NULL; atenv++)
    {
        int export = 1;
        char *eqp;

        eqp = strchr(*atenv, '=');
        if (ap == NULL)
            eqp = *atenv;
        else
        {
            size_t i;
            for (i=0; i<sizeof(no_export)/sizeof(no_export[0]); i++)
            {
                export = export
                         && (strncmp(*atenv, no_export[i],
                                     (size_t) (eqp-*atenv)) != 0);
            }
            eqp++;
        }

        if (export)
        {
            fwrite(*atenv, sizeof(char), eqp-*atenv, fp);
            for(ap = eqp; *ap != '\0'; ap++)
            {
                if (*ap == '\n')
                    fprintf(fp, "\"\n\"");
                else
                {
                    if (!isalnum(*ap)) {
                        switch (*ap) {
                        case '%':
                        case '/':
                        case '{':
                        case '[':
                        case ']':
                        case '=':
                        case '}':
                        case '@':
                        case '+':
                        case '#':
                        case ',':
                        case '.':
                        case ':':
                        case '-':
                        case '_':
                            break;
                        default:
                            fputc('\\', fp);
                            break;
                        }
                    }
                    fputc(*ap, fp);
                }
            }
            fputs("; export ", fp);
            fwrite(*atenv, sizeof(char), eqp-*atenv -1, fp);
            fputc('\n', fp);

        }
    }
int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
    char asecFileName[255];
    char loopDevice[255];
    char mountPoint[255];

    if (gid < AID_APP) {
        SLOGE("Group ID is not in application range");
        return -1;
    }

    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
        SLOGE("Couldn't find ASEC %s", id);
        return -1;
    }

    char idHash[33];
    if (!asecHash(id, idHash, sizeof(idHash))) {
        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
        return -1;
    }

    if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
        SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
        return -1;
    }

    unsigned int nr_sec = 0;
    struct asec_superblock sb;

    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
        return -1;
    }

    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
        SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
        return -1;
    }

    int result = 0;
    if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
        return 0;
    }

    int ret = Ext4::doMount(loopDevice, mountPoint,
            false /* read-only */,
            true  /* remount */,
            false /* executable */);
    if (ret) {
        SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
        return -1;
    }

    char *paths[] = { mountPoint, NULL };

    FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
    if (fts) {
        // Traverse the entire hierarchy and chown to system UID.
        for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
            // We don't care about the lost+found directory.
            if (!strcmp(ftsent->fts_name, "lost+found")) {
                continue;
            }

            /*
             * There can only be one file marked as private right now.
             * This should be more robust, but it satisfies the requirements
             * we have for right now.
             */
            const bool privateFile = !strcmp(ftsent->fts_name, filename);

            int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
            if (fd < 0) {
                SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
                result = -1;
                continue;
            }

            result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);

            if (ftsent->fts_info & FTS_D) {
                result |= fchmod(fd, 0755);
            } else if (ftsent->fts_info & FTS_F) {
                result |= fchmod(fd, privateFile ? 0640 : 0644);
            }
            close(fd);
        }
        fts_close(fts);

        // Finally make the directory readable by everyone.
        int dirfd = open(mountPoint, O_DIRECTORY);
        if (dirfd < 0 || fchmod(dirfd, 0755)) {
            SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
            result |= -1;
        }
        close(dirfd);
    } else {
        result |= -1;
    }

    result |= Ext4::doMount(loopDevice, mountPoint,
            true /* read-only */,
            true /* remount */,
            true /* execute */);

    if (result) {
        SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
        return -1;
    }

    if (mDebug) {
        SLOGD("ASEC %s permissions fixed", id);
    }
    return 0;
}
Example #27
0
/*
 * We make the assumption that when the 'sticky' (t) bit is requested
 * it's not save if the directory has non-root ownership or the sticky
 * bit cannot be set and fail.
 */
static int
trans_mkdir(char *path, int mode)
{
    struct stat buf;

    if (lstat(path, &buf) != 0) {
        if (errno != ENOENT) {
            PRMSG(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n",
                  path, errno, 0);
            return -1;
        }
        /* Dir doesn't exist. Try to create it */

#ifndef WIN32
        /*
         * 'sticky' bit requested: assume application makes
         * certain security implications. If effective user ID
         * is != 0: fail as we may not be able to meet them.
         */
        if (geteuid() != 0) {
            if (mode & 01000) {
                PRMSG(1, "mkdir: ERROR: euid != 0,"
                      "directory %s will not be created.\n",
                      path, 0, 0);
#ifdef FAIL_HARD
                return -1;
#endif
            } else {
                PRMSG(1, "mkdir: Cannot create %s with root ownership\n",
                      path, 0, 0);
            }
        }
#endif

#ifndef WIN32
        if (mkdir(path, mode) == 0) {
            if (chmod(path, mode)) {
                PRMSG(1, "mkdir: ERROR: Mode of %s should be set to %04o\n",
                      path, mode, 0);
#ifdef FAIL_HARD
                return -1;
#endif
            }
#else
        if (mkdir(path) == 0) {
#endif
        } else {
            PRMSG(1, "mkdir: ERROR: Cannot create %s\n",
                  path, 0, 0);
            return -1;
        }

        return 0;

    } else {
        if (S_ISDIR(buf.st_mode)) {
            int updateOwner = 0;
            int updateMode = 0;
            int updatedOwner = 0;
            int updatedMode = 0;
            int status = 0;
            /* Check if the directory's ownership is OK. */
            if (buf.st_uid != 0)
                updateOwner = 1;

            /*
             * Check if the directory's mode is OK.  An exact match isn't
             * required, just a mode that isn't more permissive than the
             * one requested.
             */
            if ((~mode) & 0077 & buf.st_mode)
                updateMode = 1;

            /*
             * If the directory is not writeable not everybody may
             * be able to create sockets. Therefore warn if mode
             * cannot be fixed.
             */
            if ((~buf.st_mode) & 0022 & mode) {
                updateMode = 1;
                status |= WARN_NO_ACCESS;
            }

            /*
             * If 'sticky' bit is requested fail if owner isn't root
             * as we assume the caller makes certain security implications
             */
            if (mode & 01000) {
                status |= FAIL_IF_NOT_ROOT;
                if (!(buf.st_mode & 01000)) {
                    status |= FAIL_IF_NOMODE;
                    updateMode = 1;
                }
            }

#ifdef HAS_FCHOWN
            /*
             * If fchown(2) and fchmod(2) are available, try to correct the
             * directory's owner and mode.  Otherwise it isn't safe to attempt
             * to do this.
             */
            if (updateMode || updateOwner) {
                int fd = -1;
                struct stat fbuf;
                if ((fd = open(path, O_RDONLY)) != -1) {
                    if (fstat(fd, &fbuf) == -1) {
                        PRMSG(1, "mkdir: ERROR: fstat failed for %s (%d)\n",
                              path, errno, 0);
                        return -1;
                    }
                    /*
                     * Verify that we've opened the same directory as was
                     * checked above.
                     */
                    if (!S_ISDIR(fbuf.st_mode) ||
                            buf.st_dev != fbuf.st_dev ||
                            buf.st_ino != fbuf.st_ino) {
                        PRMSG(1, "mkdir: ERROR: inode for %s changed\n",
                              path, 0, 0);
                        return -1;
                    }
                    if (updateOwner && fchown(fd, 0, 0) == 0)
                        updatedOwner = 1;
                    if (updateMode && fchmod(fd, mode) == 0)
                        updatedMode = 1;
                    close(fd);
                }
            }
#endif

            if (updateOwner && !updatedOwner) {
#ifdef FAIL_HARD
                if (status & FAIL_IF_NOT_ROOT) {
                    PRMSG(1, "mkdir: ERROR: Owner of %s must be set to root\n",
                          path, 0, 0);
                    return -1;
                }
#endif
                PRMSG(1, "mkdir: Owner of %s should be set to root\n",
                      path, 0, 0);
            }

            if (updateMode && !updatedMode) {
#ifdef FAIL_HARD
                if (status & FAIL_IF_NOMODE) {
                    PRMSG(1, "mkdir: ERROR: Mode of %s must be set to %04o\n",
                          path, mode, 0);
                    return -1;
                }
#endif
                PRMSG(1, "mkdir: Mode of %s should be set to %04o\n",
                      path, mode, 0);
                if (status & WARN_NO_ACCESS) {
                    PRMSG(1, "mkdir: this may cause subsequent errors\n",
                          0, 0, 0);
                }
            }
            return 0;
        }
        return -1;
    }

    /* In all other cases, fail */
    return -1;
}
Example #28
0
static void copy_file_attributes(int infd, int outfd, const char *outfile)
{
#ifdef WIN32
  BY_HANDLE_FILE_INFORMATION fi;
  BOOL bOk;

  bOk = GetFileInformationByHandle((HANDLE)_get_osfhandle(infd), &fi);
  trace("GetFileInformationByHandle(...) => %s\n", bOk ? "TRUE" : "FALSE");
  if (bOk) {
    bOk = SetFileTime((HANDLE)_get_osfhandle(outfd), NULL, &fi.ftLastAccessTime, &fi.ftLastWriteTime);
    trace("SetFileTime(...) => %s\n", bOk ? "TRUE" : "FALSE");
    bOk = SetFileAttributesA(outfile, fi.dwFileAttributes);
    trace("SetFileAttributesA(...) => %s\n", bOk ? "TRUE" : "FALSE");
  }
#else
  struct stat sbuf;
#ifdef HAVE_FUTIMENS
  struct timespec times[2];
#else
  struct timeval times[2];
#endif
  int rv;

  if ((rv = fstat(infd, &sbuf)) != 0) {
    trace("fstat(%d, &sbuf) => %d (errno = %d)\n",
          infd, rv, errno);
    return;
  }

  /* copy file times. */
#ifdef HAVE_FUTIMENS
  times[0].tv_sec = sbuf.st_atime;
  times[0].tv_nsec = SNZ_ST_TIME_NSEC(sbuf, a);
  times[1].tv_sec = sbuf.st_mtime;
  times[1].tv_nsec = SNZ_ST_TIME_NSEC(sbuf, m);
  rv = futimens(outfd, times);
  trace("futimens(%d, [{%ld, %ld}, {%ld, %ld}]) => %d\n",
        outfd, times[0].tv_sec, times[0].tv_nsec,
        times[1].tv_sec, times[1].tv_nsec, rv);
#else /* HAVE_FUTIMENS */
  times[0].tv_sec = sbuf.st_atime;
  times[0].tv_usec = SNZ_ST_TIME_NSEC(sbuf, a) / 1000;
  times[1].tv_sec = sbuf.st_mtime;
  times[1].tv_usec = SNZ_ST_TIME_NSEC(sbuf, m) / 1000;
#ifdef HAVE_FUTIMES
  rv = futimes(outfd, times);
  trace("futimes(%d, [{%ld, %ld}, {%ld, %ld}]) => %d\n",
        outfd, times[0].tv_sec, times[0].tv_usec,
        times[1].tv_sec, times[1].tv_usec, rv);
#else /* HAVE_FUTIMES */
  rv = utimes(outfile, times);
  trace("utimes(\"%s\", [{%ld, %ld}, {%ld, %ld}]) => %d\n",
        outfile, times[0].tv_sec, times[0].tv_usec,
        times[1].tv_sec, times[1].tv_usec, rv);
#endif /* HAVE_FUTIMES */
#endif /* HAVE_FUTIMENS */

  /* copy other attributes */
  rv = fchown(outfd, sbuf.st_uid, sbuf.st_gid);
  trace("fchown(%d, %d, %d) => %d\n",
        outfd, sbuf.st_uid, sbuf.st_gid, rv);
  rv = fchmod(outfd, sbuf.st_mode);
  trace("fchmod(%d, 0%o) => %d\n",
        outfd, sbuf.st_mode, rv);
#endif
}
Example #29
0
/*
 * Like fgets, but go through the list of files chaining them together.
 * Set len to the length of the line.
 */
int
mf_fgets(SPACE *sp, enum e_spflag spflag)
{
	struct stat sb;
	size_t len;
	char *p;
	int c;
	static int firstfile;

	if (infile == NULL) {
		/* stdin? */
		if (files->fname == NULL) {
			if (inplace != NULL)
				errx(1, "-I or -i may not be used with stdin");
			infile = stdin;
			fname = "stdin";
			outfile = stdout;
			outfname = "stdout";
		}
		firstfile = 1;
	}

	for (;;) {
		if (infile != NULL && (c = getc(infile)) != EOF) {
			(void)ungetc(c, infile);
			break;
		}
		/* If we are here then either eof or no files are open yet */
		if (infile == stdin) {
			sp->len = 0;
			return (0);
		}
		if (infile != NULL) {
			fclose(infile);
			if (*oldfname != '\0') {
				/* if there was a backup file, remove it */
				unlink(oldfname);
				/*
				 * Backup the original.  Note that hard links
				 * are not supported on all filesystems.
				 */
				if ((link(fname, oldfname) != 0) &&
				   (rename(fname, oldfname) != 0)) {
					warn("rename()");
					if (*tmpfname)
						unlink(tmpfname);
					exit(1);
				}
				*oldfname = '\0';
			}
			if (*tmpfname != '\0') {
				if (outfile != NULL && outfile != stdout)
					if (fclose(outfile) != 0) {
						warn("fclose()");
						unlink(tmpfname);
						exit(1);
					}
				outfile = NULL;
				if (rename(tmpfname, fname) != 0) {
					/* this should not happen really! */
					warn("rename()");
					unlink(tmpfname);
					exit(1);
				}
				*tmpfname = '\0';
			}
			outfname = NULL;
		}
		if (firstfile == 0)
			files = files->next;
		else
			firstfile = 0;
		if (files == NULL) {
			sp->len = 0;
			return (0);
		}
		fname = files->fname;
		if (inplace != NULL) {
			if (lstat(fname, &sb) != 0)
				err(1, "%s", fname);
			if (!(sb.st_mode & S_IFREG))
				errx(1, "%s: %s %s", fname,
				    "in-place editing only",
				    "works for regular files");
			if (*inplace != '\0') {
				strlcpy(oldfname, fname,
				    sizeof(oldfname));
				len = strlcat(oldfname, inplace,
				    sizeof(oldfname));
				if (len > sizeof(oldfname))
					errx(1, "%s: name too long", fname);
			}
			len = snprintf(tmpfname, sizeof(tmpfname),
			    "%s/.!%ld!%s", dirname(fname), (long)getpid(),
			    basename(fname));
			if (len >= sizeof(tmpfname))
				errx(1, "%s: name too long", fname);
			unlink(tmpfname);
			if ((outfile = fopen(tmpfname, "w")) == NULL)
				err(1, "%s", fname);
			fchown(fileno(outfile), sb.st_uid, sb.st_gid);
			fchmod(fileno(outfile), sb.st_mode & ALLPERMS);
			outfname = tmpfname;
			if (!ispan) {
				linenum = 0;
				resetstate();
			}
		} else {
			outfile = stdout;
			outfname = "stdout";
		}
		if ((infile = fopen(fname, "r")) == NULL) {
			warn("%s", fname);
			rval = 1;
			continue;
		}
	}
	/*
	 * We are here only when infile is open and we still have something
	 * to read from it.
	 *
	 * Use fgetln so that we can handle essentially infinite input data.
	 * Can't use the pointer into the stdio buffer as the process space
	 * because the ungetc() can cause it to move.
	 */
	p = fgetln(infile, &len);
	if (ferror(infile))
		errx(1, "%s: %s", fname, strerror(errno ? errno : EIO));
	if (len != 0 && p[len - 1] == '\n')
		len--;
	cspace(sp, p, len, spflag);

	linenum++;

	return (1);
}
Example #30
0
static void
edit_cmd(void) {
	char n[MAX_FNAME], q[MAX_TEMPSTR];
	const char *editor;
	FILE *f;
	int ch, t, x;
	sig_t oint, oabrt, oquit, ohup;
	struct stat statbuf;
	struct utimbuf utimebuf;
	long mtimensec;
	WAIT_T waiter;
	PID_T pid, xpid;

	log_it(RealUser, Pid, "BEGIN EDIT", User);
	if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) {
		errx(ERROR_EXIT, "path too long");
	}
	if (!(f = fopen(n, "r"))) {
		if (errno != ENOENT) {
			err(ERROR_EXIT, "cannot open `%s'", n);
		}
		warnx("no crontab for `%s' - using an empty one", User);
		if (!(f = fopen(_PATH_DEVNULL, "r"))) {
			err(ERROR_EXIT, "cannot open `%s'", _PATH_DEVNULL);
		}
	}

	if (fstat(fileno(f), &statbuf) < 0) {
		warn("cannot stat crontab file");
		goto fatal;
	}
	utimebuf.actime = statbuf.st_atime;
	utimebuf.modtime = statbuf.st_mtime;
	mtimensec = statbuf.st_mtimensec;

	/* Turn off signals. */
	ohup = signal(SIGHUP, SIG_IGN);
	oint = signal(SIGINT, SIG_IGN);
	oquit = signal(SIGQUIT, SIG_IGN);
	oabrt = signal(SIGABRT, SIG_IGN);

	if (!glue_strings(Filename, sizeof Filename, _PATH_TMP,
	    "crontab.XXXXXXXXXX", '/')) {
		warnx("path too long");
		goto fatal;
	}
	if (-1 == (t = mkstemp(Filename))) {
		warn("cannot create `%s'", Filename);
		goto fatal;
	}
#ifdef HAS_FCHOWN
	x = fchown(t, MY_UID(pw), MY_GID(pw));
#else
	x = chown(Filename, MY_UID(pw), MY_GID(pw));
#endif
	if (x < 0) {
		warn("cannot chown `%s'", Filename);
		goto fatal;
	}
	if (!(NewCrontab = fdopen(t, "r+"))) {
		warn("cannot open fd");
		goto fatal;
	}

	Set_LineNum(1);

	skip_header(&ch, f);

	/* copy the rest of the crontab (if any) to the temp file.
	 */
	for (; EOF != ch; ch = get_char(f))
		(void)putc(ch, NewCrontab);
	(void)fclose(f);
	if (fflush(NewCrontab) < OK) {
		err(ERROR_EXIT, "cannot flush output for `%s'", Filename);
	}
	(void)utime(Filename, &utimebuf);
 again:
	rewind(NewCrontab);
	if (ferror(NewCrontab)) {
		warn("error while writing new crontab to `%s'", Filename);
 fatal:
		(void)unlink(Filename);
		exit(ERROR_EXIT);
	}

	if (((editor = getenv("VISUAL")) == NULL || *editor == '\0') &&
	    ((editor = getenv("EDITOR")) == NULL || *editor == '\0')) {
		editor = EDITOR;
	}

	/* we still have the file open.  editors will generally rewrite the
	 * original file rather than renaming/unlinking it and starting a
	 * new one; even backup files are supposed to be made by copying
	 * rather than by renaming.  if some editor does not support this,
	 * then don't use it.  the security problems are more severe if we
	 * close and reopen the file around the edit.
	 */

	switch (pid = fork()) {
	case -1:
		warn("cannot fork");
		goto fatal;
	case 0:
		/* child */
		if (setgid(MY_GID(pw)) < 0) {
			err(ERROR_EXIT, "cannot setgid(getgid())");
		}
		if (setuid(MY_UID(pw)) < 0) {
			err(ERROR_EXIT, "cannot setuid(getuid())");
		}
		if (chdir(_PATH_TMP) < 0) {
			err(ERROR_EXIT, "cannot chdir to `%s'", _PATH_TMP);
		}
		if (!glue_strings(q, sizeof q, editor, Filename, ' ')) {
			errx(ERROR_EXIT, "editor command line too long");
		}
		(void)execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", q, (char *)0);
		err(ERROR_EXIT, "cannot start `%s'", editor);
		/*NOTREACHED*/
	default:
		/* parent */
		break;
	}

	/* parent */
	for (;;) {
		xpid = waitpid(pid, &waiter, WUNTRACED);
		if (xpid == -1) {
			if (errno != EINTR)
				warn("waitpid() failed waiting for PID %ld "
				    "from `%s'", (long)pid, editor);
		} else if (xpid != pid) {
			warnx("wrong PID (%ld != %ld) from `%s'",
			    (long)xpid, (long)pid, editor);
			goto fatal;
		} else if (WIFSTOPPED(waiter)) {
			(void)kill(getpid(), WSTOPSIG(waiter));
		} else if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
			warnx("`%s' exited with status %d\n",
			    editor, WEXITSTATUS(waiter));
			goto fatal;
		} else if (WIFSIGNALED(waiter)) {
			warnx("`%s' killed; signal %d (%score dumped)",
			    editor, WTERMSIG(waiter),
			    WCOREDUMP(waiter) ? "" : "no ");
			goto fatal;
		} else
			break;
	}
	(void)signal(SIGHUP, ohup);
	(void)signal(SIGINT, oint);
	(void)signal(SIGQUIT, oquit);
	(void)signal(SIGABRT, oabrt);

	if (fstat(t, &statbuf) < 0) {
		warn("cannot stat `%s'", Filename);
		goto fatal;
	}
	if (utimebuf.modtime == statbuf.st_mtime &&
	    mtimensec == statbuf.st_mtimensec) {
		warnx("no changes made to crontab");
		goto remove;
	}
	warnx("installing new crontab");
	switch (replace_cmd()) {
	case 0:
		break;
	case -1:
		for (;;) {
			(void)fpurge(stdin);
			(void)printf("Do you want to retry the same edit? ");
			(void)fflush(stdout);
			q[0] = '\0';
			(void) fgets(q, (int)sizeof(q), stdin);
			switch (q[0]) {
			case 'y':
			case 'Y':
				goto again;
			case 'n':
			case 'N':
				goto abandon;
			default:
				(void)printf("Enter Y or N\n");
			}
		}
		/*NOTREACHED*/
	case -2:
	abandon:
		warnx("edits left in `%s'", Filename);
		goto done;
	default:
		warnx("panic: bad switch() in replace_cmd()");
		goto fatal;
	}
 remove:
	(void)unlink(Filename);
 done:
	log_it(RealUser, Pid, "END EDIT", User);
}