コード例 #1
0
ファイル: main.c プロジェクト: AhmadTux/DragonFlyBSD
static int
opentty(const char *ttyn, int flags)
{
	int i, j = 0;
	int failopenlogged = 0;

	while (j < 10 && (i = open(ttyn, flags)) == -1)
	{
		if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) {
			syslog(LOG_ERR, "open %s: %m", ttyn);
			failopenlogged = 1;
		}
		j++;
		sleep(60);
	}
	if (i == -1) {
		syslog(LOG_ERR, "open %s: %m", ttyn);
		return 0;
	}
	else {
		if (login_tty(i) < 0) { 
			if (daemon(0,0) < 0) {
				syslog(LOG_ERR,"daemon: %m");
				close(i);
				return 0;
			}
			if (login_tty(i) < 0) {
				syslog(LOG_ERR, "login_tty %s: %m", ttyn);
				close(i);
				return 0;
			}
		}
		return 1;
	}
}
コード例 #2
0
ファイル: main.c プロジェクト: AhmadTux/freebsd
static int
opentty(const char *tty, int flags)
{
	int i;
	int failopenlogged = 0;

	while ((i = open(tty, flags)) == -1)
	{
		if (!failopenlogged) {
			syslog(LOG_ERR, "open %s: %m", tty);
			failopenlogged = 1;
		}
		sleep(60);
	}
	if (login_tty(i) < 0) { 
		if (daemon(0,0) < 0) {
			syslog(LOG_ERR,"daemon: %m");
			close(i);
			return 0;
		}
		if (login_tty(i) < 0) {
			syslog(LOG_ERR, "login_tty %s: %m", tty);
			close(i);
			return 0;
		}
	}
	return 1;
}
コード例 #3
0
ファイル: pty.c プロジェクト: 2asoft/freebsd
int
forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
{
	int master, slave, pid;

	if (openpty(&master, &slave, name, termp, winp) == -1)
		return (-1);
	switch (pid = fork()) {
	case -1:
		return (-1);
	case 0:
		/*
		 * child
		 */
		(void) close(master);
		login_tty(slave);
		return (0);
	}
	/*
	 * parent
	 */
	*amaster = master;
	(void) close(slave);
	return (pid);
}
コード例 #4
0
ファイル: init.c プロジェクト: ngkaho1234/freebsd
/*
 * Start a session and allocate a controlling terminal.
 * Only called by children of init after forking.
 */
static void
open_console(void)
{
	int fd;

	/*
	 * Try to open /dev/console.  Open the device with O_NONBLOCK to
	 * prevent potential blocking on a carrier.
	 */
	revoke(_PATH_CONSOLE);
	if ((fd = open(_PATH_CONSOLE, O_RDWR | O_NONBLOCK)) != -1) {
		(void)fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
		if (login_tty(fd) == 0)
			return;
		close(fd);
	}

	/* No luck.  Log output to file if possible. */
	if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
		stall("cannot open null device.");
		_exit(1);
	}
	if (fd != STDIN_FILENO) {
		dup2(fd, STDIN_FILENO);
		close(fd);
	}
	fd = open(_PATH_INITLOG, O_WRONLY | O_APPEND | O_CREAT, 0644);
	if (fd == -1)
		dup2(STDIN_FILENO, STDOUT_FILENO);
	else if (fd != STDOUT_FILENO) {
		dup2(fd, STDOUT_FILENO);
		close(fd);
	}
	dup2(STDOUT_FILENO, STDERR_FILENO);
}
コード例 #5
0
ファイル: pty.cpp プロジェクト: daddy366/anarchy-bionic
int forkpty(int* master, char* name, const termios* t, const winsize* ws) {
  int slave;
  if (openpty(master, &slave, name, t, ws) == -1) {
    return -1;
  }

  pid_t pid = fork();
  if (pid == -1) {
    close(*master);
    close(slave);
    return -1;
  }

  if (pid == 0) {
    // Child.
    close(*master);
    if (login_tty(slave) == -1) {
      _exit(1);
    }
    return 0;
  }

  // Parent.
  close(slave);
  return pid;
}
コード例 #6
0
ファイル: oinit.c プロジェクト: edgar-pek/PerspicuOS
int
start_session(int vty, int argc, char **argv)
{
    int fd;
    char *t;

    close(0);
    close(1);
    close(2);
    revoke(ttys[vty].tty);
    fd=open(ttys[vty].tty,O_RDWR);
    dup2(fd,0);
    dup2(fd,1);
    dup2(fd,2);
    if(fd>2) close(fd);
    login_tty(fd);
    setpgid(0,getpid());
    putenv("TERM=xterm");
    putenv("HOME=/");
    putenv("PATH=/stand:/bin:/usr/bin:/sbin:.");
    signal(SIGHUP,SIG_DFL);
    signal(SIGINT,SIG_DFL);
    signal(SIGQUIT,SIG_DFL);
    signal(SIGTERM,SIG_DFL);
    chdir("/");
    t=(char *)(rindex(ttys[vty].tty,'/')+1);
    printf("\n\n\nStarting session on %s.\n",t);
    ttys[vty].func(argc,argv);
    _exit(0);
}
コード例 #7
0
ファイル: channel_forkpty.c プロジェクト: LlsDimple/tinyssh
long long channel_forkpty(int fd[3], int master, int slave) {

    long long pid;

    if (!ttyname(slave)) return -1;
    
    fd[0] = fd[1] = master;
    fd[2] = -1;

    pid = fork();
    switch (pid) {
        case -1:
            close(slave);
            close(master);
            return -1;
        case 0:
            close(master);
#ifdef HASLOGINTTY
            if (!ttyname(slave)) global_die(111);
            if (login_tty(slave) == -1) global_die(111);
#else
            if (_login_tty(slave) == -1) global_die(111);
#endif
            return 0;
        default:
            coe_enable(master);
            blocking_disable(master);
            close(slave);
            return pid;
    }
}
コード例 #8
0
ファイル: forkpty.c プロジェクト: Distrotech/gnulib
int
forkpty (int *amaster, char *name,
         const struct termios *termp, const struct winsize *winp)
{
  int master, slave, pid;

  if (openpty (&master, &slave, name, termp, winp) == -1)
    return -1;

  switch (pid = fork ())
    {
    case -1:
      close (master);
      close (slave);
      return -1;

    case 0:
      /* Child.  */
      close (master);
      if (login_tty (slave))
        _exit (1);
      return 0;

    default:
      /* Parent.  */
      *amaster = master;
      close (slave);
      return pid;
    }
}
コード例 #9
0
ファイル: pty.c プロジェクト: GNOME/gftp
static int
_gftp_ptys_open (int fdm, int fds, char *pts_name)
{
  if (login_tty (fds) < 0)
    return (GFTP_EFATAL);

  return (fds);
}
コード例 #10
0
ファイル: linux.cpp プロジェクト: ronw23/prime-osx
LinuxProcess::LinuxProcess(Screen *scr, Font *f, const char *cmdline) : Process(scr, f, cmdline) {

  fd_master=posix_openpt(O_RDWR|O_NOCTTY);
  ppid=getpid();  // Process ID of parent
  cpid=-1;    // Get child PID later

  s = scr;

  assert( fd_master >= 0 );  // Did master terminal open?

  assert( unlockpt(fd_master) >= 0 );  // Unlock PTY
  assert( grantpt(fd_master) >= 0 );  // Grant PTY
  
  assert( (pts=ptsname(fd_master)) != NULL ); // Get slave name

  // Create a child process to use the slave pty
  assert( (cpid=fork()) >= 0);

  // set size...
  struct winsize size;
  int ret;
  memset(&size, 0, sizeof(size));
  size.ws_row = scr->sy;
  size.ws_col = scr->sx;
  ret = ioctl(fd_master, TIOCSWINSZ, &size);
  if (ret != 0) {
    logfile && fprintf(logfile, "failed to set window size\n");
    }

  if(cpid == 0) {
    int fd_slave=-1;  // Slave PTY

    assert( close(fd_master) >= 0 ); // Ditch master PTY

    fd_slave=open(pts,O_RDWR);
    
    assert( fd_slave >= 0);

    // This will dup fd over stdin,out,err then close fd
    // This function needs compilation with -lutil
    assert( login_tty(fd_slave) >= 0 );

    // we are simulating the 'linux' terminal
    setenv("TERM", "linux", 1);
    
    // todo: should also disable UTF8

    int s = system(cmdline);
    
    exit(WEXITSTATUS(s));
    }
  
  isActive = true;
  
  resetConsole();
  }
コード例 #11
0
ファイル: run-program.c プロジェクト: deadtrickster/sbcl
int
set_pty(char *pty_name)
{
    int fd;

    if ((fd = open(pty_name, O_RDWR, 0)) == -1 ||
        login_tty(fd) == -1)
        return (0);
    return (set_noecho(STDIN_FILENO));
}
コード例 #12
0
ファイル: termim.c プロジェクト: buganini/termim
static void
dodock()
{
	char *argv[]={"termim-next", NULL};
	(void)close(tube[0]);
	(void)close(master2);
	login_tty(slave2);
	execvp(argv[0], argv);
	warn("%s", "ime");
	fail();
}
コード例 #13
0
int forkpty(int *pm, char *name, const struct termios *tio, const struct winsize *ws)
{
	int m, s, ec=0, p[2], cs;
	pid_t pid=-1;
	sigset_t set, oldset;

	if (openpty(&m, &s, name, tio, ws) < 0) return -1;

	sigfillset(&set);
	pthread_sigmask(SIG_BLOCK, &set, &oldset);
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);

	if (pipe2(p, O_CLOEXEC)) {
		close(s);
		goto out;
	}

	pid = fork();
	if (!pid) {
		close(m);
		close(p[0]);
		if (login_tty(s)) {
			write(p[1], &errno, sizeof errno);
			_exit(127);
		}
		close(p[1]);
		pthread_setcancelstate(cs, 0);
		pthread_sigmask(SIG_SETMASK, &oldset, 0);
		return 0;
	}
	close(s);
	close(p[1]);
	if (read(p[0], &ec, sizeof ec) > 0) {
		int status;
		waitpid(pid, &status, 0);
		pid = -1;
		errno = ec;
	}
	close(p[0]);

out:
	if (pid > 0) *pm = m;
	else close(m);

	pthread_setcancelstate(cs, 0);
	pthread_sigmask(SIG_SETMASK, &oldset, 0);

	return pid;
}
コード例 #14
0
ファイル: script.c プロジェクト: ampledata/ckl
static void script_start_shell(ckl_script_t *s, int mpty, int spty)
{
  int rv = 0;
  close(mpty);

  rv = login_tty(spty);
  if (rv) {
    perror("login_tty(slave) failed:");
    exit(EXIT_FAILURE);
  }

  execl(s->shell, s->shell, "-i", NULL);
  perror("execl of shell failed!");
  exit(EXIT_FAILURE);
}
コード例 #15
0
/*
 * Start a session and allocate a controlling terminal.
 * Only called by children of init after forking.
 */
static void
setctty(const char *name)
{
	int fd;

	revoke(name);
	if ((fd = open(name, O_RDWR)) == -1) {
		stall("can't open %s: %m", name);
		_exit(1);
	}
	if (login_tty(fd) == -1) {
		stall("can't get %s for controlling terminal: %m", name);
		_exit(1);
	}
}
コード例 #16
0
ファイル: oinit.c プロジェクト: alexandermerritt/dragonfly
static int
setctty(const char *name)
{
	int fd;

	revoke(name);
	if ((fd = open(name, O_RDWR)) == -1) {
		exit(1);
	}

	if (login_tty(fd) == -1) {
		exit(1);
	}

	return fd;
}
コード例 #17
0
ファイル: test-login_tty.c プロジェクト: ajnelson/gnulib
int
main ()
{
  int master;
  int slave;

  /* Open a pseudo-terminal, as a master-slave pair.  */
  {
    int res = openpty (&master, &slave, NULL, NULL, NULL);
    if (res != 0)
      {
        fprintf (stderr, "openpty returned %d\n", res);
        return 1;
      }
  }

  /* Create a new session and make it the controlling tty of this session.  */
  {
    int res = login_tty (slave);
    if (res < 0)
      {
        fprintf (stderr, "login_tty failed\n");
        return 1;
      }
  }

  /* From here on, we cannot use stderr for error messages any more.
     If a test fails, just abort.  */

  /* Check that fd = 0, 1, 2 are now open to the controlling terminal for the
     current process and that it is a session of its own.  */
  {
    int fd;
    for (fd = 0; fd < 3; fd++)
      if (!(tcgetpgrp (fd) == getpid ()))
        abort ();
    for (fd = 0; fd < 3; fd++)
      {
        int sid = tcgetsid (fd);
        if (!(sid == -1 ? errno == ENOSYS : sid == getpid ()))
          abort ();
      }
  }

  return 0;
}
コード例 #18
0
ファイル: pty.c プロジェクト: kissthink/acess2
pid_t forkpty(int *amaster, char *name, const struct termios *termp, const struct winsize *winp)
{
	int child;
	
	int ret = openpty(amaster, &child, name, termp, winp);
	if(ret)	return -1;
	
	pid_t rv = fork();
	if(rv)	return rv;

	login_tty(child);

	// In child
	dup2(child, 0);
	dup2(child, 1);
	dup2(child, 2);
	close(child);

	return 0;
}
コード例 #19
0
ファイル: termim.c プロジェクト: buganini/termim
static void
doshell(char **av)
{
	const char *shell;

	shell = getenv("SHELL");
	if (shell == NULL)
		shell = _PATH_BSHELL;

	(void)close(master);
	login_tty(slave);
	if (av[0]) {
		execvp(av[0], av);
		warn("%s", av[0]);
	} else {
		execl(shell, shell, "-i", (char *)NULL);
		warn("%s", shell);
	}
	fail();
}
コード例 #20
0
pid_t forkpty(int *masterp, char *name, struct termios * termp, struct winsize * winp) {
  int master, slave;
  char ptname[PATH_MAX];
  pid_t pid;

  master = open_master(ptname, sizeof (ptname));
  if (master < 0) {
    return -1;
  }

  slave = open_slave(ptname);
  if (slave < 0) {
    close(master);
    return -1;
  }

  if (name)
    strcpy(name, ptname);

  if (termp)
    tcsetattr(slave, TCSAFLUSH, termp);
  if (winp)
    ioctl(slave, TIOCSWINSZ, winp);

  pid = fork();
  if (pid < 0) {
    close(slave);
    close(master);
    return -1;
  } else if (pid == 0) {
    /* child/slave */
    close(master);
    login_tty(slave);
    return 0;
  }

  /* parent/master */
  *masterp = master;
  close(slave);
  return pid;
}
コード例 #21
0
ファイル: ssh_server_fork.c プロジェクト: cedral/libssh
static int exec_pty(const char *mode, const char *command,
                    struct channel_data_struct *cdata) {
    switch(cdata->pid = fork()) {
        case -1:
            close(cdata->pty_master);
            close(cdata->pty_slave);
            fprintf(stderr, "Failed to fork\n");
            return SSH_ERROR;
        case 0:
            close(cdata->pty_master);
            if (login_tty(cdata->pty_slave) != 0) {
                exit(1);
            }
            execl("/bin/sh", "sh", mode, command, NULL);
            exit(0);
        default:
            close(cdata->pty_slave);
            /* pty fd is bi-directional */
            cdata->child_stdout = cdata->child_stdin = cdata->pty_master;
    }
    return SSH_OK;
}
コード例 #22
0
ファイル: openpty.c プロジェクト: sdoro/old-netkit-site
int main() {
    int fdm, fds;
    int pid, i;
    fd_set set;
    char buf[64];

    if (openpty(&fdm, &fds, NULL, NULL, NULL))
        exit(1);
    if ((pid = fork()) < 0)
        exit(2);
    if (!pid) {
        /*child*/
        close(fdm);
        login_tty(fds);
        execl("/bin/sh", "sh", NULL);
        exit(3);
    }
    /*father: copy stdin/stdout to/from master */
    close(fds);
    system("stty raw -echo");
    FD_ZERO(&set);
    while (waitpid(pid, &i, WNOHANG)!=pid) {
        FD_SET(0,&set);
        FD_SET(fdm,&set);
        select(fdm+1, &set, NULL, NULL, NULL);
        if (FD_ISSET(0, &set)) {
            i = read(0, buf, 64);
            if (i>0) write(fdm, buf, i);
        }
        if (FD_ISSET(fdm, &set)) {
            i = read(fdm, buf, 64);
            if (i>0) write(1, buf, i);
        }
    }
    system("stty sane");
    exit(0);
}
コード例 #23
0
ファイル: run.c プロジェクト: ryo/netbsd-src
/*
 * launch a program inside a subwindow, and report its return status when done
 */
static int
launch_subwin(WINDOW **actionwin, char **args, struct winsize *win, int flags,
    const char *scmd, const char **errstr)
{
	int n, i;
	int selectfailed;
	int status, master, slave;
	fd_set active_fd_set, read_fd_set;
	pid_t child, pid;
	char ibuf[MAXBUF];
	char pktdata;
	char *cp, *ncp;
	struct termios rtt, tt;
	struct timeval tmo;
	static int do_tioccons = 2;

	(void)tcgetattr(STDIN_FILENO, &tt);
	if (openpty(&master, &slave, NULL, &tt, win) == -1) {
		*errstr = "openpty() failed";
		return -1;
	}

	rtt = tt;

	/* ignore tty signals until we're done with subprocess setup */
	ttysig_ignore = 1;
	ioctl(master, TIOCPKT, &ttysig_ignore);

	/* Try to get console output into our pipe */
	if (do_tioccons) {
		if (ioctl(slave, TIOCCONS, &do_tioccons) == 0
		    && do_tioccons == 2) {
			/* test our output - we don't want it grabbed */
			write(1, " \b", 2);
			ioctl(master, FIONREAD, &do_tioccons);
			if (do_tioccons != 0) {
				do_tioccons = 0;
				ioctl(slave, TIOCCONS, &do_tioccons);
			} else
				do_tioccons = 1;
		}
	}

	if (logfp)
		fflush(logfp);
	if (script)
		fflush(script);

	child = fork();
	switch (child) {
	case -1:
		ttysig_ignore = 0;
		refresh();
		*errstr = "fork() failed";
		return -1;
	case 0:	/* child */
		(void)close(STDIN_FILENO);
		/* silently stop curses */
		(void)close(STDOUT_FILENO);
		(void)open("/dev/null", O_RDWR, 0);
		dup2(STDIN_FILENO, STDOUT_FILENO);
		endwin();
		(void)close(master);
		rtt = tt;
		rtt.c_lflag |= (ICANON|ECHO);
		(void)tcsetattr(slave, TCSANOW, &rtt);
		login_tty(slave);
		if (logfp) {
			fprintf(logfp, "executing: %s\n", scmd);
			fclose(logfp);
			logfp = NULL;
		}
		if (script) {
			fprintf(script, "%s\n", scmd);
			fclose(script);
			script = NULL;
		}
		if (strcmp(args[0], "cd") == 0 && strcmp(args[2], "&&") == 0) {
			target_chdir_or_die(args[1]);
			args += 3;
		}
		if (flags & RUN_XFER_DIR)
			target_chdir_or_die(xfer_dir);
		/*
		 * If target_prefix == "", the chroot will fail, but
		 * that's ok, since we don't need it then.
		 */
		if (flags & RUN_CHROOT && *target_prefix()
		    && chroot(target_prefix()) != 0)
			warn("chroot(%s) for %s", target_prefix(), *args);
		else {
			execvp(*args, args);
			warn("execvp %s", *args);
		}
		_exit(EXIT_FAILURE);
		// break; /* end of child */
	default:
		/*
		 * parent: we've set up the subprocess.
		 * forward tty signals to its process group.
		 */
		ttysig_forward = child;
		ttysig_ignore = 0;
		break;
	}

	/*
	 * Now loop transferring program output to screen, and keyboard
	 * input to the program.
	 */

	FD_ZERO(&active_fd_set);
	FD_SET(master, &active_fd_set);
	FD_SET(STDIN_FILENO, &active_fd_set);

	for (selectfailed = 0;;) {
		if (selectfailed) {
			const char mmsg[] =
			    "select(2) failed but no child died?";
			if (logfp)
				(void)fprintf(logfp, mmsg);
			errx(1, mmsg);
		}
		read_fd_set = active_fd_set;
		tmo.tv_sec = flags & RUN_SILENT ? 20 : 2;
		tmo.tv_usec = 0;
		i = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tmo);
		if (i == 0 && *actionwin == NULL && (flags & RUN_SILENT) == 0)
			*actionwin = show_cmd(scmd, win);
		if (i < 0) {
			if (errno != EINTR) {
				warn("select");
				if (logfp)
					(void)fprintf(logfp,
					    "select failure: %s\n",
					    strerror(errno));
				selectfailed = 1;
			}
		} else for (i = 0; i < FD_SETSIZE; ++i) {
			if (!FD_ISSET(i, &read_fd_set))
				continue;
			n = read(i, ibuf, sizeof ibuf - 1);
			if (n <= 0) {
				if (n < 0)
					warn("read");
				continue;
			}
			ibuf[n] = 0;
			cp = ibuf;
			if (i == STDIN_FILENO) {
				(void)write(master, ibuf, (size_t)n);
				if (!(rtt.c_lflag & ECHO))
					continue;
			} else {
				pktdata = ibuf[0];
				if (pktdata != 0) {
					if (pktdata & TIOCPKT_IOCTL)
						memcpy(&rtt, ibuf, sizeof(rtt));
					continue;
				}
				cp += 1;
			}
			if (*cp == 0 || flags & RUN_SILENT)
				continue;
			if (logfp) {
				fprintf(logfp, "%s", cp);
				fflush(logfp);
			}
			if (*actionwin == NULL)
				*actionwin = show_cmd(scmd, win);
			/* posix curses is braindead wrt \r\n so... */
			for (ncp = cp; (ncp = strstr(ncp, "\r\n")); ncp += 2) {
				ncp[0] = '\n';
				ncp[1] = '\r';
			}
			waddstr(*actionwin, cp);
			wrefresh(*actionwin);
		}
		pid = wait4(child, &status, WNOHANG, 0);
 		if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status)))
			break;
	}
	close(master);
	close(slave);
	if (logfp)
		fflush(logfp);

	/* from here on out, we take tty signals ourselves */
	ttysig_forward = 0;

	reset_prog_mode();

	if (WIFEXITED(status)) {
		*errstr = msg_string(MSG_Command_failed);
		return WEXITSTATUS(status);
	}
	if (WIFSIGNALED(status)) {
		*errstr = msg_string(MSG_Command_ended_on_signal);
		return WTERMSIG(status);
	}
	return 0;
}
コード例 #24
0
ファイル: libxl_bootloader.c プロジェクト: nypdmax/RT-Xen
static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
{
    libxl__bootloader_state *bl = CONTAINER_OF(op, *bl, openpty);
    STATE_AO_GC(bl->ao);
    int rc, r;
    char *const env[] = { "TERM", "vt100", NULL };

    if (bl->openpty.rc) {
        rc = bl->openpty.rc;
        goto out;
    }

    /*
     * We need to present the bootloader's tty as a pty slave that xenconsole
     * can access.  Since the bootloader itself needs a pty slave,
     * we end up with a connection like this:
     *
     * xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader
     *
     * where we copy characters between the two master fds, as well as
     * listening on the bootloader's fifo for the results.
     */

    char *dom_console_xs_path;
    char dom_console_slave_tty_path[PATH_MAX];
    rc = setup_xenconsoled_pty(egc, bl,
                               &dom_console_slave_tty_path[0],
                               sizeof(dom_console_slave_tty_path));
    if (rc) goto out;

    char *dompath = libxl__xs_get_dompath(gc, bl->domid);
    if (!dompath) {
        rc = ERROR_FAIL;
        goto out;
    }

    dom_console_xs_path = GCSPRINTF("%s/console/tty", dompath);

    rc = libxl__xs_write(gc, XBT_NULL, dom_console_xs_path, "%s",
                         dom_console_slave_tty_path);
    if (rc) {
        LOGE(ERROR,"xs write console path %s := %s failed",
             dom_console_xs_path, dom_console_slave_tty_path);
        rc = ERROR_FAIL;
        goto out;
    }

    bl->deathcheck.what = "stopping bootloader";
    bl->deathcheck.domid = bl->domid;
    bl->deathcheck.callback = bootloader_domaindeath;
    rc = libxl__domaindeathcheck_start(gc, &bl->deathcheck);
    if (rc) goto out;

    if (bl->console_available)
        bl->console_available(egc, bl);

    int bootloader_master = libxl__carefd_fd(bl->ptys[0].master);
    int xenconsole_master = libxl__carefd_fd(bl->ptys[1].master);

    libxl_fd_set_nonblock(CTX, bootloader_master, 1);
    libxl_fd_set_nonblock(CTX, xenconsole_master, 1);

    bl->keystrokes.writefd   = bl->display.readfd   = bootloader_master;
    bl->keystrokes.writewhat = bl->display.readwhat = "bootloader pty";

    bl->keystrokes.readfd   = bl->display.writefd   = xenconsole_master;
    bl->keystrokes.readwhat = bl->display.writewhat = "xenconsole client pty";

    bl->keystrokes.ao = ao;
    bl->keystrokes.maxsz = BOOTLOADER_BUF_OUT;
    bl->keystrokes.copywhat =
        GCSPRINTF("bootloader input for domain %"PRIu32, bl->domid);
    bl->keystrokes.callback =         bootloader_keystrokes_copyfail;
    bl->keystrokes.callback_pollhup = bootloader_keystrokes_copyfail;
    /* pollhup gets called with errnoval==-1 which is not otherwise
     * possible since errnos are nonnegative, so it's unambiguous */
    rc = libxl__datacopier_start(&bl->keystrokes);
    if (rc) goto out;

    bl->display.ao = ao;
    bl->display.maxsz = BOOTLOADER_BUF_IN;
    bl->display.copywhat =
        GCSPRINTF("bootloader output for domain %"PRIu32, bl->domid);
    bl->display.callback =         bootloader_display_copyfail;
    bl->display.callback_pollhup = bootloader_display_copyfail;
    rc = libxl__datacopier_start(&bl->display);
    if (rc) goto out;

    LOG(DEBUG, "executing bootloader: %s", bl->args[0]);
    for (const char **blarg = bl->args;
            *blarg;
            blarg++)
        LOG(DEBUG, "  bootloader arg: %s", *blarg);

    struct termios termattr;

    pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished);
    if (pid == -1) {
        rc = ERROR_FAIL;
        goto out;
    }

    if (!pid) {
        /* child */
        r = login_tty(libxl__carefd_fd(bl->ptys[0].slave));
        if (r) {
            LOGE(ERROR, "login_tty failed");
            exit(-1);
        }
        libxl__exec(gc, -1, -1, -1, bl->args[0], (char **) bl->args, env);
        exit(-1);
    }

    /* parent */

    /*
     * On Solaris, the master pty side does not have terminal semantics,
     * so don't try to set any attributes, as it will fail.
     */
#if !defined(__sun__)
    tcgetattr(bootloader_master, &termattr);
    cfmakeraw(&termattr);
    tcsetattr(bootloader_master, TCSANOW, &termattr);
#endif

    return;

out:
    bootloader_callback(egc, bl, rc);
}
コード例 #25
0
ファイル: pty-server.c プロジェクト: artisdom/mini-rpc
int main(int argc, char **argv)
{
	int fdm, fds, pid, exitval = 0;
	struct minipc_ch *ch;
	struct pty_counts counters = {0,};

	/* First, open the pty */
	if (openpty(&fdm, &fds, NULL, NULL, NULL) < 0) {
		fprintf(stderr, "%s: openpty(): %s\n", argv[0],
			strerror(errno));
		exit(1);
	}

	/* Run a shell and let it go by itself before we open the rpc */
	fprintf(stderr, "%s: Running a sub-shell in a new pty\n", argv[0]);
	if ((pid = fork()) < 0) {
		fprintf(stderr, "%s: fork(): %s\n", argv[0],
			strerror(errno));
		exit(1);
	}
	if (!pid) {
		/* Child: become a shell and disappear... */
		close(fdm);
		login_tty(fds);
		execl("/bin/sh", "sh", NULL);
		fprintf(stderr, "%s: exec(/bin/sh): %s\n", argv[0],
			strerror(errno));
		exit(1);
	}

	/* Open the RPC server channel */
	ch = minipc_server_create(PTY_RPC_NAME, 0);
	if (!ch) {
		fprintf(stderr, "%s: rpc_open(): %s\n", argv[0],
			strerror(errno));
		exit(1);
	}

	/* Log file for diagnostics */
	{
		char name[] = "/tmp/pty-server.XXXXXX";
		int logfd;
		FILE *logf;

		logfd = mkstemp(name);
		if (logfd >= 0) {
			logf = fdopen(logfd, "w");
			if (logf)
				minipc_set_logfile(ch, logf);
		}
	}

	/* Register your functions: all our RPC is split to another source */
	if (pty_export_functions(ch, fdm, &counters)) {
		fprintf(stderr, "%s: exporting RPC functions: %s\n", argv[0],
			strerror(errno));
		exit(1);
	}

	/*
	 * Now, we must mirror stdin/stdout to the pty master, with RPC too.
	 * The first step is horribly changing the termios of our tty
	 */
	close(fds); system("stty raw -echo");

	while (waitpid(pid, NULL, WNOHANG) != pid) {
		fd_set set;
		int nfd, i;
		char buf[256];

		/* ask the RPC engine its current fdset and augment it */
		minipc_server_get_fdset(ch, &set);
		FD_SET(STDIN_FILENO, &set);
		FD_SET(fdm, &set);

		/* wait for any of the FD to be active */
		nfd = select(64 /* Hmmm... */, &set, NULL, NULL, NULL);
		if (nfd < 0 && errno == EINTR)
			continue;
		if (nfd < 0) {
			fprintf(stderr, "%s: select(): %s\n", argv[0],
			strerror(errno));
			exitval = 1;
			break;
		}

		/* Handle fdm and fds by just mirroring stuff and counting */
		if (FD_ISSET(STDIN_FILENO, &set)) {
			i = read(0, buf, sizeof(buf));
			if (i > 0) {
				write(fdm, buf, i);
				counters.in += i;
			}
			nfd--;
		}
		if (FD_ISSET(fdm, &set)) {
			i = read(fdm, buf, sizeof(buf));
			if (i > 0) {
				write(1, buf, i);
				counters.out += i;
			}
			nfd--;
		}

		/* If there are no more active fd, loop over */
		if (!nfd)
			continue;

		/*
		 * If we are there, there has been an RPC call.
		 * We tell the library to use a 0 timeout, since we know
		 * for sure that at least one of its descriptors is pending.
		 */
		minipc_server_action(ch, 0);
	}

	/* The child shell exited, reset the tty and exit. Let RPC die out */
	system("stty sane");
	exit(exitval);
}
コード例 #26
0
ファイル: interactive.c プロジェクト: mm79/sud
void
exec_shell(struct conf *cfp, int fd, int parentfd)
{
	int master, slave;
	pid_t pid;
	char line[MAXPATHLEN];	
	char *tty;
#ifdef HAVE_UTMP_H
	struct utmp ut;
#elif HAVE_UTMPX_H
	struct utmpx ut;
	struct timeval tv;
#endif

#if defined(HAVE_UTMP_H) || defined(HAVE_UTMPX_H)
	memset(&ut, 0, sizeof(ut));
#endif

	if (pipe(pipechld) < 0) {
		syslog(LOG_ERR, "exec_shell() pipe %m");
		_exit(1);
	}

	(void)non_blocking(pipechld[0]);
	(void)non_blocking(pipechld[1]);

	if (openpty(&master, &slave, line, NULL, NULL) == -1) {
		syslog(LOG_ERR, "openpty %m");
		_exit(1) ;
	}

	/*
	 * pts/x compatible
	 */
	if ((tty = strstr(line, "/dev/"))) 
        	tty += 5;
       	else
       		tty = line;
#if defined(HAVE_UTMP_H) || defined(HAVE_UTMPX_H)
	if (cfp->utmp) {
		if (cfp->utname) {
#ifdef HAVE_UTMP_H
                	(void)strncpy(ut.ut_name, cfp->utname, 
				sizeof(ut.ut_name)-1);
			ut.ut_name[sizeof(ut.ut_name)-1] = '\0';
#elif HAVE_UTMPX_H
			(void)strncpy(ut.ut_user, cfp->utname,
				sizeof(ut.ut_user)-1);
			ut.ut_user[sizeof(ut.ut_user)-1] = '\0';
#endif
		} else {
			struct passwd *pw;
			pw = get_pwentry(cfp->havesetuser ? cfp->setuser : \
				0);
#ifdef HAVE_UTMP_H
			(void)strncpy(ut.ut_name, pw->pw_name, 
				sizeof(ut.ut_name)-1); 

			ut.ut_name[sizeof(ut.ut_name)-1] = '\0';
#elif HAVE_UTMPX_H
			(void)strncpy(ut.ut_user, pw->pw_name,
				sizeof(ut.ut_user)-1);

			ut.ut_user[sizeof(ut.ut_user)-1] = '\0';
#endif
		}
    
		(void)strncpy(ut.ut_line, tty, sizeof(ut.ut_line)-1);
		ut.ut_line[sizeof(ut.ut_line)-1] = '\0';

		if (cfp->uthost) {
			(void)strncpy(ut.ut_host, cfp->uthost, 
				sizeof(ut.ut_host)-1);
			ut.ut_host[sizeof(ut.ut_host)-1] = '\0';
		}
#ifdef HAVE_UTMP_H	
		(void)time(&ut.ut_time);	
#elif HAVE_UTMPX_H 
		(void)gettimeofday(&tv, NULL);
		ut.ut_tv.tv_sec = tv.tv_sec;
		ut.ut_tv.tv_usec = tv.tv_usec;

		(void)strncpy(ut.ut_id, ut.ut_line, sizeof(ut.ut_id)-1);
		ut.ut_line[sizeof(ut.ut_line)-1] = '\0';

		ut.ut_pid = getpid();
		ut.ut_type = USER_PROCESS;
#endif
	}
#endif

        /*
         * overwriting signal disposition
         */
        (void)signal(SIGCHLD, sig_chld);

	switch (pid = fork()) {
	case -1:
		syslog(LOG_ERR, "forkpty: %m");
		_exit(1);	
	case 0:
		(void)close(parentfd);
		(void)close(pipechld[0]);
		(void)close(pipechld[1]);
		(void)close(master);
               	(void)close(fd);	
		(void)login_tty(slave);
#ifdef HAVE_UTMP_H
		login(&ut);
#elif HAVE_UTMPX_H
		setutxent();
		(void)pututxline(&ut);
#endif

		set_privileges(cfp);		

		/*
		 * SUIP PROGRAM HERE
		 */
#ifdef __NetBSD__
		(void)execl(_PATH_BSHELL,"sh", "-c",cfp->suipfile,(char *)NULL);
#else
		(void)execl(_PATH_BSHELL, "sh", "-p", "-c", cfp->suipfile, 
			(char *)NULL);
#endif
		_exit(127);
	default:
	{
		int ctrls;	
		int exit_status = 0;
	
		(void)close(slave);
	
		/*
		 * trying to open a control channel
		 * control_create() returns the number of bytes which were 
		 * written
		 * select_fd() returns -1 if errors exist you can check errno
		 */
		if (control_create(&ctrls, fd) == 1) { 
			if (select_fd(cfp, fd, master, ctrls, parentfd) < 0)
				exit_status = 1; 
		} else {
			syslog(LOG_ERR, "can't open ctrl chan");
			exit_status = 1;
		}
#if defined(HAVE_UTMP_H) || defined(HAVE_UTMPX_H)
		if (cfp->utmp) {
#ifdef HAVE_UTMP_H
			if (!logout(tty)) { 
				syslog(LOG_ERR, "unable to logout on %s", tty);
				exit_status = 1;
			} else
				logwtmp(tty, "", "");
#elif HAVE_UTMPX_H
			ut.ut_type = DEAD_PROCESS;
			(void)gettimeofday(&tv, NULL);
			ut.ut_tv.tv_sec = tv.tv_sec;
			ut.ut_tv.tv_usec = tv.tv_usec;

			(void)memset(&ut.ut_user, 0, sizeof(ut.ut_user));	
			setutxent();
			if (pututxline(&ut) == NULL) {
				syslog(LOG_ERR, 
					"unable to logout on %s (utmpx)",
					tty);
				exit_status = 1;
			}	
			endutxent();
#endif
		}
#endif

		cleanup(line);
		_exit(exit_status);
	}}	

	/*
	 * never reached
	 */
	_exit(1);
}
コード例 #27
0
ファイル: dm.c プロジェクト: mit-athena/dm
static void console_login(char *conf, char *msg)
{
  int i, cfirst = TRUE;
  char *nl = "\r\n";
  struct termios ttybuf;
  char *p, **cargv;
  int fd;

  syslog(LOG_DEBUG, "Performing console login: %s", msg);
  sigemptyset(&sig_zero);
  if (login_running != NONEXISTENT && login_running != STARTUP)
    kill(loginpid, SIGKILL);
  if (console_running != NONEXISTENT)
    {
      if (cfirst)
	kill(consolepid, SIGHUP);
      else
	kill(consolepid, SIGKILL);
      cfirst = FALSE;
    }
  if (x_running != NONEXISTENT)
    kill(xpid, SIGTERM);

  x_stop_wait();

  unlink(dmpidf);

  p = getconf(conf, "ttylogin");
  if (p == NULL)
    {
      fprintf(stderr, "dm: Can't find login command line\n");
      exit(1);
    }
  cargv = parseargs(p, NULL, NULL, NULL);

  setpgid(0, 0);		/* We have to reset the tty pgrp */
  if (tcsetpgrp(0, getpgrp()) == -1)
    syslog(LOG_ERR, "tcsetpgrp failed in console login (%s)",
	   strerror(errno));
  tcflush(0, TCIOFLUSH);

  (void) tcgetattr(0, &ttybuf);
  ttybuf.c_lflag |= (ICANON | ISIG | ECHO);
  (void) tcsetattr(0, TCSADRAIN, &ttybuf);
  (void) sigprocmask(SIG_SETMASK, &sig_zero, NULL);
  max_fd = sysconf(_SC_OPEN_MAX);

  for (i = 3; i < max_fd; i++)
    close(i);

  if (msg)
    fprintf(stderr, "%s", msg);
  else
    fprintf(stderr, "%s", nl);

  fd = open("/dev/console", O_RDWR);
  if (fd >= 0)
    login_tty(fd);

  execv(p, cargv);

  fprintf(stderr, "dm: Unable to start console login: %s\n", strerror(errno));
  _exit(1);
}
コード例 #28
0
ファイル: dm.c プロジェクト: mit-athena/dm
int main(int argc, char **argv)
{
  char *consoletty, *p;
  char **dmargv, **xargv, **consoleargv = NULL, **loginargv;
  char xpidf[256], line[16], buf[256];
  fd_set readfds;
  int pgrp, file, tries, count, redir = TRUE;
  char dpyacl[40];
  Display *dpy;
  XHostAddress *hosts, localhost;
  int nhosts, dpynum = 0;
  struct stat hostsinfo;
  Bool state;
  time_t now, last_console_failure = 0;
  struct sigaction sigact;
  sigset_t mask;
#if defined(SRIOCSREDIR) || defined(TIOCCONS)
  int on;
#endif
  int fd;
  int conspipe[2];
  XIOErrorHandler xioerror_handler;

  sigemptyset(&sigact.sa_mask);
  sigact.sa_flags = 0;
  (void) sigemptyset(&sig_zero);

  /* Create a localhost entity for access control purposes. */
  localhost.family = FamilyLocalHost;
  localhost.length = 0;
  localhost.address = "";

/*
 * Note about setting environment variables in dm:
 *
 *   All environment variables passed to dm and set in dm are
 *   subsequently passed to any children of dm. This is usually
 *   true of processes that exec in children, so that's not a
 *   big surprise.
 *
 *   However, xlogin is one of the children dm forks, and it goes
 *   to lengths to ensure that the environments of users logging in
 *   are ISOLATED from xlogin's own environment. Therefore, do not
 *   expect that setting an environment variable here will reach the
 *   user unless you have gone to lengths to make sure that xlogin
 *   passes it on. Put another way, if you set a new environment
 *   variable here, consider whether or not it should be seen by the
 *   user. If it should, go modify verify.c as well. Consider also
 *   whether the variable should be seen _only_ by the user. If so,
 *   make the change only in xlogin, and not here.
 *
 *   As an added complication, xlogin _does_ pass environment variables
 *   on to the pre-login options. Therefore, if you set an environment
 *   variable that should _not_ be seen, you must filter it in xlogin.c.
 *
 *   Confused? Too bad. I'm in a nasty, if verbose, mood this year.
 *
 * General summary:
 *
 *   If you add an environment variable here there are three likely
 *   possibilities:
 *
 *     1. It's for the user only, not needed by any of dm's children.
 *        --> Don't set it here. Set it in verify.c for users and in
 *        --> xlogin.c for the pre-login options, if appropriate.
 *
 *     2. It's for dm and its children only, and _should not_ be seen
 *        by the user or pre-login options.
 *        --> You must filter the option from the pre-login options
 *        --> in xlogin.c. No changes to verify.c are required.
 *
 *     3. It's for dm and the user and the pre-login options.
 *        --> You must pass the option explicitly to the user in
 *        --> verify.c. No changes to xlogin.c are required.
 *
 *                                                   --- cfields
 */
#ifdef notdef
  putenv("LD_LIBRARY_PATH=/usr/openwin/lib");
  putenv("OPENWINHOME=/usr/openwin");
#endif

  if (argc < 2)
    {
      fprintf(stderr, "dm: first argument must be configuration file\n");
      sleep(60);
      exit(1);
    }

  conf = argv[1];

  if (argc != 4 && (argc != 5 || strcmp(argv[3], "-noconsole")))
    {
      fprintf(stderr,
	      "usage: %s configfile logintty [-noconsole] consoletty\n",
	      argv[0]);
      console_login(conf, NULL);
    }
  if (argc == 5)
    redir = FALSE;

  /* parse argument lists */
  /* ignore argv[2] */
  consoletty = argv[argc - 1];
#ifdef SOLARIS
  /* On Solaris, use the console tty name for the utmp line field,
   * as the Solaris finger requires an actual device name there.
   * Elsewhere, we will use the display name (see below).
   */
  utmp_line = consoletty;
#endif

  openlog("dm", 0, LOG_USER);

  /* We use options from the config file rather than taking
   * them from the command line because the current command
   * line form is gross (why???), and I don't see a good way
   * to extend it without making things grosser or breaking
   * backwards compatibility. So, we take a line from the
   * config file and use real parsing.
   */
  p = getconf(conf, "dm");
  if (p != NULL)
    {
      dmargv = parseargs(p, NULL, NULL, NULL);
      while (*dmargv)
	{
	  if (!strcmp(*dmargv, "-display"))
	    {
	      dmargv++;
	      if (*dmargv)
		{
		  dpynum = atoi(*(dmargv) + 1);
		  dmargv++;
		}
	    }
	  else
	    dmargv++;
	}
    }

  p = getconf(conf, "X");
  if (p == NULL)
    console_login(conf, "\ndm: Can't find X command line\n");
  xargv = parseargs(p, NULL, NULL, NULL);

  p = getconf(conf, "console");
  if (p == NULL)
    console_login(conf, "\ndm: Can't find console command line\n");

  /* We will pass the read side of the pipe created below to console
   * on descriptor 3.
   */
  consoleargv = parseargs(p, "-inputfd", "3", NULL);

  /* Signal Setup */
  sigact.sa_handler = SIG_IGN;
  sigaction(SIGTSTP, &sigact, NULL);
  sigaction(SIGTTIN, &sigact, NULL);
  sigaction(SIGTTOU, &sigact, NULL);
  /* so that X pipe errors don't nuke us */
  sigaction(SIGPIPE, &sigact, NULL);
  sigact.sa_handler = shutdown;
  sigaction(SIGFPE, &sigact, NULL);
  sigact.sa_handler = die;
  sigaction(SIGHUP, &sigact, NULL);
  sigaction(SIGINT, &sigact, NULL);
  sigaction(SIGTERM, &sigact, NULL);
  sigact.sa_handler = child;
  sigaction(SIGCHLD, &sigact, NULL);
  sigact.sa_handler = catchalarm;
  sigaction(SIGALRM, &sigact, NULL);

  strcpy(line, "/dev/");
  strcat(line, consoletty);

  fd = open(line, O_RDWR);
  if (fd == -1)
    {
      syslog(LOG_ERR, "Cannot open %s: %m", line);
      /* This probably won't work, but it seems to be the appropriate
	 punt location. */
      console_login(conf, "Cannot open tty.\n");
    }

  if (login_tty(fd) == -1)
    syslog(LOG_ERR, "Cannot set the console as a login terminal (%s)",
	   strerror(errno));
  else
    {
      /* Set the console characteristics so we don't lose later */
      setpgid(0, pgrp = getpid());	/* Reset the tty pgrp  */
      if (tcsetpgrp(0, pgrp) == -1)
	syslog(LOG_ERR, "tcsetpgrp failed for console terminal (%s)",
	       strerror(errno));
    }

  /* save our pid file */
  writepid(dmpidf, getpid());

  /* Fire up X */
  xpid = 0;
  for (tries = 0; tries < 3; tries++)
    {
      syslog(LOG_DEBUG, "Starting X, try #%d", tries + 1);
      x_running = STARTUP;
      sigact.sa_handler = xready;
      sigaction(SIGUSR1, &sigact, NULL);
      switch (fork_and_store(&xpid))
	{
	case 0:
	  if (fcntl(2, F_SETFD, 1) == -1)
	    close(2);
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, (sigset_t *) 0);

	  /* ignoring SIGUSR1 will cause the server to send us a SIGUSR1
	   * when it is ready to accept connections
	   */
	  sigact.sa_handler = SIG_IGN;
	  sigaction(SIGUSR1, &sigact, NULL);
	  p = *xargv;
	  *xargv = "X";
	  execv(p, xargv);
	  fprintf(stderr, "dm: X server failed exec: %s\n", strerror(errno));
	  _exit(1);
	case -1:
	  fprintf(stderr, "dm: Unable to fork to start X server: %s\n",
		  strerror(errno));
	  break;
	default:
	  sprintf(xpidf, xpids, dpynum);
	  writepid(xpidf, xpid);

	  if (x_running == STARTUP)
	    {
	      alarm(X_START_WAIT);
	      alarm_running = RUNNING;
	      sigsuspend(&sig_zero);
	    }
	  if (x_running != RUNNING)
	    {
	      syslog(LOG_DEBUG, "X failed to start; alarm_running=%d",
		     alarm_running);
	      if (alarm_running == NONEXISTENT)
		fprintf(stderr, "dm: Unable to start X\n");
	      else
		fprintf(stderr, "dm: X failed to become ready\n");

	      /* If X wouldn't run, it could be that an existing X
	       * process hasn't shut down.  Wait X_STOP_WAIT seconds
	       * for that to happen.
	       */
	      x_stop_wait();
	    }
	  sigact.sa_handler = SIG_IGN;
	  sigaction(SIGUSR1, &sigact, NULL);
	}
      if (x_running == RUNNING)
	break;
    }
  alarm(0);
  if (x_running != RUNNING)
    {
      syslog(LOG_DEBUG, "Giving up on starting X.");
      console_login(conf, "\nUnable to start X, doing console login "
		    "instead.\n");
    }

  /* Tighten up security a little bit. Remove all hosts from X's
   * access control list, assuming /etc/X0.hosts does not exist or
   * has zero length. If it does exist with nonzero length, this
   * behavior is not wanted. The desired effect of removing all hosts
   * is that only connections from the Unix domain socket will be
   * allowed.       

   * More secure code using Xau also exists, but there wasn't
   * time to completely flesh it out and resolve a couple of
   * issues. This code is probably good enough, but we'll see.
   * Maybe next time. 

   * This code has the added benefit of leaving an X display
   * connection open, owned by dm. This provides a less-hacky
   * solution to the config_console problem, where if config_console
   * is the first program run on user login, it causes the only
   * X app running at the time, console, to exit, thus resetting
   * the X server. Thus this code also allows the removal of the
   * hack in xlogin that attempts to solve the same problem, but
   * fails on the RS/6000 for reasons unexplored.

   * P.S. Don't run this code under Solaris 2.2- (2.3 is safe).
   * Removing all hosts from the acl on that server results in
   * no connections, not even from the Unix domain socket, being
   * allowed. --- cfields
   */

  sprintf(dpyacl, xhosts, dpynum);
  sprintf(dpyname, ":%d", dpynum);

#ifndef SOLARIS
  /* Use the display name for the utmp line field, except on Solaris. */
  utmp_line = dpyname;
#endif

  /* Put in our own error handler, open the display, then reset the handler. */
  xioerror_handler = XSetIOErrorHandler(handle_xioerror);
  dpy = XOpenDisplay(dpyname);
  XSetIOErrorHandler(xioerror_handler);

  if (dpy != NULL && (stat(dpyacl, &hostsinfo) || hostsinfo.st_size == 0))
    {
      hosts = XListHosts(dpy, &nhosts, &state);
      if (hosts != NULL)
	{
	  XRemoveHosts(dpy, hosts, nhosts);
	  XFree(hosts);
	}
      XAddHost(dpy, &localhost);
      XFlush(dpy);
    }
  /* else if (dpy == NULL)
   *   Could've sworn the X server was running now.
   *   Follow the original code path. No need introducing new bugs
   *   to this hairy code, just preserve the old behavior as though
   *   this code had never been added.
   */

  /* set up the console pty */
  if (openpty(&console_master_fd, &console_slave_fd, NULL, NULL, NULL) == -1)
    console_login(conf, "Cannot allocate pseudo-terminal\n");

  if (redir)
    {
      /* Redirect /dev/console output to the pty slave. */
#ifdef SRIOCSREDIR
      on = open("/dev/console", O_RDONLY);
      if (on >= 0)
	{
	  ioctl(on, SRIOCSREDIR, console_slave_fd);
	  close(on);
	}
#else
#ifdef TIOCCONS
      on = 1;
      ioctl(console_slave_fd, TIOCCONS, &on);
#endif
#endif
    }

  /* Set up the console pipe. */
  if (pipe(conspipe) == -1)
    console_login(conf, "Cannot create pipe for console\n");

  /* start up console */
  start_console(console_master_fd, conspipe[0], consoleargv);

  /* Set up to invoke xlogin. */
  p = getconf(conf, "login");
  if (p == NULL)
    console_login(conf, "\ndm: Can't find login command line\n");
  loginargv = parseargs(p, "-line", utmp_line, NULL);

  /* Fire up the X login */
  for (tries = 0; tries < 3; tries++)
    {
      syslog(LOG_DEBUG, "Starting xlogin, try #%d", tries + 1);
      login_running = STARTUP;
      sigact.sa_handler = loginready;
      sigaction(SIGUSR1, &sigact, NULL);
      switch (fork_and_store(&loginpid))
	{
	case 0:
	  max_fd = sysconf(_SC_OPEN_MAX);
	  for (file = 3; file < max_fd; file++)
	    {
	      if (file != conspipe[1])
		close(file);
	    }

	  setsid();
	  
	  file = open("/dev/null", O_RDONLY);
	  if (file >= 0)
	    {
	      dup2(file, 0);
	      if (file != 0)
		close(file);
	    }
	  
	  file = conspipe[1];
	  if (file == -1)
	    file = open("/dev/null", O_WRONLY);
	  if (file >= 0)
	    {
	      if (file != 1)
		dup2(file, 1);
	      if (file != 2)
		dup2(file, 2);
	      if (file != 1 && file != 2)
		close(file);
	    }

	  (void) sigprocmask(SIG_SETMASK, &sig_zero, (sigset_t *) 0);
	  /* ignoring SIGUSR1 will cause xlogin to send us a SIGUSR1
	   * when it is ready
	   */
	  sigact.sa_handler = SIG_IGN;
	  sigaction(SIGUSR1, &sigact, NULL);
	  /* dm ignores sigpipe; because of this, all of the children (ie, */
	  /* the entire session) inherit this unless we fix it now */
	  sigact.sa_handler = SIG_DFL;
	  sigaction(SIGPIPE, &sigact, NULL);
	  execv(loginargv[0], loginargv);
	  fprintf(stderr, "dm: X login failed exec: %s\n", strerror(errno));
	  _exit(1);
	case -1:
	  fprintf(stderr, "dm: Unable to fork to start X login: %s\n",
		  strerror(errno));
	  break;
	default:
	  alarm(LOGIN_START_WAIT);
	  alarm_running = RUNNING;
	  while (login_running == STARTUP && alarm_running == RUNNING)
	    sigsuspend(&sig_zero);
	  if (login_running != RUNNING)
	    {
	      syslog(LOG_DEBUG, "xlogin failed to start; alarm_running=%d",
		     alarm_running);
	      kill(loginpid, SIGKILL);
	      if (alarm_running != NONEXISTENT)
		fprintf(stderr, "dm: Unable to start Xlogin\n");
	      else
		fprintf(stderr, "dm: Xlogin failed to become ready\n");
	    }
	}
      if (login_running == RUNNING)
	break;
    }
  sigact.sa_handler = SIG_IGN;
  sigaction(SIGUSR1, &sigact, NULL);
  alarm(0);
  if (login_running != RUNNING)
    {
      syslog(LOG_DEBUG, "Giving up on starting xlogin.");
      console_login(conf, "\nUnable to start xlogin, doing console login "
		    "instead.\n");
    }

  /* main loop.  Wait for SIGCHLD, waking up every minute anyway. */
  (void) sigemptyset(&sig_cur);
  (void) sigaddset(&sig_cur, SIGCHLD);
  (void) sigprocmask(SIG_BLOCK, &sig_cur, NULL);
  while (1)
    {
      /* Wait for something to hapen */
      if (console_failed)
	{
	  /* if no console is running, we must copy bits from the console
	   * (master side of pty) to the real console to appear as black
	   * bar messages.
	   */
	  FD_ZERO(&readfds);
	  FD_SET(console_master_fd, &readfds);
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, &mask);
	  count = select(console_master_fd + 1, &readfds, NULL, NULL, NULL);
	  (void) sigprocmask(SIG_BLOCK, &mask, NULL);
	  if (count > 0 && FD_ISSET(console_master_fd, &readfds))
	    {
	      file = read(console_master_fd, buf, sizeof(buf));
	      if (file != -1)
		write(1, buf, file);
	    }
	}
      else
	{
	  alarm(60);
	  sigsuspend(&sig_zero);
	}

      if (login_running == STARTUP)
	{
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, NULL);
	  console_login(conf, "\nConsole login requested.\n");
	}
      if (console_running == FAILED)
	{
	  console_running = NONEXISTENT;
	  time(&now);
	  if (now - last_console_failure <= 3)
	    {
	      /* Give up on console.  Set the console characteristics so
	       * we don't lose later. */
	      syslog(LOG_ERR, "Giving up on the console");
	      setpgid(0, pgrp = getpid());	/* Reset the tty pgrp */
	      tcsetpgrp(0, pgrp);
	      console_failed = TRUE;
	    }
	  else
	    last_console_failure = now;
	}
      if (console_running == NONEXISTENT && !console_failed)
	start_console(console_master_fd, conspipe[0], consoleargv);
      if (login_running == NONEXISTENT || x_running == NONEXISTENT)
	{
	  syslog(LOG_DEBUG, "login_running=%d, x_running=%d, quitting",
		 login_running, x_running);
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, NULL);
	  cleanup(utmp_line);
	  _exit(0);
	}
    }
}
コード例 #29
0
ファイル: rlogind.c プロジェクト: Jactry/shishi
int main(int argc, char **argv) {
	struct sockaddr_storage peer_sa;
	struct sockaddr *peer = (struct sockaddr *)&peer_sa;
	int peerlen = sizeof(peer_sa);
	
	char user[1024];
	char luser[1024];
	char term[1024];
		
	int port;
	
	struct passwd *pw;
	
	int err;
	
	char opt;

	char host[NI_MAXHOST];
	
	char buf[4096];
	int len;
	
	struct pollfd pfd[3];
	
	struct winsize winsize;
	uint16_t winbuf[4];
	int i;
	
	int master, slave;
	char *tty;

	pam_handle_t *handle;		
	struct pam_conv conv = {conv_h, NULL};
	const void *item;
	char *pamuser;
	
	int pid;
	
	argv0 = argv[0];
	
	/* Process options */
			
	while((opt = getopt(argc, argv, "+")) != -1) {
		switch(opt) {
			default:
				syslog(LOG_ERR, "Unknown option!");
				usage();
				return 1;
		}
	}
	
	if(optind != argc) {
		syslog(LOG_ERR, "Too many arguments!");
		usage();
		return 1;
	}
	
	/* Check source of connection */
	
	if(getpeername(0, peer, &peerlen)) {
		syslog(LOG_ERR, "Can't get address of peer: %m");
		return 1;
	}
	
	/* Unmap V4MAPPED addresses */
	
	if(peer->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)peer)->sin6_addr)) {
		((struct sockaddr_in *)peer)->sin_addr.s_addr = ((struct sockaddr_in6 *)peer)->sin6_addr.s6_addr32[3];
		peer->sa_family = AF_INET;
	}

	/* Lookup hostname */
	
	if((err = getnameinfo(peer, peerlen, host, sizeof(host), NULL, 0, 0))) {
		syslog(LOG_ERR, "Error resolving address: %s", gai_strerror(err));
		return 1;
	}
	
	/* Check if connection comes from a privileged port */
	
	switch(peer->sa_family) {
		case AF_INET:
			port = ntohs(((struct sockaddr_in *)peer)->sin_port);
			break;
		case AF_INET6:
			port = ntohs(((struct sockaddr_in6 *)peer)->sin6_port);
			break;
		default:
			port = -1;
			break;
	}

	if(port != -1 && (port < 512 || port >= 1024)) {
		syslog(LOG_ERR, "Connection from %s on illegal port %d.", host, port);
		return 1;
	}
	
	/* Wait for NULL byte */
	
	if(read(0, buf, 1) != 1 || *buf) {
		syslog(LOG_ERR, "Didn't receive NULL byte from %s: %m\n", host);
		return 1;
	}

	/* Read usernames and terminal info */
	
	if(readtonull(0, user, sizeof(user)) <= 0 || readtonull(0, luser, sizeof(luser)) <= 0) {
		syslog(LOG_ERR, "Error while receiving usernames from %s: %m", host);
		return 1;
	}
	
	if(readtonull(0, term, sizeof(term)) <= 0) {
		syslog(LOG_ERR, "Error while receiving terminal from %s: %m", host);
		return 1;
	}
	
	syslog(LOG_NOTICE, "Connection from %s@%s for %s", user, host, luser);
	
	/* We need to have a pty before we can use PAM */
	
	if(openpty(&master, &slave, 0, 0, &winsize) != 0) {
		syslog(LOG_ERR, "Could not open pty: %m");
		return 1;
	}
	
	tty = ttyname(slave);

	/* Start PAM */
	
	if((err = pam_start("rlogin", luser, &conv, &handle)) != PAM_SUCCESS) {
		safewrite(1, "Authentication failure\n", 23);
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}
		
	pam_set_item(handle, PAM_USER, luser);
	pam_set_item(handle, PAM_RUSER, user);
	pam_set_item(handle, PAM_RHOST, host);
	pam_set_item(handle, PAM_TTY, tty);

	/* Write NULL byte to client so we can give a login prompt if necessary */
	
	if(safewrite(1, "", 1) == -1) {
		syslog(LOG_ERR, "Unable to write NULL byte: %m");
		return 1;
	}
	
	/* Try to authenticate */
	
	err = pam_authenticate(handle, 0);
	
	/* PAM might ask for a new password */
	
	if(err == PAM_NEW_AUTHTOK_REQD) {
		err = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK);
		if(err == PAM_SUCCESS)
			err = pam_authenticate(handle, 0);
	}
	
	if(err != PAM_SUCCESS) {
		safewrite(1, "Authentication failure\n", 23);
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}

	/* Check account */
	
	err = pam_acct_mgmt(handle, 0);
	
	if(err != PAM_SUCCESS) {
		safewrite(1, "Authentication failure\n", 23);
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}

	/* PAM can map the user to a different user */
	
	err = pam_get_item(handle, PAM_USER, &item);
	
	if(err != PAM_SUCCESS) {
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}
	
	pamuser = strdup((char *)item);
	
	if(!pamuser || !*pamuser) {
		syslog(LOG_ERR, "PAM didn't return a username?!");
		return 1;
	}

	pw = getpwnam(pamuser);

	if (!pw) {
		syslog(LOG_ERR, "PAM_USER does not exist?!");
		return 1;
	}
	
	if (setgid(pw->pw_gid)) {
		syslog(LOG_ERR, "setgid() failed: %m");
		return 1;
	}
	
	if (initgroups(pamuser, pw->pw_gid)) {
		syslog(LOG_ERR, "initgroups() failed: %m");
		return 1;
	}
	
	err = pam_setcred(handle, PAM_ESTABLISH_CRED);
	
	if(err != PAM_SUCCESS) {
		syslog(LOG_ERR, "PAM error: %s", pam_strerror(handle, err));
		return 1;
	}
	
	/* Authentication succeeded */
	
	pam_end(handle, PAM_SUCCESS);
	
	/* spawn login shell */
	
	if((pid = fork()) < 0) {
		syslog(LOG_ERR, "fork() failed: %m");
		return 1;
	}
	
	if(send(1, "\x80", 1, MSG_OOB) <= 0) {
		syslog(LOG_ERR, "Unable to write OOB \x80: %m");
		return 1;
	}
	
	if(pid) {
		/* Parent process, still the rlogin server */
		
		close(slave);

		/* Process input/output */

		pfd[0].fd = 0;
		pfd[0].events = POLLIN | POLLERR | POLLHUP;
		pfd[1].fd = master;
		pfd[1].events = POLLIN | POLLERR | POLLHUP;
		
		for(;;) {
			errno = 0;

			if(poll(pfd, 2, -1) == -1) {
				if(errno == EINTR)
					continue;
				break;
			}

			if(pfd[0].revents) {
				len = read(0, buf, sizeof(buf));
				if(len <= 0)
					break;

				/* Scan for control messages. Yes this is evil and should be done differently. */
				
				for(i = 0; i < len - 11;) {
					if(buf[i++] == (char)0xFF)
					if(buf[i++] == (char)0xFF)
					if(buf[i++] == 's')
					if(buf[i++] == 's') {
						memcpy(winbuf, buf + i, 8);
						winsize.ws_row = ntohs(winbuf[0]);
						winsize.ws_col = ntohs(winbuf[1]);
						winsize.ws_xpixel = ntohs(winbuf[2]);
						winsize.ws_ypixel = ntohs(winbuf[3]);
						if(ioctl(master, TIOCSWINSZ, &winsize) == -1)
							break;
						memcpy(buf + i - 4, buf + i + 8, len - i - 8);
						i -= 4;
						len -= 12;
					}
				}
				
				if(safewrite(master, buf, len) == -1)
					break;
				pfd[0].revents = 0;
			}

			if(pfd[1].revents) {
				len = read(master, buf, sizeof(buf));
				if(len <= 0) {
					errno = 0;
					break;
				}
				if(safewrite(1, buf, len) == -1)
					break;
				pfd[1].revents = 0;
			}
		}

		/* The end */
		
		if(errno) {
			syslog(LOG_NOTICE, "Closing connection with %s@%s: %m", user, host);
			return 1;
		} else {
			syslog(LOG_NOTICE, "Closing connection with %s@%s", user, host);
			return 0;
		}
		
		close(master);
	} else {
		/* Child process, will become the shell */
		
		char *speed;
		struct termios tios;
		char *envp[2];

		/* Prepare tty for login */

		close(master);
		if(login_tty(slave)) {
			syslog(LOG_ERR, "login_tty() failed: %m");
			return 1;
		}

		/* Fix terminal type and speed */
		
		tcgetattr(0, &tios);

		if((speed = strchr(term, '/'))) {
			*speed++ = '\0';
			cfsetispeed(&tios, atoi(speed));
			cfsetospeed(&tios, atoi(speed));
		}
		
		tcsetattr(0, TCSADRAIN, &tios);

		/* Create environment */

		asprintf(&envp[0], "TERM=%s", term);
		envp[1] = NULL;

		/* Spawn login process */
		
		execle("/bin/login", "login", "-p", "-h", host, "-f", pamuser, NULL, envp);

		syslog(LOG_ERR, "Failed to spawn login process: %m");
		return 1;
	}
}
コード例 #30
0
IProcess* UnixProcessImpl::Execute(
    wxEvtHandler* parent, const wxString& cmd, size_t flags, const wxString& workingDirectory, IProcessCallback* cb)
{
    wxUnusedVar(flags);

    make_argv(cmd);
    if(argc == 0) {
        return NULL;
    }

    // fork the child process
    wxString curdir = wxGetCwd();

    // Prentend that we are a terminal...
    int master, slave;
    openpty(&master, &slave, NULL, NULL, NULL);

    int rc = fork();
    if(rc == 0) {
        login_tty(slave);
        close(master); // close the un-needed master end

        // at this point, slave is used as stdin/stdout/stderr
        // Child process
        if(workingDirectory.IsEmpty() == false) {
            wxSetWorkingDirectory(workingDirectory);
        }

        // execute the process
        execvp(argv[0], argv);

        // if we got here, we failed...
        exit(0);

    } else if(rc < 0) {
        // Error

        // restore the working directory
        wxSetWorkingDirectory(curdir);

        return NULL;

    } else {

        // Parent
        close(slave);
        freeargv(argv);
        argc = 0;

        // disable ECHO
        struct termios termio;
        tcgetattr(master, &termio);
        termio.c_lflag = ICANON;
        termio.c_oflag = ONOCR | ONLRET;
        tcsetattr(master, TCSANOW, &termio);

        // restore the working directory
        wxSetWorkingDirectory(curdir);

        UnixProcessImpl* proc = new UnixProcessImpl(parent);
        proc->m_callback = cb;
        proc->SetReadHandle(master);
        proc->SetWriteHandler(master);
        proc->SetPid(rc);
        proc->m_flags = flags; // Keep the creation flags

        if(!(proc->m_flags & IProcessCreateSync)) {
            proc->StartReaderThread();
        }
        return proc;
    }
}