-/* $OpenBSD: session.c,v 1.238 2008/05/09 16:16:06 markus Exp $ */
+/* $OpenBSD: session.c,v 1.251 2010/01/12 08:33:17 dtucker Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
#include <kafs.h>
#endif
+#define IS_INTERNAL_SFTP(c) \
+ (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
+ (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
+ c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
+ c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
+
/* func */
Session *session_new(void);
-void session_set_fds(Session *, int, int, int);
+void session_set_fds(Session *, int, int, int, int);
void session_pty_cleanup(Session *);
void session_proctitle(Session *);
int session_setup_x11fwd(Session *);
static int sessions_nalloc = 0;
static Session *sessions = NULL;
-#define SUBSYSTEM_NONE 0
-#define SUBSYSTEM_EXT 1
-#define SUBSYSTEM_INT_SFTP 2
+#define SUBSYSTEM_NONE 0
+#define SUBSYSTEM_EXT 1
+#define SUBSYSTEM_INT_SFTP 2
+#define SUBSYSTEM_INT_SFTP_ERROR 3
#ifdef HAVE_LOGIN_CAP
login_cap_t *lc;
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, "auth socket", 1);
- strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
+ nc->path = xstrdup(auth_sock_name);
return 1;
authsock_err:
signal(WJSIGNAL, cray_job_termination_handler);
#endif /* _UNICOS */
#ifdef HAVE_CYGWIN
- if (is_winnt)
- cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+ cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
s->pid = pid;
close(perr[0]);
perr[0] = -1;
}
- session_set_fds(s, pin[1], pout[0], perr[0]);
+ session_set_fds(s, pin[1], pout[0], perr[0], 0);
} else {
/* Enter the interactive session. */
server_loop(pid, pin[1], pout[0], perr[0]);
*/
if (compat20) {
session_set_fds(s, inout[1], inout[1],
- s->is_subsystem ? -1 : err[1]);
+ s->is_subsystem ? -1 : err[1], 0);
if (s->is_subsystem)
close(err[1]);
} else {
* Do common processing for the child, such as execing
* the command.
*/
- do_child(s, command);
- /* NOTREACHED */
+ do_child(s, command);
+ /* NOTREACHED */
default:
break;
}
signal(WJSIGNAL, cray_job_termination_handler);
#endif /* _UNICOS */
#ifdef HAVE_CYGWIN
- if (is_winnt)
- cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+ cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
s->pid = pid;
s->ptymaster = ptymaster;
packet_set_interactive(1);
if (compat20) {
- session_set_fds(s, ptyfd, fdout, -1);
+ session_set_fds(s, ptyfd, fdout, -1, 1);
} else {
server_loop(pid, ptyfd, fdout, -1);
/* server_loop _has_ closed ptyfd and fdout. */
if (options.adm_forced_command) {
original_command = command;
command = options.adm_forced_command;
- if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
- s->is_subsystem = SUBSYSTEM_INT_SFTP;
- else if (s->is_subsystem)
+ if (IS_INTERNAL_SFTP(command)) {
+ s->is_subsystem = s->is_subsystem ?
+ SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
+ } else if (s->is_subsystem)
s->is_subsystem = SUBSYSTEM_EXT;
debug("Forced command (config) '%.900s'", command);
} else if (forced_command) {
original_command = command;
command = forced_command;
- if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
- s->is_subsystem = SUBSYSTEM_INT_SFTP;
- else if (s->is_subsystem)
+ if (IS_INTERNAL_SFTP(command)) {
+ s->is_subsystem = s->is_subsystem ?
+ SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
+ } else if (s->is_subsystem)
s->is_subsystem = SUBSYSTEM_EXT;
debug("Forced command (key option) '%.900s'", command);
}
fromlen = sizeof(from);
if (packet_connection_is_on_socket()) {
if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & from, &fromlen) < 0) {
+ (struct sockaddr *)&from, &fromlen) < 0) {
debug("getpeername: %.100s", strerror(errno));
cleanup_exit(255);
}
/*
* Sets the value of the given variable in the environment. If the variable
- * already exists, its value is overriden.
+ * already exists, its value is overridden.
*/
void
child_set_env(char ***envp, u_int *envsizep, const char *name,
u_int i, envsize;
char **env, *laddr;
struct passwd *pw = s->pw;
-#ifndef HAVE_LOGIN_CAP
+#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
char *path = NULL;
#endif
do_nologin(struct passwd *pw)
{
FILE *f = NULL;
- char buf[1024];
+ char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
+ struct stat sb;
#ifdef HAVE_LOGIN_CAP
- if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
- f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
- _PATH_NOLOGIN), "r");
+ if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+ return;
+ nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
#else
- if (pw->pw_uid)
- f = fopen(_PATH_NOLOGIN, "r");
+ if (pw->pw_uid == 0)
+ return;
+ nl = def_nl;
#endif
- if (f) {
- /* /etc/nologin exists. Print its contents and exit. */
- logit("User %.100s not allowed because %s exists",
- pw->pw_name, _PATH_NOLOGIN);
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stderr);
- fclose(f);
- fflush(NULL);
- exit(254);
+ if (stat(nl, &sb) == -1) {
+ if (nl != def_nl)
+ xfree(nl);
+ return;
}
+
+ /* /etc/nologin exists. Print its contents if we can and exit. */
+ logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
+ if ((f = fopen(nl, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), f))
+ fputs(buf, stderr);
+ fclose(f);
+ }
+ exit(254);
}
/*
if (getuid() == 0 || geteuid() == 0)
#endif /* HAVE_CYGWIN */
{
-
-#ifdef HAVE_SETPCRED
- if (setpcred(pw->pw_name, (char **)NULL) == -1)
- fatal("Failed to set process credentials");
-#endif /* HAVE_SETPCRED */
#ifdef HAVE_LOGIN_CAP
# ifdef __bsdi__
setpgid(0, 0);
free(chroot_path);
}
+#ifdef HAVE_SETPCRED
+ if (setpcred(pw->pw_name, (char **)NULL) == -1)
+ fatal("Failed to set process credentials");
+#endif /* HAVE_SETPCRED */
#ifdef HAVE_LOGIN_CAP
if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
perror("unable to set user context (setuser)");
#endif
}
-#ifdef HAVE_CYGWIN
- if (is_winnt)
-#endif
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
char *argv[ARGV_MAX];
const char *shell, *shell0, *hostname = NULL;
struct passwd *pw = s->pw;
+ int r = 0;
/* remove hostkey from the child's memory */
destroy_sensitive_data();
/* Change current directory to the user's home directory. */
if (chdir(pw->pw_dir) < 0) {
- fprintf(stderr, "Could not chdir to home directory %s: %s\n",
- pw->pw_dir, strerror(errno));
+ /* Suppress missing homedir warning for chroot case */
#ifdef HAVE_LOGIN_CAP
- if (login_getcapbool(lc, "requirehome", 0))
- exit(1);
+ r = login_getcapbool(lc, "requirehome", 0);
#endif
+ if (r || options.chroot_directory == NULL)
+ fprintf(stderr, "Could not chdir to home "
+ "directory %s: %s\n", pw->pw_dir,
+ strerror(errno));
+ if (r)
+ exit(1);
}
closefrom(STDERR_FILENO + 1);
/* restore SIGPIPE for child */
signal(SIGPIPE, SIG_DFL);
- if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
+ if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
+ printf("This service allows sftp connections only.\n");
+ fflush(NULL);
+ exit(1);
+ } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
extern int optind, optreset;
int i;
char *p, *args;
- setproctitle("%s@internal-sftp-server", s->pw->pw_name);
- args = strdup(command ? command : "sftp-server");
+ setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
+ args = xstrdup(command ? command : "sftp-server");
for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
if (i < ARGV_MAX - 1)
argv[i++] = p;
argv[i] = NULL;
optind = optreset = 1;
__progname = argv[0];
+#ifdef WITH_SELINUX
+ ssh_selinux_change_context("sftpd_t");
+#endif
exit(sftp_server_main(i, argv, s->pw));
}
+ fflush(NULL);
+
if (options.use_login) {
launch_login(pw, hostname);
/* NEVERREACHED */
if (strcmp(subsys, options.subsystem_name[i]) == 0) {
prog = options.subsystem_command[i];
cmd = options.subsystem_args[i];
- if (!strcmp(INTERNAL_SFTP_NAME, prog)) {
+ if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
s->is_subsystem = SUBSYSTEM_INT_SFTP;
- } else if (stat(prog, &st) < 0) {
- error("subsystem: cannot stat %s: %s", prog,
- strerror(errno));
- break;
+ debug("subsystem: %s", prog);
} else {
+ if (stat(prog, &st) < 0)
+ debug("subsystem: cannot stat %s: %s",
+ prog, strerror(errno));
s->is_subsystem = SUBSYSTEM_EXT;
+ debug("subsystem: exec() %s", cmd);
}
- debug("subsystem: exec() %s", cmd);
success = do_exec(s, cmd) == 0;
break;
}
}
void
-session_set_fds(Session *s, int fdin, int fdout, int fderr)
+session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty)
{
if (!compat20)
fatal("session_set_fds: called for proto != 2.0");
channel_set_fds(s->chanid,
fdout, fdin, fderr,
fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
- 1,
- CHAN_SES_WINDOW_DEFAULT);
+ 1, is_tty, CHAN_SES_WINDOW_DEFAULT);
}
/*